Visualizing Grid Topology#

Authors: Philip Chmielowiec

Overview#

This usage example showcases how to use UXarray’s plotting API to visualize the topology of an unstructured grid (i.e., the elements that make up a grid). The majority of this notebook uses the Primal Mesh of an MPAS Ocean Grid, with the final example using an MPAS Atmosphere Grid.

Note

UXarray’s Plotting API is build around the Holoviews package. For details about customization and accepted parameters, pleases refer to their documentation.

import uxarray as ux
from holoviews import opts
base_path = "../../test/meshfiles/mpas/QU/"
grid_path = base_path + "oQU480.231010.nc"
uxds = ux.open_dataset(grid_path, grid_path)
grid = uxds.uxgrid

Using the Grid.plot() Accessor#

Each Grid object is initialized with a plotting accessor, which enables plotting routines to be called directly on the object. By default, calling .plot() on a Grid instance plots all the edges of a grid.

grid.plot(title="Default Grid Plot Method", height=350, width=700)

Since all of our plotting methods are built around the Holoviews package, you can select between Matplotlib and Bokeh backends if desired (Bokeh is the default and is suggested).

grid.plot(backend="matplotlib", title="Default Grid Plot Method with Matplotlib Backend", fig_size=200)

Since each UxDataArray and UxDataset is paired with a Grid objected through the .uxgrid attribute, the same function calls can be executed

uxds.uxgrid.plot(title="Default Plot Method through uxgrid Accessor", height=350, width=700)

Visualizing Grid Elements#

As described in previous sections, a Grid is composed of nodes and edges that connect to create our unstructured grid. These elements can be visualized directly through a Grid instance.

grid.plot.nodes(title="Node Plot", size=1, height=350, width=700)
grid.plot.edges(title="Edge Plot", height=350, width=700)

Since the edge plot above outlines the geometry of our mesh, another way to call it is through the plot.mesh() call. Both plot.mesh() and plot.edges() takes in an optional argument called exclude_antimeridian, which generates the visualuzation with or without correcting polygons that cross at the antimeridian (+- 180 longitude)

grid.plot.mesh(exclude_antimeridian=True, height=350, width=700)

Zooming in and overlaying both the edge and node plots together shows us the relationship between how the nodes are connected to form edges and faces.

(grid.plot.edges(color="Black") * \
 grid.plot.nodes(color="Red", size=5)).opts(xlim = (-150,-90), ylim = (20, 50), height=350, width=700, title="Nodes and Edges")

Visualization Grid Coordinates (Nodes, Edge Centers, & Face Centers)#

We saw above that Nodes are plotted as points using latitude and longitude coordinates. In addition to nodes, one may want to visualize other coordinates, such as face centers or edge centers. Since these elements are also represented in terms of the latitude and longitude, we can also plot them as points like we did with the Nodes.

(uxds.uxgrid.plot.mesh(color="Black", line_dash='dashed', line_width=2, exclude_antimeridian=False) * \
 uxds.uxgrid.plot.nodes(color = "Red", size=4) * \
 uxds.uxgrid.plot.face_centers(color = "Blue",  size=4) * \
 uxds.uxgrid.plot.edge_centers(color = "Green",  size=4)).opts(title="Node, Edge, & Face Coordinates", xlim=(-150,-90), ylim=(20, 50), width=700, height=350)

You can also plot each of these elements using the plot.node_coords(), plot.face_coords(), and plot.edge_coords() methods, which are equivalent to the ones shown above.

( uxds.uxgrid.plot.mesh(color="Black", line_dash='dashed', line_width=2, exclude_antimeridian=False) * \
 uxds.uxgrid.plot.node_coords(color = "Red", size=4) * \
 uxds.uxgrid.plot.face_coords(color = "Blue",  size=4) * \
 uxds.uxgrid.plot.edge_coords(color = "Green",  size=4)).opts(title="Node, Edge, & Face Coordinates", xlim=(-150,-90), ylim=(20, 50), width=700, height=350)

MPAS Voronoi Mesh#

The dataset used in the examples above is an MPAS Ocean Mesh, which as of the most recent release can only be loaded correctly using the Primal Mesh in UXarray. The following mesh is taken from the atmospheric component of MPAS, which covers the whole surface of the earth, and can be properly loaded in with UXarray in both the Primal and Dual formats.

base_path = "../../test/meshfiles/mpas/QU/"
grid_path = base_path + "mesh.QU.1920km.151026.nc"
primal_grid = ux.open_grid(grid_path, use_dual=False)
dual_grid = ux.open_grid(grid_path, use_dual=True)

We can plot the Nodes and Edges of both the Primal and Dual meshes together to form a Voronoi Mesh, which can be read about here.

(primal_grid.plot.edges(color="Blue", line_width=2) * \
 primal_grid.plot.nodes(color="Blue", size=10) * \
 dual_grid.plot.edges(color="Red", line_width = 2) * \
 dual_grid.plot.nodes(color="Red", size=10)).opts(title="MPAS Primal & Dual Mesh", xlim=(-50, 50), ylim=(-25, 25), width=700, height=350)