Skip to content

carto_flow.flow_cartogram.grid

Grid construction and management utilities for flow-based cartography.

This module provides functions for creating and managing spatial grids used in flow-based cartogram algorithms. It includes utilities for constructing regular grids, multi-resolution grids, and grid information containers.

Classes:

  • Grid

    Structured grid information container with lazy computation and caching.

Functions:

Notes

All grid functions return Grid objects that provide both array-based and property-based access to grid coordinates and metadata. The grids are designed to work seamlessly with FFT-based algorithms and maintain proper aspect ratios for cartographic applications.

Examples:

>>> from carto_flow.flow_cartogram.grid import Grid, build_multilevel_grids
>>> grid = Grid.from_bounds((0, 0, 100, 80), size=200)
>>> print(f"Grid shape: {grid.shape}")
Grid shape: (100, 200)
>>> grids = build_multilevel_grids((0, 0, 100, 80), 256, n_levels=3)
>>> print(f"Number of resolution levels: {len(grids)}")
Number of resolution levels: 3

Grid

Grid(
    bounds: tuple[float, float, float, float],
    size: int | tuple[int | None, int | None],
    margin: float = 0.0,
    square: bool = False,
)

Grid class with lazy computation and caching of coordinate arrays.

This class provides flexible grid construction with multiple class methods and lazy computation with caching of coordinate arrays for optimal performance.

Construction Methods (Preferred)
  1. From bounds and size: Grid.from_bounds(bounds, size, margin=0.0, square=False)

  2. From bounds and spacing: Grid.from_bounds_and_spacing(bounds, spacing, margin=0.0, strict=False)

  3. From size and spacing: Grid.from_size_and_spacing(size, spacing)

Parameters (Internal)

xmin : float Minimum x-coordinate of the grid bounds. ymin : float Minimum y-coordinate of the grid bounds. xmax : float Maximum x-coordinate of the grid bounds. ymax : float Maximum y-coordinate of the grid bounds. sx : int Number of grid cells in x-direction (columns). sy : int Number of grid cells in y-direction (rows). dx : float Grid cell width in coordinate units. dy : float Grid cell height in coordinate units.

Properties

bounds : tuple of float Grid bounds as (xmin, ymin, xmax, ymax). size : tuple of int Grid size as (sx, sy). spacing : tuple of float Grid spacing as (dx, dy). shape : tuple of int Grid shape as (sy, sx).

Examples:

>>> from carto_flow.grid import Grid
>>> grid = Grid.from_bounds((0, 0, 10, 5), size=100)
>>> print(f"Grid shape: {grid.shape}")
Grid shape: (50, 100)
>>> print(f"Grid bounds: {grid.bounds}")
Grid bounds: (0.0, 0.0, 10.0, 5.0)
>>> x_coords = grid.x_coords  # Computed and cached on first access
>>> X = grid.X  # Computed and cached on first access
Notes

Use the class methods (from_bounds, from_bounds_and_spacing, from_size_and_spacing) for construction rather than the direct constructor to ensure parameter consistency. The class uses lazy computation with caching for coordinate arrays. Arrays are computed once on first access and then cached for performance.

Parameters:

  • bounds (tuple of float) –

    Grid bounds as (xmin, ymin, xmax, ymax).

  • size (int or tuple) –

    Grid size specification: - int: number of points along longest edge - (sx, sy): exact grid dimensions - (sx, None): sx points in x, computed sy for similar dx/dy - (None, sy): computed sx, sy points in y for similar dx/dy

  • margin (float, default: 0.0 ) –

    Margin to add around bounds as fraction. Default is 0.0.

  • square (bool, default: False ) –

    If True, adjust bounds to ensure dx == dy. Default is False.

Methods:

