Hatch area using pcolormesh in Basemap

6.3k Views Asked by At

I try to hatch only the regions where I have statistically significant results. How can I do this using Basemap and pcolormesh?

plt.figure(figsize=(12,12))

lons = iris_cube.coord('longitude').points
lats = iris_cube.coord('latitude').points

m = Basemap(llcrnrlon=lons[0], llcrnrlat=lats[0], urcrnrlon=lons[-1], urcrnrlat=lats[-1], resolution='l')

lon, lat = np.meshgrid(lons, lats)

plt.subplot(111)

cs = m.pcolormesh(lon, lat, significant_data, cmap=cmap, norm=norm, hatch='/')
2

There are 2 best solutions below

1
On

I have a simple solution for this problem, using only pcolormesh and not pcolor: Plot the color mesh, then hatch the entire plot, and then plot the original mesh again, this time by masking statistically significant cells, so that the only hatching visible is those on significant cells. Alternatively, you can put a marker on every cell (looks good too), instead of hatching the entire figure.

(I use cartopy instead of basemap, but this shouldn't matter.)

Step 1: Plot your field (z) normally, using pcolormesh.

mesh = plt.pcolormesh(x,y,z)

where x/y can be lons/lats.

Step 2: Hatch the entire plot. For this, use fill_between:

hatch = plt.fill_between([xmin,xmax],y1,y2,hatch='///////',color="none",edgecolor='black')

Check details of fill_between to set xmin, xmax, y1 and y2. You simply define two horizontal lines beyond the bounds of your plot, and hatch the area in between. Use more, or less /s to set hatch density.

To adjust hatch thickness, use below lines:

import matplotlib as mpl
mpl.rcParams['hatch.linewidth'] = 0.3

As an alternative to hatching everything, you can plot all your x-y points (or, lon-lat couples) as markers. A simple solution is putting a dot (x also looks good).

hatch = plt.plot(x,y,'.',color='black',markersize=1.5)

One of the above will be the basis of your 'hatch'. This is how it should look after Step 2:

This is how it should look after Step 2

Step 3: On top of these two, plot your color mesh once again with pcolormesh, this time masking cells containing statistically significant values. This way, the markers on your 'insignificant' cells become invisible again, while significant markers stay visible.

Assuming you have an identically sized array containing the t statistic for each cell (t_z), you can mask significant values using numpy's ma module.

z_masked = numpy.ma.masked_where(t_z >= your_threshold, z)

Then, plot the color mesh, using the masked array.

mesh_masked = plt.pcolormesh(x,y,z_masked)

Use zorder to make sure the layers are in correct order. This is how it should look after Step 3:

This is how it should look after Step 3

0
On

It seems pcolormesh does not support hatching (see https://github.com/matplotlib/matplotlib/issues/3058). Instead, the advice is to use pcolor, which starting from this example would look like,

import matplotlib.pyplot as plt
import numpy as np

dx, dy = 0.15, 0.05
y, x = np.mgrid[slice(-3, 3 + dy, dy),
                slice(-3, 3 + dx, dx)]
z = (1 - x / 2. + x ** 5 + y ** 3) * np.exp(-x ** 2 - y ** 2)
z = z[:-1, :-1]
zm = np.ma.masked_less(z, 0.3)

cm = plt.pcolormesh(x, y, z)
plt.pcolor(x, y, zm, hatch='/', alpha=0.)
plt.colorbar(cm)
plt.show()

where a mask array is used to get the values of z greater than 0.3 and these are hatched using pcolor.

enter image description here

To avoid plotting another colour over the top (so you get only hatching) I've set alpha to 0. in pcolor which feels a bit like a hack. The alternative is to use patch and assign to the areas you want. See this example Python: Leave Numpy NaN values from matplotlib heatmap and its legend. This may be more tricky for basemaps, etc than just choosing areas with pcolor.