evefile 0.1.0rc2__py3-none-any.whl → 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
evefile/entities/data.py CHANGED
@@ -1,4 +1,4 @@
1
- """
1
+ r"""
2
2
 
3
3
  *Entities representing an eveH5 file on the data level.*
4
4
 
@@ -55,6 +55,77 @@ the :mod:`evefile.entities.metadata` module.
55
55
  You may click on the image for a larger view.
56
56
 
57
57
 
58
+ Array channels
59
+ --------------
60
+
61
+ Array channels in their general form are channels collecting 1D data.
62
+ Typical devices used here are MCAs, but oscilloscopes and vector signal
63
+ analysers (VSA) would be other typical array channels. Hence, for these
64
+ quite different types of array channels, distinct subclasses of the
65
+ generic :class:`ArrayChannelData` class exist, see
66
+ :numref:`Fig. %s <fig-uml_arraychannel_api>`.
67
+
68
+
69
+ .. _fig-uml_arraychannel_api:
70
+
71
+ .. figure:: /uml/arraychannel.*
72
+ :align: center
73
+ :width: 500px
74
+
75
+ Preliminary data model for the :class:`ArrayChannelData` classes. The
76
+ basic hierarchy is identical to :numref:`Fig. %s
77
+ <fig-uml_evefile.data_api>`. Details for the
78
+ :class:`MCAChannelData` class can be found in :numref:`Fig. %s
79
+ <fig-uml_mcachannel_api>`.
80
+
81
+
82
+ Multi Channel Analysers (MCA) generally collect 1D data and typically have
83
+ separate regions of interest (ROI) defined, containing the sum of the
84
+ counts for the given region. For the EPICS MCA record,
85
+ see https://millenia.cars.aps.anl.gov/software/epics/mcaRecord.html.
86
+
87
+
88
+ .. _fig-uml_mcachannel_api:
89
+
90
+ .. figure:: /uml/mcachannel.*
91
+ :align: center
92
+ :width: 750px
93
+
94
+ Preliminary data model for the :class:`MCAChannelData` classes. The basic
95
+ hierarchy is identical to :numref:`Fig. %s
96
+ <fig-uml_evefile.data_api>`, and here, the relevant part of the
97
+ metadata class hierarchy from :numref:`Fig. %s
98
+ <fig-uml_evefile_entities_metadata>` is shown as well. Separating the
99
+ :class:`MCAChannelCalibration
100
+ <evefile.entities.metadata.MCAChannelCalibration>` class from the
101
+ :class:`ArrayChannelMetadata
102
+ <evefile.entities.metadata.ArrayChannelMetadata>` allows to
103
+ add distinct behaviour, *e.g.* creating calibration curves from the
104
+ parameters.
105
+
106
+
107
+ Note: The scalar attributes for ArrayChannelROIs will currently be saved
108
+ as snapshots regardless of whether the actual ROI has been defined/used.
109
+ Hence, the evefile package needs to decide based on the existence of the
110
+ actual data whether to create a ROI object and attach it to
111
+ :class:`ArrayChannelData`.
112
+
113
+ The calibration parameters are needed to convert the *x* axis of the MCA
114
+ spectrum into a real energy axis. Hence,
115
+ the :class:`MCAChannelCalibration
116
+ <evefile.entities.metadata.MCAChannelCalibration>`
117
+ class will have methods for performing exactly this conversion. The
118
+ relationship between calibrated units (cal) and channel number (chan) is
119
+ defined as cal=CALO + chan\*CALS + chan^2\*CALQ. The first channel in the
120
+ spectrum is defined as chan=0. However, not all MCAs/SDDs have these
121
+ calibration values: Ketek SDDs seem to not have these values (internal
122
+ calibration?).
123
+
124
+ The real_time and life_time values can be used to get an idea of the
125
+ amount of pile up occurring, *i.e.* having two photons with same energy
126
+ within a short time interval reaching the detector being detected as one
127
+ photon with twice the energy. Hence, latest in the radiometry package,
128
+ distinct methods for this kind of analysis should be implemented.
58
129
 
