Gridded Plotting (marEx.plotX.gridded)

The marEx.plotX.gridded module provides specialised plotting functionality for structured (regular) grids, such as latitude-longitude gridded datasets commonly found in climate models, reanalysis products, and satellite observations.

Overview

This module implements the GriddedPlotter class, which is optimised for handling regular rectangular grids with coordinates organised as (time, lat, lon) or similar structures. It provides advanced geographic visualisation capabilities with full cartographic projection support through Cartopy.

Key Features:

  • Geographic Projections: Full support for cartographic projections via Cartopy

  • Longitude Wrapping: Automatic handling of periodic longitude boundaries

  • High-Performance Rendering: Optimised for large gridded datasets

  • Seamless Integration: Works seamlessly with xarray DataArrays via .plotX accessor

Classes

GriddedPlotter(xarray_obj[, dimensions, ...])

Plotter for structured oceanographic data on regular rectangular grids.

GriddedPlotter Class

class marEx.plotX.gridded.GriddedPlotter(xarray_obj, dimensions=None, coordinates=None)[source]

Bases: PlotterBase

Plotter for structured oceanographic data on regular rectangular grids.

Initialise GriddedPlotter.

Parameters:
__init__(xarray_obj, dimensions=None, coordinates=None)[source]

Initialise GriddedPlotter.

Parameters:
Return type:

None

wrap_lon(data)[source]

Handle periodic boundary in longitude by adding a column of data.

Parameters:

data (DataArray)

Return type:

DataArray

plot(ax, cmap='viridis', clim=None, norm=None)[source]

Implement plotting for gridded (i.e. regular grid) data.

Parameters:
Return type:

Tuple[Axes, QuadMesh]

The GriddedPlotter class handles structured grids with regular lat/lon coordinates:

# GriddedPlotter is typically accessed via the plotX accessor
# Automatic selection based on grid type detection

import xarray as xr
import marEx

# Load regular gridded data
data = xr.open_dataset('regular_grid.nc').temperature

# Plotting automatically uses GriddedPlotter
config = marEx.PlotConfig(title='Temperature', var_units='°C')
fig, ax, im = data.plotX.single_plot(config)

Methods

Longitude Wrapping

GriddedPlotter.wrap_lon(data)[source]

Handle periodic boundary in longitude by adding a column of data.

Parameters:

data (DataArray)

Return type:

DataArray

The wrap_lon method handles periodic longitude boundaries for global datasets:

# Longitude wrapping is automatically applied when needed
# For global data spanning 360 degrees, adds duplicate column at lon=360

# Example: data with longitude from 0 to 359.5
# wrap_lon will add a column at lon=360 equal to lon=0
# This prevents gaps in global plots

Plot Method

GriddedPlotter.plot(ax, cmap='viridis', clim=None, norm=None)[source]

Implement plotting for gridded (i.e. regular grid) data.

Parameters:
Return type:

Tuple[Axes, QuadMesh]

The core plotting method for structured grids:

# The plot method is called internally by single_plot, multi_plot, etc.
# It handles:
# - Longitude wrapping for global data
# - Cartopy coordinate transformations
# - Optimal rendering with pcolormesh

Basic Usage Examples

Simple Gridded Plot

import xarray as xr
import marEx

# Load gridded SST data
sst = xr.open_dataset('sst_gridded.nc').sst

# Basic plot with automatic grid detection
config = marEx.PlotConfig(
    title='Sea Surface Temperature',
    var_units='°C',
    cmap='thermal'
)

fig, ax, im = sst.plotX.single_plot(config)

Global Dataset Visualization

# Global dataset with longitude wrapping
config = marEx.PlotConfig(
    title='Global Temperature',
    var_units='°C',
    cmap='RdBu_r',
    issym=True,
    show_colorbar=True,
    grid_lines=True,
    grid_labels=True
)

# Longitude wrapping handled automatically
fig, ax, im = global_temp.plotX.single_plot(config)

Regional Subset

# Regional subset (no longitude wrapping needed)
regional_data = sst.sel(lat=slice(30, 60), lon=slice(-180, -120))

config = marEx.PlotConfig(
    title='North Pacific SST',
    var_units='°C',
    cmap='coolwarm',
    show_colorbar=True,
    grid_lines=True,
    grid_labels=True
)

fig, ax, im = regional_data.plotX.single_plot(config)

Time Series Visualization

Multi-Panel Time Series

# Plot multiple time steps
config = marEx.PlotConfig(
    var_units='°C',
    cmap='RdBu_r',
    issym=True,
    show_colorbar=True
)

# Create wrapped subplots
fig, axes = sst.plotX.multi_plot(config, col='time', col_wrap=4)

