Tutorial 3 - Plotting¶
Download notebook: ccsne_tutorial3.ipynb
This tutorial goes through the different plots avaliable in SIMPLE and how to customise them.
import matplotlib.pyplot as plt
from matplotlib.ticker import AutoMinorLocator, LogLocator
import simple
simple.set_logging_level('INFO')
models = simple.load_collection('data/CCSNe_FeNi.hdf5')
SIMPLE.models - INFO - Loading existing file: data/CCSNe_FeNi.hdf5 SIMPLE.models - INFO - Loading file: data/CCSNe_FeNi.hdf5 SIMPLE.models - INFO - Loading ref: W17 (IsoRef) SIMPLE.models - INFO - Loading ref: iniab2.0E-02GN93 (IsoRef) SIMPLE.models - INFO - Loading ref: iniab2.0E-02GN93_Lo03 (IsoRef) SIMPLE.models - INFO - Loading ref: iniab1.3E-02Lo03_Lo03_merged (IsoRef) SIMPLE.models - INFO - Loading ref: rau_solar_ref (IsoRef) SIMPLE.models - INFO - Loading ref: iniab1.3E-02As09_As09_merged (IsoRef) SIMPLE.models - INFO - Loading model: Ri18_m15 (CCSNe) SIMPLE.models - INFO - Loading model: Ri18_m20 (CCSNe) SIMPLE.models - INFO - Loading model: Ri18_m25 (CCSNe) SIMPLE.models - INFO - Loading model: Pi16_m15 (CCSNe) SIMPLE.models - INFO - Loading model: Pi16_m20 (CCSNe) SIMPLE.models - INFO - Loading model: Pi16_m25 (CCSNe) SIMPLE.models - INFO - Loading model: La22_m15 (CCSNe) SIMPLE.models - INFO - Loading model: La22_m20 (CCSNe) SIMPLE.models - INFO - Loading model: La22_m25 (CCSNe) SIMPLE.models - INFO - Loading model: Si18_m15 (CCSNe) SIMPLE.models - INFO - Loading model: Si18_m20 (CCSNe) SIMPLE.models - INFO - Loading model: Si18_m25 (CCSNe) SIMPLE.models - INFO - Loading model: Ra02_m15 (CCSNe) SIMPLE.models - INFO - Loading model: Ra02_m20 (CCSNe) SIMPLE.models - INFO - Loading model: Ra02_m25 (CCSNe) SIMPLE.models - INFO - Loading model: LC18_m15 (CCSNe) SIMPLE.models - INFO - Loading model: LC18_m20 (CCSNe) SIMPLE.models - INFO - Loading model: LC18_m25 (CCSNe) SIMPLE.models - INFO - Time to load file: 0:00:00.199670
simple.plot(models, '.abundance[o16/c12]', 'o16', where='.dataset==Ra02',
ax_xscale='log', default_attrname='abundance');
simple.plot_ccsne(models, 'o16', where='.dataset==Ra02', default_attrname='abundance');
Histograms¶
simple.hist(models, 'o16/c12', where='.dataset==Ra02', default_attrname='abundance');
SIMPLE.plot - INFO - Normalising weights so that the sum of all weights is equal to 1.
simple.hist(models, ykey='o16/c12', where='.dataset==Ra02', default_attrname='abundance');
SIMPLE.plot - INFO - Normalising weights so that the sum of all weights is equal to 1.
If both xkey and ykey are given then a circular histogram of the x/y slope is shown on a custom rose projection, a subclass of the polar projection.
Note if the original projection is not rose then the original plot will be deleted and replaced with a new plot with he right projection. This can lead to outdated references
simple.hist(models, xkey='c12', ykey='o16', where='.dataset==Ra02', default_attrname='abundance');
SIMPLE.plot - INFO - Normalising weights so that the sum of all weights is equal to 1. SIMPLE.plot - WARNING - Wrong Axes projection for rose plot. Deleting axes and creating a new one.
Slope Plots¶
The slope plot shows mixing lines between the x and y values with an arrow pointing towards the end member location. For CCSNe models the slope for each mass coordinate is shown, which can lead to somewhat difficult to interpret figures such as the one below.
simple.slope(models, xkey='c12', ykey='o16', where='.dataset==Ra02', default_attrname='abundance');
Combination plots¶
Creating a series of subplots can be done using the create_subplots function, which in turn is based on matplotlib's subplot_mosaic function.
Here we can compare the slope plot from above with a circular histogram. The histogram provides a much clearer idea of the distribution of the different slopes than the slope plot does.
simple.create_subplots('AB', fig_size=(12, 5.5));
simple.slope(models, xkey='c12', ykey='o16', where='.dataset==Ra02', default_attrname='abundance',
ax='A', legend=False, ax_xlim=(0, 1), ax_ylim=(0, 1));
simple.hist(models, xkey='c12', ykey='o16', where='.dataset==Ra02', default_attrname='abundance', rose_segment='NE', ax='B');
SIMPLE.plot - INFO - Normalising weights so that the sum of all weights is equal to 1. SIMPLE.plot - WARNING - Wrong Axes projection for rose plot. Deleting axes and creating a new one.
The standard plot has the built-in option to automatically create histograms for each axis using the hist argument. You choose only a single axis using xhist or yhist instead.
Note that the width of the bins is always linear which is why the bin size is uneven for the logarithmic x-axis in the example below.
simple.plot(models, '.abundance[o16/c12]', 'o16', where='.dataset==Ra02',
ax_xscale='log', default_attrname='abundance', hist=True);
SIMPLE.plot - INFO - Normalising weights so that the sum of all weights is equal to 1.
This also works for the CCSNe plot. Keep in mind that the histogram will look different for the CCSNe plot due to the difference in how the weight for each data point is calculated. By default there is no histogram for the x-axis as it would only show the distribution of the mass along the x-axis which should be uniform (Although, can vary a little depending on spacing). You can add the x-axis histogram by passing xhist=True to the function.
simple.plot_ccsne(models, 'o16', where='.dataset==Ra02', default_attrname='abundance', hist=True, yhist_ax_xlabel='Something');
SIMPLE.ccsne - INFO - Multiplying all weights by the mass coordinate mass SIMPLE.plot - INFO - Normalising weights so that the sum of all weights is equal to 1.
Adjusting Plots¶
Customising labels¶
Informative labels are autogenerated by the plotting functions. By default, information that is common to all data points is included in the axis labels to keep the data point labels short. Information that can be contained in the labels are: name of the attribute, or its label if one has been defined, the isotope or ratio key, the unit of the data, and finally the model name. The inclusion of these can be modified using the appropriate argument, see the get_data() function for more details.
By default, the attribute name is included in the label only if is different than the one defined by the default_attrname or the attribute name is defined in the key.
simple.plot(models, '.abundance[o16/c12]', 'o16', where='.dataset==Ra02',
ax_xscale='log', default_attrname='abundance', legend=True);
To change the label behaviour you can give either a single argument that is used for all axis or you can supply a list containing one value per axis. It is also possible to specify the value for a single axis by prefixing the argument name with the name of the axis, e.g. xunit_in_label. This will override any argument passed to the generic argument for this axis.
simple.plot(models, '.abundance[o16/c12]', 'o16', where='.dataset==Ra02',
ax_xscale='log', attrname_in_label=False, yunit_in_label=False, legend=True);
You can provide your own labels to the datapoints by giving a list to the label argument. Similarly, you can define the axis labels by prefixing the label argument by the axis name as in the example below.
simple.plot(models, '.abundance[o16/c12]', 'o16', where='.dataset==Ra02',
ax_xscale='log', label=['a', 'b', 'c'], xlabel='X-axis', ylabel='Y-axis', legend=True);
Styling Plots¶
The SIMPLE plotting functions allow you to update the axes or figure object using keyword arguments. To update the axes object pass the name of the method, minus the set_ part, with the prefix ax_ equal to the desired value, e.g. ax_ylim=(1,2). You can do the same for axes.xaxis and axis.yaxis methods using the prefix xax_ and yax_. To update the figure object use the prefix fig_.
You can pass multiple arguments to the methods by passing a tuple or a dictionary which will be unpacked when the method is called. You can also define keyword arguments separately using the ax_kw_<method>_<keyword> prefix. Note however that the method is only called is the ax_<method> argument is also present. Setting the ax_<method> to False will not call the function while setting it to True will call the method with no arguments, unless keyword arguments are specified as described above. To pass a boolean value to a method simple place it within a tuple, e.g. (True, ).
If you want to reuse the same style arguments repeatedly you can place them in a dictionary and unpack it when needed.
abundance_kwargs = {'ax_tick_params': dict(left=True,right=True,top=True,labelleft=True,which='both'),
'xax_minor_locator': AutoMinorLocator(),
'yax_major_locator': LogLocator(subs=(1.0, ),numticks=999),
'yax_minor_locator': LogLocator(numticks=999, subs='auto'),
'ax_yscale': 'log'}
simple.plot_ccsne.abundance(models, 'o16/c12', where='.dataset==Ra02', unit='mol',
**abundance_kwargs);
SIMPLE.models - INFO - Ra02_m15.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number SIMPLE.models - INFO - Ra02_m20.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number SIMPLE.models - INFO - Ra02_m25.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number
Updating the Default Style¶
The default style of the plotting functions can be found through the kwargs attribute.
simple.plot.kwargs
DefaultKwargs.Dict({'default_attrname': None, 'unit': None, 'where': None, 'mask': None, 'mask_na': True, 'ax': None, 'legend': None, 'update_ax': True, 'update_fig': True, 'hist': False, 'hist_size': 0.3, 'hist_pad': 0.05, 'linestyle': False, 'color': True, 'marker': True, 'linestyle_by_model': None, 'color_by_model': None, 'marker_by_model': None, 'ax_kw_xlabel_fontsize': 15, 'ax_kw_ylabel_fontsize': 15, 'plt_markersize': 4, 'legend_outside': True, 'ax_tick_params': {'axis': 'both', 'left': True, 'right': True, 'top': True}, 'fig_size': (7, 6.5)})
The ccsne plotting functions inherits the style of the generic plotting functions. Similarly, by default, shortcuts will inherit the style of the plotting function they are attached to. The kwargs attribute contains all the kwargs of the function, including inherited ones.
simple.plot_ccsne.kwargs
DefaultKwargs.Dict({'default_attrname': None, 'unit': None, 'where': None, 'mask': None, 'mask_na': True, 'ax': None, 'legend': None, 'update_ax': True, 'update_fig': True, 'hist': False, 'hist_size': 0.3, 'hist_pad': 0.05, 'linestyle': True, 'color': True, 'marker': False, 'linestyle_by_model': None, 'color_by_model': None, 'marker_by_model': None, 'ax_kw_xlabel_fontsize': 15, 'ax_kw_ylabel_fontsize': 15, 'plt_markersize': 4, 'legend_outside': True, 'ax_tick_params': {'axis': 'both', 'left': True, 'right': True, 'top': True}, 'fig_size': (10, 5), 'semilog': False, 'onion': None, 'xhist': False})
simple.plot_ccsne.abundance.kwargs
DefaultKwargs.Dict({'default_attrname': 'abundance', 'unit': None, 'where': None, 'mask': None, 'mask_na': True, 'ax': None, 'legend': None, 'update_ax': True, 'update_fig': True, 'hist': False, 'hist_size': 0.3, 'hist_pad': 0.05, 'linestyle': True, 'color': True, 'marker': False, 'linestyle_by_model': None, 'color_by_model': None, 'marker_by_model': None, 'ax_kw_xlabel_fontsize': 15, 'ax_kw_ylabel_fontsize': 15, 'plt_markersize': 4, 'legend_outside': True, 'ax_tick_params': {'axis': 'both', 'left': True, 'right': True, 'top': True}, 'fig_size': (10, 5), 'semilog': False, 'onion': None, 'xhist': False})
You can update the default style using the update, remove and clear methods.
simple.plot.update_kwargs(ax_tick_params = dict(left=True,right=True,top=True,labelleft=True,which='both'),
ax_grid = (True,))
simple.plot_ccsne.abundance(models, 'o16/c12', where='.dataset==Ra02', unit='mol');
SIMPLE.models - INFO - Ra02_m15.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number SIMPLE.models - INFO - Ra02_m20.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number SIMPLE.models - INFO - Ra02_m25.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number
Shortcuts¶
Shortcuts are a convenient way to predefine a set of arguments for a plotting function. For example the intnorm and stdnorm shortcut sets the default_attrname to the path of the result from these normalisations. Using these shortcuts means you only have to specify the isotope or ratio you want to plot.
You can create your own shortcuts using the add_shortcut function attached to anything with a kwargs dictionary.
simple.plot_ccsne.add_shortcut('abulogy', ax_yscale='log', default_attrname='abundance')
simple.plot_ccsne.abulogy(models, 'o16/c12', where='.dataset==Ra02', unit='mol');
SIMPLE.models - INFO - Ra02_m15.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number SIMPLE.models - INFO - Ra02_m20.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number SIMPLE.models - INFO - Ra02_m25.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number
Creating Custom Plots¶
The get_data function allows you to extract data to create your own plotting functions.
model_datapoints, axis_labels = simple.get_data(models, 'x, y', xkey='.masscoord', ykey='.abundance[o16/c12]',
where='.dataset==Ra02', yunit='mol')
plt.set_xlabel = axis_labels['x']
plt.set_ylabel = axis_labels['y']
# Iterate though the data and plot it
for model_name, datapoints in model_datapoints.items():
for dp in datapoints:
plt.plot(dp['x'], dp['y'], label=dp['label'])
plt.legend();
SIMPLE.models - INFO - Ra02_m15.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number SIMPLE.models - INFO - Ra02_m20.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number SIMPLE.models - INFO - Ra02_m25.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number
The update_axes function allows you to update the axes, axis and figure objects using the same arguments used for the simple plotting functions. If you want the plots to look similar you can copy the default_kwargs dictionary of the plotting function. The create_legend function can also be used to place the legend outside the plot.
You can also import the parse_lscm function from simple.plotting to get the default linestyles, colors and marker shapes.
from simple.plotting import parse_lscm
model_datapoints, axis_labels = simple.get_data(models, 'x, y', xkey='.masscoord', ykey='.abundance[o16/c12]',
where='.dataset==Ra02', yunit='mol')
# The account for the inheritance of default kwargs
default_kwargs = simple.plot_ccsne.kwargs
default_kwargs['ax_xlabel'] = axis_labels['x']
default_kwargs['ax_ylabel'] = axis_labels['y']
simple.update_axes(plt, default_kwargs)
# Get the default linestyles and colours, and disable markers
ls, c, m = parse_lscm(linestyle=default_kwargs.get('linestyle', True),
color=default_kwargs.get('color', True),
marker=default_kwargs.get('marker', False))
# Iterate though the data and plot it
for i, (model_name, datapoints) in enumerate(model_datapoints.items()):
for j, dp in enumerate(datapoints):
plt.plot(dp['x'], dp['y'], label=dp['label'], linestyle=ls[i], color=c[i], marker=m[i])
simple.create_legend(plt, outside=True)
SIMPLE.models - INFO - Ra02_m15.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number SIMPLE.models - INFO - Ra02_m20.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number SIMPLE.models - INFO - Ra02_m25.abundance: Converting array from ``mass`` to ``mole`` unit by dividing the data by the mass number