From 2251210d7f2cbffb224f5210bd5ccba9353e5728 Mon Sep 17 00:00:00 2001 From: Reto Trappitsch Date: Thu, 17 Mar 2022 13:58:52 -0400 Subject: [PATCH] Add GUI for plotting integrals per package (#26) * Add GUI for plotting integrals per package * Fix docstring * Add `integrals_packages` to documentation - Fix typos in documentation of special functions --- docs/dev/api/guis.rst | 18 ++++++++++ docs/pkg/special.rst | 32 +++++++++++++++-- rimseval/guis/__init__.py | 3 +- rimseval/guis/plots.py | 74 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 3 deletions(-) diff --git a/docs/dev/api/guis.rst b/docs/dev/api/guis.rst index 5073318..effad44 100644 --- a/docs/dev/api/guis.rst +++ b/docs/dev/api/guis.rst @@ -174,6 +174,14 @@ Create a PyQt app and run it. .. autofunction:: dt_ions +************************** +:func:`integrals_packages` +************************** + +Create a PyQt app and run it. + +.. autofunction:: integrals_packages + ************************* :func:`nof_ions_per_shot` ************************* @@ -202,6 +210,16 @@ Matplotlib PyQt figure to plot histogram for arrival time differences between io :members: :undoc-members: +**************************** +:class:`IntegralsPerPackage` +**************************** + +Matplotlib PyQt figure to integrals per package. + +.. autoclass:: IntegralsPerPackage + :members: + :undoc-members: + ******************** :class:`IonsPerShot` ******************** diff --git a/docs/pkg/special.rst b/docs/pkg/special.rst index 6755ac3..3c709c3 100644 --- a/docs/pkg/special.rst +++ b/docs/pkg/special.rst @@ -30,7 +30,7 @@ The following code shows you how to do this: .. code-block:: python - from typing import Path + from pathlib import Path from rimseval import CRDFileProcessor from rimseval.guis import hist_nof_shots @@ -70,7 +70,7 @@ This number is of course user-defined and can be omitted. .. code-block:: python - from typing import Path + from pathlib import Path from rimseval import CRDFileProcessor from rimseval.guis import dt_ions @@ -80,3 +80,31 @@ This number is of course user-defined and can be omitted. crd.spectrum_full() dt_ions(crd, max_ns=100) + + +--------------------- +Integrals per package +--------------------- + +If you have split your spectrum into packages +and have defined integrals, +this routine allows you to show a figure +of all integrals per package +versus the number of the package. +This is especially interesting to find bursts in your measurements, +i.e., when measuring with the desorption laser. + +The following example shows how the plot is generated: + +.. code-block:: python + + from pathlib import Path + + from rimseval import CRDFileProcessor + from rimseval.guis import integrals_packages + + my_file = Path("path/to/my_file.crd") + crd = CRDFileProcessor(crd) + crd.spectrum_full() + + integrals_packages(crd) diff --git a/rimseval/guis/__init__.py b/rimseval/guis/__init__.py index ba4853b..45aace4 100644 --- a/rimseval/guis/__init__.py +++ b/rimseval/guis/__init__.py @@ -2,12 +2,13 @@ from .integrals import define_backgrounds_app, define_integrals_app from .mcal import create_mass_cal_app -from .plots import dt_ions, nof_ions_per_shot +from .plots import dt_ions, integrals_packages, nof_ions_per_shot __all__ = [ "create_mass_cal_app", "define_backgrounds_app", "define_integrals_app", "dt_ions", + "integrals_packages", "nof_ions_per_shot", ] diff --git a/rimseval/guis/plots.py b/rimseval/guis/plots.py index 6452e1f..c8b2fde 100644 --- a/rimseval/guis/plots.py +++ b/rimseval/guis/plots.py @@ -1,5 +1,6 @@ """Plotting capability for specialty functions.""" +import itertools import sys from typing import Tuple @@ -20,6 +21,10 @@ from rimseval.processor import CRDFileProcessor +# markers to cycle through +MARKERS = ("o", "^", "s", "v", "<", ">", "+", "x", "*", "1", "2", "3", "4") + + class PlotFigure(QtWidgets.QMainWindow): """QMainWindow to plot a Figure.""" @@ -157,6 +162,60 @@ def calc_and_draw(self) -> None: self.sc.draw() +class IntegralsPerPackage(PlotFigure): + """Plot integrals of all packages versus package number.""" + + def __init__( + self, crd: CRDFileProcessor, logy: bool = False, theme: str = None + ) -> None: + """Initialize the class. + + :param crd: CRD file to process. + :param logy: Plot with logarithmic y-axis? Defaults to ``True`` + :param theme: Theme to plot in, defaults to ``None``. + + :raises OSError: Packages are not defined + """ + super().__init__(logy=logy, theme=theme) + + self.setWindowTitle("Integrals per package") + + self.crd = crd + + if crd.integrals_pkg is None: + raise OSError("Integrals for packages are not available.") + + self.calc_and_draw() + + def calc_and_draw(self) -> None: + """Create the plot for all the defined integrals.""" + int_names = self.crd.def_integrals[0] + integrals_pkg = self.crd.integrals_pkg + + xdata = np.arange(len(integrals_pkg)) + 1 # start with 1 + counts = integrals_pkg[:, :, 0] + errors = integrals_pkg[:, :, 1] + + # plot + marker = itertools.cycle(MARKERS) + for it in range(counts.shape[1]): # loop through all defined integrals + dat = counts[:, it] + err = errors[:, it] + self.axes.errorbar( + xdata, dat, yerr=err, ls="--", label=int_names[it], marker=next(marker) + ) + + # labels + self.axes.set_xlabel("Package number") + self.axes.set_ylabel("Counts in integral") + self.axes.set_title( + f"Integrals per package - {self.crd.fname.with_suffix('').name}" + ) + self.axes.legend() + + self.sc.draw() + + class IonsPerShot(PlotFigure): """Plot histogram for number of ions per shot.""" @@ -222,6 +281,21 @@ def dt_ions( app.exec() +def integrals_packages( + crd: CRDFileProcessor, logy: bool = False, theme: str = None +) -> None: + """Plot all the integrals versus package number for data split into packages. + + :param crd: CRD file to process. + :param logy: Plot with logarithmic y axis? Defaults to ``True`` + :param theme: Theme to plot in, defaults to ``None``. + """ + app = QtWidgets.QApplication(sys.argv) + window = IntegralsPerPackage(crd, logy=logy, theme=theme) + window.show() + app.exec() + + def nof_ions_per_shot( crd: CRDFileProcessor, logy: bool = False, theme: str = None ) -> None: