Skip to content

mpas_plot config examples and use cases

Michael Kavulich edited this page Dec 8, 2025 · 11 revisions

Simple use cases

Plotting a single 2d variable from a single MPAS history file

This is the simplest case. In the dataset: section, at least one input file (files:) must be specified, and at least one variable (vars:) must be specified. The vars: section includes a dedicated section for each variable to plot, and each variable should have source: native as a subsection (later when we review derived variables this will make more sense).

dataset:
  files: '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/history.2025-05-14_00.00.00.nc'
  vars:
    t2m:
      source: native
plot:
  filename: 'global_data/{var}_lev{lev}_{date}_{time}.png'
  title:
    text: 'Plot of {varln}, level {lev} for MPAS forecast, {date} {time}'
t2m_lev0_2025-05-14_00:00:00

Plotting from an MPAS diag file

MPAS diag files introduce slightly more complexity; because diag files do not contain all the necessary native grid data, we need to read that grid data from a file that contains it. Here we use the input grid file we used to create the MPAS domain, but often MPAS history files can be used as well.

dataset:
  files: '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/diag.2025-05-14_00.00.00.nc'
  gridfile: '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/x1.40962.init.nc'
  vars:
    mslp:
      source: native
plot:
  filename: 'global_data/{var}_lev{lev}_{date}_{time}.png'
  title:
    text: 'Plot of {varln}, level {lev} for MPAS forecast, {date} {time}'
mslp_lev0_2025-05-14_00:00:00

Note the various bracket {} keywords used for the output filename and plot title; these are described in more detail in default_options.yaml

Plotting data from multiple MPAS files

This utility can plot data from multiple MPAS files simultaneously. This can be done by either providing a list of files, or wildcard pattern matching.

dataset:
  files:
    - '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/history.2025-05-14_00.00.00.nc'
    - '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/history.2025-05-14_06.00.00.nc'
    - '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/history.2025-05-14_12.00.00.nc'
    - '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/history.2025-05-14_18.00.00.nc'
  gridfile: '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/x1.40962.init.nc'
  vars:
    u_pv:
      source: native
plot:
  filename: 'global_data/{var}_lev{lev}_{date}_{time}.png'
  title:
    text: 'Plot of {varln}, level {lev} for MPAS forecast, {date} {time}'
u_pv_lev0_2025-05-14_00:00:00 u_pv_lev0_2025-05-14_06:00:00 u_pv_lev0_2025-05-14_12:00:00 u_pv_lev0_2025-05-14_18:00:00

Next we will plot a 3d variable relhum ("Relative Humidity"). By default, all vertical levels of a 3d variable will be plotted, so this results in 220 plots (55 vertical levels times 4 time steps).

dataset:
  files: '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/history.2025-05-14_*.nc'
  gridfile: '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/x1.40962.init.nc'
  vars:
    relhum:
      source: native
plot:
  filename: 'global_data/{var}_lev{lev}_{date}_{time}.png'
  title:
    text: 'Plot of {varln}, level {lev} for MPAS forecast, {date} {time}'

Level 0:

relhum_lev0_2025-05-14_00:00:00 relhum_lev0_2025-05-14_06:00:00 relhum_lev0_2025-05-14_12:00:00 relhum_lev0_2025-05-14_18:00:00

Level 10:

relhum_lev10_2025-05-14_00:00:00 relhum_lev10_2025-05-14_06:00:00 relhum_lev10_2025-05-14_12:00:00 relhum_lev10_2025-05-14_18:00:00

Level 50:

relhum_lev50_2025-05-14_00:00:00 relhum_lev50_2025-05-14_06:00:00 relhum_lev50_2025-05-14_12:00:00 relhum_lev50_2025-05-14_18:00:00

When making large numbers of plots, it's highly recommended you take advantage of plot_mpas's parallel capability through Python's multiprocessing:

python plot_mpas_netcdf.py -p 16

Controlling plot dimensions and quality

Plotting different vertical levels

Plotting a subset of all vertical levels

If the user only wishes to plot a single vertical level, or some subset of the vertical levels, this can be done with the lev: setting:

dataset:
  files: '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/history.2025-05-08_00.00.00.nc'
  gridfile: '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/x1.40962.init.nc'
  vars:
    vorticity:
      source: native
      lev:
        - 0
        - 1
        - 2
        - 3
    qv:
      source: native
      lev:
        - 10
    surface_pressure:
      source: native
vorticity_3 qv_10

Note that all dimensions are zero-indexed, typically bottom-up, so level "10" is actually the 11th vertical level from the bottom.

Variables with non-standard vertical levels

By default, mpas_plot will attempt to plot all vertical levels by referencing the dimension nVertLevels, which is the standard MPAS variable name for vertical levels for atmospheric 3-dimensional variables. However, some variables typically have different sets of dimensions, such as vertical velocity or soil levels, which results in a plotting error:

$ python plot_mpas_netcdf.py
INFO     Loading user config settings
INFO     Loading data from netcdf files
INFO     Setting up plot tasks
INFO     Submitting to starmap
INFO     Starting plotit() for var='w', lev=0
CRITICAL Expected a 1D DataArray over 'n_face', but got 2 dimensions: ('n_face', 'nVertLevelsP1')
...
...
ERROR    PlotError:
ERROR    Variable w may not have standard vertical levels (nVertLevels):
dimensions=('n_face', 'nVertLevelsP1')
Check documentation for how to handle variables with non-standard vertical levels

To avoid this error, you can specify the vertical coordinate (found in "dimensions" printed in the error message) in this way:

dataset:
  files: '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/history.2025-05-08_00.00.00.nc'
  vars:
    w:
      source: native
      lev:
        - 0
      vertcoord: nVertLevelsP1
w_0

Projection settings

By default mpas_plot will plot all the data from the MPAS file(s), either a full global projection for global data or the regional domain for limited area MPAS, using the default "Plate Carée" projection, which is a lat-lon projection.

Plotting subdomains

To plot a specific subdomain, you can use the latrange and lonrange settings under projection:

dataset:
  files: '/glade/work/kavulich/MPAS/plotting/hires_data/diag.2020-08-10_06.00.00.nc'
  gridfile: /glade/work/kavulich/MPAS/plotting/hires_data/history.2020-08-10_00.00.00.nc
  vars:
    vorticity_925hPa:
      source: native
      plot:
        colormap: PuOr
plot:
  filename: 'hires_data/{var}_{date}_{time}.png'
  title:
    text: 'Plot of {varln} for MPAS forecast, {date} {time}'
  boundaries:
    detail: 2
    scale: '10m'
    color: ['k','gray','lightgray']
    linewidth: [1,0.5,0.2]
  projection:
    projection: PlateCarree
    latrange:
      - 35
      - 40
    lonrange:
      - -95
      - -85
vorticity_925hPa_2020-08-10_06:00:00

Note that with this regional domain, we have specified a plotting region that extends outside of the domain; in this case the script will simply plot no data.

You can plot different subdomains for different variables if desired:

dataset:
  files: '/glade/work/kavulich/MPAS/plotting/hires_data/diag.2020-08-10_06.00.00.nc'
  gridfile: /glade/work/kavulich/MPAS/plotting/hires_data/history.2020-08-10_00.00.00.nc
  vars:
    temperature_925hPa:
      source: native
      plot:
        colormap: jet
        projection:
          latrange:
            - 38
            - 43
          lonrange:
            - -95
            - -90
    dewpoint_925hPa:
      source: native
      plot:
        colormap: YlGn
        projection:
          latrange:
            - 40
            - 45
          lonrange:
            - -90
            - -85
plot:
  filename: 'hires_data/{var}_{date}_{time}.png'
  title:
    text: 'Plot of {varln} for MPAS forecast, {date} {time}'
  boundaries:
    detail: 2
    scale: '10m'
    color: ['k','gray','lightgray']
    linewidth: [1,0.5,0.2]
  lakes:
    enable: True
    scale: '10m'
    color: 'lightblue'
  dpi: 200
  figheight: 3
  figwidth: 6
dewpoint_925hPa_2020-08-10_06:00:00 temperature_925hPa_2020-08-10_06:00:00

Using custom colormaps

mpas_plot supports all matplotlib colormaps listed on this page, but also allows users to specify custom colormaps. One built-in custom colormap (defined in colormaps/radar_refl.yaml) is for radar reflectivity output:

dataset:
  files: '/glade/work/kavulich/MPAS/plotting/hires_data/diag.2020-08-10_06.00.00.nc'
  gridfile: /glade/work/kavulich/MPAS/plotting/hires_data/history.2020-08-10_00.00.00.nc
  vars:
    refl10cm_1km:
      source: native
      plot:
        colormap: radar_refl
        dpi: 600
        lakes:
          scale: '10m'
          enable: True
          color: 'lightblue'
plot:
  filename: 'hires_data/{var}_{date}_{time}.png'
  title:
    text: 'Plot of {varln} for MPAS forecast, {date} {time}'
  boundaries:
    detail: 2
    scale: '10m'
    color: ['k','gray','lightgray']
    linewidth: [1,0.5,0.2]
refl10cm_1km_2020-08-10_06:00:00

This is a higher resolution domain, so we will plot county and state boundaries in addition to the default country boundaries, as well as lake outlines.

If we view the colormap file colormaps/radar_refl.yaml, we can see that it also specifies some specific settings aside from the colorbar that allow it to fully imitate traditional radar displays:

vmin: 5
vmax: 75
plot_under: False
colors:
 - "#9C9C9C"
 - "#767676"
 - "#AAAAFF"
 - "#8C8CEE"
 - "#7070C9"
 - "#00FB90"
 - "#00BB00"
 - "#FFFF70"
 - "#D0D060"
 - "#FF6060"
 - "#DA0000"
 - "#AE0000"
 - "#0000FF"
 - "#FFFFFF"
 - "#E700FF"

The settings vmin and vmax specify the minimum and maximum values for the specific color mapping, and plot_under: False specifies that values less than vmin should not be plotted.

Calculating derived variables

mpas_plot provides the capability to calculate derived variables on the MPAS native grid. These simple functions take advantage of UxArray's capabilities to do matrix operations on the native grid (at least, those matrix operations that do not require a structured grid). These variables can be derived using pre-defined functions in custom_functions.py; users can define their own functions in this file if they wish.

diff_prev_timestep

diff_prev_timestep is a function that will take a given field and calculate the difference between that field and the values from the previous timestep (assuming the user has provided multiple timesteps of input).

dataset:
  files: '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/history.2025-05-14_*.nc'
  vars:
    delta_rainnc:
      source: derived
      function: diff_prev_timestep
      inputs:
        - "rainnc"
      attrs:
        long_name: "6-hour total grid-scale precipitation"
        units: "mm"
      vmax: 300
plot:
  filename: 'hires_data/{var}_{date}_{time}.png'
  title:
    text: 'Plot of {varln} for MPAS forecast, {date} {time}'
delta_rainnc_2025-05-14_00:00:00-0 delta_rainnc_2025-05-14_06:00:00-0 delta_rainnc_2025-05-14_12:00:00-0 delta_rainnc_2025-05-14_18:00:00-0

In another example, we specify a different colormap that better illustrates the changes of a non-monotonic field like temperature. This is a higher resolution domain, so we will plot county and state boundaries in addition to the default country boundaries. We also specify vmin and vmax so that the color scale remains consistent across all plots.

dataset:
  files: '/glade/work/kavulich/MPAS/plotting/hires_data/diag.2020-08-10_0[0-6].00.00.nc'
  gridfile: /glade/work/kavulich/MPAS/plotting/hires_data/history.2020-08-10_00.00.00.nc
  vars:
    delta_t2m:
      source: derived
      function: diff_prev_timestep
      inputs:
        - "t2m"
      attrs:
        long_name: "1-hour change in 2m temperature"
        units: "K"
      plot:
        colormap: seismic
        vmin: -10
        vmax: 10
plot:
  filename: 'hires_data/{var}_{date}_{time}.png'
  title:
    text: 'Plot of {varln} for MPAS forecast, {date} {time}'
  boundaries:
    detail: 2
    scale: '10m'
    color: ['k','gray','lightgray']
    linewidth: [1,0.5,0.2]
  pixel_ratio: 2
  dpi: 400
delta_t2m_2020-08-10_01:00:00-1 delta_t2m_2020-08-10_02:00:00-1 delta_t2m_2020-08-10_03:00:00-1 delta_t2m_2020-08-10_04:00:00-1 delta_t2m_2020-08-10_05:00:00-1

Because this is a high-resolution domain, to see more plot detail we set pixel_ratio: 2 and dpi: 400.

Limitations

There are limitations that need to be kept in mind when using these custom functions. Notice that here we have to provide our own file attributes such as long_name and units if we want them to display properly in filenames and titles. This is because this is a generic function that has no knowledge of what quantities it is deriving, it just knows that it is calculating the difference of values at one timestep from another.

Note also that because the script relies on the files passed in by the user, its assumes that these files, when sorted alphanumerically, are from a single forecast. The script has no knowledge of files that are not passed in, so you must pass in multiple files in order to see appropriate results (the first time step of this derived variable will always be undefined/a blank plot, as seen above). The script also has no knowledge of the time delta between timesteps; in the above examples we have a forecasts with 6-hour and 1-hour output intervals respectively, so that is reflected in the long_name field we specified.

More examples

Vertical max/min of a 3d-field

The functions vert_max and vert_min are provided for plotting the vertical max/min respectively of a 3d field:

dataset:
  files: '/glade/work/kavulich/MPAS/tutorial/120km_global/rundir/history.2025-05-08_00.00.00.nc'
  vars:
    vert_max_meridional:
      source: derived
      function: vert_max
      inputs:
        - "uReconstructMeridional"
      attrs:
        long_name: "Maximum meridional wind speed across full depth of atmosphere"
        units: "m/s"
    vert_min_meridional:
      source: derived
      function: vert_min
      inputs:
        - "uReconstructMeridional"
      attrs:
        long_name: "Minimum meridional wind speed across full depth of atmosphere"
        units: "m/s"
plot:
  filename: 'vertmax/{var}_{date}_{time}.png'
  title:
    text: 'Plot of {varln}, for MPAS forecast, {date} {time}'
  boundaries:
    detail: 0
    scale: '10m'
    color: 'k'
    linewidth: 0.5
  coastlines:
    scale: '10m'
    color: 'k'
    linewidth: 0.2
  colorbar:
    orientation: horizontal
    label: 'Units: {units}'
  colormap: "PiYG"
  dpi: 300
  figwidth: 5
  vmin: -50
  vmax: 50
vert_max_meridional_2025-05-08_00:00:00 vert_min_meridional_2025-05-08_00:00:00