Visualizing grid meshes
The purpose of this page is to document strategies to plot/visualize raw mesh files. The most common example is plotting mesh files in “SCRIP” format. These files contain information about the cell vertices, cell centers, and grid area for each cell in a mesh. One way of visualizing such a mesh is to draw polygons based on each cell vertex. The following is sufficient to do this using matplotlib, using a low-resolution MPAS mesh for illustrative purposes:
from xarray import open_dataset
from matplotlib.collections import PatchCollection, PolyCollection
import numpy
from matplotlib import pyplot, patches
# Fix longitudes to go from -180 to 180 instead of 0 to 360
def fix_lon(lon):
lon = numpy.where(lon > 180, lon - 360, lon)
return lon
# Wrap coords around edge of projection
# NOTE: this is a dumb way to do this, we should wrap in projection space
def wrap_coords(x, y):
if (any(x < -90) and any(x > 90)):
x = numpy.where(x < -90, 360 + x, x)
if (any(y < -45) and any(y > 45)):
y = numpy.where(y < -45, 180 + y, y)
return x, y
# Plot polygons defined by cell vertices
def plot_scrip(xv, yv, **kwargs):
# Wrap edges
for i in range(xv.shape[0]):
xv[i,...], yv[i,...] = wrap_coords(xv[i,...], yv[i,...])
# Create array of cell vertices, indexed [npoints, ncorners, 2]
corners = numpy.stack([xv, yv], axis=2)
# Create a PatchCollection from our aggregated list of PathPatches
p = PolyCollection(corners, **kwargs)
# Add the collection to the axes
ax = pyplot.gca()
ax.add_collection(p)
# Set sane axes limits
ax.set_xlim([xv.min(), xv.max()])
ax.set_ylim([yv.min(), yv.max()])
# Return collection of patches
return p
figure = pyplot.figure(figsize=(20, 10))
ax = figure.add_subplot(111)
with open_dataset(grid_file) as ds:
pl = plot_scrip(fix_lon(ds['grid_corner_lon']), ds['grid_corner_lat'], facecolor='none', edgecolor='dodgerblue')
This will probably be slow for large grids, since it draws each polygon in a loop, but serves for illustrative purposes. The resulting image for the QU240 grid:
Perhaps a better way to visualize these grids, especially for large grids, would be to plot the grid area. The following will plot native grid data given the scrip cell vertices:
from xarray import open_dataset
from matplotlib import pyplot
from matplotlib.collections import PolyCollection
import numpy
def plot_unstructured(
xv, yv, data, vmin=None, vmax=None, **kwargs):
"""
Plot unstructured data. xv and yv specify the x and y coordinates
of the vertices of each cell and should have shape [ni,nv] where ni
is the size of the grid (number of cells) and nv is the number of
vertices for each cell. Data contains the values of the data you
want to plot, and should have dimension [ni,]. The intent with this
function is that you will need to read in an auxillary SCRIP-format
file that describes the grid (unless this information is present in
the same file that contains the data; unlikely) as well as the file
that contains the data, and grab the cell corner information from
the SCRIP file and the data from the data file. This function will
then plot the data on the native grid by looping over each cell and
drawing patches for each. Note that this will probably be really
slow for big grids! Seems to work alright up to about ne120 or so,
but really some more clever techniques should probably be used here
(parallelism?).
NOTE: To avoid artifacts due to antialiasing, you should probably pass
antialiaseds=False to **kwargs.
"""
# Wrap edges
for i in range(xv.shape[0]):
xv[i,...], yv[i,...] = wrap_coords(xv[i,...], yv[i,...])
# Create array of cell vertices, indexed [npoints, ncorners, 2]
corners = numpy.stack([xv, yv], axis=2)
# Create a PatchCollection from our aggregated list of PathPatches
p = PolyCollection(corners, array=data, **kwargs)
# Set scale, mimicking vmin and vmax plot kwargs
if vmin is not None and vmax is not None:
p.set_clim([vmin, vmax])
# Add the collection to the axes
ax = pyplot.gca()
ax.add_collection(p)
# Set sane axes limits
ax.set_xlim([xv.min(), xv.max()])
ax.set_ylim([yv.min(), yv.max()])
# Return collection of patches
return p
with open_dataset(grid_file) as ds:
figure = pyplot.figure(figsize=(20, 10))
ax = figure.add_subplot(111)
pl = plot_unstructured(fix_lon(ds['grid_corner_lon']), ds['grid_corner_lat'], ds['grid_area'], antialiaseds=False)