Animation

# Create time series animation
config = marEx.PlotConfig(
    title='SST Evolution',
    var_units='°C',
    cmap='thermal',
    show_colorbar=True
)

# Generate animation (requires ffmpeg)
movie_path = sst.plotX.animate(
    config,
    plot_dir='./animations',
    file_name='sst_evolution'
)

Advanced Configuration

Custom Dimension Names

# For data with non-standard coordinate names
config = marEx.PlotConfig(
    title='Temperature',
    var_units='°C',
    cmap='viridis',
    # Custom dimension mapping
    dimensions={'time': 'time', 'y': 'latitude', 'x': 'longitude'},
    coordinates={'time': 'time', 'y': 'latitude', 'x': 'longitude'}
)

fig, ax, im = data.plotX.single_plot(config)

Color Scaling Options

# Percentile-based scaling
config = marEx.PlotConfig(
    title='Temperature Anomalies',
    var_units='°C',
    cmap='RdBu_r',
    cperc=[5, 95],  # Use 5th and 95th percentiles
    extend='both'
)

# Symmetric scaling around zero
config = marEx.PlotConfig(
    title='Temperature Anomalies',
    var_units='°C',
    cmap='RdBu_r',
    issym=True,     # Symmetric around zero
    extend='both'
)

# Manual color limits
config = marEx.PlotConfig(
    title='Temperature',
    var_units='°C',
    cmap='plasma',
    clim=(-2, 5),   # Manual color limits
    extend='both'
)

Integration with Matplotlib

Custom Figure Setup

import matplotlib.pyplot as plt
import cartopy.crs as ccrs

# Create custom figure with specific projection
fig = plt.figure(figsize=(12, 8))
ax = plt.axes(projection=ccrs.PlateCarree())

# Use existing axes
config = marEx.PlotConfig(
    title='Custom Projection',
    var_units='°C',
    cmap='viridis'
)

fig, ax, im = data.plotX.single_plot(config, ax=ax)

# Add custom elements
ax.set_title('Modified Title', fontsize=16)
plt.tight_layout()

Subplot Integration

# Multi-panel comparison with custom layout
fig, axes = plt.subplots(2, 2, figsize=(16, 12))

datasets = [sst_obs, sst_model1, sst_model2, sst_diff]
titles = ['Observations', 'Model 1', 'Model 2', 'Difference']

for ax, dataset, title in zip(axes.flat, datasets, titles):
    config = marEx.PlotConfig(
        title=title,
        var_units='°C',
        cmap='RdBu_r',
        show_colorbar=False  # Add single colorbar later
    )

    fig, ax, im = dataset.plotX.single_plot(config, ax=ax)

# Add single colorbar for all subplots
fig.subplots_adjust(right=0.9)
cbar_ax = fig.add_axes([0.92, 0.15, 0.02, 0.7])
fig.colorbar(im, cax=cbar_ax, extend='both')

Geographic Projections

The GriddedPlotter uses Cartopy for geographic projections. The default projection is Robinson, but data is always transformed from PlateCarree:

# Default projection handling:
# - Data coordinates assumed to be in PlateCarree (regular lat/lon)
# - Display projection defaults to Robinson
# - Coordinate transformation handled automatically

# The plot method internally uses:
plot_kwargs = {
    'transform': ccrs.PlateCarree(),  # Input data coordinate system
    'cmap': cmap,
    'shading': 'auto'
}

# And the axes are created with:
ax = plt.axes(projection=ccrs.Robinson())  # Display projection

Global vs Regional Data

Longitude Wrapping Logic

The wrap_lon method automatically detects if longitude wrapping is needed:

# Wrapping is applied when:
# - Data spans approximately 360 degrees
# - abs(360 - (lon.max() - lon.min())) < 2 * lon_spacing

# Example: longitude from 0 to 359.5 with 0.5 degree spacing
# - Total span: 359.5 degrees
# - Spacing: 0.5 degrees
# - 360 - 359.5 = 0.5 < 2 * 0.5 = 1.0 → wrapping applied

# No wrapping for regional data:
# - longitude from -180 to -120 (60 degree span)
# - longitude from 0 to 90 (90 degree span)

Grid Detection

The GriddedPlotter is automatically selected when:

  • Data has separate latitude and longitude dimensions

  • Coordinates follow structured grid patterns

  • Typical dimension structure: (time, lat, lon) or (lat, lon)

# Automatic detection based on:
# - 'lat' and 'lon' in data.dims
# - Regular spacing in lat/lon coordinates
# - Rectangular grid structure

# Override detection if needed:
marEx.specify_grid(grid_type='gridded')

See Also