Skip to content

carto_flow.voronoi_cartogram.result

Result container for Voronoi cartogram operations.

Classes:

TopologyAnalysis dataclass

TopologyAnalysis(
    discontiguous_groups: list[tuple[Any, list[Any]]],
    violated_adjacency: list[tuple[Any, Any]],
    n_adjacency_pairs: int,
    misaligned_orientation: list[tuple[Any, Any, float]],
    mean_orientation_cosine: float | None,
    degenerate_cells: list[Any] = list(),
)

Topology state of a Voronoi cartogram across all three repair stages.

All identifier fields use the GDF index labels of the source GeoDataFrame (not integer slot positions), making them easy to cross-reference with the original data.

Attributes:

  • discontiguous_groups (list of (group_id, [gdf_label, ...])) –

    One entry per satellite component: the group identifier and the GDF index labels of the cells in that satellite. Empty when group_by was not provided or all groups are fully contiguous.

  • violated_adjacency (list of (label_i, label_j)) –

    Input-adjacent district pairs that are not Voronoi-adjacent in the current tessellation. Empty when adjacency information was not available.

  • n_adjacency_pairs (int) –

    Total number of input-adjacent pairs checked (denominator for :attr:adjacency_fraction). 0 when adjacency was not checked.

  • misaligned_orientation (list of (label_i, label_j, cosine)) –

    Voronoi-adjacent pairs whose relative spatial direction is inverted (cosine similarity ≤ 0) compared to the input geometry directions. Empty when adjacency information was not available.

  • mean_orientation_cosine (float or None) –

    Mean cosine similarity across all Voronoi-adjacent pairs that appear in the input adjacency list. None when adjacency was not available or no Voronoi-adjacent pairs exist.

  • degenerate_cells (list of gdf_label) –

    GDF index labels of cells that collapsed to a Point or a zero-area geometry (see :attr:VoronoiCartogram.degenerate_cells).

Methods:

  • plot –

    Plot topology issues overlaid on the Voronoi cells.

adjacency_fraction property

adjacency_fraction: float | None

Fraction of input-adjacent pairs that ARE Voronoi-adjacent.

None when no adjacency pairs were checked.

any_issues property

any_issues: bool

True if any topology issue exists across all three stages.

n_discontiguous_groups property

n_discontiguous_groups: int

Number of satellite components across all groups.

n_misaligned_orientation property

n_misaligned_orientation: int

Number of Voronoi-adjacent pairs with cosine similarity ≤ 0.

n_violated_adjacency property

n_violated_adjacency: int

Number of input-adjacent pairs that are not Voronoi-adjacent.

plot

plot(
    cartogram: VoronoiCartogram,
    *,
    show_base: bool | None = None,
    show_contiguity: bool = True,
    show_adjacency: bool = True,
    show_orientation: bool = True,
    ax: Any | None = None,
    figsize: tuple[float, float] = (10, 8),
    title: str = "Topology Analysis",
) -> VoronoiPlotResult

Plot topology issues overlaid on the Voronoi cells.

Parameters:

  • cartogram (VoronoiCartogram) –

    The cartogram whose cells provide the spatial context.

  • show_base (bool or None, default: None ) –

    Draw all cells as a gray background layer. None (default) draws the base only when ax is None (new figure); when an existing ax is supplied the base is skipped so prior content is not hidden. Pass True or False to override.

  • show_contiguity (bool, default: True ) –

    Highlight satellite cells (stage 1 issues). Default True.

  • show_adjacency (bool, default: True ) –

    Draw lines between centroids of violated adjacency pairs (stage 2 issues). Default True.

  • show_orientation (bool, default: True ) –

    Draw arrows for misaligned Voronoi-adjacent pairs (stage 3 issues). Default True.

  • ax (matplotlib Axes or None, default: None ) –

    Axes to draw on. A new figure is created if None.

  • figsize (tuple of float, default: (10, 8) ) –

    Figure size when ax is None.

  • title (str, default: 'Topology Analysis' ) –

    Axis title.

Returns:

TopologyRepairReport dataclass

TopologyRepairReport(
    cartogram: VoronoiCartogram,
    before: TopologyAnalysis,
    after: TopologyAnalysis,
    stages_run: list[str],
    reassigned: list[Any],
    _original_cartogram: VoronoiCartogram | None = None,
)

