Example #1
0
    def interactive(self):
        """
        Generates a jupyter widgets UI for exploring a spectra.
        """
        import ipywidgets as wid
        from IPython.display import display
        is_nm = self.freq_unit is 'nm'
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        ds = self.dataset
        x = ds.wavelengths if is_nm else ds.wavenumbers
        # fig, ax = plt.subplots()
        wl_slider = wid.FloatSlider(None,
                                    min=x.min(),
                                    max=x.max(),
                                    step=1,
                                    description='Freq (%s)' % self.freq_unit)

        def func(x):

            # ax.cla()
            self.trans([x])
            # plt.show()

        ui = wid.interactive(func, x=wl_slider, continuous_update=False)
        display(ui)
        return ui
Example #2
0
    def interactive(self):
        """
        Generates a jupyter widgets UI for exploring a spectra.
        """
        import ipywidgets as wid
        from IPython.display import display

        is_nm = self.freq_unit is "nm"
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        ds = self.dataset
        x = ds.wavelengths if is_nm else ds.wavenumbers
        # fig, ax = plt.subplots()
        wl_slider = wid.FloatSlider(
            None,
            min=x.min(),
            max=x.max(),
            step=1,
            description="Freq (%s)" % self.freq_unit,
        )

        def func(x):

            # ax.cla()
            self.trans([x])
            # plt.show()

        ui = wid.interactive(func, x=wl_slider, continuous_update=False)
        display(ui)
        return ui
Example #3
0
    def svd(self, n=5):
        """
        Plot the SVD-components of the dataset.

        Parameters
        ----------
        n : int or list of int
            Determines the plotted SVD-components. If `n` is an int, it plots
            the first n components. If `n` is a list of ints, then every
            number is a SVD-component to be plotted.
        """
        is_nm = self.freq_unit is 'nm'
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        ds = self.dataset
        x = ds.wavelengths if is_nm else ds.wavenumbers
        fig, axs = plt.subplots(3, 1, figsize=(4, 5))
        u, s, v = np.linalg.svd(ds.data)
        axs[0].stem(s)
        axs[0].set_xlim(0, 11)
        try:
            len(n)
            comps = n
        except TypeError:
            comps = range(n)

        for i in comps:
            axs[1].plot(ds.t, u.T[i], label='%d' % i)
            axs[2].plot(x, v[i])
        ph.lbl_trans(axs[1], use_symlog=True)
        self.lbl_spec(axs[2])
Example #4
0
    def svd(self, n=5):
        """
        Plot the SVD-components of the dataset.

        Parameters
        ----------
        n : int or list of int
            Determines the plotted SVD-components. If `n` is an int, it plots
            the first n components. If `n` is a list of ints, then every
            number is a SVD-component to be plotted.
        """
        is_nm = self.freq_unit is "nm"
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        ds = self.dataset
        x = ds.wavelengths if is_nm else ds.wavenumbers
        fig, axs = plt.subplots(3, 1, figsize=(4, 5))
        u, s, v = np.linalg.svd(ds.data)
        axs[0].stem(s)
        axs[0].set_xlim(0, 11)
        try:
            len(n)
            comps = n
        except TypeError:
            comps = range(n)

        for i in comps:
            axs[1].plot(ds.t, u.T[i], label="%d" % i)
            axs[2].plot(x, v[i])
        ph.lbl_trans(axs[1], use_symlog=True)
        self.lbl_spec(axs[2])