Attributes:

  • X (ndarray) –

    2D array of x-coordinates in meshgrid format (computed and cached).

  • Y (ndarray) –

    2D array of y-coordinates in meshgrid format (computed and cached).

  • bounds (tuple[float, float, float, float]) –

    Grid bounds as (xmin, ymin, xmax, ymax), including any margin.

  • data_bounds (tuple[float, float, float, float]) –

    Original data bounds as (xmin, ymin, xmax, ymax), without margin.

  • dx (float) –

    Grid cell width in coordinate units.

  • dy (float) –

    Grid cell height in coordinate units.

  • shape (tuple[int, int]) –

    Grid shape as (sy, sx).

  • size (tuple[int, int]) –

    Grid size as (sx, sy).

  • spacing (tuple[float, float]) –

    Grid spacing as (dx, dy).

  • sx (int) –

    Number of grid cells in x-direction (columns).

  • sy (int) –

    Number of grid cells in y-direction (rows).

  • x_coords (ndarray) –

    1D array of x-coordinates for grid columns (computed and cached).

  • x_edges (ndarray) –

    1D array of x-coordinates for cell edges (computed and cached).

  • xmax (float) –

    Maximum x-coordinate of the grid bounds.

  • xmin (float) –

    Minimum x-coordinate of the grid bounds.

  • y_coords (ndarray) –

    1D array of y-coordinates for grid rows (computed and cached).

  • y_edges (ndarray) –

    1D array of y-coordinates for cell edges (computed and cached).

  • ymax (float) –

    Maximum y-coordinate of the grid bounds.

  • ymin (float) –

    Minimum y-coordinate of the grid bounds.

X property

X: ndarray

2D array of x-coordinates in meshgrid format (computed and cached).

Y property

Y: ndarray

2D array of y-coordinates in meshgrid format (computed and cached).

bounds property

bounds: tuple[float, float, float, float]

Grid bounds as (xmin, ymin, xmax, ymax), including any margin.

data_bounds property

data_bounds: tuple[float, float, float, float]

Original data bounds as (xmin, ymin, xmax, ymax), without margin.

dx property

dx: float

Grid cell width in coordinate units.

dy property

dy: float

Grid cell height in coordinate units.

shape property

shape: tuple[int, int]

Grid shape as (sy, sx).

size property

size: tuple[int, int]

Grid size as (sx, sy).

spacing property

spacing: tuple[float, float]

Grid spacing as (dx, dy).

sx property

sx: int

Number of grid cells in x-direction (columns).

sy property

sy: int

Number of grid cells in y-direction (rows).

x_coords property

x_coords: ndarray

1D array of x-coordinates for grid columns (computed and cached).

x_edges property

x_edges: ndarray

1D array of x-coordinates for cell edges (computed and cached).

xmax property

xmax: float

Maximum x-coordinate of the grid bounds.

xmin property

xmin: float

Minimum x-coordinate of the grid bounds.

y_coords property

y_coords: ndarray

1D array of y-coordinates for grid rows (computed and cached).

y_edges property

y_edges: ndarray

1D array of y-coordinates for cell edges (computed and cached).

ymax property

ymax: float

Maximum y-coordinate of the grid bounds.

ymin property

ymin: float

Minimum y-coordinate of the grid bounds.

__repr__

__repr__() -> str

Concise string representation for terminal display.

from_bounds classmethod

from_bounds(
    bounds: tuple[float, float, float, float],
    size: int | tuple[int | None, int | None],
    margin: float = 0.0,
    square: bool = False,
) -> Grid

Create a Grid from bounds and size specification.

Parameters:

  • bounds (tuple of float) –

    Grid bounds as (xmin, ymin, xmax, ymax).

  • size (int or tuple) –

    Grid size specification: - int: number of points along longest edge - (sx, sy): exact grid dimensions - (sx, None): sx points in x, computed sy for similar dx/dy - (None, sy): computed sx, sy points in y for similar dx/dy

  • margin (float, default: 0.0 ) –

    Margin to add around bounds as fraction. Default is 0.0.

  • square (bool, default: False ) –

    If True, adjust bounds to ensure dx == dy. Default is False.

Returns:

  • Grid

    New Grid instance.

Examples:

>>> bounds = (0, 0, 10, 5)
>>> grid = Grid.from_bounds(bounds, size=100)  # 100 points along longest edge
>>> grid = Grid.from_bounds(bounds, size=(50, 25))  # Exact dimensions
>>> grid = Grid.from_bounds(bounds, size=(50, None))  # 50 in x, computed in y

from_bounds_and_spacing classmethod

from_bounds_and_spacing(
    bounds: tuple[float, float, float, float],
    spacing: float | tuple[float, float],
    margin: float = 0.0,
    strict: bool = False,
) -> Grid

Create a Grid from bounds and spacing specification.