Result of a post-hoc topology repair on a :class:VoronoiCartogram.

Attributes:

  • cartogram (VoronoiCartogram) –

    New cartogram with cells (and positions) permuted to address topology issues. The original cartogram is unchanged.

  • before (TopologyAnalysis) –

    Topology state before repair.

  • after (TopologyAnalysis) –

    Topology state after repair.

  • stages_run (list of str) –

    Repair stages that were executed (subset of ["group_contiguity", "adjacency", "orientation"]).

  • reassigned (list) –

    GDF index labels of districts whose cell assignment changed.

Methods:

  • plot –

    Plot a before/after comparison of the topology repair.

fully_repaired property

fully_repaired: bool

True when no topology issues remain after repair.

improved property

improved: bool

True when at least one issue count decreased.

plot

plot(
    *,
    show_base: bool | None = None,
    show_issues: bool = True,
    show_reassigned: bool = True,
    axes: Any | None = None,
    figsize: tuple[float, float] = (16, 8),
    title: str | None = None,
) -> VoronoiPlotResult

Plot a before/after comparison of the topology repair.

Parameters:

  • show_base (bool or None, default: None ) –

    Draw all cells as a gray background layer in each panel. None (default) draws the base only when axes is None (new figure); when existing axes are supplied the base is skipped so prior content is not hidden. Pass True or False to override.

  • show_issues (bool, default: True ) –

    Overlay topology-issue highlights (satellite cells, violated adjacency lines, misaligned orientation arrows) on both panels. Default True.

  • show_reassigned (bool, default: True ) –

    Highlight reassigned cells in the after panel with a thick green border. Default True.

  • axes (sequence of two Axes, or None, default: None ) –

    Existing axes to draw on. A new (1, 2) figure is created when None.

  • figsize (tuple of float, default: (16, 8) ) –

    Figure size when axes is None. Default (16, 8).

  • title (str or None, default: None ) –

    Figure suptitle. Defaults to "Topology Repair — {stages_run}".

Returns:

Notes

When :attr:_original_cartogram is None (e.g., the report was reconstructed from disk), only the after panel is rendered and a UserWarning is emitted.

VoronoiCartogram dataclass

VoronoiCartogram(
    positions: ndarray,
    cells: ndarray,
    metrics: dict[str, Any],
    options: VoronoiOptions,
    _source_gdf: GeoDataFrame | None = None,
    convergence_history: list[float] = list(),
    history: History | None = None,
    _field: Any = None,
    area_errors: ndarray | None = None,
    _weighted: bool = False,
)

Result of a Voronoi cartogram (Lloyd relaxation) computation.

Attributes:

  • positions ((ndarray, shape(G, 2))) –

    Final centroid positions after relaxation.

  • cells (np.ndarray of shapely.Geometry, shape (G,)) –

    Voronoi cell polygon for each centroid, clipped to the outer boundary.

  • metrics (dict) –

    Scalar summary of the run:

    • "n_iterations": number of iterations completed
    • "converged": True if the displacement tolerance was reached before n_iter was exhausted
    • "initial_area_cv": coefficient of variation of the input geometry areas before any relaxation (baseline for comparison)
    • "final_area_cv": coefficient of variation of cell areas at the last iteration (0 = perfect equal-area distribution)
    • "mean_area_error_pct": mean absolute area error (%) across all cells, where error = (actual_area / target_area - 1) x 100. A degenerate cell (see :attr:degenerate_cells) has zero area and so contributes an error of -100%.
    • "max_area_error_pct": maximum absolute area error (%) across all cells. A degenerate cell counts as -100%.
  • options (VoronoiOptions) –

    Options used for this run.

  • convergence_history (list of float) –

    Area CV recorded after each completed iteration, in order. Length equals metrics["n_iterations"].

  • history (History or None) –

    Per-iteration snapshots (:class:~carto_flow.voronoi_cartogram.history.VoronoiSnapshot) captured when options.record_history=True. None otherwise.

Methods:

  • analyze_topology –

    Analyze the topology of the current Voronoi tessellation.

  • plot –

    Plot Voronoi cells.

  • plot_displacement –

    Plot centroids and displacement arrows on a single axis.

  • repair_topology –

    Return a new cartogram with topology issues repaired.

  • to_geodataframe –

    Return a GeoDataFrame with original columns and Voronoi cell geometries.

boundary_debug property

