Plotting Universes and Multiverses

Utopia makes plotting multidimensional data easy. This page describes how to create plot functions and configurations for plotting data from individual universes as well as from the multiverse.

Note

This page documents only a selection of the plotting capabilities. Make sure to also visit the dantro documentation, where the plotting framework is implemented.


Plots from Universe Data

To create plots that use data from a single universe, use the UniversePlotCreator. It allows specifying a set of universes from which to create plots, and passes data from the selected universes to the plotting function.

The plot configuration needs to know which universes to plot. This is done via the universes argument:

---
my_universe_plot:
  universes: all        # can also be 'first', 'any', or a dict specifying
                        # a multiverse subspace to restrict the plots to
  # ... more arguments

Without DAG framework

Without the DAG framework, the data needs to be selected manually:

from utopya import DataManager, UniverseGroup
from utopya.plotting import is_plot_func, PlotHelper, UniversePlotCreator

@is_plot_func(creator_type=UniversePlotCreator)
def my_plot(dm: DataManager, *, uni: UniverseGroup, hlpr: PlotHelper,
            **additional_kwargs):
    """A universe-specific plot function using the data transformation
    framework and the plot helper framework.

    Args:
        dm: The DataManager, containing *all* data
        uni: The currently selected universe. Select the data from here.
        hlpr: The associated plot helper.
        **additional_kwargs: Anything else from the plot config. Ideally,
            specify these explicitly rather than gathering them via ``**``.
    """
    # Get the data
    x = uni['data/MyModel/foo']
    y = uni['data/MyModel/bar']

    # Plot the data
    hlpr.ax.plot(x, y)

    # Add some information from the universe configuration
    cfg = uni['cfg']
    some_param = cfg['MyModel']['some_param']
    hlpr.provide_defaults('set_title',
                          title="Some Parameter: {}".format(some_param))

    # Done. The plot helper saves the plot.

Note how the data selection is hard-coded in this example. In other words, when not using the data selection and transformation framework, you have to either hard-code the selection or parametrize it.


Plots from Multiverse Data

To create plots that use data from more than one universe — which in Utopia is called multiverse data — use the MultiversePlotCreator. This creator selects and combines the data from all selected individual universes and passes the combined data to plot function. This requires handling multidimensional data and depends on the dimensionality of the chosen parameter space. For instance, say the selected data from each universe has dimensionality three and a parameter sweep was done over four dimensions: the data provided to the plot function then has seven dimensions.

See below on how to control the selection and combination of data.

Without DAG framework (legacy approach)

Deprecated since version 0.6.

Warning

This approach of selecting data from the multiverse is deprecated. Use the data selection and transformation interface described above instead.

The signature for such a plot function looks like this:

import xarray as xr

from utopya import DataManager
from utopya.plotting import is_plot_func, PlotHelper, MultiversePlotCreator

@is_plot_func(creator_type=MultiversePlotCreator)
def multiverse_plot(dm: DataManager, *, hlpr: PlotHelper,
                    mv_data: xr.Dataset, **plot_kwargs):
"""...

Args:
    dm (DataManager): The data manager from which to retrieve the data
    hlpr (PlotHelper): The PlotHelper that instantiates the figure and
        takes care of plot aesthetics (labels, title, ...) and saving
    mv_data (xr.Dataset): The selected multiverse data
    **plot_kwargs: Any additional kwargs
"""
# ...

To select the mv_data, specify the select key in the configuration. The associated MultiverseGroup will then take care to select the desired multidimensional data. The resulting data is then bundled into a xr.Dataset; see the xarray documentation for more information.

The select argument allows a number of ways to specify which data is to be selected. The examples below range from the simplest to the most explicit:

# Select a single field from the data
select:
  field: data/MyModel/density  # will be available as 'density' data variable

# Select multiple data variables from a subspace of the parameter space
select:
  fields:
    data: data/MyModel/some_data
    std:
      path: data/MyModel/stddev_of_some_data
  subspace:
    some_param:      [23, 42]              # select two entries by value
    another_param:   !slice [1.23, None]   # select a slice by value
    one_more_param:  {idx: -1}             # select single entry by index
    one_more_param2: {idx: [0, 10, 20]}    # select multiple by index

The fields data and std are then made available to the mv_data argument to the plotting function.