59
130
 
60
131
  Individual classes
@@ -86,6 +157,18 @@ documentation:
86
157
 
87
158
  * :class:`IntervalNormalizedChannelData`
88
159
 
160
+ * :class:`ArrayChannelData`
161
+
162
+ * :class:`MCAChannelData`
163
+
164
+ * :class:`MCAChannelROIData`
165
+
166
+ * :class:`DataImporter`
167
+
168
+ * :class:`HDF5DataImporter`
169
+
170
+ * :class:`Axis`
171
+
89
172
 
90
173
 
91
174
  Special aspects
@@ -392,6 +475,100 @@ class Data:
392
475
  return dataframe
393
476
 
394
477
 
478
+ class Axis:
479
+ """Axis for data.
480
+
481
+ An axis contains always both, numerical values and the metadata
482
+ necessary to create axis labels and to make sense of the numerical
483
+ information.
484
+
485
+ Attributes
486
+ ----------
487
+ quantity : :class:`str`
488
+ quantity of the numerical data, usually used as first part of an
489
+ automatically generated axis label
490
+
491
+ unit : :class:`str`
492
+ unit of the numerical data, usually used as second part of an
493
+ automatically generated axis label
494
+
495
+ symbol : :class:`str`
496
+ symbol for the quantity of the numerical data, usually used as first
497
+ part of an automatically generated axis label
498
+
499
+ label : :class:`str`
500
+ manual label for the axis, particularly useful in cases where no
501
+ quantity and unit are provided or should be overwritten.
502
+
503
+
504
+ .. note::
505
+ There are three alternative ways of writing axis labels, one with
506
+ using the quantity name and the unit, one with using the quantity
507
+ symbol and the unit, and one using both, quantity name and symbol,
508
+ usually separated by comma. Quantity and unit shall always be
509
+ separated by a slash. Which way you prefer is a matter of personal
510
+ taste and given context.
511
+
512
+
513
+ Raises
514
+ ------
515
+ ValueError
516
+ Raised when trying to set axis values to another type than numpy array
517
+ IndexError
518
+ Raised when trying to set axis values to an array with more than one
519
+ dimension.
520
+ Raised if index does not have the same length as values.
521
+
522
+
523
+ .. versionadded:: 0.2
524
+
525
+ """
526
+
527
+ def __init__(self):
528
+ super().__init__()
529
+ self._values = np.zeros(0)
530
+ self.quantity = ""
531
+ self.symbol = ""
532
+ self.unit = ""
533
+ self.label = ""
534
+
535
+ @property
536
+ def values(self):
537
+ """
538
+ Get or set the numerical axis values.
539
+
540
+ Values require to be a one-dimensional numpy array. Trying to set
541
+ values to either a different type that cannot be converted to a
542
+ numpy array or a numpy array with more than one dimension will raise
543
+ a corresponding error.
544
+
545
+ Raises
546
+ ------
547
+ ValueError
548
+ Raised if axis values are of wrong type
549
+ IndexError
550
+ Raised if axis values are of wrong dimension, i.e. not a vector
551
+
552
+ """
553
+ return self._values
554
+
555
+ @values.setter
556
+ def values(self, values):
557
+ if not isinstance(values, type(self._values)):
558
+ values = np.asarray(values)
559
+ if (
560
+ not isinstance(values, type(self._values))
561
+ or values.dtype != self._values.dtype
562
+ ):
563
+ raise ValueError(
564
+ f"Wrong type: expected {self._values.dtype}, "
565
+ f"got {values.dtype}"
566
+ )
567
+ if values.ndim > 1:
568
+ raise IndexError("Values need to be one-dimensional")
569
+ self._values = values
570
+
571
+
395
572
  class MonitorData(Data):
396
573
  """
397
574
  Data from devices monitored, but not controlled by the eve engine.
@@ -562,7 +739,7 @@ class MeasureData(Data):
562
739
  """
563
740
  Retrieve Pandas DataFrame with data as column.
564
741
 
565
- The index is named "positions" and contains the values of the
742
+ The index is named "position" and contains the values of the
566
743
  :attr:`position_counts` attribute of the data object.
567
744
 
568
745
  .. important::
@@ -701,6 +878,47 @@ class DeviceData(MeasureData):
701
878
  super().__init__()
702
879
  self.metadata = metadata.DeviceMetadata()
703
880
 
881
+ def join(self, positions=None):
882
+ """
883
+ Perform a left join of the data on the provided list of positions.
884
+
885
+ The main "quantisation" axis of the values for a device and the
886
+ common reference is the list of positions. To sensibly compare the
887
+ data of different devices or plot different device data against each
888
+ other, the data need to be harmonised, *i.e.* share a common set of
889
+ positions as indices.
890
+
891
+ If positions are not present in the original data, the previous
892
+ value present is automatically taken for this position. This is a
893
+ valid assumption, as the underlying EPICS monitors only record a
894
+ new value if the actual value has changed.
895
+
896
+ .. note::
897
+
898
+ The method will *alter* the data and positions of the underlying
899
+ :obj:`DeviceData` object. Hence, make sure to make a copy if
900
+ this is not your intended use case.
901
+
902
+
903
+ Parameters
904
+ ----------
905
+ positions : :class:`numpy.ndarray`
906
+ Array with positions the data should be mapped to.
907
+
908
+ Raises
909
+ ------
910
+ ValueError
911
+ Raised if no positions are provided
912
+
913
+ """
914
+ if positions is None:
915
+ raise ValueError("No positions provided")
916
+ new_positions = (
917
+ np.searchsorted(self.position_counts, positions, side="right") - 1
918
+ )
919
+ self.position_counts = positions
920
+ self.data = self.data[new_positions]
921
+
704
922
 
705
923
  class AxisData(MeasureData):
706
924
  """
@@ -788,6 +1006,10 @@ class AxisData(MeasureData):
788
1006
  detailed discussion, see the :mod:`evefile.controllers.joining`
789
1007
  module.
790
1008
 
1009
+ If a snapshot preceding a non-existing position is available,
1010
+ the value from this snapshot is automatically taken for the given
1011
+ position.
1012
+
791
1013
  .. note::
792
1014
 
793
1015
  The method will *alter* the data and positions of the underlying
@@ -1090,6 +1312,35 @@ class AverageChannelData(ChannelData):
1090
1312
  """
1091
1313
  return self.data
1092
1314
 
1315
+ def get_dataframe(self): # pylint: disable=useless-parent-delegation
1316
+ """
1317
+ Retrieve Pandas DataFrame with data as columns.
1318
+
1319
+ The DataFrame contains two columns, each corresponding to the
1320
+ respective attribute of the class:
1321
+
1322
+ * data
1323
+ * attempts
1324
+
1325
+ The index is named "position" and contains the values of the
1326
+ :attr:`position_counts` attribute of the data object.
1327
+
1328
+ .. important::
1329
+
1330
+ While working with a Pandas DataFrame may seem convenient,
1331
+ you're loosing basically all the relevant metadata of the
1332
+ datasets. Hence, this method is rather a convenience method to
1333
+ be backwards-compatible to older interfaces, but it is
1334
+ explicitly *not* suggested for extensive use.
1335
+
1336
+ Returns
1337
+ -------
1338
+ dataframe : :class:`pandas.DataFrame`
1339
+ Pandas DataFrame containing data as columns.
1340
+
1341
+ """
1342
+ return super().get_dataframe()
1343
+
1093
1344
 
1094
1345
  class IntervalChannelData(ChannelData):
1095
1346
  """
@@ -1187,6 +1438,36 @@ class IntervalChannelData(ChannelData):
1187
1438
  """
1188
1439
  return self.data
1189
1440
 
1441
+ def get_dataframe(self): # pylint: disable=useless-parent-delegation
1442
+ """
1443
+ Retrieve Pandas DataFrame with data as columns.
1444
+
1445
+ The DataFrame contains three columns, each corresponding to the
1446
+ respective attribute of the class:
1447
+
1448
+ * data
1449
+ * counts
1450
+ * std
1451
+
1452
+ The index is named "position" and contains the values of the
1453
+ :attr:`position_counts` attribute of the data object.
1454
+
1455
+ .. important::
1456
+
1457
+ While working with a Pandas DataFrame may seem convenient,
1458
+ you're loosing basically all the relevant metadata of the
1459
+ datasets. Hence, this method is rather a convenience method to
1460
+ be backwards-compatible to older interfaces, but it is
1461
+ explicitly *not* suggested for extensive use.
1462
+
1463
+ Returns
1464
+ -------
1465
+ dataframe : :class:`pandas.DataFrame`
1466
+ Pandas DataFrame containing data as columns.
1467
+
1468
+ """
1469
+ return super().get_dataframe()
1470
+
1190
1471
 
1191
1472
  class NormalizedChannelData:
1192
1473
  """
@@ -1349,6 +1630,36 @@ class SinglePointNormalizedChannelData(
1349
1630
  def normalizing_data(self, normalizing_data=None):
1350
1631
  self._normalizing_data = normalizing_data
1351
1632
 
1633
+ def get_dataframe(self): # pylint: disable=useless-parent-delegation
1634
+ """
1635
+ Retrieve Pandas DataFrame with data as columns.
1636
+
1637
+ The DataFrame contains three columns, each corresponding to the
1638
+ respective attribute of the class:
1639
+
1640
+ * data
1641
+ * normalized_data
1642
+ * normalizing_data
1643
+
1644
+ The index is named "position" and contains the values of the
1645
+ :attr:`position_counts` attribute of the data object.
1646
+
1647
+ .. important::
1648
+
1649
+ While working with a Pandas DataFrame may seem convenient,
1650
+ you're loosing basically all the relevant metadata of the
1651
+ datasets. Hence, this method is rather a convenience method to
1652
+ be backwards-compatible to older interfaces, but it is
1653
+ explicitly *not* suggested for extensive use.
1654
+
1655
+ Returns
1656
+ -------
1657
+ dataframe : :class:`pandas.DataFrame`
1658
+ Pandas DataFrame containing data as columns.
1659
+
1660
+ """
1661
+ return super().get_dataframe()
1662
+
1352
1663
 
1353
1664
  class AverageNormalizedChannelData(AverageChannelData, NormalizedChannelData):
1354
1665
  """
@@ -1435,6 +1746,37 @@ class AverageNormalizedChannelData(AverageChannelData, NormalizedChannelData):
1435
1746
  def normalizing_data(self, normalizing_data=None):
1436
1747
  self._normalizing_data = normalizing_data
1437
1748
 
1749
+ def get_dataframe(self): # pylint: disable=useless-parent-delegation
1750
+ """
1751
+ Retrieve Pandas DataFrame with data as columns.
1752
+
1753
+ The DataFrame contains four columns, each corresponding to the
1754
+ respective attribute of the class:
1755
+
1756
+ * data
1757
+ * attempts
1758
+ * normalized_data
1759
+ * normalizing_data
1760
+
1761
+ The index is named "position" and contains the values of the
1762
+ :attr:`position_counts` attribute of the data object.
1763
+
1764
+ .. important::
1765
+
1766
+ While working with a Pandas DataFrame may seem convenient,
1767
+ you're loosing basically all the relevant metadata of the
1768
+ datasets. Hence, this method is rather a convenience method to
1769
+ be backwards-compatible to older interfaces, but it is
1770
+ explicitly *not* suggested for extensive use.
1771
+
1772
+ Returns
1773
+ -------
1774
+ dataframe : :class:`pandas.DataFrame`
1775
+ Pandas DataFrame containing data as columns.
1776
+
1777
+ """
1778
+ return super().get_dataframe()
1779
+
1438
1780
 
1439
1781
  class IntervalNormalizedChannelData(
1440
1782
  IntervalChannelData, NormalizedChannelData
@@ -1523,6 +1865,298 @@ class IntervalNormalizedChannelData(
1523
1865
  def normalizing_data(self, normalizing_data=None):
1524
1866
  self._normalizing_data = normalizing_data
1525
1867
 
1868
+ def get_dataframe(self): # pylint: disable=useless-parent-delegation
1869
+ """
1870
+ Retrieve Pandas DataFrame with data as columns.
1871
+
1872
+ The DataFrame contains five columns, each corresponding to the
1873
+ respective attribute of the class:
1874
+
1875
+ * data
1876
+ * counts
1877
+ * std
1878
+ * normalized_data
1879
+ * normalizing_data
1880
+
1881
+ The index is named "position" and contains the values of the
1882
+ :attr:`position_counts` attribute of the data object.
1883
+
1884
+ .. important::
1885
+
1886
+ While working with a Pandas DataFrame may seem convenient,
1887
+ you're loosing basically all the relevant metadata of the
1888
+ datasets. Hence, this method is rather a convenience method to
1889
+ be backwards-compatible to older interfaces, but it is
1890
+ explicitly *not* suggested for extensive use.
1891
+
1892
+ Returns
1893
+ -------
1894
+ dataframe : :class:`pandas.DataFrame`
1895
+ Pandas DataFrame containing data as columns.
1896
+
1897
+ """
1898
+ return super().get_dataframe()
1899
+
1900
+
1901
+ class ArrayChannelData(ChannelData):
1902
+ """
1903
+ Data for channels with numeric 1D data.
1904
+
1905
+ Detector channels can be distinguished by the dimension of their data:
1906
+
1907
+ 0D
1908
+ scalar values per position, including average and interval channels
1909
+ 1D
1910
+ array values, *i.e.* vectors, per position
1911
+ 2D
1912
+ area values, *i.e.* images, per position
1913
+
1914
+ This class represents 1D array values.
1915
+
1916
+ Individual arrays are stored one per row in the :attr:`data` attribute.
1917
+ This allows for intuitive indexing of the individual arrays.
1918
+
1919
+
1920
+ Attributes
1921
+ ----------
1922
+ metadata : :class:`evefile.entities.metadata.ArrayChannelMetadata`
1923
+ Relevant metadata for the individual device.
1924
+
1925
+
1926
+ Examples
1927
+ --------
1928
+ The :class:`ArrayChannelData` class is not meant to be used
1929
+ directly, as any entities, but rather indirectly by means of the
1930
+ respective facades in the boundaries technical layer of the
1931
+ ``evefile`` package.
1932
+ Hence, for the time being, there are no dedicated examples how to use
1933
+ this class. Of course, you can instantiate an object as usual.
1934
+
1935
+
1936
+ .. versionadded:: 0.2
1937
+
1938
+ """
1939
+
1940
+ def __init__(self):
1941
+ super().__init__()
1942
+ self.metadata = metadata.ArrayChannelMetadata()
1943
+
1944
+ def get_data(self):
1945
+ """
1946
+ Load data (and variable option data) using the respective importer.
1947
+
1948
+ Data are loaded only on demand. Hence, upon the first access of the
1949
+ :attr:`data` property, this method will be called, calling out to
1950
+ the respective importers.
1951
+
1952
+ As :obj:`Data` objects may contain (variable) options that are
1953
+ themselves data, but loading these data is only triggered when
1954
+ accessing the :attr:`data` property, you can either once access the
1955
+ :attr:`data` property or call this method.
1956
+
1957
+ Data may be spread over several HDF5 datasets, depending on the
1958
+ version of the eveH5 file read. Hence, there may be several
1959
+ importers, and they are dealt with sequentially.
1960
+
1961
+ Furthermore, for each importer type, there is a special private
1962
+ method ``_import_from_<importer-type>``, with ``<importer-type>``
1963
+ being the lowercase class name. Those classes using additional
1964
+ importers beyond :class:`HDF5DataImporter` need to implement
1965
+ additional private methods to handle the special importer classes. A
1966
+ typical use case is the :class:`AreaChannelData` class dealing with
1967
+ image data stored mostly in separate files.
1968
+
1969
+ """
1970
+ data = []
1971
+ for idx, importer in enumerate(self.importer):
1972
+ importer.load()
1973
+ if "data" in importer.mapping.values():
1974
+ data.append(importer.data[:, 0])
1975
+ else:
1976
+ for column_name, attribute in importer.mapping.items():
1977
+ setattr(self, attribute, importer.data[column_name])
1978
+ if self._data is None and data:
1979
+ self._data = np.ndarray(
1980
+ [len(data), len(data[0])], dtype=data[0].dtype
1981
+ )
1982
+ for idx in range(len(data)): # noqa
1983
+ self._data[idx, :] = data[idx]
1984
+
1985
+ def get_dataframe(self):
1986
+ """
1987
+ Retrieve Pandas DataFrame with data as column.
1988
+
1989
+ .. important::
1990
+
1991
+ While working with a Pandas DataFrame may seem convenient,
1992
+ you're loosing basically all the relevant metadata of the
1993
+ datasets. Hence, this method is rather a convenience method to
1994
+ be backwards-compatible to older interfaces, but it is
1995
+ explicitly *not* suggested for extensive use.
1996
+
1997
+ Returns
1998
+ -------
1999
+ dataframe : :class:`pandas.DataFrame`
2000
+ Pandas DataFrame containing data as column.
2001
+
2002
+ """
2003
+ if self.data is not None:
2004
+ index = np.arange(1, self.data.shape[0] + 1)
2005
+ else:
2006
+ index = [0]
2007
+ dataframe = pd.DataFrame(
2008
+ columns=self._data_attributes,
2009
+ index=index,
2010
+ )
2011
+ dataframe["data"] = dataframe["data"].astype(object)
2012
+ for idx, row in enumerate(index):
2013
+ dataframe.loc[row, "data"] = self.data[idx, :]
2014
+ if self.position_counts is not None and self.position_counts.ndim:
2015
+ dataframe.index = self.position_counts
2016
+ dataframe.index.name = "position"
2017
+ return dataframe
2018
+
2019
+
2020
+ class MCAChannelData(ArrayChannelData):
2021
+ """
2022
+ Data for multichannel analyzer (MCA) channels.
2023
+
2024
+ MCA channel data are usually 1D data, *i.e.* arrays or vectors.
2025
+
2026
+
2027
+ Attributes
2028
+ ----------
2029
+ metadata : :class:`evefile.entities.metadata.MCAChannelMetadata`
2030
+ Relevant metadata for the individual device.
2031
+
2032
+ roi : :class:`list`
2033
+ List of data for the individual ROIs defined.
2034
+
2035
+ Individual items in the list are objects of class
2036
+ :class:`MCAChannelROIData`.
2037
+
2038
+ life_time : :class:`numpy.ndarray`
2039
+ Elapsed life time
2040
+
2041
+ After a read status operation, this field contains the elapsed
2042
+ live time, as reported by the hardware.
2043
+
2044
+ real_time : :class:`numpy.ndarray`
2045
+ Elapsed real time
2046
+
2047
+ After a read status operation, this field contains the elapsed
2048
+ real time, as reported by the hardware.
2049
+
2050
+ axis : :class:`Axis`
2051
+ Data and metadata for the x-axis of the array data
2052
+
2053
+ MCAs record array data, and to make sense of the indices of the
2054
+ arrays, usually some calibration parameters are recorded that can
2055
+ be used to convert the indices of the array to an actual axis - be
2056
+ it energy or time or else.
2057
+
2058
+ See :class:`evefile.entities.metadata.MCAChannelCalibration` for
2059
+ details of the calibration data that may be available for your MCA.
2060
+
2061
+
2062
+ Examples
2063
+ --------
2064
+ The :class:`MCAChannelData` class is not meant to be used
2065
+ directly, as any entities, but rather indirectly by means of the
2066
+ respective facades in the boundaries technical layer of the
2067
+ ``evefile`` package.
2068
+ Hence, for the time being, there are no dedicated examples how to use
2069
+ this class. Of course, you can instantiate an object as usual.
2070
+
2071
+
2072
+ .. versionadded:: 0.2
2073
+
2074
+ """
2075
+
2076
+ def __init__(self):
2077
+ super().__init__()
2078
+ self.metadata = metadata.MCAChannelMetadata()
2079
+ self.roi = []
2080
+ self.life_time = np.ndarray(shape=[])
2081
+ self.real_time = np.ndarray(shape=[])
2082
+ self.axis = Axis()
2083
+
2084
+ def get_data(self):
2085
+ """
2086
+ Load data (and variable option data) using the respective importer.
2087
+
2088
+ Data are loaded only on demand. Hence, upon the first access of the
2089
+ :attr:`data` property, this method will be called, calling out to
2090
+ the respective importers.
2091
+
2092
+ As :obj:`Data` objects may contain (variable) options that are
2093
+ themselves data, but loading these data is only triggered when
2094
+ accessing the :attr:`data` property, you can either once access the
2095
+ :attr:`data` property or call this method.
2096
+
2097
+ Data may be spread over several HDF5 datasets, depending on the
2098
+ version of the eveH5 file read. Hence, there may be several
2099
+ importers, and they are dealt with sequentially.
2100
+
2101
+ Furthermore, for each importer type, there is a special private
2102
+ method ``_import_from_<importer-type>``, with ``<importer-type>``
2103
+ being the lowercase class name. Those classes using additional
2104
+ importers beyond :class:`HDF5DataImporter` need to implement
2105
+ additional private methods to handle the special importer classes. A
2106
+ typical use case is the :class:`AreaChannelData` class dealing with
2107
+ image data stored mostly in separate files.
2108
+
2109
+ """
2110
+ super().get_data()
2111
+ if self._data is not None:
2112
+ indices = np.linspace(
2113
+ 0, self.data.shape[1], self.data.shape[1], endpoint=False
2114
+ )
2115
+ if self.axis.values.size == 0:
2116
+ self.axis.values = (
2117
+ self.metadata.calibration.offset
2118
+ + indices * self.metadata.calibration.slope
2119
+ + indices**2 * self.metadata.calibration.quadratic
2120
+ )
2121
+
2122
+
2123
+ class MCAChannelROIData(ChannelData):
2124
+ """
2125
+ Data for an individual ROI of an MCA detector channel.
2126
+
2127
+ Many MCAs allow to define one or several regions of interest (ROI).
2128
+ This class contains the relevant data for an individual ROI.
2129
+
2130
+
2131
+ Attributes
2132
+ ----------
2133
+ label : :class:`str`
2134
+ Label for the ROI provided by the operator.
2135
+
2136
+ marker : :class:`numpy.ndarray`
2137
+ Two-element vector of integer values containing the left and right
2138
+ boundary of the ROI.
2139
+
2140
+
2141
+ Examples
2142
+ --------
2143
+ The :class:`MCAChannelROIData` class is not meant to be used
2144
+ directly, as any entities, but rather indirectly by means of the
2145
+ respective facades in the boundaries technical layer of the
2146
+ ``evefile`` package.
2147
+ Hence, for the time being, there are no dedicated examples how to use
2148
+ this class. Of course, you can instantiate an object as usual.
2149
+
2150
+
2151
+ .. versionadded:: 0.2
2152
+
2153
+ """
2154
+
2155
+ def __init__(self):
2156
+ super().__init__()
2157
+ self.label = ""
2158
+ self.marker = np.asarray([0, 0], dtype=int)
2159
+
1526
2160
 
1527
2161
  class DataImporter:
1528
2162
  """