The PlotManager¶
The PlotManager orchestrates the whole plotting framework.
This document describes what it is and how it works together with the Plot Creators to generate plots.
Overview¶
The PlotManager manages the creation of plots.
So far, so obvious.
The idea of the PlotManager is that it is aware of all available data and then gets instructed to create a set of plots from this data.
The :py:class`~dantro.plot_mngr.PlotManager` does not actually carry out any plots. Its purpose is to handle the configuration of some plot creator <plot_creators classes; those implement the actual plotting functionality.
This way, the plots can be configured in a consistent way, profiting from the shared interface and the already implemented functions, while keeping the flexibility of having multiple ways to create plots.
To create the plots, a set of plot configurations gets passed to the PlotManager which then determines which plot creator it will need to instantiate.
It then passes the plot configuration on to the respective plot creator, which takes care of all the actual plotting work.
The main methods to interact with the PlotManager are the following:
plot()expects the configuration for a single plot.plot_from_cfg()expects a set of plot configurations and, for each configuration, creates the specified plots usingplot().
This configuration-based approach makes the PlotManager quite versatile and provides a set of features that the individual plot creators need not be aware of.
The Plot Configuration¶
A set of plot configurations may look like this:
This will create two plots: values_over_time and my_fancy_plot.
Both are using ExternalPlotCreator (known to PlotManager by its name, external) and are loading certain functions to use for plotting.
Parameter sweeps in plot configurations¶
With the configuration-based approach, it becomes possible to use parameter sweeps in the plot specification; the manager detects that it will need to create multiple plots and does so by repeatedly invoking the instantiated plot creator using the respective arguments for the respective point in the parameter space.
This will create two files, one with values over times, one with more_values over times.
By defining further !pdims, the combination of those parameters are each leading to a plot.
Auto-Detection of a Plot Creator¶
The PlotManager has as class variable a dictionary of CREATORS, which is a mapping of common name strings to plot creator types, i.e. AbstractPlotCreator-derived classes.
Usually, the creator argument to the PlotManager’s plot() function is used to extract the plot creator type from that dictionary and then initialize the object.
However, the plot manager also has a auto_detect_creator feature.
This boolean argument can be given both to __init__() as well as to plot() and it can also be part of the plot configuration passed to plots_from_cfg().
If set, the creator argument need no longer be given in the plot configuration. By going through all registered CREATORS and instantiating them, it is found out if they declare that they can_plot() the given configuration.
Each creator can implement this method as they see fit.
In unambiguous cases, the manager than uses the single candidate creator and continues plotting with that creator.
Auto-detection for ExternalPlotCreators¶
The ExternalPlotCreator and derived classes try auto-detection by checking if it can use the given plot configuration to resolve a plotting function.
Furthermore, it checks whether the plot function is marked with attributes that may specify which creator to use. The attributes that are looked at are, in this order:
creator_type: The type of the plot creator to use (or a parent type)creator_name: The name of the plot creator as registered in the manager’sCREATORSdict
To conveniently add these attributes to the plot function, the is_plot_func() decorator can be used:
from dantro.plot_creators import is_plot_func
# Specify directly with the plot creator type
from dantro.plot_creators import MultiversePlotCreator
@is_plot_func(creator_type=MultiversePlotCreator)
def my_mv_plot_func(dm: DataManager, *, out_path: str, mv_data, **kwargs):
# ...
# Alternatively: Specify only via the _name_ known to the PlotManager
@is_plot_func(creator_name="universe")
def my_uni_plot_func(dm: DataManager, *, out_path: str, uni, **kwargs):
# ...
Hint
When using the data transformation framework, the signature of the plot functions is averse to the choice of a creator.
This makes it possible to implement generic plotting functions, which can be used for all ExternalPlotCreator-derived plot creators.
In such cases, simply omit the creator_* argument to the decorator and specify the creator via the plot configuration.
Note
Setting only the creator_name is recommended for scenarios where the import of the creator type is not desired.
In other scenarios, it’s best to use creator_type
Deprecated since version 0.10: If no plot function attributes are given, there is still another way to auto-detect the desired plot creator: inspecting the plot function signature.
This works, because derived creators might require a different plot function signature.
For example, MultiversePlotCreator) additionally passes mv_data as keyword-only argument.
However, this approach can lead to ambiguous results and thus failing auto-detection. For those cases, it makes sense to specify plot function attributes via the decorator.
Due to the ambiguity and the many different ways in which a plot function can be defined, this feature will be removed in v0.11.