Flow Cartogram¶
Cartogram generation with flow-based morphing.
Overview¶
The flow_cartogram module generates flow-based contiguous cartograms where polygon areas are deformed to be proportional to a data variable (e.g., population, GDP). It uses a diffusion-based algorithm that preserves topology while smoothly transforming geometries.
Core Algorithm: Iteratively computes density → velocity → displacement fields until regions reach target areas.
graph TD
A[Input GeoDataFrame] --> B[Compute Density Field]
B --> C[FFT Velocity Computation]
C --> D[Anisotropy Modulation]
D --> E[Displace Coordinates]
E --> F[Convergence Check]
F -->|Not Converged| B
F -->|Converged| G[Cartogram Output]
Main Interface¶
| Sub-module | Description |
|---|---|
| API | High-level functions (morph_gdf, multiresolution_morph) |
| Options | Configuration options and status enums |
| Cartogram | Cartogram result class with visualization and export |
| Workflow | Workflow class for iterative refinement |
| Errors | Error metrics computation |
Computation¶
| Sub-module | Description |
|---|---|
| Algorithm | Core morphing algorithm |
| Grid | Grid utilities for spatial discretization |
| Density | Density field computation and density modulators |
| Velocity | Velocity field computation using FFTW |
| Displacement | Coordinate displacement with numba |
| Anisotropy | Velocity modulator system (BoundaryDecay, BoundaryNormalDecay, DirectionalTensor, …) |
Analysis¶
| Sub-module | Description |
|---|---|
| History | Iteration history and snapshots |
| Metrics | Quality metrics and validation |
| Comparison | Comparison utilities for results |
Output¶
| Sub-module | Description |
|---|---|
| Visualization | Plotting utilities for results |
| Animation | Animation generation utilities |
| Serialization | Export and save/load utilities |
Workflow Patterns¶
Basic Cartogram Generation¶
from carto_flow.flow_cartogram import morph_gdf, MorphOptions
cartogram = morph_gdf(gdf, "population",
options=MorphOptions.preset_balanced())
cartogram.plot()
print(f"Status: {cartogram.status}")
print(f"Error: {cartogram.get_errors().mean_error_pct:.1f}%")
Iterative Refinement¶
from carto_flow.flow_cartogram import CartogramWorkflow
workflow = CartogramWorkflow(gdf, "population")
cartogram = workflow.morph() # Initial pass
cartogram = workflow.morph(mean_tol=0.02) # Refine with stricter tolerance
workflow.pop() # Undo if needed
Multi-Resolution Cartogram¶
from carto_flow.flow_cartogram import multiresolution_morph
cartogram = multiresolution_morph(gdf, "population",
resolution=512, levels=3)
With Displacement Field Output¶
import numpy as np
x = np.linspace(0, 100, 50)
y = np.linspace(0, 80, 40)
X, Y = np.meshgrid(x, y)
displacement_coords = np.column_stack([X.ravel(), Y.ravel()])
cartogram = morph_gdf(gdf, "population",
displacement_coords=displacement_coords)
displaced = cartogram.get_coords()
Visualization and Export¶
from carto_flow.flow_cartogram import morph_gdf, MorphOptions
from carto_flow.flow_cartogram.visualization import plot_comparison, plot_convergence
from carto_flow.flow_cartogram.animation import animate_morph_history, save_animation
cartogram = morph_gdf(gdf, "population",
options=MorphOptions(save_internals=True))
plot_comparison(gdf, cartogram)
plot_convergence(cartogram.convergence)
anim = animate_morph_history(cartogram, duration=5.0)
save_animation(anim, "morph.gif", fps=15)
cartogram.save("output/cartogram.gpkg")
Velocity Modulators¶
Velocity modulators control how the velocity field is transformed each iteration.
Modulators are chained with + and passed as MorphOptions(anisotropy=...).
from carto_flow.flow_cartogram import (
morph_gdf, MorphOptions,
BoundaryDecay, BoundaryNormalDecay, DirectionalTensor, VelocitySmooth,
)
# Suppress outward boundary drift while preserving tangential flow
mod = BoundaryNormalDecay(decay_length=50_000) + VelocitySmooth(sigma=20_000)
cartogram = morph_gdf(gdf, "population",
options=MorphOptions(anisotropy=mod))
# Simple multiplicative falloff combined with a radial directional bias
mod = BoundaryDecay(decay_length=80_000) + DirectionalTensor.radial(Dpar=2.0)
cartogram = morph_gdf(gdf, "population",
options=MorphOptions(anisotropy=mod))
Density Modulators¶
Density modulators adjust the density field before velocity computation each iteration.
They are passed as MorphOptions(density_mod=...).
from carto_flow.flow_cartogram import morph_gdf, MorphOptions, DensityBorderExtension, DensitySmooth
mod = DensityBorderExtension(extension_width=50_000, transition_width=200_000) + DensitySmooth(sigma=20_000)
cartogram = morph_gdf(gdf, "population",
options=MorphOptions(density_mod=mod))
Error Handling¶
| Exception | Description |
|---|---|
MorphOptionsError |
Base exception for option validation errors |
MorphOptionsValidationError |
Invalid option values (type, range, format) |
MorphOptionsConsistencyError |
Contradictory options (e.g., mean_tol > max_tol) |
ValueError |
Input validation failures |