Skip to content

carto_flow.symbol_cartogram.result

Result container for symbol cartogram operations.

Classes:

  • SimulationHistory

    Per-iteration diagnostics and optional position snapshots from simulation.

  • SymbolCartogram

    Rendered symbol cartogram ready for visualization and export.

SimulationHistory dataclass

SimulationHistory(
    positions: list[NDArray[floating]] | None = None,
    drift: NDArray[floating] | None = None,
    jitter: NDArray[floating] | None = None,
    drift_rate: NDArray[floating] | None = None,
    drift_rate_neg_frac: NDArray[floating] | None = None,
    velocity: NDArray[floating] | None = None,
    overlaps: NDArray[intp] | None = None,
)

Per-iteration diagnostics and optional position snapshots from simulation.

All array fields share an iteration axis: index i corresponds to iteration i. Fields are None when the simulator does not produce them.

Attributes:

  • positions (list[ndarray] | None) –

    Position snapshots, each of shape (n, 2). Only populated when save_history=True.

  • drift (ndarray | None) –

    Per-iteration drift (mean relative smoothed displacement). Populated by TopologyPreservingSimulator. Shape: (n_iters,).

  • jitter (ndarray | None) –

    Per-iteration jitter (mean relative displacement std). Populated by TopologyPreservingSimulator. Shape: (n_iters,).

  • drift_rate (ndarray | None) –

    EMA-smoothed derivative of drift (drift[k] - drift[k-1]). Approaches zero when drift plateaus (system converged to stable oscillation). Populated by TopologyPreservingSimulator. Shape: (n_iters,).

  • drift_rate_neg_frac (ndarray | None) –

    Running sign test: EMA of 1{drift_rate < 0}. Approaches 0.5 at plateau (equal positive/negative signs), near 1.0 during active convergence (drift predominantly decreasing). Populated by TopologyPreservingSimulator. Shape: (n_iters,).

  • velocity (ndarray | None) –

    Per-iteration max velocity. Populated by CirclePhysicsSimulator. Shape: (n_iters,).

  • overlaps (ndarray | None) –

    Per-iteration overlap count. Populated by both simulators. Shape: (n_iters,).

Methods:

  • __len__

    Number of recorded iterations.

__len__

__len__() -> int

Number of recorded iterations.

SymbolCartogram dataclass

SymbolCartogram(
    symbols: GeoDataFrame,
    status: SymbolCartogramStatus = (
        lambda: SymbolCartogramStatus.COMPLETED
    )(),
    metrics: dict[str, Any] = dict(),
    simulation_history: SimulationHistory | None = None,
    layout_result: LayoutResult | None = None,
    styling: Styling | None = None,
    _source_gdf: Any | None = None,
    _valid_mask: NDArray[bool_] | None = None,
    _tiling_result: Any | None = None,
    _assignments: NDArray[intp] | None = None,
)

Rendered symbol cartogram ready for visualization and export.

Supports the layout-styling separation pattern with layout_result and styling fields for the new API.

Attributes:

  • symbols (GeoDataFrame) –

    GeoDataFrame containing symbol geometries with columns: - geometry: Symbol polygon (circle/square/hexagon) - _symbol_x, _symbol_y: Symbol center position - _symbol_size: Symbol size (radius for circles, half-side for squares) - _displacement: Distance from original centroid to symbol center - original_index: Index in original GeoDataFrame

  • status (SymbolCartogramStatus) –

    Computation status (CONVERGED, COMPLETED, ORIGINAL)

  • metrics (dict) –

    Quality metrics: - displacement_mean: Mean distance from original centroid - displacement_max: Maximum displacement - displacement_std: Standard deviation of displacement - topology_preservation: Fraction of adjacencies preserved (if computed) - iterations: Number of iterations used (free placement) - n_skipped: Number of geometries skipped due to null values

  • simulation_history (SimulationHistory | None) –

    Per-iteration diagnostics and optional position snapshots. None when no simulation was run (e.g. grid placement).

  • layout_result (LayoutResult | None) –

    Immutable layout result (new API). Contains canonical symbol, transforms, and preprocessing data (positions, sizes, adjacency, bounds, crs).

  • styling (Styling | None) –

    Styling configuration used (new API).

Private Attributes

