Source code for neural_lam.datastore.plot_example

"""CLI helper to plot slices from datastores for manual inspection."""

# Third-party
import matplotlib.figure
import matplotlib.pyplot as plt

# Local
from . import DATASTORES, init_datastore
from .base import BaseDatastore


[docs] def plot_example_from_datastore( category: str, datastore: BaseDatastore, col_dim: str, split: str = "train", standardize: bool = True, selection: dict = {}, index_selection: dict = {}, ) -> matplotlib.figure.Figure: """ Create a plot of the data from the datastore. Parameters ---------- category : str Category of data to plot, one of "state", "forcing", or "static". datastore : Datastore Datastore to retrieve data from. col_dim : str Dimension to use for plot facetting into columns. This can be a template string that can be formatted with the category name. split : str, optional Split of data to plot, by default "train". standardize : bool, optional Whether to standardize the data before plotting, by default True. selection : dict, optional Selections to apply to the dataarray, for example `time="1990-09-03T0:00"` would select this single timestep, by default {}. index_selection: dict, optional Index-based selection to apply to the dataarray, for example `time=0` would select the first item along the `time` dimension, by default {}. Returns ------- Figure Matplotlib figure object. Raises ------ NotImplementedError If the datastore is not on a rectilinear grid. """ if not datastore.is_on_rectilinear_grid: raise NotImplementedError( "Plotting requires a datastore on a rectilinear grid." ) da = datastore.get_dataarray(category=category, split=split) assert da is not None if standardize: da_stats = datastore.get_standardization_dataarray(category=category) da = (da - da_stats[f"{category}_mean"]) / da_stats[f"{category}_std"] da = datastore.unstack_grid_coords(da) if len(selection) > 0: da = da.sel(**selection) if len(index_selection) > 0: da = da.isel(**index_selection) col = col_dim.format(category=category) # check that the column dimension exists and that the resulting shape is 2D if col not in da.dims: raise ValueError(f"Column dimension {col} not found in dataarray.") da_col_item = da.isel({col: 0}).squeeze() if not len(da_col_item.shape) == 2: raise ValueError( f"Column dimension {col} and selection {selection} does not " "result in a 2D dataarray. Please adjust the column dimension " "and/or selection. Instead the resulting dataarray is:\n" f"{da_col_item}" ) crs = datastore.coords_projection col_wrap = min(4, int(da[col].count())) g = da.plot( # ty: ignore[missing-argument] x="x", y="y", col=col, col_wrap=col_wrap, subplot_kws={"projection": crs}, transform=crs, size=4, ) for ax in (g.axs if hasattr(g, "axs") else g.axes).flat: ax.coastlines() ax.gridlines(draw_labels=["left", "bottom"]) ax.set_extent(datastore.get_xy_extent(category=category), crs=crs) return g.fig
if __name__ == "__main__": # Standard library import argparse def _parse_dict(arg_str: str) -> tuple[str, int | float | str]: """Parse ``key=value`` CLI arguments into typed dictionary entries.""" key, value = arg_str.split("=") typed_value: int | float | str = value for op in [int, float]: try: typed_value = op(value) break except ValueError: pass return key, typed_value parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser.add_argument( "--datastore_kind", type=str, choices=DATASTORES.keys(), default="mdp", help="Kind of datastore to use", ) parser.add_argument( "--datastore_config_path", type=str, default=None, help="Path for the datastore config", ) parser.add_argument( "--category", default="state", help="Category of data to plot", choices=["state", "forcing", "static"], ) parser.add_argument( "--split", default="train", help="Split of data to plot" ) parser.add_argument( "--col-dim", default="{category}_feature", help="Dimension to use for plot facetting into columns", ) parser.add_argument( "--disable-standardize", dest="standardize", action="store_false", help="Disable standardization of data", ) # add the ability to create dictionary of kwargs parser.add_argument( "--selection", nargs="+", default=[], type=_parse_dict, help="Selections to apply to the dataarray, for example " "`time='1990-09-03T0:00' would select this single timestep", ) parser.add_argument( "--index-selection", nargs="+", default=[], type=_parse_dict, help="Index-based selection to apply to the dataarray, for example " "`time=0` would select the first item along the `time` dimension", ) args = parser.parse_args() assert args.datastore_config_path is not None, ( "Specify your datastore config with --datastore_config_path" ) selection = dict(args.selection) index_selection = dict(args.index_selection) datastore_kind = args.datastore_kind # check that column dimension is not in the selection if args.col_dim.format(category=args.category) in selection: raise ValueError( f"Column dimension {args.col_dim.format(category=args.category)} " f"cannot be in the selection ({selection}). Please adjust the " "column dimension and/or selection." ) datastore = init_datastore( datastore_kind=datastore_kind, config_path=args.datastore_config_path, ) plot_example_from_datastore( args.category, datastore, split=args.split, col_dim=args.col_dim, standardize=args.standardize, selection=selection, index_selection=index_selection, ) plt.show()