Skip to content

carto_flow.voronoi_cartogram.backends

Backend objects for create_voronoi_cartogram.

Each backend encapsulates algorithm-specific parameters and factory methods. api.py calls build_field() and relax_step() without knowing which concrete field class is in use.

Classes:

  • AdhesiveBoundary –

    Snap boundary centroids toward the outer boundary after each Lloyd step.

  • ElasticBoundary –

    FFT-driven elastic boundary deformation (RasterBackend only).

  • ExactBackend –

    Exact scipy Voronoi + shapely clipping backend (Lloyd relaxation).

  • RasterBackend –

    Raster nearest-neighbor Lloyd relaxation backend.

  • RelaxationSchedule –

    Decaying successive over-relaxation (SOR) schedule.

AdhesiveBoundary dataclass

AdhesiveBoundary(strength: float = 0.3)

Snap boundary centroids toward the outer boundary after each Lloyd step.

Parameters:

  • strength (float, default: 0.3 ) –

    Adhesion strength in [0, 1]. 1.0 = full snap to boundary; 0.3-0.5 = partial pull. Only affects centroids whose original geometry intersects the outer boundary.

ElasticBoundary dataclass

ElasticBoundary(
    strength: float = 0.3,
    step_scale: float = 1.0,
    density_smooth: float | None = None,
    min_boundary_points: int | None = None,
    adhesion_strength: float = 0.0,
)

FFT-driven elastic boundary deformation (RasterBackend only).

Each iteration the outer boundary is deformed by a velocity field driven by cell-area pressure, allowing the outer shape to adapt to the centroid distribution. Set relaxation=0.0 in :class:RasterBackend for pure FFT-flow mode (no Lloyd centroid updates).

Parameters:

  • strength (float, default: 0.3 ) –

    Deformation strength in [0, 1]. 0 = rigid hard-clip.

  • step_scale (float, default: 1.0 ) –

    Boundary advection speed as a fraction of the centroid advection speed, in (0, 1]. 1.0 = boundary and centroids co-advect at the same rate. Values < 1 make the boundary move more slowly.

  • density_smooth (float or None, default: None ) –

    Gaussian smoothing sigma applied to the density field before solving the FFT velocity field. None = no smoothing.

  • min_boundary_points (int or None, default: None ) –

    Minimum number of vertices to distribute along the boundary for elastic deformation tracking. Simple shapes such as "bbox" or "convex_hull" have only a handful of corners after internal simplification — set this to roughly backend.resolution for smooth deformation. None (default) uses whatever vertices remain after simplification, which preserves the original behavior for complex union boundaries.

  • adhesion_strength (float, default: 0.0 ) –

    Snap strength for boundary-touching centroids in [0, 1]. 0 (default) = no snapping. When > 0, centroids whose original geometry touches the outer boundary are pulled toward the current deformed boundary after each elastic step — combining the elastic shape change with centroid adhesion in one pass. Equivalent to using :class:AdhesiveBoundary together with elastic deformation, but with the snap target tracking the evolving boundary shape.

ExactBackend dataclass

ExactBackend(
    relaxation: float
    | str
    | RelaxationSchedule
    | Callable[[int], float] = "overrelax",
    adjacency_spring: float = 0.0,
    intra_group_spring: float | None = None,
    boundary: AdhesiveBoundary | None = None,
)

Exact scipy Voronoi + shapely clipping backend (Lloyd relaxation).

Parameters:

  • relaxation (float, str, RelaxationSchedule, or callable, default: 'overrelax' ) –

    Relaxation factor schedule. Accepted forms:

    • float — constant factor at every iteration. 1.0 = standard Lloyd; values above 1 overshoot (faster convergence).
    • "lloyd" — constant 1.0 (standard Lloyd).
    • "overrelax" (default) — :class:RelaxationSchedule decaying from 1.9 → 1.0 over the run.
    • :class:RelaxationSchedule — explicit (start, decay, minimum).
    • callable (iteration: int) -> float — fully custom schedule.
  • adjacency_spring (float, default: 0.0 ) –

    Strength of the spring force pulling input-adjacent centroids together, blended into each Lloyd step. 0 = pure Lloyd. Values of 0.1-0.3 gently prevent neighboring centroids from drifting apart.

  • boundary (AdhesiveBoundary or None, default: None ) –

    Boundary snap behavior. None = off. Pass :class:AdhesiveBoundary to snap boundary centroids toward the outer boundary after each step.

Examples:

>>> from carto_flow import create_voronoi_cartogram, ExactBackend, VoronoiOptions
>>> result = create_voronoi_cartogram(
...     gdf,
...     backend=ExactBackend(relaxation=RelaxationSchedule(start=1.9, decay=0.95)),
...     options=VoronoiOptions(n_iter=100),
... )

RasterBackend dataclass

RasterBackend(
    resolution: int = 300,
    relaxation: float
    | str
    | RelaxationSchedule
    | Callable[[int], float] = "overrelax",
    adjacency_spring: float = 0.0,
    intra_group_spring: float | None = None,
    boundary: AdhesiveBoundary
    | ElasticBoundary
    | None = None,
    distance_mode: Literal[
        "euclidean", "geodesic"
    ] = "euclidean",
    area_equalizer_rate: float = 0.1,
    weight_ramp_iters: int = 10,
    output_resolution: int | None = None,
    cell_smoothing_px: float = 3.0,
)