_source_gdf : gpd.GeoDataFrame | None Reference to original input GeoDataFrame (for attribute merging). Only set when created via create_symbol_cartogram() with the original gdf. _valid_mask : np.ndarray | None Boolean mask indicating which rows had valid (non-null) values. _tiling_result : Any | None Tiling result for grid layouts (algorithm-specific). _assignments : np.ndarray | None Grid assignments for grid layouts.

Methods:

  • get_displacement_vectors

    Get displacement vectors from original centroid to symbol center.

  • load

    Load a symbol cartogram from a JSON file.

  • plot

    Plot the symbol cartogram with per-symbol visual styling.

  • restyle

    Create a NEW cartogram with different styling.

  • save

    Save the symbol cartogram to a JSON file.

  • to_geodataframe

    Export symbols as GeoDataFrame with original attributes.

get_displacement_vectors

get_displacement_vectors() -> NDArray[np.floating]

Get displacement vectors from original centroid to symbol center.

Returns:

  • np.ndarray of shape (n, 2)

    Displacement vectors [dx, dy] for each symbol.

Raises:

  • ValueError

    If no original positions are available (via layout_result or _source_gdf).

load classmethod

load(path: str | Path) -> SymbolCartogram

Load a symbol cartogram from a JSON file.

Restores a SymbolCartogram saved by save(), including symbol geometries, layout result, source GeoDataFrame, and metrics.

Parameters:

  • path (str) –

    Path to saved JSON file.

Returns:

  • SymbolCartogram

    Restored cartogram. Supports plot(), to_geodataframe(), and restyle() (if layout_result was present at save time).

Examples:

>>> loaded = SymbolCartogram.load('cartogram.json')
>>> loaded.plot(facecolor='population')
>>> restyled = loaded.restyle(symbol='hexagon')

plot

plot(
    column: str | None = None,
    cmap: str | dict[str, Any] = "viridis",
    norm: Any | None = None,
    vmin: float | None = None,
    vmax: float | None = None,
    legend: bool = True,
    legend_kwds: dict[str, Any] | None = None,
    ax: Axes | None = None,
    figsize: tuple[float, float] = (10, 8),
    source_gdf: Any | None = None,
    facecolor: Any = None,
    alpha: Any = 0.9,
    alpha_range: tuple[float, float] = (0.2, 1.0),
    edgecolor: Any = "none",
    edge_cmap: str | dict[str, Any] | None = None,
    linewidth: Any = 0.5,
    linewidth_range: tuple[float, float] = (0.5, 3.0),
    hatch: Any = None,
    hatch_map: dict[str, str] | None = None,
    edge_legend: bool = True,
    edge_legend_kwds: dict[str, Any] | None = None,
    hatch_legend: bool = True,
    hatch_legend_kwds: dict[str, Any] | None = None,
    linewidth_legend: bool = True,
    linewidth_legend_kwds: dict[str, Any] | None = None,
    alpha_legend: bool = True,
    alpha_legend_kwds: dict[str, Any] | None = None,
    label: Any = None,
    label_color: Any = "black",
    label_cmap: str | dict[str, Any] | None = None,
    label_legend: bool = True,
    label_legend_kwds: dict[str, Any] | None = None,
    label_fontsize: Any = 8,
    label_fontsize_range: tuple[float, float] = (6.0, 14.0),
    label_kwargs: dict[str, Any] | None = None,
    title: str | None = None,
    zorder: int = 1,
) -> SymbolsPlotResult

Plot the symbol cartogram with per-symbol visual styling.

Every visual property can be set globally (scalar / colour string), data-driven (column name → automatic mapping), or per-symbol (list / NumPy array, one value per symbol).