boundary_debug: dict[str, ndarray] | None

Diagnostic arrays from the last boundary-deformation step.

Returns None when boundary_elasticity == 0 or when no deformation step has run yet.

Keys

area_pressure : (G,) float Per-centroid fractional density excess at the last iteration: density_i / target_density - 1. Positive = cell is smaller than target (high pressure, boundary expands); negative = cell is larger than target (low pressure, boundary contracts). rho : (ny, nx) float Density field fed to the FFT velocity solver (area_pressure + 1 for active pixels, 1.0 for inactive pixels). vx : (ny, nx) float X-component of the normalized velocity field from the FFT solver. vy : (ny, nx) float Y-component of the normalized velocity field from the FFT solver. vertex_xy : (V, 2) float Current (displaced) boundary vertex positions. vertex_disp : (V,) float Scalar displacement of each vertex from its original position. vertex_disp_vec : (V, 2) float 2-D displacement vector for each vertex (current_position - original_position). Pass the x and y components directly to ax.quiver.

degenerate_cells property

degenerate_cells: list[Any]

Index labels of cells that collapsed to a point or (near-)zero area.

A cell degenerates for one of two reasons:

  • starved generator -- the generator lost all of its raster pixels, typically because the grid resolution is too coarse for the smallest target areas. Raising the backend resolution is the usual remedy.
  • extraction failure -- the generator owns pixels, but converting them to a polygon failed (e.g. the clip against a boundary carrying degenerate rings collapsed the cell). This emits its own RuntimeWarning naming the seed; raising the resolution does not help.

Either way the cell has no area, so it contributes an area error of -100%, is omitted from plots, and is exported by :meth:to_geodataframe as a Point.

A polygon counts as degenerate when its area is below 1e-9 of the mean cell area, which catches slivers that are not exactly zero.

Returns:

  • list –

    GDF index labels of the degenerate cells (integer positions when no source GeoDataFrame is available). Empty when all cells are proper polygons.

geodesic_debug property

geodesic_debug: dict | None

Diagnostic dict from the last geodesic-labeling call.

Returns None when debug_geodesic=False (the default) or when the field has not been labeled yet.

Requires RasterBackend(labeling="geodesic", debug_geodesic=True).

Keys

seed_rows, seed_cols : (n_seeds,) int32 Grid row/column of every placed BFS seed. seed_components : (n_seeds,) int32 scipy component id (1-based) of each seed. centroid_components : (G,) int32 Component id of the nearest active pixel to each original centroid. misplaced_mask : (G,) bool True for centroids whose seed is in a different component than their nearest active pixel. n_misplaced : int Number of misplaced seeds. comp_2d : (ny, nx) int32 Full component label grid (0 = inactive, 1..n = components). unseeded_comp_ids : (k,) int32 Component IDs that had no seed before the fix; non-empty means the fix fired this call. n_unseeded : int Number of components that required an extra seed. unseeded_pixel_mask : (ny, nx) bool Active pixels that belonged to unseeded components. seed_centroid_distances : (G,) float or None Euclidean distance from each centroid to its seed's world position. None if grid coordinate arrays were not available.

analyze_topology

analyze_topology(
    group_by: str | None = None,
    *,
    adj_pairs: list[tuple[int, int]] | None = None,
    group_contiguity: bool | None = None,
    adjacency: bool | None = None,
    orientation: bool | None = None,
    adj_min_shared_length: float | None = None,
) -> TopologyAnalysis

Analyze the topology of the current Voronoi tessellation.

Checks all three topology stages without modifying the cartogram.

Parameters:

  • group_by (str or None, default: None ) –

    Column in the source GeoDataFrame identifying groups (e.g. state for congressional districts). Required for stage 1 (group contiguity). None → stage 1 is skipped.

  • adj_pairs (list of (i, j) or None, default: None ) –

    Input-adjacent district index pairs for stages 2 (adjacency) and 3 (orientation). None → auto-computed from the source GeoDataFrame geometries. If no source GDF is available, stages 2 & 3 are skipped.

  • group_contiguity (bool or None, default: None ) –

    Run stage 1 (group contiguity check). None (default) → True when group_by is provided, False otherwise.

  • adjacency (bool or None, default: None ) –

    Run stage 2 (adjacency violation check). None (default) → True when group_by is None, False otherwise.

  • orientation (bool or None, default: None ) –

    Run stage 3 (orientation alignment check). None (default) → True when group_by is None, False otherwise.

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

    Minimum shared border length for two cells to be considered adjacent. None = no extra filter.

