Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Plotting different grids

Many meteorological and climate datasets are not stored on simple regular latitude/longitude grids, or even on regular geospatial coordinate systems. Modern NWP models often use alternative grid structures - such as HEALPix (Hierarchical Equal Area isoLatitude Pixelization) and Octahedral reduced Gaussian grids — which offer better spatial uniformity or computational efficiency. Visualising these grids naively can be frustrating with typical open-source tooling: the data points don’t align to a regular mesh, so you can’t simply call standard matplotlib/cartopy methods like contour or pcolormesh.

With earthkit, as long as your data carries the right metadata (e.g. a GRIB file with a gridType key), earthkit-plots (underpinned by earthkit-geo) can identify the grid type and choose an appropriate rendering strategy automatically — no manual coordinate juggling required.

Plotting methods for non-regular grids

earthkit-plots provides four methods that work out of the box with unstructured or reduced grids:

MethodWhat it drawsBest for
point_cloudA scatter marker at every grid point, coloured by valueQuick previews; very fast
grid_cellsEach grid cell rendered as a filled polygonAccurate cell-boundary visualisation
contourfInterpolated filled contours resampled onto a regular gridSmooth, continuous visualisations that look more “physical”
grid_pointsMarker at every grid point (no fill)Inspecting grid density/distribution

point_cloud and grid_points are the lightest options — they plot one marker per data point and require no interpolation. grid_cells draws the true shape of each cell, which is most faithful to the underlying discretisation but can be slower for high-resolution grids. contourf resamples the irregular data onto a regular target grid first (using earthkit-geo under the hood) and then applies standard matplotlib contouring, giving smooth, visually clean results.

HEALPix grids

Let’s start with some temperature data on a HEALPix grid. First, let’s access a sample HEALPix dataset and inspect the grid.

| NOTE: To visualise HEALPix grid cells, you need the healpy library:

!pip install healpy
import earthkit.data as ekd
import earthkit.plots as ekp

healpix_data = ekd.from_source("sample", "healpix-h128-nested-2t.grib")
healpix_data.to_fieldlist().geography.grid_spec()

Now let’s visualise the data over a small domain (France and Spain) so that we can see the details of the grid, using the four methods described above.

figure = ekp.Figure(rows=2, columns=2, domain=["France", "Spain"])

style = ekp.styles.Style(
    levels=range(0, 21),
    colors="Spectral_r",
    units="celsius",
)

for method in ["point_cloud", "grid_cells", "contourf"]:
    subplot = figure.add_map()
    getattr(subplot, method)(healpix_data, style=style)
    subplot.title(f"${method}$".replace("_", "\_"))
    
subplot = figure.add_map()
subplot.grid_points(healpix_data)
subplot.title("$grid\_points$")

figure.coastlines()
figure.gridlines()

figure.title("Plotting HEALPix grid data with various methods")

figure.legend(location="right")

figure.show()

Octahedral reduced Gaussian

Now let’s do the same with Octahedral reduced Gaussian grid data. First, let’s access a sample dataset and inspect the grid.

rgg_data = ekd.from_source("url", "https://get.ecmwf.int/repository/test-data/earthkit-regrid/test-data/global_0_360/O32.grib")
rgg_data.to_fieldlist().geography.grid_spec()

Now let’s plot it. Note that other than the change in domain and style, the code we use to plot this dataset is exactly the same as the code we used to plot the HEALPix data above.

figure = ekp.Figure(rows=2, columns=2, domain="Arctic")

style = ekp.styles.Style(
    levels=range(-40, 40),
    colors="Spectral_r",
    units="celsius",
)

for method in ["point_cloud", "grid_cells", "contourf"]:
    subplot = figure.add_map()
    getattr(subplot, method)(rgg_data, style=style)
    subplot.title(f"${method}$".replace("_", "\_"))
    
subplot = figure.add_map()
subplot.grid_points(rgg_data)
subplot.title("$grid\_points$")

figure.title("Plotting Octahedral grid data with various methods")

figure.coastlines()
figure.borders()
figure.legend(location="right")

figure.show()

When metadata is missing

So far we have been loading data from GRIB files, which carry rich metadata about the grid that earthkit can read directly. When you convert GRIB data to an xarray Dataset with to_xarray(), that metadata is embedded in the _earthkit attribute on each variable. earthkit-plots reads this attribute automatically, so the same plotting calls work without any extra configuration.

However, the cell below deliberately removes the _earthkit attribute to simulate a common real-world scenario: you have an xarray Dataset whose spatial structure is not described in its metadata — perhaps it was produced by a third-party tool, loaded from a NetCDF file, or had its attributes stripped. In this case earthkit-plots cannot infer the grid type on its own.

healpix_ring_data = ekd.from_source("sample", "healpix-h128-ring-2t.grib")
ds = healpix_ring_data.to_xarray()
ds.t.attrs.pop("_earthkit")
ds

When your dataset lacks the _earthkit metadata, you can supply the grid specification directly via the resample argument. The Regrid resampler accepts an in_grid dictionary that describes the source grid — here {"grid": "H128", "order": "ring"} tells earthkit-geo that the data lives on a HEALPix grid with nside=128 in ring ordering.

earthkit-plots passes this information to earthkit-geo, which regrids the data onto a regular lat/lon grid before plotting. The result is identical to the GRIB-backed example above; the only difference is that we had to be explicit about the grid type because the metadata was absent.

from earthkit.plots.resample import Regrid

style = ekp.styles.Style(
    levels=range(0, 21),
    colors="Spectral_r",
    units="celsius",
)

ekp.geo.plot(
    ds, domain=["France", "Spain"], style=style,
    resample=Regrid(in_grid={"grid": "H128", "order": "ring"}),
).show()

Exercises

  1. Given the regular lat-lon grid data below, can you visualise it in the same four ways we visualised reduced Gaussian and HEALPix data, over Spain?

era5_2t = ekd.from_source("sample", "era5-monthly-mean-2t-199312.grib")