Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*-
chemreac.util.plotting ----------------------
This module collects convenience functions to create matplotlib plots of results. """
else: if not hasattr(ax, 'plot'): ax = plt.axes(**ax)
""" Convenience method for either showing or saving current matplotlib figure.
Parameters ---------- show: bool or None Show plot, when None only show when savefig is not used default: None savefig: string path to output file of figure. If extension is html, mpld3 will be used to generate a d3 backed html output.
""" if savefig is not None and savefig != 'None': if savefig.endswith('.html'): # Export using mpld3 import mpld3 open(savefig, 'wt').write(mpld3.fig_to_html(plt.gcf())) else: plt.savefig(savefig)
if show is None: show = False else: if show is None: show = True
if show: plt.show()
symmetric_colorbar=False, **kwargs): """ Convenience function for using matplotlib to generate a spy plot for inspecting e.g. a jacobian matrix or its LU decomposition.
Parameters ---------- A: 2D array Array to inspect, populated e.g. by jacobian callback. cmap_name: string (default: coolwarm) name of matplotlib colormap to use, kwargs["cmap"] overrides this. log: bool or int (default: False) if True: SymLogNorm if np.any(A<0) else LogNorm if isinstance(log, int): SymLogNorm(10**log) note: "norm" in kwargs overrides this. symmetric_colorbar: bool or float to make divergent colormaps pass through zero as intended. if float: max abolute value of colormap (linear)
Returns ------- Pair (tuple) of axes plotted to (spy, colorbar)
.. note:: colorbar does not play nicely with \ SymLogNorm why a custom colorbar axes is drawn.
"""
symmetric_colorbar is not False): Amin = -symmetric_colorbar Amax = symmetric_colorbar else:
Amin = -max(-Amin, Amax) Amax = -Amin
log = int(np.round(np.log10(Amax) - 13)) else: minlog = int(ceil(np.log10(-Amin))) tick_locations.extend([-(10**x) for x in range( minlog, log-1, -1)]) tick_locations.extend([0]) else:
pass # Ticks already reach 0 else: else: raise TypeError("log kwarg not understood: {}".format(log)) else:
np.linspace(ticks[i], ticks[i+1], 9, endpoint=False) for i in range(len(ticks)-1) ]+[np.array([ticks[-1]])]).flatten() else: cmap=kwargs['cmap'])
# Note that you really need yout - not Cout
# Note that you really need yout - not Cout
# It is bad practice to have global state in module, refactor this: ls=['-', ':', '--', '-.'], c='krgbycm' )
titles=None, lintreshy=1e-10, logx=True, legend_kwargs=None, ls=None, c=None): """ Parameters ---------- cb: callback callback with signature (rd, tout, yout, indices) returning 3-dimensional array with shape (tout.size, len(axes), len(labels)) labels: sequence of strings labels of individual plots rd: ReactionDiffusion instance tout: 1-dimensional array of floats yout: solver output indices: 4th argument for callback axes: sequence of matplotlib Axes instances (default: len(indices) number of subplot axes) titles: titles per axis lintreshy: float symlog option 'linthreshy' (default: 1e-10) logx: set x scale to 'log' legend_kwargs: dict dict of kwargs to pass to matplotlib legend function (default: {'loc': None, 'prop': {'size': 11}}), set to False to suppress legend. ls: sequence of strings linestyles c: sequence of strings colors """ dict(loc=None, prop={'size': 11})) len(indices))] else: assert len(axes) == len(indices) ls=ls[istl % len(ls)])
""" Plots time evolution of Jacobian values (useful when investigating numerical instabilities).
Parameters ---------- rd: ReactionDiffusion system at hand tout: array_like output time from integration yout: array_like output data from integration (differs from Cout for logy=True) substances: iterable of int or string indices or names of substances to plot jacobian values for """ si in substances] indices, titles=[ print_names[i] for i in indices], **kwargs) "$\\frac{\\partial r_{tot}}{\partial C_i}~/~s^{-1}$")
a = integr.rd.units return plot_jacobian(integr.rd, ) # TODO: finish this
field_yields=False, **kwargs): """ Plots contributions to concentration derivatives of selected substances from individual reactions.
Parameters ---------- integr: Integration instance substances: sequence of Substance instances equilibria: set of tuples of reaction indices (optional) When passed only net effect of equilibria reaction will be plotted field_yields: bool (default: False) If ``True`` contributions from g_values times field will be shown **kwargs: kwargs passed on to _plot_analysis
Returns ------- list of matplotlib.axes.Axes instances """ # should be quite straight forward to implement raise NotImplementedError
for ri in substances] else: print_names = rd.substance_names use_tex = False
# Let's use negative reaction indices for each field -1: 0, -2: 1 rxn_indices = range(-len(rd.fields), 0) else:
equilibria_participants = [] for rxnidxs in equilibria: equilibria_participants.extend(rxnidxs) rxn_indices.append(rxnidxs) for ri in range(rd.nr): if ri not in equilibria_participants: rxn_indices.append(ri) else:
rd.to_Reaction(rxns).render( dict(zip(rd.substance_names, print_names)), use_tex)) else: # Field production! fi = -rxns - 1 if rd.g_value_parents[fi] == -1: # No parents parent = '' else: parent = (print_names[rd.g_value_parents[fi]] + '$\\rightsquigarrow$' if use_tex else ' ~~~> ') labels.append('G_' + str(fi) + ': ' + parent + ', '.join( [print_names[si] for si in range(rd.n) if rd.g_values[fi][si] != 0])) else: labels.append('R(' + ', '.join(map(str, rxns)) + '): ' + rd.to_Reaction(rxns[0]).render( dict(zip(rd.substance_names, print_names)), use_tex, equilibrium=True))
len(rxn_indices))) else: fi = -rxns - 1 for sii, si in enumerate(specie_indices_): out[:, sii, i] = rd.g_values[fi][si]*rd.fields[fi][bi] else: for rxn_idx in rxns: out[:, :, i] += per_rxn[:, :, rxn_idx]
titles=[print_names[i] for i in indices], **kwargs)
# helper func.. else: s if isinstance(s, int) else rd.substance_names.index(s) for s in substances]
except AttributeError: names = list(map(str, substance_idxs)) else: assert len(labels) == len(substance_idxs)
rd, tout, Cout, bi=0, ax=None, labels=None, xscale='log', yscale='log', substances=None, ttlfmt=(r"C(t) in bin: {0:.2g} m $\langle$" + r" x $\langle$ {1:.2g} m"), legend_kwargs=None, ls=None, c=None, xlabel=None, ylabel=None): """ Plots bin local concentration as function of time for selected substances.
Parameters ---------- rd: ReactionDiffusion tout: 1D array of floats Cout: concentration trajectories from solver bi: bin index ax: Axes instance labels: sequence of strings xscale: matplotlib scale choice (e.g. 'log', 'symlog') yscale: matplotlib scale choice (e.g. 'log', 'symlog') substances: sequence of indies or names of substances ttlfmt: string formatted with bin boundaries (set to empty to suppress) legend_kwargs: dict kwargs passed to matplotlib legend function, (default: {'loc': None, 'prop': {'size': 11}}), set to False to suppress legend. ls: sequence of strings linestyles c: sequence of strings colors
Returns ======= Axes instance """ dict(loc='best', prop={'size': 11})) rd, ax, substances, labels, xscale, yscale) ls=ls[i % len(ls)], c=c[i % len(c)]) ax.set_ylabel(ylabel or "C / " + str(Cout.dimensionality.latex))
xscale='log', yscale='log', basetitle="C(x)"): """ Plots concentration as function of x for selected substances at time index 'ti'.
Parameters ---------- rd: ReactionDiffusion tout: 1D array of floats Cout: concentration trajectories from solver substances: sequence of indies or names of substances ti: int time index ax: Axes instance labels: sequence of strings xscale: matplotlib scale choice (e.g. 'log', 'symlog') yscale: matplotlib scale choice (e.g. 'log', 'symlog') basetitle: string
Returns ======= Axes instance """ rd, ax, substances, labels, xscale, yscale)
**plot_kwargs): """ Plots 3D surface of concentration as function of time and x for a selected substance.
Parameters ---------- rd: ReactionDiffusion tout: 1D array of floats Cout: concentration trajectories from solver substance: int or string index or name of substance ax: Axes instance log10: bool Use log logarithmic (base 10) axis **plot_kwargs: passed onto plot_surface
Returns ======= Axes3D instance """ # it would be nice to accpet kwargs # xscale='log', yscale='log', zscale='log' # but it's currently not supported by matplotlib: # http://matplotlib.1069221.n5.nabble.com/ # plot-surface-fails-with-log-axes-td10206.html rd.substance_names.index(substance))
**plot_kwargs)
else: name = rd.substance_names[substance]
""" Convenience function to inspect fields in of ReactionDiffusion instance
Parameters ---------- rd: ReactionDiffusion ax: Axes instance or dict if ax is a dict it is used as keyword arguments passed to matplotlib.pyplot.axes (default: None) indices: sequence of integers what field strengths sequences to plot rho: float (optional) density, with consistent unit. If passed doserate will be plotted instead. """ factors = factors/rho
integration, Cref=0, ax=None, x=None, ti=slice(None), bi=0, si=0, plot_kwargs=None, fill_between_kwargs=None, scale_err=1.0, fill=True, **kwargs): """ Parameters ---------- integration: chemreac.integrate.Integration result from integration. Cref: array or float analytic solution to compare with ax: Axes instance or dict if ax is a dict it is used as key word arguments passed to matplotlib.pyplot.axes (default: None) x: array (optional) x-values, when None it is deduced to be either t or x (when ti or bi are slices repecitvely) (default: None) ti: slice time indices bi: slice bin indices si: integer specie index plot_kwargs: dict keyword arguments passed to matplotlib.pyplot.plot (default: None) fill_between_kwargs: dict keyword arguments passed to matplotlib.pyplot.fill_between (default: None) scale_err: float value with which errors are scaled. (default: 1.0) fill: bool whether or not to fill error span \*\*kwargs common keyword arguments of plot_kwargs and fill_between_kwargs, e.g. 'color', (default: None).
See Also -------- plot_solver_linear_excess_error """ elif isinstance(bi, slice): x = integration.rd.xcenters[bi] else: raise NotImplementedError("Failed to deduce x-axis.")
**plot_kwargs)
integration, ti=ti, bi=bi, si=si) np.asarray(x), np.asarray(scale_err*Cerr_l), np.asarray(scale_err*Cerr_u), **fill_between_kwargs)
ti=slice(None), bi=0, si=0, **kwargs): """ Plots the excess error commited by the intergrator, divided by the span of the tolerances (atol + rtol*|y_i|).
Parameters ---------- integration: chemreac.integrate.Integration result from integration. Cref: array or float analytic solution to compare with ax: Axes instance or dict if ax is a dict it is used as \*\*kwargs passed to matplotlib.pyplot.axes (default: None) x: array (optional) x-values, when None it is deduced to be either t or x (when ti or bi are slices repecitvely) (default: None) ti: slice time indices bi: slice bin indices si: integer specie index plot_kwargs: dict keyword arguments passed to matplotlib.pyplot.plot (default: None) fill_between_kwargs: dict keyword arguments passed to matplotlib.pyplot.fill_between (default: None) scale_err: float value with which errors are scaled. (default: 1.0) fill: bool whether or not to fill error span \*\*kwargs: common keyword arguments of plot_kwargs and fill_between_kwargs, e.g. 'color', (default: None).
See Also -------- plot_solver_linear_error """ elif isinstance(bi, slice): x = integration.rd.xcenters[bi] else: raise NotImplementedError("Failed to deduce x-axis.") 0, 'concentration') 0, 'concentration') Eexcess_u[..., np.newaxis]), axis=-1) np.asarray(Eexcess/le_span), **kwargs) |