Returns:

  • TopologyAnalysis –

    Snapshot of the current topology state with GDF index labels.

plot

plot(
    column: str | None = None,
    cmap: str | None = None,
    show_edges: bool = True,
    legend: bool = False,
    labels: bool | str | list[str] | None = None,
    label_fontsize: int = 8,
    label_color: str = "black",
    ax: Any | None = None,
    **kwargs: Any,
) -> VoronoiPlotResult

Plot Voronoi cells.

Parameters:

  • column (str or None, default: None ) –

    Column from the source GeoDataFrame to use for choropleth coloring. None (default) colors each cell with a distinct categorical color derived from its index. Pass "area_error_pct" to plot the signed per-cell area error as a diverging choropleth.

  • cmap (str or None, default: None ) –

    Colormap name. Defaults to "tab20" for categorical coloring (column=None), "RdBu_r" for "area_error_pct", and "viridis" for other numeric columns.

  • show_edges (bool, default: True ) –

    Draw cell borders. Default True.

  • legend (bool, default: False ) –

    Show a legend or colorbar. Default False.

  • labels (bool, str, list of str, or None, default: None ) –

    Annotate each cell with a text label. True = index values; str = column name; list[str] = explicit strings; None = no labels (default).

  • label_fontsize (int, default: 8 ) –

    Font size for cell labels. Default 8.

  • label_color (str, default: 'black' ) –

    Text color for cell labels. Default "black".

  • ax (matplotlib Axes or None, default: None ) –

    Axes to draw on. A new figure is created if None.

  • **kwargs (Any, default: {} ) –

    Passed to GeoDataFrame.plot().

Returns:

Examples:

>>> pr = result.plot()
>>> pr.ax.set_title("Equal-area Voronoi")
>>> pr = result.plot(column="population", cmap="Blues", legend=True)
>>> pr = result.plot(column="area_error_pct", legend=True)
>>> pr = result.plot(labels=True)

plot_displacement

plot_displacement(
    *,
    state: str = "final",
    show_geometries: bool = True,
    show_centroids: bool = True,
    show_adjacency: bool = True,
    show_positions: bool = False,
    show_displacement: bool = True,
    legend: bool = True,
    geometry_style: dict | None = None,
    adjacency_style: dict | None = None,
    centroid_style: dict | None = None,
    position_style: dict | None = None,
    displacement_style: dict | None = None,
    ax: Any | None = None,
    figsize: tuple[float, float] = (10, 8),
    title: str = "Voronoi cartogram — centroid redistribution",
) -> VoronoiPlotResult

Plot centroids and displacement arrows on a single axis.

Parameters:

  • state (('original', 'final'), default: "original" ) –

    Which state to visualize. "original" draws the source geometries and their centroids; "final" (default) draws the Voronoi cells and their centroids. Displacement arrows always run original → final regardless of this setting.

  • show_geometries (bool, default: True ) –

    Draw geometry polygons behind the centroid scatter. Default True.

  • show_centroids (bool, default: True ) –

    Draw centroid scatter markers. Default True.

  • show_adjacency (bool, default: True ) –

    Draw adjacency graph edges. Default True.

  • show_positions (bool, default: False ) –

    Also scatter self.positions (the Lloyd generator points) as a secondary marker (only used when state="final"). Default False.

  • show_displacement (bool, default: True ) –

    Draw colored arrows from original to final cell-centroid positions. Default True.

  • legend (bool, default: True ) –

    Show the displacement-magnitude colorbar (and any other legends). Default True.

  • geometry_style (dict or None, default: None ) –

    Styling for geometry polygons, merged over defaults {"facecolor": "#e8eef4", "edgecolor": "#9aafc4", "linewidth": 0.4, "alpha": 0.6}. All keys forwarded to GeoDataFrame.plot().

    The "color" key supports multi-type resolution:

    • str matching a column → choropleth; use "cmap" (default "Blues") to set the colormap.
    • any other str → solid fill color.
    • 1-D numeric array → per-geometry values mapped via "cmap".
    • list/array of color strings → per-geometry colors.
  • adjacency_style (dict or None, default: None ) –

    Styling for adjacency graph edges, merged over defaults {"color": "#6b8fa8", "linewidth": 0.6, "alpha": 0.5, "zorder": 2}. All keys forwarded to ax.plot().

  • centroid_style (dict or None, default: None ) –

    Styling for centroid scatter markers, merged over defaults {"s": 18, "c": "#1a5276", "zorder": 3, "linewidths": 0}. All keys forwarded to ax.scatter().

    The "c" (or "color") key supports the same multi-type resolution as geometry_style["color"]; use "cmap" (default "viridis") for column/numeric cases.

  • position_style (dict or None, default: None ) –

    Styling for the self.positions generator-point overlay (only used when show_positions=True), merged over defaults {"s": 14, "marker": "x", "c": "#e74c3c", "zorder": 5, "linewidths": 0.8}. All keys forwarded to ax.scatter().

  • displacement_style (dict or None, default: None ) –

    Styling for displacement arrows, merged over defaults {"cmap": "plasma", "lw": 0.9, "mutation_scale": 6, "arrowstyle": "-|>", "min_frac": 0.01}.

    • "cmap" — arrow/colorbar colormap.
    • "min_frac" — skip arrows whose magnitude is below this fraction of the maximum.
    • remaining keys forwarded into arrowprops.
  • ax (matplotlib Axes or None, default: None ) –

    Axes to draw on. A new figure is created if None.

  • figsize (tuple of float, default: (10, 8) ) –

    Figure size used when ax is None.

  • title (str, default: 'Voronoi cartogram — centroid redistribution' ) –

    Axis title.

