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
¶
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 roughlybackend.resolutionfor 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:AdhesiveBoundarytogether 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:RelaxationScheduledecaying from 1.9 → 1.0 over the run.- :class:
RelaxationSchedule— explicit(start, decay, minimum). - callable
(iteration: int) -> float— fully custom schedule.
- float — constant factor at every iteration.
-
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:AdhesiveBoundaryto 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_byin :func:~carto_flow.voronoi_cartogram.create_voronoi_cartogram). When set,adjacency_springapplies only to cross-group adjacent pairs andintra_group_springapplies only to same-group adjacent pairs. Use a higher value thanadjacency_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_springthen 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. Setrelaxation=0.0for pure FFT-flow mode (no Lloyd centroid updates).
- :class:
-
distance_mode(('euclidean', 'geodesic'), default:"euclidean") –Pixel-to-centroid distance algorithm.
"euclidean"cKDTree nearest-neighbor (default, fastest). Compatible witharea_equalizer_rate > 0."geodesic"Multi-source BFS; wavefront cannot cross inactive (water) pixels, eliminating cross-bay assignments.area_equalizer_rateis 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 thatdist² - λᵢdrives cells toward equal area. Ignored whenweightsare provided (useweight_ramp_itersinstead). Default0.1. Ignored whendistance_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. Default10. -
output_resolution(int or None, default:None) –Upsampled grid resolution used only for final cell extraction when
distance_mode="geodesic"orarea_equalizer_rate > 0. Ignored for plain euclidean witharea_equalizer_rate=0.None= same asresolution. -
cell_smoothing_px(float, default:3.0) –Tolerance for smoothing pixel staircases on extracted cells, in final-grid pixels (the extraction grid is
output_resolutionor 4xresolution). Resolution-independent by construction. For cartographic generalisation in map units, apply :func:carto_flow.geo_utils.simplify_coverageto the result instead.0disables smoothing. Default3.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
¶
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 towardminimum. -
minimum(float, default:1.0) –Floor value after decay.
1.0(default) transitions to standard Lloyd in the final iterations.