Example #5
0
    def spec(self, t_list, norm=False, ax=None, n_average=0, **kwargs):
        """
        Plot spectra at given times.

        Parameters
        ----------
        t_list : list or ndarray
            List of the times where the spectra are plotted.
        norm : bool
            If true, each spectral will be normalized.
        ax : plt.Axis or None.
            Axis where the spectra are plotted. If none, the current axis will
            be used.
        n_average : int
            For noisy data it may be preferred to average multiple spectra
            together. This function plots the average of `n_average` spectra
            around the specific time-points.

        Returns
        -------
        list of `Lines2D`
            List containing the Line2D objects belonging to the spectra.
        """

        if ax is None:
            ax = plt.gca()
        is_nm = self.freq_unit == 'nm'
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        ds = self.dataset
        x = ds.wavelengths if is_nm else ds.wavenumbers
        li = []
        for i in t_list:
            idx = dv.fi(ds.t, i)
            if n_average > 0:
                dat = uniform_filter(ds, (2 * n_average + 1, 1)).data[idx, :]
            elif n_average == 0:
                dat = ds.data[idx, :]
            else:
                raise ValueError('n_average must be an Integer >= 0.')

            if norm:
                dat = dat / abs(dat).max()
            li += ax.plot(x,
                          dat,
                          label=ph.time_formatter(ds.t[idx], ph.time_unit),
                          **kwargs)

        self.lbl_spec(ax)
        if not is_nm:
            ax.set_xlim(x.max(), x.min())
        return li
Example #6
0
    def spec(self, t_list, norm=False, ax=None, n_average=0, **kwargs):
        """
        Plot spectra at given times.

        Parameters
        ----------
        t_list : list or ndarray
            List of the times where the spectra are plotted.
        norm : bool
            If true, each spectral will be normalized.
        ax : plt.Axis or None.
            Axis where the spectra are plotted. If none, the current axis will
            be used.
        n_average : int
            For noisy data it may be preferred to average multiple spectra
            together. This function plots the average of `n_average` spectra
            around the specific time-points.

        Returns
        -------
        list of `Lines2D`
            List containing the Line2D objects belonging to the spectra.
        """

        if ax is None:
            ax = plt.gca()
        is_nm = self.freq_unit == "nm"
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        ds = self.dataset
        x = ds.wavelengths if is_nm else ds.wavenumbers
        li = []
        for i in t_list:
            idx = dv.fi(ds.t, i)
            if n_average > 0:
                dat = uniform_filter(ds, (2 * n_average + 1, 1)).data[idx, :]
            elif n_average == 0:
                dat = ds.data[idx, :]
            else:
                raise ValueError("n_average must be an Integer >= 0.")

            if norm:
                dat = dat / abs(dat).max()
            li += ax.plot(
                x, dat, label=ph.time_formatter(ds.t[idx], ph.time_unit), **kwargs
            )

        self.lbl_spec(ax)
        if not is_nm:
            ax.set_xlim(x.max(), x.min())
        return li
Example #7
0
    def trans_anisotropy(self, wls, symlog=True, ax=None, freq_unit='auto'):
        """
        Plots the anisotropy over time for given frequencies.
        Parameters
        ----------
        wls : list of floats
            Which frequencies are plotted.
        symlog : bool
            Use symlog scale
        ax : plt.Axes or None
            Matplotlib Axes, if `None`, defaults to `plt.gca()`.

        Returns
        -------
        : list of Line2D
            List with the line objects.

        """
        if ax is None:
            ax = ax.gca()
        ds = self.pol_ds
        tmp = self.freq_unit if freq_unit == 'auto' else freq_unit
        is_nm = tmp == 'nm'
        x = ds.wavelengths if is_nm else ds.wavenumbers
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        l = []
        for i in wls:
            idx = dv.fi(x, i)
            pa, pe = ds.para.data[:, idx], ds.perp.data[:, idx]
            aniso = (pa - pe) / (2 * pe + pa)
            l += ax.plot(ds.para.t,
                         aniso,
                         label=ph.time_formatter(ds.t[idx], ph.time_unit))
        ph.lbl_trans(use_symlog=symlog)
        if symlog:
            ax.set_xscale('symlog')
        ax.set_xlim(-1, )
        return l
