Style Symbol Cartograms¶
This guide shows how to use data-driven styling when plotting a symbol cartogram.
The plot() method maps any data column to fill color, opacity, edge color,
line width, hatching, or symbol shape — each independently.
The workflow separates layout (expensive, run once) from styling (fast, experiment freely):
create_layout()— computes symbol positions; stores them in an immutableLayoutResultlayout_result.style()— applies symbol shapescartogram.plot()— maps data to color, opacity, hatching, labels
import matplotlib.pyplot as plt
import carto_flow.symbol_cartogram as sym
from carto_flow.data import load_us_census
from carto_flow.symbol_cartogram.styling import Styling
gdf = load_us_census(poverty=True)
gdf.head()
| Population | Total Poverty | Below Poverty Level | Above Poverty Level | STATE | State Abbreviation | State Name | geometry | Region | Division | Population (Millions) | Population Density | Below Poverty Level % | Above Poverty Level % | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 12794885 | 11697147 | 1354558 | 10342589 | 42 | PA | Pennsylvania | POLYGON ((1200847.835 331701.964, 1203743.68 3... | Northeast | Middle Atlantic | 12.794885 | 109.040186 | 0.115802 | 0.884198 |
| 1 | 39346023 | 36223360 | 4451904 | 31771456 | 06 | CA | California | MULTIPOLYGON (((-1979058.42 -528956.745, -1975... | West | Pacific | 39.346023 | 96.001918 | 0.122901 | 0.877099 |
| 2 | 1807426 | 1662817 | 276138 | 1386679 | 54 | WV | West Virginia | POLYGON ((1100235.176 -108059.819, 1102295.003... | South | South Atlantic | 1.807426 | 28.802429 | 0.166066 | 0.833934 |
| 3 | 3151239 | 2856137 | 255847 | 2600290 | 49 | UT | Utah | POLYGON ((-1396894.253 368735.242, -1392505.21... | West | Mountain | 3.151239 | 14.331142 | 0.089578 | 0.910422 |
| 4 | 19514849 | 17890963 | 2360844 | 15530119 | 36 | NY | New York | MULTIPOLYGON (((1253147.537 375607.401, 125587... | Northeast | Middle Atlantic | 19.514849 | 153.727217 | 0.131957 | 0.868043 |
Compute the layout once¶
create_layout() runs the circle packing simulation and returns a LayoutResult.
All styling variations below reuse this single result — no re-simulation needed.
layout_result = sym.create_layout(gdf, "Population", layout="topology", size_normalization="total", show_progress=False)
cartogram = layout_result.style()
Color by a numeric column¶
Pass a column name to facecolor together with a colormap.
vmin and vmax pin the color range.
fig, ax = plt.subplots(figsize=(12, 7))
plot = cartogram.plot(
ax=ax,
# pass the original DataFrame
# to have access to the data columns
source_gdf=gdf,
# numeric-column-driven face color
facecolor="Below Poverty Level %",
cmap="YlOrRd",
# show colorbar
legend=True,
legend_kwds={"shrink": 0.6},
)
ax.set_title("Symbols sized by Population and colored by Poverty Level")
ax.axis("off")
plt.tight_layout()
Color by a categorical column¶
Pass a categorical column name and a color_map dict that maps each value to a color.
region_colors = {
"Northeast": "#4e79a7",
"South": "#f28e2b",
"Midwest": "#59a14f",
"West": "#e15759",
}
fig, ax = plt.subplots(figsize=(12, 7))
cartogram.plot(
ax=ax,
# pass the original DataFrame
# to have access to the data columns
source_gdf=gdf,
# categorical-column-driven facecolor
facecolor="Region",
# specify custom category to color mapping
cmap=region_colors,
# show legend
legend=True,
legend_kwds={"loc": "upper left", "framealpha": 0.8},
)
ax.set_title("Colored by Census Region")
ax.axis("off")
plt.tight_layout()
Different symbol shapes per category¶
Build a Styling object and call set_symbol() with a boolean mask for each category.
Shape assignment is independent of plot() color options — both can vary at the same time.
region_shapes = {
"Northeast": "square",
"South": "circle",
"Midwest": "hexagon",
"West": "diamond",
}
# style symbol shapes
styling = Styling(scale=0.85)
for region, shape in region_shapes.items():
mask = (gdf["Region"] == region).values
styling = styling.set_symbol(shape, mask=mask)
# note that cartograms can be restyled
cartogram_shapes = cartogram.restyle(styling=styling)
fig, ax = plt.subplots(figsize=(12, 7))
cartogram_shapes.plot(
ax=ax,
# pass the original DataFrame
# to have access to the data columns
source_gdf=gdf,
facecolor="steelblue",
)
ax.set_title("Shape encodes Census region")
ax.axis("off")
plt.tight_layout()
Data-driven opacity¶
Pass a column name to alpha. alpha_range sets the min and max opacity.
fig, ax = plt.subplots(figsize=(12, 7))
cartogram.plot(
ax=ax,
# pass the original DataFrame
# to have access to the data columns
source_gdf=gdf,
facecolor="steelblue",
# numeric-column-driven alpha
alpha="Below Poverty Level %",
alpha_range=(0.2, 1.0),
alpha_legend=True,
)
ax.set_title("Opacity encodes Poverty Level")
ax.axis("off")
plt.tight_layout()
Data-driven edge color and line width¶
edgecolor accepts a column name plus an optional edge_cmap.
linewidth accepts a column name plus linewidth_range.
fig, ax = plt.subplots(figsize=(12, 7))
cartogram.plot(
ax=ax,
# pass the original DataFrame
# to have access to the data columns
source_gdf=gdf,
facecolor="lightgray",
# category-column-driven edge color
# with custom color mapping
edgecolor="Region",
edge_cmap=region_colors,
# numeric-column-driven line width
linewidth="Below Poverty Level %",
linewidth_range=(0.3, 3.0),
# legends
edge_legend=True,
edge_legend_kwds={"loc": "upper center"},
linewidth_legend=True,
linewidth_legend_kwds={"loc": "upper left"},
)
ax.set_title("Edge color encodes Region and edge width encodes Poverty Level")
ax.axis("off")
plt.tight_layout()
Hatching¶
hatch accepts a column name and hatch_map maps each category to a matplotlib hatch string.
hatch_legend=True adds a legend entry for each hatch pattern.
hatch_map = {
"Northeast": "////",
"South": "....",
"Midwest": "xxxx",
"West": "----",
}
fig, ax = plt.subplots(figsize=(12, 7))
cartogram.plot(
ax=ax,
# pass the original DataFrame
# to have access to the data columns
source_gdf=gdf,
facecolor="Below Poverty Level %",
legend_kwds={"shrink": 0.7},
hatch="Region",
hatch_map=hatch_map,
hatch_legend=True,
hatch_legend_kwds={"title": "Region", "loc": "upper left"},
# set edge color for hatching
edgecolor="white",
)
ax.set_title("Color encoded Poverty Level and hatching encodes region")
ax.axis("off")
plt.tight_layout()
Labels¶
label adds text from a column. label_color and label_fontsize can each be
a fixed value or a data column name.
fig, ax = plt.subplots(figsize=(14, 8))
cartogram.plot(
ax=ax,
source_gdf=gdf,
facecolor="Region",
alpha=0.5,
# color_map=region_colors,
edgecolor="white",
linewidth=0.3,
label="State Abbreviation",
label_color="Below Poverty Level %",
label_cmap="hot",
label_fontsize=8,
label_kwargs={"fontweight": "bold"},
label_legend=True,
)
ax.set_title("Abbreviated State name labels with Poverty Level encoded text color")
ax.axis("off")
plt.tight_layout()