'How to add hatching by condition with GEOPANDAS and matplotlib

I try to plot a map, where a value should define the type of hatching for each polygon. I managed to get a hatch for the total plot, but not based on a condition. Is there a way to do this with geopandas? My code:

import matplotlib as mpl
import matplotlib.pyplot as plt
import geopandas as gpd
from matplotlib.colors import Normalize

project_data = 'XXX'
border = gpd.read_file(f'{project_data}GIS/border.json')
data = gpd.read_file(f'{project_data}GIS/shape.json')

def marker(row, field):
    m = ''
    if (row[field] <= 0):
        m = ''
    elif (row[field] <= 0.5):
        m = '--'
    elif (row[field] <= 1):
        m = '/////'
    elif (row[field] <= 1.6):
        m = 'x'
    return m

data['UI_P45_M'] = data.apply(marker, field='UI_P45', axis=1)

field1 = 'AL_CUR_I'
hatch1 = 'UI_P45_M'
cmap = mpl.cm.get_cmap('pink_r')

fig, ax = plt.subplots(1)
ax.axis('off')
border.plot(facecolor="none", edgecolor="black",
       ax=ax, zorder=2, linewidth=0.5)
data.plot(
column=field1, linewidth=0, norm=Normalize(0, 1.2),
cmap=cmap, ax=ax, hatch=hatch1, zorder=1
)

fig = plt.gcf()

plt.savefig(f'{project_data}results/hatched.pdf')
plt.close(fig)

I also tried to put a layer on top where I do the hatching like this:

border.plot(facecolor="none", edgecolor="black",
           ax=ax,  zorder=3, linewidth=0.5)

data.plot(
    column=field1, linewidth=0,norm=Normalize(0,1.2),
    cmap=cmap, ax=ax, zorder=1
)
data.plot(
    column=field1, linewidth=0, hatch=hatch1,
    facecolor='none',
    ax=ax, zorder=2
)

... but still it doesn't show up. The picture that I get is this:

What am I doing wrong?



Solution 1:[1]

Plotting a geodataframe with polygon geometries leverages matplotlib's Polygon artists, so the hatch keyword argument is passed there.

From the Polygon docs, you can see that the hatch keyword is itself interpreted by matplotlib.patches.Patch.set_hatch. From these docs:

set_hatch(hatch)

Set the hatching pattern.

hatch can be one of:

/   - diagonal hatching
\   - back diagonal
|   - vertical
-   - horizontal
+   - crossed
x   - crossed diagonal
o   - small circle
O   - large circle
.   - dots
*   - stars

Letters can be combined, in which case all the specified hatchings are done. If same letter repeats, it increases the density of hatching of that pattern.

So the issue is actually that you can't specify a column name as the hatch indicator. Instead, subset the data for each hatch type, then choose one of the valid hatches, e.g.:

data.loc[some_criteria_1].plot(..., hatch='/')
data.loc[some_criteria_2].plot(..., hatch='|')
# etc

Solution 2:[2]

import geopandas as gpd
import folium
from folium.plugins import StripePattern

gdf = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres")).loc[
    lambda d: (d["continent"] == "Europe") & (~d["iso_a3"].isin(["-99", "RUS"]))
]
# classify countries into 4 with a label
gdf["fill_cat"] = pd.qcut(gdf["pop_est"], 4, labels=list("abcd"))

m = folium.Map(
    location=(gdf.total_bounds[[1, 3]].mean(), gdf.total_bounds[[0, 2]].mean()),
    height=300,
    width=500,
)
m.fit_bounds([gdf.total_bounds[[1, 0]].tolist(), gdf.total_bounds[[3, 2]].tolist()])

# category config
hatch_style = {
    "a": {"angle": 0, "color": "grey"},
    "b": {"angle": 45, "color": "red"},
    "c": {"angle": 90, "color": "green"},
    "d": {"angle": 135, "color": "blue"},
}
folium.GeoJson(
    gdf.__geo_interface__,
    tooltip=gpd.explore._tooltip_popup("tooltip", True, gdf),
    style_function=lambda p: {
        "color": hatch_style[p["properties"]["fill_cat"]]["color"],
        "weight": 1,
        "fillPattern": StripePattern(**hatch_style[p["properties"]["fill_cat"]]),
    },
).add_to(m)

m

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Michael Delgado
Solution 2 Rob Raymond