Coastal and Peninsula Regions¶
The default distance_mode="euclidean" assigns each raster pixel to its nearest generator in straight-line distance. When land regions are separated by a bay, strait, or other water body, this straight line can cross the water and claim pixels that geographically belong to the other shore. With distance_mode="geodesic", each region's label spreads outward through land pixels only — it cannot jump across water — so coastal regions separated by a bay are never incorrectly merged.
Note: fully isolated islands (no pixel path to the mainland) are handled by a seed-snapping fallback in both modes — the geodesic fix targets connected land areas divided by water inlets.
See also: Explanation: Geodesic Labeling · Tutorial
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)
Euclidean vs Geodesic Labeling¶
Run the same equal-area cartogram twice — once with the default euclidean mode and once with geodesic. The difference shows up in coastal states where the straight-line path between generator and pixel crosses a water body.
Note that distance_mode="geodesic" is only supported for equal-area cartograms (i.e., weights=None) and does not support power-diagram updates that speed up convergence. Because of the geodesic constraint, the final result may be far from equal-area convergence.
result_eucl = vor.create_voronoi_cartogram(
us_states,
backend=vor.RasterBackend(distance_mode="euclidean"),
)
result_geo = vor.create_voronoi_cartogram(
us_states,
backend=vor.RasterBackend(distance_mode="geodesic"),
)
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
for ax, res, title in zip(
axes,
[result_eucl, result_geo],
["euclidean (default)", "geodesic"],
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();
Zoomed View — Chesapeake Bay Area¶
The effect is most visible around bays and straits. Zoom into the mid-Atlantic coast where Maryland and Virginia are separated by the Chesapeake Bay.
# Approximate bounding box of the Chesapeake Bay region (CRS: EPSG:5070 / Albers)
bay_xlim = (1_300_000, 1_800_000)
bay_ylim = (-300_000, 200_000)
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
for ax, res, title in zip(
axes,
[result_eucl, result_geo],
["euclidean", "geodesic"],
strict=False,
):
res.plot(column="area_error_pct", ax=ax, cmap="RdYlGn_r", vmin=-70, vmax=70, legend=False)
us_states.boundary.plot(ax=ax, linewidth=0.5, color="black", alpha=0.4)
for cell, label in zip(res.cells, us_states["State Abbreviation"], strict=False):
cx, cy = cell.centroid.x, cell.centroid.y
if bay_xlim[0] < cx < bay_xlim[1] and bay_ylim[0] < cy < bay_ylim[1]:
ax.text(cx, cy, label, fontsize=8, ha="center", va="center", fontweight="bold")
ax.set_xlim(*bay_xlim)
ax.set_ylim(*bay_ylim)
ax.set(title=title)
ax.axis("off")
plt.suptitle("Mid-Atlantic coast — Chesapeake Bay area", y=1.01)
plt.tight_layout();
When to Use Geodesic Mode¶
| Dataset | Recommended mode |
|---|---|
| Landlocked regions only | "euclidean" (default, faster) |
| Coastal regions with bays or straits between neighbors | "geodesic" |
Geodesic mode is exclusive to RasterBackend. The BFS is Numba-compiled; the first call has a JIT warm-up overhead but subsequent calls are fast.
See Also¶
- Explanation: Geodesic Labeling — BFS algorithm details and seed snapping
- Reference: RasterBackend
- Tutorial