Choose the Right Backend¶
Two backends are available: RasterBackend (default) and ExactBackend. This guide explains the difference and gives a decision guide so you can pick the right one. For most use cases, the RasterBackend is the preferred and more versatile backend.
See the tutorial for a basic introduction to create_voronoi_cartogram.
import time
import matplotlib.pyplot as plt
import carto_flow.data as examples
import carto_flow.voronoi_cartogram as vor
us_states = examples.load_us_census(population=True)
RasterBackend¶
RasterBackend labels a pixel grid (the size determined by the resolution parameter) by nearest generator using a cKDTree query. The centroid of each labeled region is the new generator position. This approximation is faster than the exact approach and scales well to large datasets. By default, area_equalizer_rate=0.1 enables power-diagram updates that drive cells more quickly to equal area (only when weights=None).
t0 = time.perf_counter()
result_raster = vor.create_voronoi_cartogram(
us_states,
backend=vor.RasterBackend(resolution=300),
options=vor.VoronoiOptions(n_iter=300),
)
t_raster = time.perf_counter() - t0
print(f"RasterBackend: {t_raster:.1f}s | final area CV: {result_raster.metrics['final_area_cv']:.4f}")
RasterBackend: 2.2s | final area CV: 0.0246
ExactBackend¶
ExactBackend computes the Voronoi diagram exactly using scipy.spatial.Voronoi and clips each cell against the outer boundary with the Shapely library. Cell boundaries are not limited by pixel resolution. It does not support weights or ElasticBoundary. There is no power-diagram support, which means that convergence to equal-area Voronoi cells is generally slow.
t0 = time.perf_counter()
result_exact = vor.create_voronoi_cartogram(
us_states,
backend=vor.ExactBackend(),
options=vor.VoronoiOptions(n_iter=300),
)
t_exact = time.perf_counter() - t0
print(f"ExactBackend: {t_exact:.1f}s | final area CV: {result_exact.metrics['final_area_cv']:.4f}")
print(f"Speed ratio: {t_exact / t_raster:.1f}x")
ExactBackend: 10.0s | final area CV: 0.1288 Speed ratio: 4.6x
Side-by-Side Comparison¶
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
for ax, res, title in zip(axes, [result_raster, result_exact], ["RasterBackend", "ExactBackend"], strict=False):
res.plot(
column="area_error_pct",
ax=ax,
cmap="RdYlGn_r",
vmin=-70,
vmax=70,
legend=True,
legend_kwds={"shrink": 0.7, "label": "Area error (%)"},
)
for cell, label in zip(res.cells, us_states["State Abbreviation"], strict=False):
ax.text(cell.centroid.x, cell.centroid.y, label, fontsize=6, ha="center", va="center")
ax.set(title=title)
ax.axis("off")
plt.tight_layout();
Decision Guide¶
| Situation | Recommended backend |
|---|---|
| Exploratory analysis, large datasets | RasterBackend |
| Need geometrically exact Voronoi boundaries (no pixel approximation) | ExactBackend |
Need ElasticBoundary |
RasterBackend (ExactBackend doesn't support it) |
Weighted cartogram (weights= argument) |
RasterBackend (ExactBackend doesn't support weights) |
| More than ~200 regions | RasterBackend (ExactBackend is too slow) |
See Also¶
- Tutorial: Quick Start
- Explanation: CVT Algorithm — how the two backends implement Lloyd relaxation
- Reference: Backends