To access the default universe configuration for such a multiverse plot, use dm['multiverse'].pspace.default. Be aware that it contains only default values for all sweep dimensions; as the sweep values are different for each universe, the sweep parameters only make sense in the context of the selected data: you find them as coordinates of mv_data.

For further documentation, see the functions invoked by MultiversePlotCreator, ParamSpaceGroup.select and paramspace.paramspace.ParamSpace.activate_subspace():

class dantro.groups.ParamSpaceGroup(*, name: str, pspace: Optional[paramspace.paramspace.ParamSpace] = None, containers: Optional[list] = None, **kwargs)[source]

Bases: dantro.mixins.indexing.PaddedIntegerItemAccessMixin, dantro.groups.ordered.IndexedDataGroup

The ParamSpaceGroup is associated with a ParamSpace object and the loaded results of an iteration over this parameter space.

Thus, the groups that are stored in the ParamSpaceGroup need all relate to a state of the parameter space, identified by a zero-padded string name. In fact, this group allows no other kinds of groups stored inside.

To make access to a specific state easier, it allows accessing a state by its state number as integer.

Initialize a OrderedDataGroup from the list of given containers.

Parameters
  • name (str) – The name of this group.

  • pspace (ParamSpace, optional) – Can already pass a ParamSpace object here.

  • containers (list, optional) – A list of containers to add, which need to be ParamSpaceStateGroup objects.

  • **kwargs – Further initialisation kwargs, e.g. attrs

__init__(*, name: str, pspace: Optional[paramspace.paramspace.ParamSpace] = None, containers: Optional[list] = None, **kwargs)[source]

Initialize a OrderedDataGroup from the list of given containers.

Parameters
  • name (str) – The name of this group.

  • pspace (ParamSpace, optional) – Can already pass a ParamSpace object here.

  • containers (list, optional) – A list of containers to add, which need to be ParamSpaceStateGroup objects.

  • **kwargs – Further initialisation kwargs, e.g. attrs

property pspace: Optional[paramspace.paramspace.ParamSpace]

Reads the entry named _PSPGRP_PSPACE_ATTR_NAME in .attrs and returns a ParamSpace object, if available there.

Returns

The associated parameter space, or None,

if there is none associated yet.

Return type

Union[ParamSpace, None]

__abstractmethods__ = frozenset({})
__module__ = 'dantro.groups.pspgrp'
property only_default_data_present: bool

Returns true if only data for the default point in parameter space is available in this group.

select(*, field: Optional[Union[str, List[str]]] = None, fields: Optional[Dict[str, List[str]]] = None, subspace: Optional[dict] = None, method: str = 'concat', idx_as_label: bool = False, base_path: Optional[str] = None, **kwargs) xarray.core.dataset.Dataset[source]

Selects a multi-dimensional slab of this ParamSpaceGroup and the specified fields and returns them bundled into an xarray.Dataset with labelled dimensions and coordinates.

Parameters
  • field (Union[str, List[str]], optional) – The field of data to select. Should be path or a list of strings that points to an entry in the data tree. To select multiple fields, do not pass this argument but use the fields argument.

  • fields (Dict[str, List[str]], optional) – A dict specifying the fields that are to be loaded into the dataset. Keys will be the names of the resulting variables, while values should specify the path to the field in the data tree. Thus, they can be strings, lists of strings or dicts with the path key present. In the latter case, a dtype can be specified via the dtype key in the dict.

  • subspace (dict, optional) – Selector for a subspace of the parameter space. Adheres to the ParamSpace.activate_subspace signature.

  • method (str, optional) –

    How to combine the selected datasets.

    • concat: concatenate sequentially along all parameter space dimensions. This can preserve the data type but it does not work if one data point is missing.

    • merge: merge always works, even if data points are missing, but will convert all dtypes to float.

  • idx_as_label (bool, optional) – If true, adds the trivial indices as labels for those dimensions where coordinate labels were not extractable from the loaded field. This allows merging for data with different extends in an unlabelled dimension.

  • base_path (str, optional) – If given, path specifications for each field can be seen as relative to this path

  • **kwargs – Passed along either to xr.concat or xr.merge, depending on the method argument.

Raises
  • KeyError – On invalid state key.

  • ValueError – Raised in multiple scenarios: If no ParamSpace was associated with this group, for wrong argument values, if the data to select cannot be extracted with the given argument values, exceptions passed on from xarray.

Returns

The selected hyperslab of the parameter space, holding

the desired fields.

Return type

xr.Dataset