Parameters:

  • column (str, default: None ) –

    Convenience shorthand for facecolor=column. Kept for backward compatibility. When both column and facecolor are provided, facecolor takes precedence.

  • cmap (str or dict, default: 'viridis' ) –

    Colormap for data-driven facecolor. Pass a colormap name string for numeric columns (e.g. "viridis", "plasma"), or a dict of {category: colour} for categorical columns (e.g. {"Europe": "#2ca02c", "Africa": "#d62728"}). Unspecified categories receive auto-assigned "tab10" colours. Default "viridis".

  • norm (matplotlib Normalize, default: None ) –

    Custom normalisation for the colour mapping.

  • vmin (float, default: None ) –

    Explicit data limits for the colourmap normalisation.

  • vmax (float, default: None ) –

    Explicit data limits for the colourmap normalisation.

  • legend (bool, default: True ) –

    Display a colorbar (numeric) or patch legend (categorical) when facecolor is data-driven. Default True.

  • legend_kwds (dict, default: None ) –

    Extra keyword arguments forwarded to Figure.colorbar() (numeric columns) or Axes.legend() (categorical columns). Use "title" to label the legend.

  • ax (Axes, default: None ) –

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

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

    Figure size when a new figure is created. Default (10, 8).

  • source_gdf (GeoDataFrame, default: None ) –

    External GeoDataFrame for column lookups (highest priority). Useful when the column you want to map is not stored on the cartogram's own symbols table.

  • facecolor (color, column name, or array-like, default: None ) –

    Symbol fill colour. Accepts:

    • A matplotlib colour string ("steelblue").
    • A column name → numeric: mapped via cmap / norm; categorical: auto-assigned from the "tab10" palette (pass a dict to cmap to override specific categories).
    • A 1-D numeric array → mapped via cmap / norm.
    • An (n, 3) or (n, 4) float array (RGB / RGBA).
    • A list of colour strings or RGBA tuples.

    Defaults to "steelblue" when None.

  • alpha (float, column name, or array-like, default: 0.9 ) –

    Symbol opacity (0 = transparent, 1 = opaque). A column name is linearly interpolated into alpha_range. Default 0.9.

  • alpha_range ((float, float), default: (0.2, 1.0) ) –

    (min, max) alpha range for column-driven transparency. Default (0.2, 1.0).

  • edgecolor (color, column name, or array-like, default: 'none' ) –

    Symbol edge colour. Same forms as facecolor. Default "none" (no visible border).

  • edge_cmap (str or dict, default: None ) –

    Colormap for edge colour column mapping. Accepts the same forms as cmap (string name for numeric, dict for categorical). Falls back to cmap (string only) when None.

  • linewidth (float, column name, or array-like, default: 0.5 ) –

    Edge line width. A column name is linearly interpolated into linewidth_range. Default 0.5.

  • linewidth_range ((float, float), default: (0.5, 3.0) ) –

    (min, max) linewidth range for column-driven widths. Default (0.5, 3.0).

  • hatch (str, column name, or sequence, default: None ) –

    Fill hatching. A matplotlib hatch pattern string ("///") is applied globally; a column name maps each category to a pattern from hatch_map or the default cycle; a list / array applies per-symbol patterns.

    .. note:: Hatching is only visible when edgecolor is not "none".

  • hatch_map (dict, default: None ) –

    Per-category hatch overrides when hatch is a column name. Example: {"urban": "///", "rural": "..."}.

  • edge_legend (bool, default: True ) –

    Show a separate legend for edgecolor when it is data-driven from a different column than facecolor. Default True.

  • edge_legend_kwds (dict, default: None ) –

    Same as legend_kwds but for the edge-colour legend.

  • hatch_legend (bool, default: True ) –

    Show a patch legend for the hatch ↔ category mapping when hatch is a column name. No effect for global patterns or lists. Default True.

  • hatch_legend_kwds (dict, default: None ) –

    Axes.legend() kwargs for the hatch legend, plus an optional nested "patch_kw" dict controlling legend-patch appearance.

  • linewidth_legend (bool, default: True ) –

    Show a discrete line-sample legend when linewidth is data-driven. Displays ~5 representative values as grey lines of increasing thickness. Default True.

  • linewidth_legend_kwds (dict, default: None ) –

    Axes.legend() kwargs for the linewidth legend. Use "title" to override the legend title.

  • alpha_legend (bool, default: True ) –

    Show a colorbar for alpha when it is data-driven and facecolor is a constant colour. The colorbar displays the constant colour ramping from transparent to opaque across the data range. Default True.

  • alpha_legend_kwds (dict, default: None ) –

    Extra keyword arguments forwarded to Figure.colorbar(). Use "title" to override the colorbar label.

  • label (str, column name, or sequence, default: None ) –

    Per-symbol text labels. A column name uses the string representation of each value; a list / array provides explicit strings.

  • label_color (color, column name, or array-like, default: 'black' ) –

    Text colour for labels. Accepts the same forms as facecolor. Default "black".

  • label_cmap (str or dict, default: None ) –

    Colormap for data-driven label_color. Accepts the same forms as cmap. Defaults to cmap (string only) when None.

  • label_fontsize (float, column name, or array-like, default: 8 ) –

    Label font size. A column name is linearly interpolated into label_fontsize_range. Default 8.

  • label_fontsize_range ((float, float), default: (6.0, 14.0) ) –

    (min, max) font-size range for column-driven sizing. Default (6.0, 14.0).

  • label_kwargs (dict, default: None ) –

    Extra keyword arguments forwarded to Axes.text() for every label (e.g. {"fontweight": "bold"}).

  • title (str, default: None ) –

    Axes title.

  • zorder (int, default: 1 ) –

    Matplotlib drawing order. Default 1.