Raster nearest-neighbor Lloyd relaxation backend.

Uses a precomputed grid of land pixels for Voronoi labeling — typically 10-50x faster than the exact scipy backend.

Parameters:

  • resolution (int, default: 300 ) –

    Grid resolution applied to the longest bounding-box dimension; the shorter dimension is scaled proportionally. 200-400 is a good starting point.

  • relaxation (float, str, RelaxationSchedule, or callable, default: 'overrelax' ) –

    Relaxation factor schedule (see :class:ExactBackend).

  • adjacency_spring (float, default: 0.0 ) –

    Spring force strength for input-adjacent centroids (see :class:ExactBackend).

  • intra_group_spring (float or None, default: None ) –

    Spring force strength applied to centroids that belong to the same group (as specified via group_by in :func:~carto_flow.voronoi_cartogram.create_voronoi_cartogram). When set, adjacency_spring applies only to cross-group adjacent pairs and intra_group_spring applies only to same-group adjacent pairs. Use a higher value than adjacency_spring (e.g. adjacency_spring=0.1, intra_group_spring=0.5) to keep districts within the same state/region spatially cohesive. None (default) disables the intra-group spring; adjacency_spring then applies to all adjacent pairs regardless of group membership.

  • boundary (AdhesiveBoundary, ElasticBoundary, or None, default: None ) –

    Boundary behavior. None = rigid hard-clip (default).

    • :class:AdhesiveBoundary — snap boundary centroids toward the outer boundary after each step.
    • :class:ElasticBoundary — deform the outer boundary each iteration via an FFT velocity field. Set relaxation=0.0 for pure FFT-flow mode (no Lloyd centroid updates).
  • distance_mode (('euclidean', 'geodesic'), default: "euclidean" ) –

    Pixel-to-centroid distance algorithm.

    "euclidean" cKDTree nearest-neighbor (default, fastest). Compatible with area_equalizer_rate > 0. "geodesic" Multi-source BFS; wavefront cannot cross inactive (water) pixels, eliminating cross-bay assignments. area_equalizer_rate is ignored in this mode. Weights are not supported in geodesic mode (ignored with a warning).

  • area_equalizer_rate (float, default: 0.1 ) –

    Learning rate for the power-diagram area equaliser (distance_mode="euclidean" only, unweighted case). Each iteration, per-centroid offsets λᵢ are updated so that dist² - λᵢ drives cells toward equal area. Ignored when weights are provided (use weight_ramp_iters instead). Default 0.1. Ignored when distance_mode="geodesic".

  • weight_ramp_iters (int, default: 10 ) –

    Number of iterations over which weights are linearly ramped from 1 (uniform) to their target values. Prevents early engulfment when weight ratios are large (e.g. US state populations). 0 = no ramp. Default 10.

  • output_resolution (int or None, default: None ) –

    Upsampled grid resolution used only for final cell extraction when distance_mode="geodesic" or area_equalizer_rate > 0. Ignored for plain euclidean with area_equalizer_rate=0. None = same as resolution.

  • cell_smoothing_px (float, default: 3.0 ) –

    Tolerance for smoothing pixel staircases on extracted cells, in final-grid pixels (the extraction grid is output_resolution or 4x resolution). Resolution-independent by construction. For cartographic generalisation in map units, apply :func:carto_flow.geo_utils.simplify_coverage to the result instead. 0 disables smoothing. Default 3.0.

Examples:

>>> from carto_flow import create_voronoi_cartogram, RasterBackend
>>> result = create_voronoi_cartogram(gdf, backend=RasterBackend(resolution=300))
>>> result = create_voronoi_cartogram(
...     gdf, backend=RasterBackend(resolution=300, distance_mode="geodesic")
... )
>>> result = create_voronoi_cartogram(
...     gdf, backend=RasterBackend(resolution=300, boundary=ElasticBoundary(0.3))
... )

Pure FFT-flow mode (no Lloyd relaxation):

>>> result = create_voronoi_cartogram(
...     gdf,
...     backend=RasterBackend(
...         resolution=300,
...         relaxation=0.0,
...         boundary=ElasticBoundary(strength=0.3, step_scale=0.8),
...         distance_mode="geodesic",
...     ),
... )

RelaxationSchedule dataclass

RelaxationSchedule(
    start: float = 1.9,
    decay: float = 0.98,
    minimum: float = 1.0,
)

Decaying successive over-relaxation (SOR) schedule.

At each iteration i, the relaxation factor is:

.. code-block:: python

max(minimum, start * decay**i)

Parameters:

  • start (float, default: 1.9 ) –

    Initial relaxation factor. 1.0 = standard Lloyd (move straight to cell centroid). Values above 1 overshoot, cutting the number of iterations needed by 3-5x. Values above 2 may diverge.

  • decay (float, default: 0.98 ) –

    Multiplicative factor applied each iteration, in [0, 1]. 1.0 = constant; values below 1 gradually anneal toward minimum.

  • minimum (float, default: 1.0 ) –

    Floor value after decay. 1.0 (default) transitions to standard Lloyd in the final iterations.