Parameters:

  • bounds (tuple of float) –

    Grid bounds as (xmin, ymin, xmax, ymax).

  • spacing (float or tuple) –

    Grid spacing: - float: same spacing in both directions - (dx, dy): different spacing in each direction

  • margin (float, default: 0.0 ) –

    Margin to add around bounds as fraction. Default is 0.0.

  • strict (bool, default: False ) –

    If True, adjust bounds to ensure exact spacing. Default is False.

Returns:

  • Grid

    New Grid instance.

Examples:

>>> bounds = (0, 0, 10, 5)
>>> grid = Grid.from_bounds_and_spacing(bounds, spacing=1.0)  # Same spacing
>>> grid = Grid.from_bounds_and_spacing(bounds, spacing=(1.0, 0.5))  # Different spacing

from_size_and_spacing classmethod

from_size_and_spacing(
    size: int | tuple[int, int],
    spacing: float | tuple[float, float],
    center: tuple[float, float] = (0.0, 0.0),
) -> Grid

Create a Grid from size and spacing specification.

Parameters:

  • size (int or tuple) –

    Grid size: - int: same number of points in both directions - (sx, sy): different size in each direction

  • spacing (float or tuple) –

    Grid spacing: - float: same spacing in both directions - (dx, dy): different spacing in each direction

  • center (tuple of float, default: (0.0, 0.0) ) –

    Center coordinates of the grid as (center_x, center_y). Default is (0.0, 0.0).

Returns:

  • Grid

    New Grid instance with bounds computed around the specified center.

Examples:

>>> grid = Grid.from_size_and_spacing(size=100, spacing=1.0)  # Centered at origin
>>> grid = Grid.from_size_and_spacing(size=(50, 25), spacing=(1.0, 2.0))  # Centered at origin
>>> grid = Grid.from_size_and_spacing(size=100, spacing=1.0, center=(10.0, 5.0))  # Custom center

build_multilevel_grids

build_multilevel_grids(
    bounds: tuple[float, float, float, float],
    N: int,
    n_levels: int = 3,
    margin: float = 0.5,
    square: bool = False,
) -> list

Build dyadically scaled FFT-friendly grids for multi-resolution cartography.

Creates a hierarchy of grids with dyadically increasing resolution levels, starting from the lowest resolution and doubling at each level. Each level has dimensions exactly double the previous level, making them ideal for multi-resolution cartogram algorithms and FFT-based computations.

Parameters:

  • bounds (tuple of float) –

    The bounding box as (xmin, ymin, xmax, ymax) coordinates that define the spatial extent for all resolution levels.

  • N (int) –

    Number of grid points along the longest bounding box edge at the lowest resolution level (grids[0]).

  • n_levels (int, default: 3 ) –

    Number of resolution levels to create. Each level doubles the dimensions of the previous level. Default is 3.

  • margin (float, default: 0.5 ) –

    Margin to add around the bounds as a fraction of the bounding box dimensions before computing grid sizes. Default is 0.5.

Returns:

  • list of Grid

    List of Grid objects ordered from lowest to highest resolution:

    • grids[0] : Grid Lowest resolution grid with approximately N points along the long axis
    • grids[1] : Grid Second resolution level with dimensions doubled from previous
    • grids[n_levels-1] : Grid Highest resolution grid with approximately N * 2^(n_levels-1) points

    Each Grid object contains coordinate arrays and metadata for its respective resolution level.

Examples:

>>> bounds = (0, 0, 100, 80)  # Rectangular bounding box
>>> grids = build_multilevel_grids(bounds, N=64, n_levels=3)
>>> print(f"Number of levels: {len(grids)}")
Number of levels: 3
>>> print(f"Level 0 (lowest res) shape: {grids[0].shape}")
Level 0 (lowest res) shape: (64, 51)
>>> print(f"Level 1 shape: {grids[1].shape}")
Level 1 shape: (128, 102)
>>> print(f"Level 2 (highest res) shape: {grids[2].shape}")
Level 2 (highest res) shape: (256, 204)
Notes

The algorithm ensures FFT-friendly dimensions by:

  1. Computing base dimensions that maintain aspect ratio at the lowest level
  2. Finding the best short-axis resolution to minimize aspect distortion
  3. Creating grids where each level has exactly double the dimensions of the previous

The returned grids are ordered from lowest to highest resolution, making them suitable for algorithms that progressively refine solutions from coarse to fine scales.