# Multiplots#

Summary

• use .plot.multiplot to plot different plot kinds onto individual axes of a single figure

• use .plot.multiplot to plot different plot kinds onto a single axis

• use the PlotHelper adjust the style of the figure and each individual axis

The multiplot() is a highly versatile yet simple way of plotting different types of plots onto a single figure. Essentially, the plot function allows to invoke arbitrary functions on the individual subplots of a figure, with data supplied via the plot configuration or the data transformation framework.

In the example below, we are plotting an errorbar plot and a scatter plot onto a single subplot. The errorbar shows the density of susceptible agents with a standard deviation, and the scattered dots display the recovered agent density, with the density of infected agents as the hue:

Perhaps a little much for a single frame: but hopefully it illustrates the capability of multiplotting! Such plots are simply achieved using the .plot.multiplot function, an overview of which is given in the following. Refer to the dantro multiplot documentation for further details.

## Example: Double kdeplot#

Let us go through an example in detail. We wish to plot two smoothed densities showing the maximum peaks of infection for different values of the transmissivity in a single figure:

Here, we are using a seaborn function. On the left, we see the distribution of infection peaks for a lower transmissivity (0.4), on the right, for a higher transmissivity (0.6). Naturally, as the transmissivity increases, so does the height of peak infection.

To create this plot, first select the data and transform it accordingly:

double_kdeplot:

# Base the plot on a creator (universe or multiverse) and .plot.multiplot:
based_on:
- .creator.multiverse
- .plot.multiplot

select_and_combine:
fields:
infected:
path: densities
transform:
- .sel: [!dag_prev , {kind: infected}]

# Calculate the maxima of the infection densities for two different
# transmission rates
transform:
- .sel: [!dag_tag infected, {transmission rate: 0.4}]
- np.max: [!dag_prev , 2]
- .squeeze: !dag_prev
tag: data_low

- .sel: [!dag_tag infected, {transmission rate: 0.6}]
- np.max: [!dag_prev , 2]
- .squeeze: !dag_prev
tag: data_high


Naturally, this requires a sweep to have been performed over a transmission rate variable. The .squeeze transformation is required since we will be using the :py:funcseaborn.kdeplot function, which expects a flat array.

Next, distribute the plots onto the axes. This requires setting up the figure accordingly using the PlotHelper:

double_kdeplot:

# Everything as above ...

# Distribute the plots
to_plot:
[0, 0]:                               # select the axis,
- function: sns.kdeplot             # the plot function,
data: !dag_result data_low        # the data,
label: $p_\mathrm{transmit}=0.4$  # and add any kwargs the plot function accepts
fill: true
[1, 0]:
- function: sns.kdeplot
data: !dag_result data_high
label: $p_\mathrm{transmit}=0.6$
fill: true
color: darkblue
helper:
setup_figure:
ncols: 2


Note

We are using !dag_result placeholders rather than !dag_tag to pass data to the plot functions. This will however raise a small warning saying that many of the calculated dag tags are being ignored. To suppress this, you can exclude tags that are not used in the transformation DAG by removing them from the compute_only key in the plot configuration; for instance, above you can do

compute_only: []


## Multiple figures in a single axis#

You can of course also plot multiple plots on a single axis; in this case, there is no need to setup the figure, and you also do not need to specify the axis on which to plot (since there is only one):

double_kdeplot:
# Everything as above ...

# Distribute the plots
to_plot:
- function: sns.kdeplot
data: !dag_result data_low
label: $p_\mathrm{transmit}=0.4$
linestyle: dashed
color: red
- function: sns.kdeplot
data: !dag_result data_high
label: $p_\mathrm{transmit}=0.6$
color: yellow


## Importing callables on the fly#

Many matplotlib and seaborn plots are available with a simple call, as above; see here for a list of all available functions. However, you can also import callables on the fly by passing a 2-tuple of (module, name) to function:

plot:
to_plot:
[0, 0]:
- function: [xarray.plot, scatter]
# args, kwargs here ...


## Modifying figure-level and axis-specific features#

Let us now go about modifying the plot appearance somewhat. To control the color, notice how in the previous example we set

double_kdeplot:

# Everything as above ...

color: darkblue


This makes color a shared keyword argument, one that is passed to all plot function calls. Specifying arguments within the to_plot entries can still overwrite the entries given on the shared level.

double_kdeplot:

# Everything as above ...

to_plot:
- function: sns.kdeplot
data: !dag_result data_low
color: red
linestyle: dashed
- function: sns.kdeplot
data: !dag_result data_low
color: yellow


This gives you complete control over the appearance of each individual plot.

With the plot helper framework, you can control such things as shared axes, the spacing between subplots, limits, and axis scales. For instance, to modify horizontal or vertical distancing between plots and have figures share their axes, do

helper:
# set the number of rows and columns with shared axes
setup_figure:
ncols: 2
nrows: 3
sharex: true
sharey: true

# adjust horizontal and vertical spacing between subplots
hspace: 0.1
wspace: 0.3


The subplots_adjust entries are passed to matplotlib.figure.Figure.subplots_adjust(), whereas setup_figure is passed to matplotlib.pyplot.subplots().

The PlotHelper gives you a variety of options to adjust the plot appearance. You can choose to apply these to the entire plot, or only individual axes. For instance,

multiplot:
helper:
set_limits:
x: [0, 1]


will set the x limits on all axes to [0, 1]. You can use the axis_specific helper to only modify certain axes:

multiplot:
helper:
axis_specific:
axis1:            # some arbitrary axis name
axis: [0, 0]    # the x and y coordinates of the subplot in the plot
set_limits:
x: [0, 1]
axis2:
axis: [1, 0]
set_limits:
x: [-1, 0]


All helper functions are available under axis_specific, giving you complete control over the appearance of the individual axes. Furthermore, helpers specified on the top level apply to all axes.