Returns:

  • SymbolsPlotResult

    Result with the axes and captured artists (collections, labels, colorbars, legends). Access the axes via result.ax.

Examples:

>>> # Backward-compatible usage
>>> result.plot(column="pop_est", cmap="YlOrRd")
>>> # Global style
>>> result.plot(facecolor="steelblue", edgecolor="white", linewidth=0.8)
>>> # Data-driven fill → automatic colorbar
>>> result.plot(facecolor="gdp_per_capita", cmap="plasma")
>>> # Categorical fill with qualitative palette
>>> result.plot(facecolor="continent")
>>> # Per-symbol alpha driven by a data column
>>> result.plot(facecolor="#4C72B0", alpha="pop_est", alpha_range=(0.3, 1.0))
>>> # Hatching by category (needs visible edge colour)
>>> result.plot(facecolor="none", edgecolor="black", linewidth=0.5,
...             hatch="region",
...             hatch_map={"A": "///", "B": "...", "C": "xxx"})
>>> # Explicit per-symbol colour array
>>> import numpy as np
>>> colors = np.random.rand(len(result.symbols), 4)
>>> result.plot(facecolor=colors, legend=False)
>>> # Data-driven edge colour → second legend auto-added
>>> result.plot(facecolor="steelblue", edgecolor="region")
>>> # Labels from a column
>>> result.plot(facecolor="pop_est", label="name")
>>> # Labels with column-driven colour and size
>>> result.plot(facecolor="steelblue",
...             label="iso_a3",
...             label_color="region",
...             label_fontsize="pop_est",
...             label_fontsize_range=(6, 12))

restyle

restyle(
    styling: Styling | None = None, **kwargs
) -> SymbolCartogram

Create a NEW cartogram with different styling.

Requires that the cartogram was created using the new API (with layout_result stored).

Parameters:

  • styling (Styling or None, default: None ) –

    Pre-configured Styling object. If None, creates from kwargs.

  • **kwargs

    Convenience kwargs for simple cases (symbol, scale, etc.) Creates a temporary Styling object internally.

Returns:

Raises:

  • ValueError

    If layout_result is not available (legacy cartogram).

Examples:

>>> # Restyle with different symbol
>>> new_cartogram = cartogram.restyle(symbol="hexagon")
>>> # Restyle with Styling object
>>> styling = Styling().set_symbol("hexagon").transform(scale=0.9)
>>> new_cartogram = cartogram.restyle(styling)

save

save(path: str | Path) -> None

Save the symbol cartogram to a JSON file.

Saves the symbol geometries, layout result, source GeoDataFrame, and metrics so the cartogram can be fully restored with SymbolCartogram.load().

Parameters:

  • path (str) –

    Output file path (typically .json extension).

Examples:

>>> result.save('cartogram.json')
>>> loaded = SymbolCartogram.load('cartogram.json')
>>> loaded.plot(facecolor='population')

to_geodataframe

to_geodataframe(
    source_gdf: GeoDataFrame | None = None,
) -> gpd.GeoDataFrame

Export symbols as GeoDataFrame with original attributes.

Parameters:

  • source_gdf (GeoDataFrame, default: None ) –

    Original GeoDataFrame to merge attributes from. If None, uses the stored reference from creation time (if available).

Returns:

  • GeoDataFrame

    Symbol geometries with original data columns.

Notes

If no source_gdf is available (neither passed nor stored), returns just the symbols GeoDataFrame without original attributes.