Contour Demos#
Author: Dylan Nelson
Demos of the .plot.contour() method with unstructured grids in UXarray. The grids are the small
test meshes of the UXarray repository. The plots are interactive and show the variety of ways
that plots can be generated using this method.
from pathlib import Path
import cartopy.crs as ccrs
import geoviews.feature as gf
import holoviews as hv
import numpy as np
import xarray as xr
import uxarray as ux
MESH = Path("../../../test/meshfiles")
1. Cubed sphere: edge contours#
Dataset |
Variable |
Method |
Contours |
Color |
Line width |
|---|---|---|---|---|---|
Cubed sphere |
|
|
7 levels (default) |
black |
default |
uxds = ux.open_dataset(
MESH / "ugrid/outCSne30/outCSne30.ug",
MESH / "ugrid/outCSne30/outCSne30_vortex.nc",
)
psi = uxds["psi"]
contours = psi.plot.contour(color="black")
psi.plot(
cmap="viridis",
width=800,
height=400,
title="Cubed sphere, method='edges'",
) * contours
2. MPAS ocean: interpolated contours#
Dataset |
Variable |
Method |
Contours |
Color |
Line width |
|---|---|---|---|---|---|
MPAS ocean |
|
|
2000 m and 4000 m |
white |
1 |
Using an ocean model where there are no land cells
mpas = ux.open_dataset(
MESH / "mpas/QU/oQU480.231010.nc", MESH / "mpas/QU/oQU480.231010.nc"
)
depth = mpas["bottomDepth"]
contours = depth.plot.contour(
levels=[2000, 4000],
method="interpolated",
color="white",
line_width=1,
)
depth.plot(
cmap="Blues",
width=800,
height=400,
title="MPAS ocean depth (m), method='interpolated'",
) * contours
3. ICON triangles: edge contours, without labels#
Dataset |
Variable |
Method |
Contours |
Color |
Line width |
Labels |
|---|---|---|---|---|---|---|
ICON |
|
|
about 6 levels |
crimson |
1 |
off |
The same default method on a triangular grid. The lines zigzag along triangle edges.
labels=False gives the lines without the numbered labels.
def wave(uxgrid):
lon, lat = np.radians(uxgrid.face_lon.values), np.radians(uxgrid.face_lat.values)
values = np.cos(lat) ** 2 * np.sin(3 * lon) + 0.5 * np.sin(lat)
return ux.UxDataArray(
xr.DataArray(values, dims="n_face", name="wave"), uxgrid=uxgrid
)
icon = wave(ux.open_grid(MESH / "icon/R02B04/icon_grid_0010_R02B04_G.nc"))
contours = icon.plot.contour(
levels=6,
color="crimson",
line_width=1,
labels=False,
)
icon.plot(
cmap="Greys",
width=800,
height=400,
title="ICON triangles, method='edges', labels=False",
) * contours
4. Data on nodes: interpolated contours, colored by level#
Dataset |
Variable |
Method |
Contours |
Color |
Line width |
|---|---|---|---|---|---|
Geoflow, 6,000 nodes |
|
|
−12, −6, 6, 12 |
by level, |
1.2 |
Edge contours need cells, so node data uses the interpolated method. Without a color, each line
is colored by its level.
.plot() draws node data as points, so the shading behind the lines is the same variable averaged
onto the cells with topological_mean(). Its colorbar is turned off, which
leaves the colorbar of the lines.
geoflow = ux.open_dataset(
MESH / "ugrid/geoflow-small/grid.nc", MESH / "ugrid/geoflow-small/v1.nc"
)
v1 = geoflow["v1"].isel(time=0, meshLayers=0)
contours = v1.plot.contour(
levels=[-12, -6, 6, 12],
cmap="coolwarm",
colorbar=True,
line_width=1.2,
show_legend=False,
)
v1.topological_mean(destination="face").plot(
cmap="Greys",
colorbar=False,
ylim=(-20, 20),
width=800,
height=400,
title="Geoflow v1 on nodes, method='interpolated'",
) * contours
5. HEALPix in a map projection#
Dataset |
Variable |
Method |
Contours |
Color |
Line width |
Projection |
|---|---|---|---|---|---|---|
HEALPix zoom 4, 3,072 cells |
|
|
about 5 levels |
dark orange |
1.2 |
Robinson |
With projection=, the contours and their labels come back as GeoViews objects and overlay on a
projected plot and on coastlines. The shaded plot and the contours get the same projection.
healpix = wave(ux.Grid.from_healpix(zoom=4))
projection = ccrs.Robinson()
contours = healpix.plot.contour(
levels=5, projection=projection, color="darkorange", line_width=1.2
)
(
healpix.plot(
projection=projection,
cmap="cividis",
width=800,
height=400,
title="HEALPix, method='edges', Robinson projection",
)
* contours
* gf.coastline(projection=projection)
)
6. Changing the Number of Levels#
Dataset |
Variable |
Method |
Contours |
Color |
Line width |
|---|---|---|---|---|---|
Cubed sphere |
|
|
about 3, 7 and 15 levels |
black |
default |
levels as a number lets the user decide the quantity of levels, and the function cleanly decides where to place them.
Alternatively, they can be provided as a list, with levels at each number in the list.
panels = []
for n in (3, 7, 15):
contours = psi.plot.contour(levels=n, color="black")
panels.append(
psi.plot(
cmap="viridis", colorbar=False, width=420, height=260, title=f"levels={n}"
)
* contours
)
(panels[0] + panels[1] + panels[2]).cols(3)
7. Outlined levels vs Smoothed levels#
Dataset |
Variable |
Method |
Contours |
Color |
Line width |
|---|---|---|---|---|---|
Cubed sphere |
|
|
0.7, 1.0, 1.3 |
black |
default |
levels as a list draws lines at exactly those values.
chosen = [0.7, 1.0, 1.3]
panels = []
for method in ("edges", "interpolated"):
contours = psi.plot.contour(levels=chosen, method=method, color="black")
panels.append(
psi.plot(
cmap="viridis",
colorbar=False,
width=600,
height=330,
title=f"levels={chosen}, method='{method}'",
)
* contours
)
(panels[0] + panels[1]).cols(2)
8. Across the antimeridian#
Dataset |
Variable |
Method |
Contours |
Color |
Line width |
Labels |
Projection |
|---|---|---|---|---|---|---|---|
MPAS ocean |
|
|
2000 m and 4000 m |
white |
1 |
dark grey, bold |
Robinson, centered on 180° |
The lines continue across ±180° longitude. On a map centered on the Pacific that is the middle of the picture.
The labels take the color of the lines. hv.opts.Labels restyles them after the call, here to
dark grey and bold. Many additional options can be provided through .opts. See
Applying Customizations in the
HoloViews documentation for how .opts works and how to list the options an element has.
pacific = ccrs.Robinson(central_longitude=180)
contours = depth.plot.contour(
levels=[2000, 4000],
method="interpolated",
projection=pacific,
color="white",
line_width=1,
).opts(hv.opts.Labels(text_color="#333333", text_font_style="bold"))
(
depth.plot(
projection=pacific,
cmap="Blues",
width=800,
height=400,
title="MPAS ocean depth (m), centered on 180°",
)
* contours
* gf.coastline(projection=pacific)
)