Search code examples
python-3.xmatplotlibcartopy

Map with fine hatching using Python cartopy


I try to create a geographical map using contourf including shaded areas (indicating significance).

Here is a MWE:

import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs

lats = np.arange(-90, 91, 10)
lons = np.arange(-180, 181, 20)
data = np.sin(np.arange(len(lats)*len(lons))).reshape(len(lats), len(lons))

proj = ccrs.Robinson()
fig, ax = plt.subplots(figsize=(6, 7), subplot_kw={'projection': proj})
im = ax.contourf(
    lons, lats, data,
    transform=ccrs.PlateCarree(),
)
ax.contourf(
    lons, lats, data > data.mean(),
    transform=ccrs.PlateCarree(),
    colors='none',
    levels=[.5, 1.5],
    hatches='///////',
)

ax.coastlines()
ax.set_global()
cbar = fig.colorbar(im, ax=ax, location='bottom')

What I struggle with is adjusting the properties of the hatching. It is way to coarse, I'd like to adjust this in order to be able to resolve finer structures. It is possible to do this by scaling the figure size:

scale = 10

fig, ax = plt.subplots(figsize=(6*scale, 7*scale), subplot_kw={'projection': proj})
ax.contourf(
    lons, lats, data,
    transform=ccrs.PlateCarree(),
)
ax.contourf(
    lons, lats, data > data.mean(),
    transform=ccrs.PlateCarree(),
    colors='none',
    levels=[.5, 1.5],
    hatches='///////',
)

ax.coastlines()
ax.set_global()
cbar = fig.colorbar(im, ax=ax, location='bottom')

But this literally messes up everything else (text, line width, etc.) and is probably not the best way of doing it in any case. Is there a better way of adjusting the properties of the hatching in such a case?

enter image description here enter image description here


Solution

  • The argument hatches in contourf should be a list of size 2 since you have two levels. You can then increase the density of your hatching patterns by repeating the pattern, for instance, density*'/'. So overall the line should be hatches=[density*'/',density*'/']. Below is an example when I set the density to 7:

    import numpy as np
    import matplotlib.pyplot as plt
    import cartopy.crs as ccrs
    
    lats = np.arange(-90, 91, 10)
    lons = np.arange(-180, 181, 20)
    data = np.sin(np.arange(len(lats)*len(lons))).reshape(len(lats), len(lons))
    
    proj = ccrs.Robinson()
    fig, ax = plt.subplots(figsize=(6, 7), subplot_kw={'projection': proj})
    im = ax.contourf(
        lons, lats, data,
        transform=ccrs.PlateCarree())
    density=7
    ax.contourf(
        lons, lats, data > data.mean(),
        transform=ccrs.PlateCarree(),
        colors='none',
        levels=[.5,1.5],
        hatches=[density*'/',density*'/'],
    )
    
    ax.coastlines()
    ax.set_global()
    cbar = fig.colorbar(im, ax=ax)
    

    And the output gives:

    enter image description here