Multiplots#
Summary
On this page, you will see how to
use
.plot.multiplot
to plot different plot kinds onto individual axes of a single figureuse
.plot.multiplot
to plot different plot kinds onto a single axisuse the
PlotHelper
adjust the style of the figure and each individual axis
Complete example: seaborn kde multiplot
multiplot:
based_on:
- .creator.multiverse
- .plot.multiplot
select_and_combine:
fields:
susceptible:
path: densities
transform:
- .sel: [!dag_prev , {kind: susceptible}]
kwargs:
drop: true
infected:
path: densities
transform:
- .sel: [!dag_prev , {kind: infected}]
kwargs:
drop: true
recovered:
path: densities
transform:
- .sel: [!dag_prev , {kind: recovered}]
kwargs:
drop: true
subspace:
immunity rate: 0.1
transmission rate: 0.2
compute_only: []
transform:
- .coords: [!dag_tag infected, time]
tag: time
- .mean: [!dag_tag susceptible, seed]
- .squeeze: [!dag_prev ]
tag: mean_s
- .std: [!dag_tag susceptible, seed]
- .squeeze: [!dag_prev ]
tag: std_s
- .mean: [!dag_tag infected, seed]
tag: mean_i
- .mean: [!dag_tag recovered, seed]
tag: mean_r
- xr.Dataset:
- infected: !dag_tag mean_i
recovered: !dag_tag mean_r
tag: scatter_data
to_plot:
- function: plt.errorbar
x: !dag_result time
y: !dag_result mean_s
yerr: !dag_result std_s
label: Susceptible agents
color: '#0099CC'
- function: [xarray.plot, scatter]
args:
- !dag_result scatter_data
x: time
y: recovered
hue: infected
cmap:
continuous: true
from_values:
0: '#006666'
1: '#CC3333'
label: Recovered agents
zorder: 3
linewidths: 0
helpers:
set_labels:
y: Agent density
set_legend:
use_legend: True
loc: 'best'
fontsize: 11
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:func`seaborn.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
helpers:
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
helpers:
# 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
subplots_adjust:
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:
helpers:
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:
helpers:
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.