Skip to content

Instantly share code, notes, and snippets.

@joferkington
Last active December 10, 2020 23:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joferkington/ced0d2853673d9cedb755f1c7c02084e to your computer and use it in GitHub Desktop.
Save joferkington/ced0d2853673d9cedb755f1c7c02084e to your computer and use it in GitHub Desktop.
Using a masked array for contour clipping
# There are two ways to clip data to irregular boundaries.
# One uses a masked array (and is most useful for "real" data)
# The other uses set_clip_path (and is most useful for graphics)
# This demonstrates the first (masked array)
import matplotlib.pyplot as plt
import scipy.ndimage
import numpy as np
import skimage.draw
np.random.seed(1977)
# Generate dummy data.
raster = 18 * np.random.random((5,5)) - 10
# Smoothly interpolate to a much denser cellsize
raster = scipy.ndimage.zoom(raster, 100, order=3)
# Polygon boundary (made up)...
x = np.array([93.40206186, 68.1443299, 5., 138.86597938, 194.43298969,
323.24742268, 495., 447.01030928, 419.22680412, 399.02061856,
351.03092784, 262.62886598, 179.27835052, 194.43298969,
17.62886598, 47.93814433, 93.40206186])
y = np.array([209.5296751, 168.89768023, 15.30734213, 10.15472679, 92.34232467,
5., 10.15472679, 153.62517763, 335.61141324, 450.40016541,
480.15331617, 495., 447.91714297, 345.63913876, 333.10311499,
247.49668342, 209.5296751])
# Mask out areas outside of our polygon boundary.
# There are a gazillion ways to do this. Use rasterio if you're working with
# real geographic data. Using skimage here just to avoid geospatial libs.
mask = np.ones(raster.shape, dtype=bool)
i, j = skimage.draw.polygon(y, x)
mask[i, j] = False
raster = np.ma.masked_where(mask, raster)
# Now let's make a filled contour plot
levels = [-10, -5, -2, 2, 5, 10]
fig, ax = plt.subplots(constrained_layout=True)
im = ax.contourf(raster, levels, cmap='gist_earth')
ctr = ax.contour(raster, levels, colors='k', linewidths=0.8, linestyles='solid')
cbar = fig.colorbar(im, orientation='horizontal', aspect=5, shrink=0.5)
cbar.add_lines(ctr)
# We'll draw our border over it to hide the edges
ax.fill(x, y, facecolor='none', edgecolor='k', linewidth=1.5)
# And let's configure things to roughly match the original
ax.axis('off')
cbar.ax.tick_params(length=0)
cbar.ax.xaxis.tick_top()
ax.set(aspect=1)
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment