|
| 1 | +from typing import Optional, Union |
| 2 | + |
| 3 | +import plopp as pp |
| 4 | +import scipp as sc |
| 5 | +from easyscience.job.experiment import ExperimentBase |
| 6 | +from scipp.io import load_hdf5 as sc_load_hdf5 |
| 7 | +from scipp.io import save_hdf5 as sc_save_hdf5 |
| 8 | + |
| 9 | + |
| 10 | +class Experiment(ExperimentBase): |
| 11 | + """ |
| 12 | + Holds data from an experiment as a sc.DataArray along with metadata. |
| 13 | + """ |
| 14 | + |
| 15 | + def __init__( |
| 16 | + self, |
| 17 | + name: str, |
| 18 | + data: Optional[Union[sc.DataArray, str]] = None, |
| 19 | + *args, |
| 20 | + **kwargs, |
| 21 | + ): |
| 22 | + super(Experiment, self).__init__(name, *args, **kwargs) |
| 23 | + |
| 24 | + if isinstance(data, str): |
| 25 | + self.load_hdf5(filename=data) |
| 26 | + |
| 27 | + elif isinstance(data, sc.DataArray): |
| 28 | + self._data = data |
| 29 | + |
| 30 | + def load_hdf5(self, filename: str): |
| 31 | + """ |
| 32 | + Load data from an HDF5 file. |
| 33 | +
|
| 34 | + Args: |
| 35 | + file_path (str): Path to the data file. |
| 36 | + name (str): Name to assign to the loaded dataset. |
| 37 | + """ |
| 38 | + if not isinstance(filename, str): |
| 39 | + raise TypeError(f"Filename must be a string, not {type(filename).__name__}") |
| 40 | + |
| 41 | + # TODO: Add checks of dimensions etc. I'm not yet sure what dimensions I want to allow, so for now I trust myself. |
| 42 | + |
| 43 | + self._data = sc_load_hdf5(filename) |
| 44 | + |
| 45 | + def save_hdf5(self, filename: Optional[str] = None): |
| 46 | + """Save the dataset to HDF5. |
| 47 | +
|
| 48 | + Args: |
| 49 | + filename (str): Path to the output HDF5 file. |
| 50 | + """ |
| 51 | + |
| 52 | + if filename is None: |
| 53 | + filename = f"{self.name}.h5" |
| 54 | + |
| 55 | + if not isinstance(filename, str): |
| 56 | + raise TypeError(f"Filename must be a string, not {type(filename).__name__}") |
| 57 | + |
| 58 | + if self._data is None: |
| 59 | + raise ValueError("No data to save.") |
| 60 | + |
| 61 | + import os |
| 62 | + |
| 63 | + os.makedirs(os.path.dirname(filename), exist_ok=True) |
| 64 | + sc_save_hdf5(self._data, filename) |
| 65 | + |
| 66 | + def plot_data(self): |
| 67 | + """Plot the dataset using plopp.""" |
| 68 | + |
| 69 | + if self._data is None: |
| 70 | + raise ValueError("No data to plot. Please load data first.") |
| 71 | + |
| 72 | + if not self._in_notebook(): |
| 73 | + raise RuntimeError( |
| 74 | + "plot_data() can only be used in a Jupyter notebook environment." |
| 75 | + ) |
| 76 | + |
| 77 | + from IPython.display import display |
| 78 | + |
| 79 | + fig = pp.plot(self._data.transpose(), title=f"{self.name}") |
| 80 | + display(fig) |
| 81 | + |
| 82 | + @staticmethod |
| 83 | + def _in_notebook(): |
| 84 | + try: |
| 85 | + from IPython import get_ipython |
| 86 | + |
| 87 | + shell = get_ipython().__class__.__name__ |
| 88 | + if shell == "ZMQInteractiveShell": |
| 89 | + return True # Jupyter notebook or JupyterLab |
| 90 | + elif shell == "TerminalInteractiveShell": |
| 91 | + return False # Terminal IPython |
| 92 | + else: |
| 93 | + return False |
| 94 | + except (NameError, ImportError): |
| 95 | + return False # Standard Python (no IPython) |
| 96 | + |
| 97 | + @staticmethod |
| 98 | + def _in_notebook(): |
| 99 | + try: |
| 100 | + from IPython import get_ipython |
| 101 | + |
| 102 | + shell = get_ipython().__class__.__name__ |
| 103 | + if shell == "ZMQInteractiveShell": |
| 104 | + return True # Jupyter notebook or JupyterLab |
| 105 | + elif shell == "TerminalInteractiveShell": |
| 106 | + return False # Terminal IPython |
| 107 | + else: |
| 108 | + return False |
| 109 | + except (NameError, ImportError): |
| 110 | + return False # Standard Python (no IPython) |
0 commit comments