Example #8
0
    def das(self, ax=None, **kwargs):
        """
        Plot a DAS, if available.

        Parameters
        ----------
        ax : plt.Axes or None
            Axes to plot.
        kwargs : dict
            Keyword args given to the plot function

        Returns
        -------
        Tuple of (List of Lines2D)
        """
        ds = self.pol_ds
        if not hasattr(self.pol_ds, 'fit_exp_result_'):
            raise ValueError('The PolTRSpec must have successfully fit the '
                             'data')
        if ax is None:
            ax = plt.gca()
        is_nm = self.freq_unit == 'nm'
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        f = ds.fit_exp_result_.fitter
        num_exp = f.num_exponentials
        leg_text = [
            ph.nsf(i) + ' ' + ph.time_unit for i in f.last_para[-num_exp:]
        ]
        if max(f.last_para) > 5 * f.t.max():
            leg_text[-1] = 'const.'
        n = ds.para.wavelengths.size
        x = ds.wavelengths if is_nm else ds.wavenumbers
        l1 = ax.plot(self.x, f.c[:n, :], **kwargs, **self.para_ls)
        l2 = ax.plot(self.x, f.c[n:, :], **kwargs, **self.perp_ls)

        dv.equal_color(l1, l2)
        ax.legend(l1, leg_text, title='Decay\nConstants')
        return l1, l2
Example #9
0
    def trans_anisotropy(self, wls, symlog=True, ax=None, freq_unit="auto"):
        """
        Plots the anisotropy over time for given frequencies.
        Parameters
        ----------
        wls : list of floats
            Which frequencies are plotted.
        symlog : bool
            Use symlog scale
        ax : plt.Axes or None
            Matplotlib Axes, if `None`, defaults to `plt.gca()`.

        Returns
        -------
        : list of Line2D
            List with the line objects.

        """
        if ax is None:
            ax = ax.gca()
        ds = self.pol_ds
        tmp = self.freq_unit if freq_unit == "auto" else freq_unit
        is_nm = tmp == "nm"
        x = ds.wavelengths if is_nm else ds.wavenumbers
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        l = []
        for i in wls:
            idx = dv.fi(x, i)
            pa, pe = ds.para.data[:, idx], ds.perp.data[:, idx]
            aniso = (pa - pe) / (2 * pe + pa)
            l += ax.plot(
                ds.para.t, aniso, label=ph.time_formatter(ds.t[idx], ph.time_unit)
            )
        ph.lbl_trans(use_symlog=symlog)
        if symlog:
            ax.set_xscale("symlog")
        ax.set_xlim(-1)
        return l
Example #10
0
    def overview(self):
        """
        Plots an overview figure.
        """
        is_nm = self.freq_unit is "nm"
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        ds = self.dataset
        x = ds.wavelengths if is_nm else ds.wavenumbers
        fig, axs = plt.subplots(
            3, 1, figsize=(5, 12), gridspec_kw=dict(height_ratios=(2, 1, 1))
        )
        self.map(ax=axs[0])

        times = np.hstack((0, np.geomspace(0.1, ds.t.max(), 6)))
        sp = self.spec(times, ax=axs[1])
        freqs = np.unique(np.linspace(x.min(), x.max(), 6))
        tr = self.trans(freqs, ax=axs[2])
        OverviewPlot = namedtuple("OverviewPlot", "fig axs trans spec")
        return OverviewPlot(fig, axs, tr, sp)
Example #11
0
    def das(self, ax=None, **kwargs):
        """
        Plot a DAS, if available.

        Parameters
        ----------
        ax : plt.Axes or None
            Axes to plot.
        kwargs : dict
            Keyword args given to the plot function

        Returns
        -------
        Tuple of (List of Lines2D)
        """
        ds = self.pol_ds
        if not hasattr(self.pol_ds, "fit_exp_result_"):
            raise ValueError("The PolTRSpec must have successfully fit the " "data")
        if ax is None:
            ax = plt.gca()
        is_nm = self.freq_unit == "nm"
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        f = ds.fit_exp_result_.fitter
        num_exp = f.num_exponentials
        leg_text = [ph.nsf(i) + " " + ph.time_unit for i in f.last_para[-num_exp:]]
        if max(f.last_para) > 5 * f.t.max():
            leg_text[-1] = "const."
        n = ds.para.wavelengths.size
        x = ds.wavelengths if is_nm else ds.wavenumbers
        l1 = ax.plot(self.x, f.c[:n, :], **kwargs, **self.para_ls)
        l2 = ax.plot(self.x, f.c[n:, :], **kwargs, **self.perp_ls)

        dv.equal_color(l1, l2)
        ax.legend(l1, leg_text, title="Decay\nConstants")
        return l1, l2
Example #12
0
    def overview(self):
        """
        Plots an overview figure.
        """
        is_nm = self.freq_unit is 'nm'
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        ds = self.dataset
        x = ds.wavelengths if is_nm else ds.wavenumbers
        fig, axs = plt.subplots(3,
                                1,
                                figsize=(5, 12),
                                gridspec_kw=dict(height_ratios=(2, 1, 1)))
        self.map(ax=axs[0])

        times = np.hstack((0, np.geomspace(0.1, ds.t.max(), 6)))
        sp = self.spec(times, ax=axs[1])
        freqs = np.unique(np.linspace(x.min(), x.max(), 6))
        tr = self.trans(freqs, ax=axs[2])
        OverviewPlot = namedtuple('OverviewPlot', 'fig axs trans spec')
        return OverviewPlot(fig, axs, tr, sp)
Example #13
0
    def trans(self,
              wls,
              symlog=True,
              norm=False,
              ax=None,
              freq_unit='auto',
              **kwargs):
        """
        Plot the nearest transients for given frequencies.

        Parameters
        ----------
        wls : list or ndarray
            Spectral positions, should be given in the same unit as
            `self.freq_unit`.
        symlog : bool
            Determines if the x-scale is symlog.
        norm : bool or float
            If `False`, no normalization is used. If `True`, each transient
            is divided by the maximum absolute value. If `norm` is a float,
            all transient are normalized by their signal at the time `norm`.
        ax : plt.Axes or None
            Takes a matplotlib axes. If none, it uses `plt.gca()` to get the
            current axes. The lines are plotted in this axis.
        freq_unit : 'auto', 'cm' or 'nm'
            How to interpret the given frequencies. If 'auto' it defaults to
            the plotters freq_unit.

        All other kwargs are forwarded to the plot function.

        Returns
        -------
         list of Line2D
            List containing the plotted lines.
        """
        if ax is None:
            ax = plt.gca()

        tmp = self.freq_unit if freq_unit is 'auto' else freq_unit
        is_nm = tmp == 'nm'
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        ds = self.dataset
        x = ds.wavelengths if is_nm else ds.wavenumbers

        wl, t, d = ds.wl, ds.t, ds.data
        l, plotted_vals = [], []
        for i in wls:
            idx = dv.fi(x, i)

            dat = d[:, idx]
            if norm is True:
                dat = np.sign(dat[np.argmax(abs(dat))]) * dat / abs(dat).max()
            elif norm is False:
                pass
            else:
                dat = dat / dat[dv.fi(t, norm)]
            plotted_vals.append(dat)
            l.extend(
                ax.plot(t,
                        dat,
                        label='%.1f %s' % (x[idx], ph.freq_unit),
                        **kwargs))

        if symlog:
            ax.set_xscale('symlog', linthreshx=1.)
        ph.lbl_trans(ax=ax, use_symlog=symlog)
        ax.legend(loc='best', ncol=3)
        ax.set_xlim(right=t.max())
        ax.yaxis.set_tick_params(which='minor', left=True)
        return l
Example #14
0
    def map(self,
            symlog=True,
            equal_limits=True,
            plot_con=True,
            con_step=None,
            con_filter=None,
            ax=None,
            **kwargs):
        """
        Plot a colormap of the dataset with optional contour lines.

        Parameters
        ----------
        symlog : bool
            Determines if the yscale is symmetric logarithmic.
        equal_limits : bool
            If true, it makes to colors symmetric around zeros. Note this
            also sets the middle of the colormap to zero.
            Default is `True`.
        plot_con : bool
            Plot additional contour lines if `True` (default).
        con_step : float, array or None
            Controls the contour-levels. If `con_step` is a float, it is used as
            the step size between two levels. If it is an array, its elements
            are the levels. If `None`, it defaults to 20 levels.
        con_filter : None, int or `TimeResSpec`.
            Since contours are strongly affected by noise, it can be prefered to
            filter the dataset before calculating the contours. If `con_filter`
            is a dataset, the data of that set will be used for the contours. If
            it is a tuple of int, the data will be filtered with an
            uniform filter before calculation the contours. If `None`, no data
            prepossessing will be applied.
        ax : plt.Axis or None
            Takes a matplotlib axis. If none, it uses `plt.gca()` to get the
            current axes. The lines are plotted in this axis.

        """
        if ax is None:
            ax = plt.gca()
        is_nm = self.freq_unit is 'nm'
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()

        ds = self.dataset
        x = ds.wavelengths if is_nm else ds.wavenumbers
        cmap = kwargs.pop('colormap', "bwr")
        if equal_limits:
            m = np.max(np.abs(ds.data))
            vmin, vmax = -m, m
        else:
            vmin, vmax = ds.data.max(), ds.data.min()
        mesh = ax.pcolormesh(x,
                             ds.t,
                             ds.data,
                             vmin=vmin,
                             vmax=vmax,
                             cmap=cmap,
                             **kwargs)
        if symlog:
            ax.set_yscale('symlog', linthreshy=1)
            ph.symticks(ax, axis='y')
            ax.set_ylim(-.5)
        plt.colorbar(mesh, ax=ax)

        if plot_con:
            if con_step is None:
                levels = 20
            elif isinstance(con_step, np.ndarray):
                levels = con_step
            else:
                # TODO This assumes data has positive and negative elements.
                pos = np.arange(0, ds.data.max(), con_step)
                neg = np.arange(0, -ds.data.min(), con_step)
                levels = np.hstack((-neg[::-1][:-1], pos))

            if isinstance(con_filter, TimeResSpec):
                data = con_filter.data
            elif con_filter is not None:  # must be int or tuple of int
                if isinstance(con_filter, tuple):
                    data = uniform_filter(ds, con_filter).data
                else:
                    data = svd_filter(ds, con_filter).data
            else:
                data = ds.data
            ax.contour(x,
                       ds.t,
                       data,
                       levels=levels,
                       linestyles='solid',
                       colors='k',
                       linewidths=0.5)
        ph.lbl_map(ax, symlog)
        if not is_nm:
            ax.set_xlim(*ax.get_xlim()[::-1])
Example #15
0
    def trans(self, wls, symlog=True, norm=False, ax=None, freq_unit="auto", **kwargs):
        """
        Plot the nearest transients for given frequencies.

        Parameters
        ----------
        wls : list or ndarray
            Spectral positions, should be given in the same unit as
            `self.freq_unit`.
        symlog : bool
            Determines if the x-scale is symlog.
        norm : bool or float
            If `False`, no normalization is used. If `True`, each transient
            is divided by the maximum absolute value. If `norm` is a float,
            all transient are normalized by their signal at the time `norm`.
        ax : plt.Axes or None
            Takes a matplotlib axes. If none, it uses `plt.gca()` to get the
            current axes. The lines are plotted in this axis.
        freq_unit : 'auto', 'cm' or 'nm'
            How to interpret the given frequencies. If 'auto' it defaults to
            the plotters freq_unit.

        All other kwargs are forwarded to the plot function.

        Returns
        -------
         list of Line2D
            List containing the plotted lines.
        """
        if ax is None:
            ax = plt.gca()

        tmp = self.freq_unit if freq_unit is "auto" else freq_unit
        is_nm = tmp == "nm"
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()
        ds = self.dataset
        x = ds.wavelengths if is_nm else ds.wavenumbers

        wl, t, d = ds.wl, ds.t, ds.data
        l, plotted_vals = [], []
        for i in wls:
            idx = dv.fi(x, i)

            dat = d[:, idx]
            if norm is True:
                dat = np.sign(dat[np.argmax(abs(dat))]) * dat / abs(dat).max()
            elif norm is False:
                pass
            else:
                dat = dat / dat[dv.fi(t, norm)]
            plotted_vals.append(dat)
            l.extend(
                ax.plot(t, dat, label="%.1f %s" % (x[idx], ph.freq_unit), **kwargs)
            )

        if symlog:
            ax.set_xscale("symlog", linthreshx=1.0)
        ph.lbl_trans(ax=ax, use_symlog=symlog)
        ax.legend(loc="best", ncol=3)
        ax.set_xlim(right=t.max())
        ax.yaxis.set_tick_params(which="minor", left=True)
        return l
Example #16
0
    def map(
        self,
        symlog=True,
        equal_limits=True,
        plot_con=True,
        con_step=None,
        con_filter=None,
        ax=None,
        **kwargs
    ):
        """
        Plot a colormap of the dataset with optional contour lines.

        Parameters
        ----------
        symlog : bool
            Determines if the yscale is symmetric logarithmic.
        equal_limits : bool
            If true, it makes to colors symmetric around zeros. Note this
            also sets the middle of the colormap to zero.
            Default is `True`.
        plot_con : bool
            Plot additional contour lines if `True` (default).
        con_step : float, array or None
            Controls the contour-levels. If `con_step` is a float, it is used as
            the step size between two levels. If it is an array, its elements
            are the levels. If `None`, it defaults to 20 levels.
        con_filter : None, int or `TimeResSpec`.
            Since contours are strongly affected by noise, it can be prefered to
            filter the dataset before calculating the contours. If `con_filter`
            is a dataset, the data of that set will be used for the contours. If
            it is a tuple of int, the data will be filtered with an
            uniform filter before calculation the contours. If `None`, no data
            prepossessing will be applied.
        ax : plt.Axis or None
            Takes a matplotlib axis. If none, it uses `plt.gca()` to get the
            current axes. The lines are plotted in this axis.

        """
        if ax is None:
            ax = plt.gca()
        is_nm = self.freq_unit is "nm"
        if is_nm:
            ph.vis_mode()
        else:
            ph.ir_mode()

        ds = self.dataset
        x = ds.wavelengths if is_nm else ds.wavenumbers
        cmap = kwargs.pop("colormap", "bwr")
        if equal_limits:
            m = np.max(np.abs(ds.data))
            vmin, vmax = -m, m
        else:
            vmin, vmax = ds.data.max(), ds.data.min()
        mesh = ax.pcolormesh(
            x, ds.t, ds.data, vmin=vmin, vmax=vmax, cmap=cmap, **kwargs
        )
        if symlog:
            ax.set_yscale("symlog", linthreshy=1)
            ph.symticks(ax, axis="y")
            ax.set_ylim(-0.5)
        plt.colorbar(mesh, ax=ax)

        if plot_con:
            if con_step is None:
                levels = 20
            elif isinstance(con_step, np.ndarray):
                levels = con_step
            else:
                # TODO This assumes data has positive and negative elements.
                pos = np.arange(0, ds.data.max(), con_step)
                neg = np.arange(0, -ds.data.min(), con_step)
                levels = np.hstack((-neg[::-1][:-1], pos))

            if isinstance(con_filter, TimeResSpec):
                data = con_filter.data
            elif con_filter is not None:  # must be int or tuple of int
                if isinstance(con_filter, tuple):
                    data = uniform_filter(ds, con_filter).data
                else:
                    data = svd_filter(ds, con_filter).data
            else:
                data = ds.data
            ax.contour(
                x,
                ds.t,
                data,
                levels=levels,
                linestyles="solid",
                colors="k",
                linewidths=0.5,
            )
        ph.lbl_map(ax, symlog)
        if not is_nm:
            ax.set_xlim(*ax.get_xlim()[::-1])