Returns:

Raises:

  • RuntimeError –

    If no source GeoDataFrame is stored on the result.

  • ValueError –

    If state is not "original" or "final".

repair_topology

repair_topology(
    group_by: str | None = None,
    *,
    adj_pairs: list[tuple[int, int]] | None = None,
    max_passes: int = 20,
    group_contiguity: bool | None = None,
    compactness: bool | None = None,
    adjacency: bool | None = None,
    orientation: bool | None = None,
    adj_min_shared_length: float | None = None,
) -> TopologyRepairReport

Return a new cartogram with topology issues repaired.

Applies the same three-stage permutation pipeline used during Lloyd relaxation — group contiguity (stage 1), adjacency (stage 2), and orientation (stage 3) — as a post-hoc operation. No generator positions are moved; only the cell-to-district mapping is permuted.

Parameters:

  • group_by (str or None, default: None ) –

    Column in the source GeoDataFrame identifying groups. Required for stage 1; None or group_contiguity=False disables it.

  • adj_pairs (list of (i, j) or None, default: None ) –

    Input-adjacent district index pairs. None → auto-computed from the source GeoDataFrame geometries.

  • max_passes (int, default: 20 ) –

    Maximum repair passes per active stage (default 20).

  • group_contiguity (bool or None, default: None ) –

    Run stage 1 (group contiguity repair). None (default) → True when group_by is provided, False otherwise.

  • compactness (bool or None, default: None ) –

    Run stage 1.5 (compactness enhancement). None (default) → True when group_by is provided, False otherwise.

  • adjacency (bool or None, default: None ) –

    Run stage 2 (adjacency permutation). None (default) → True when group_by is None, False otherwise.

  • orientation (bool or None, default: None ) –

    Run stage 3 (orientation alignment). None (default) → True when group_by is None, False otherwise.

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

    Minimum shared border length for two cells to be considered adjacent. None = no extra filter.

Returns:

  • TopologyRepairReport –

    Contains the repaired :attr:~TopologyRepairReport.cartogram, :attr:~TopologyRepairReport.before and :attr:~TopologyRepairReport.after analyzes, the list of :attr:~TopologyRepairReport.stages_run, and the :attr:~TopologyRepairReport.reassigned district labels.

to_geodataframe

to_geodataframe() -> gpd.GeoDataFrame

Return a GeoDataFrame with original columns and Voronoi cell geometries.

Replaces the geometry column of the source GeoDataFrame with the corresponding Voronoi cell polygon. Index and all non-geometry columns are preserved.

Returns:

  • GeoDataFrame –

Raises:

  • RuntimeError –

    If the source GeoDataFrame was not stored (should not happen in normal usage).

VoronoiPlotResult dataclass

VoronoiPlotResult(ax: Any, collections: list)

Artists produced by :meth:VoronoiCartogram.plot.