Source code for ixdat.plotters.sec_plotter

"""Plotters for spectroelectrochemistry. Makes use of those in spectrum_plotter.py"""

import matplotlib as mpl
from . import ECPlotter, SpectrumSeriesPlotter, SpectroMeasurementPlotter
from ..exceptions import SeriesNotFoundError


[docs]class SECPlotter(SpectroMeasurementPlotter): """A spectroelectrochemistry (SEC) matplotlib plotter.""" def __init__(self, measurement=None): """Initiate the plotter with its default Meausurement to plot""" super().__init__() self.measurement = measurement self.ec_plotter = ECPlotter(measurement=measurement) self.spectrum_series_plotter = SpectrumSeriesPlotter()
[docs] def plot_measurement( self, *, measurement=None, field=None, tspan=None, xspan=None, axes=None, cmap_name="inferno", make_colorbar=False, continuous=None, **kwargs, ): """Plot an SECMeasurement in two panels with time as x-asis. The top panel is a heat plot with the spectral scanning variable (x) on y-axis and color representing the value of the spectral data. The bottom panel contains electrochemistry data. Args: measurement (Measurement): The measurement to be plotted, if different from self.measurement field (Field): The field with the spectral data to plot. Defaults to `measurement.spectra` tspan (timespan): The timespan of data to keep for the measurement. xspan (iterable): The span of spectral data to plot axes (list of mpl.Axis): The axes to plot on. axes[0] is for the heat plot, axes[1] for potential, and axes[2] for current. The axes are optional and a new set of axes, where axes[1] and axes[2] are twinned on x, are generated if not provided. cmap_name (str): The name of the colormap to use. Defaults to "inferno", see https://matplotlib.org/3.5.0/tutorials/colors/colormaps.html#sequential make_colorbar (bool): Whether to make a colorbar. FIXME: colorbar at present mis-alignes axes kwargs: Additional key-word arguments are passed on to ECPlotter.plot_measurement(). continuous (bool): Optional. Whether to make a continuous heat plot (True) or a discrete heat plot for each spectrum (False). In the discrete case, each heat plot is a rectangle with the spectrum's duration as its width, if available. If the duration is not available, each spectrum heat plot extends to the start of the next one. Defaults to `measurement.spectrum_series.continuous`. Returns: list of Axes: axes=[spectra, potential, None, current] axes[0] is the top axis with the heat map of the spectra axes[1] is the bottom left axis with electrochemical potential axes[2] is None (this is where a top right axis would go) axes[3] is the bottom right axis with electrode current """ measurement = measurement or self.measurement if not axes: axes = self.new_two_panel_axes( n_bottom=2, n_top=1, emphasis="top", ) self.ec_plotter.plot_measurement( measurement=measurement, axes=[axes[1], axes[3]], tspan=tspan, **kwargs, ) axes[0] = self.spectrum_series_plotter.heat_plot( spectrum_series=measurement.spectrum_series, field=field, tspan=tspan, xspan=xspan, ax=axes[0], cmap_name=cmap_name, make_colorbar=make_colorbar, continuous=continuous, ) if make_colorbar: pass # TODO: adjust EC plot to be same width as heat plot despite colorbar. axes[1].set_xlim(axes[0].get_xlim()) return axes
[docs] def plot_vs_potential( self, *, measurement=None, field=None, tspan=None, vspan=None, U_name=None, J_name=None, xspan=None, axes=None, cmap_name="inferno", make_colorbar=False, **kwargs, ): """Plot an SECMeasurement in two panels with potential as x-asis. The top panel is a heat plot with wavelength on y-axis and color representing spectrum. At most one of V_ref and t_ref should be given, and if neither are given the measurement's default reference_spectrum is used to calculate the optical density. Args: measurement (Measurement): The measurement to be plotted, if different from self.measurement field (Field): The field with the spectral data to plot. Defaults to `measurement.spectra` tspan (timespan): The timespan of data to keep for the measurement. vspan (timespan): The potential span of data to keep for the measurement. U_name (str): Optional. The name of the data series to use as potential. J_name (str): Optional. The name of the data series to use as current. xspan (iterable): The span of spectral data to plot axes (list of numpy Axes): The axes to plot on. axes[0] is for the heat plot and axes[1] for potential. New are made by default. cmap_name (str): The name of the colormap to use. Defaults to "inferno", see https://matplotlib.org/3.5.0/tutorials/colors/colormaps.html#sequential make_colorbar (bool): Whether to make a colorbar. kwargs: Additional key-word arguments are passed on to ECPlotter.plot_vs_potential(). """ measurement = measurement or self.measurement if not axes: axes = self.new_two_panel_axes( n_bottom=1, n_top=1, emphasis="top", ) self.ec_plotter.plot_vs_potential( measurement=measurement, tspan=tspan, U_name=U_name, J_name=J_name, ax=axes[1], **kwargs, ) super().heat_plot_vs( measurement=measurement, field=field or measurement.spectra, vspan=vspan, xspan=xspan, ax=axes[0], cmap_name=cmap_name, make_colorbar=make_colorbar, vs=U_name or measurement.U_name, ) axes[1].set_xlim(axes[0].get_xlim()) return axes
def plot_stacked_spectra(self, **kwargs): kwargs.update(vs="potential") return super().plot_stacked_spectra_vs(**kwargs)
[docs]class ECOpticalPlotter(SECPlotter):
[docs] def plot_measurement( self, *, measurement=None, tspan=None, wlspan=None, axes=None, V_ref=None, t_ref=None, cmap_name="inferno", make_colorbar=False, **kwargs, ): """Plot an SECMeasurement in two panels with time as x-asis. The top panel is a heat plot with wavelength on y-axis and color representing spectrum. At most one of V_ref and t_ref should be given, and if neither are given the measurement's default reference_spectrum is used to calculate the optical density. Args: measurement (Measurement): The measurement to be plotted, if different from self.measurement tspan (timespan): The timespan of data to keep for the measurement. wlspan (iterable): The wavelength span of spectral data to plot axes (list of mpl.Axis): The axes to plot on. axes[0] is for the heat plot, axes[1] for potential, and axes[2] for current. The axes are optional and a new set of axes, where axes[1] and axes[2] are twinned on x, are generated if not provided. V_ref (float): Potential to use as reference for calculating optical density t_ref (float): Time to use as a reference for calculating optical density cmap_name (str): The name of the colormap to use. Defaults to "inferno", see https://matplotlib.org/3.5.0/tutorials/colors/colormaps.html#sequential make_colorbar (bool): Whether to make a colorbar. FIXME: colorbar at present misaligns axes kwargs: Additional key-word arguments are passed on to ECPlotter.plot_measurement(). Returns: list of Axes: axes=[spectra, potential, None, current] axes[0] is the top axis with the heat map of the spectra axes[1] is the bottom left axis with electrochemical potential axes[2] is None (this is where a top right axis would go) axes[3] is the bottom right axis with electrode current """ measurement = measurement or self.measurement dOD_series = measurement.calc_dOD(V_ref=V_ref, t_ref=t_ref) return super().plot_measurement( measurement=measurement, tspan=tspan, xspan=wlspan, axes=axes, cmap_name=cmap_name, make_colorbar=make_colorbar, field=dOD_series, **kwargs, )
[docs] def plot_vs_potential( self, *, measurement=None, tspan=None, vspan=None, U_name=None, J_name=None, wlspan=None, axes=None, V_ref=None, t_ref=None, cmap_name="inferno", make_colorbar=False, **kwargs, ): """Plot an SECMeasurement in two panels with time as x-asis. The top panel is a heat plot with wavelength on y-axis and color representing spectrum. At most one of V_ref and t_ref should be given, and if neither are given the measurement's default reference_spectrum is used to calculate the optical density. Args: measurement (Measurement): The measurement to be plotted, if different from self.measurement tspan (timespan): The timespan of data to keep for the measurement. vspan (timespan): The potential span of data to keep for the measurement. U_name (str): Optional. The name of the data series to use as potential. J_name (str): Optional. The name of the data series to use as current. wlspan (iterable): The wavelength span of spectral data to plot axes (list of mpl.Axis): The axes to plot on. axes[0] is for the heat plot, axes[1] for potential, and axes[2] for current. The axes are optional and a new set of axes, where axes[1] and axes[2] are twinned on x, are generated if not provided. V_ref (float): Potential to use as reference for calculating optical density t_ref (float): Time to use as a reference for calculating optical density cmap_name (str): The name of the colormap to use. Defaults to "inferno", see https://matplotlib.org/3.5.0/tutorials/colors/colormaps.html#sequential make_colorbar (bool): Whether to make a colorbar. FIXME: colorbar at present mis-alignes axes kwargs: Additional key-word arguments are passed on to ECPlotter.plot_measurement(). Returns: list of Axes: axes=[spectra, potential, None, current] axes[0] is the top axis with the heat map of the spectra axes[1] is the bottom left axis with electrochemical potential axes[2] is None (this is where a top right axis would go) axes[3] is the bottom right axis with electrode current """ measurement = measurement or self.measurement dOD_series = measurement.calc_dOD(V_ref=V_ref, t_ref=t_ref) return super().plot_vs_potential( measurement=measurement, tspan=tspan, vspan=vspan, U_name=U_name, J_name=J_name, xspan=wlspan, axes=axes, cmap_name=cmap_name, make_colorbar=make_colorbar, field=dOD_series, **kwargs, )
[docs] def plot_waterfall( self, *, measurement=None, ax=None, V_ref=None, t_ref=None, cmap_name="jet", make_colorbar=True, ): """Plot an SECMeasurement as spectra colored based on potential. The top panel is a heat plot with wavelength on y-axis and color representing spectrum. At most one of V_ref and t_ref should be given, and if neither are given the measurement's default reference_spectrum is used to calculate the optical density. This uses :func:`~spectrum_plotter.SpectrumSeriesPlotter.plot_waterfall()` Args: measurement (Measurement): The measurement to be plotted, if different from self.measurement ax (matplotlib Axis): The axes to plot on. A new one is made by default. V_ref (float): potential to use as reference for calculating optical density t_ref (float): time to use as a reference for calculating optical density cmap_name (str): The name of the colormap to use. Defaults to "jet", see https://matplotlib.org/3.5.0/tutorials/colors/colormaps.html make_colorbar (bool): Whether to make a colorbar. """ measurement = measurement or self.measurement dOD = measurement.calc_dOD(V_ref=V_ref, t_ref=t_ref) return super().plot_waterfall_vs( measurement=self.measurement, field=dOD, cmap_name=cmap_name, make_colorbar=make_colorbar, ax=ax, vs=measurement.U_name, )
[docs] def plot_wavelengths( self, *, measurement=None, wavelengths=None, axes=None, cmap_name="jet", tspan=None, **kwargs, ): """Plot the dO.D. for specific wavelength in the top panel and EC in bottom Args: measurement (Measurement): The measurement to be plotted, if different from self.measurement wavelengths (list of str): The names of the wavelengths to track as strings, e.g. "w400" for 400 nm axes (list of Ax): The axes to plot on, defaults to new matplotlib axes cmap_name (str): The name of the colormap to use. Defaults to "jet", see https://matplotlib.org/3.5.0/tutorials/colors/colormaps.html tspan (timespan): The timespan to plot **kwargs: Additional key-word arguments are passed on to ECPlotter.plot_measurement """ measurement = measurement or self.measurement wavelengths = wavelengths or measurement.tracked_wavelengths cmap = mpl.cm.get_cmap(cmap_name) norm = mpl.colors.Normalize(vmin=min(measurement.wl), vmax=max(measurement.wl)) if not axes: axes = self.new_two_panel_axes(n_bottom=2) for wl_str in wavelengths: x = float(wl_str[1:]) try: t, y = measurement.grab(wl_str, tspan=tspan) except SeriesNotFoundError: measurement.track_wavelength(x) t, y = measurement.grab(wl_str, tspan=tspan) axes[0].plot(t, y, color=cmap(norm(x)), label=wl_str) axes[0].legend() axes[0].set_ylabel(r"$\Delta$O.D.") self.ec_plotter.plot_measurement( measurement=measurement, axes=[axes[1], axes[3]], tspan=tspan, **kwargs ) return axes
[docs] def plot_wavelengths_vs_potential( self, *, measurement=None, wavelengths=None, axes=None, cmap_name="jet", tspan=None, **kwargs, ): """Plot the dO.D. for specific wavelength in the top panel vs potential Args: measurement (Measurement): The measurement to be plotted, if different from self.measurement wavelengths (list of str): The names of the wavelengths to track as strings, e.g. "w400" for 400 nm axes (list of Ax): The axes to plot on, defaults to new matplotlib axes cmap_name (str): The name of the colormap to use. Defaults to "jet", see https://matplotlib.org/3.5.0/tutorials/colors/colormaps.html tspan (timespan): The timespan to plot **kwargs: Additional key-word arguments are passed on to ECPlotter.plot_vs_potential """ measurement = measurement or self.measurement wavelengths = wavelengths or measurement.tracked_wavelengths cmap = mpl.cm.get_cmap(cmap_name) norm = mpl.colors.Normalize(vmin=min(measurement.wl), vmax=max(measurement.wl)) if not axes: axes = self.new_two_panel_axes() for wl_str in wavelengths: x = float(wl_str[1:]) try: t, y = measurement.grab(wl_str, tspan=tspan) except SeriesNotFoundError: measurement.track_wavelength(x) t, y = measurement.grab(wl_str, tspan=tspan) v = measurement.U axes[0].plot(v, y, color=cmap(norm(x)), label=wl_str) axes[0].legend() axes[0].set_ylabel(r"$\Delta$O.D.") self.ec_plotter.plot_vs_potential( measurement=measurement, ax=axes[1], tspan=tspan, **kwargs ) return axes