HDF5DataModel 0.2.3__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.
File without changes
@@ -0,0 +1,96 @@
1
+ from typing import List
2
+ from dataclasses import dataclass, field
3
+ from datetime import datetime
4
+ import numpy as np
5
+
6
+
7
+ @dataclass
8
+ class AttrBase:
9
+ def to_params(self):
10
+ params = []
11
+ for key, value in self.__dict__.items():
12
+ if key == 'start_time':
13
+ dt = datetime.fromtimestamp(value)
14
+ params.append({'name': key, 'type': 'str', 'value': dt.strftime('%d/%m/%y %H:%M:%S.%f')})
15
+ else:
16
+ typ, value = self.get_type_and_cast(value)
17
+ # params.append({'name': key, 'type': 'strict', 'value': value, 'opts': {'type': typ}}) # TODO : comprendre le fonctionnement de ParameterItem et parameterTypes
18
+ params.append({'name': key, 'type': typ, 'value': value})
19
+ return params
20
+
21
+ def get_type_and_cast(self, variable):
22
+ if isinstance(variable, str):
23
+ return 'str', variable
24
+ elif isinstance(variable, (int, np.int32, np.int64)):
25
+ return 'int', int(variable)
26
+ elif isinstance(variable, (float, np.float32, np.float64)):
27
+ return 'float', float(variable)
28
+ elif isinstance(variable, list):
29
+ return 'list', variable
30
+ elif isinstance(variable, bool):
31
+ return 'bool', bool(variable)
32
+ else:
33
+ return 'str', str(variable)
34
+
35
+ def set_attrs_from_dict(self, attrs_dict):
36
+ for key, value in attrs_dict.items():
37
+ setattr(self, key, value)
38
+
39
+
40
+ @dataclass
41
+ class DatasetAttrs(AttrBase):
42
+ version: str = 'HDF5DataModel 1.0'
43
+ start_time: float = 0.
44
+ experimenter: str = ''
45
+ description: str = ''
46
+
47
+
48
+ @dataclass
49
+ class AcquisitionAtrrs(AttrBase):
50
+ start_time: float = 0.
51
+ sample: str = ''
52
+ environment: str = ''
53
+ description: str = ''
54
+
55
+
56
+ @dataclass
57
+ class AcqSigAttrs(AttrBase):
58
+ type: str = 'Acquisition attributes'
59
+ start_time: float = 0.
60
+ traces_number: int = 0
61
+ position_interval: float = 0
62
+ position_offset: float = 0
63
+ hardware: str = '' # hardware used to acquire the trace
64
+
65
+
66
+ @dataclass
67
+ class GenSigAttrs(AttrBase):
68
+ type: str = 'Generation attributes'
69
+ points_number: int = 0
70
+ central_freq: int = 0
71
+ sampling_freq: int = 0
72
+ duration: float = 0
73
+ transducer: str = ''
74
+ hardware: str = ''
75
+ amplitude: float = 0
76
+ position_x: float = 0
77
+ position_y: float = 0
78
+ position_z: float = 0
79
+
80
+
81
+ @dataclass
82
+ class AcqTraceAttrs(AttrBase):
83
+ columns: List[str] = field(default_factory=list) # list of column names
84
+ units: List[str] = field(default_factory=list) # list of units for each column
85
+ start_time: float = 0 # start time of the trace, timestamp in seconds
86
+ duration: float = 0 # duration of the trace, seconds
87
+ position_x: float = 0. # position of the trace, meters
88
+ position_y: float = 0. # position of the trace, meters
89
+ position_z: float = 0. # position of the trace, meters
90
+ points_number: int = 0 # number of points in the trace
91
+ range: float = 0. # range of the trace
92
+ sampling_freq: int = 0 # sampling frequency of the trace, Hz
93
+ channel: int = 0 # acquisition channel of the trace
94
+ index: int = 0 # index of the trace in the acquisition signal
95
+ average_number: int = 0 # number of averaging
96
+ pretrig_duration: float = 0. # time between first sample and trig, second
@@ -0,0 +1,39 @@
1
+ import warnings
2
+ from PySide6.QtCore import Signal, QObject
3
+ from h5py import File
4
+ from HDF5DataModel.Model.subclasses import Dataset
5
+ from PySide6.QtWidgets import QWidget
6
+
7
+
8
+ class H5DataModel(QObject):
9
+ modelUpdated = Signal()
10
+
11
+ def __init__(self, file_path=None):
12
+ super().__init__()
13
+ self.file_path = file_path
14
+ self.file = None # ???
15
+ self.datasets = {}
16
+
17
+ def add_dataset(self, name):
18
+ self.datasets[name] = Dataset(name)
19
+ return self.datasets[name]
20
+
21
+ def to_hdf5_file(self):
22
+ with File(self.file_path, 'w') as f:
23
+ for name, dataset in self.datasets.items():
24
+ dataset.to_hdf5_file(f)
25
+
26
+ def get_datasets(self):
27
+ with File(self.file_path, 'r') as f:
28
+ for key in f.keys():
29
+ if f[key].attrs['version'][:-4] == 'HDF5DataModel':
30
+ dataset = Dataset()
31
+ dataset.from_h5(f, key)
32
+ self.datasets[key] = dataset
33
+ else:
34
+ warnings.warn('version not recognized')
35
+
36
+
37
+ if __name__ == '__main__':
38
+ h5 = H5DataModel(r'C:\Users\devie\Documents\Programmes\HDF5DataModel\test.h5')
39
+ h5.get_datasets()
@@ -0,0 +1,28 @@
1
+ from pyqtgraph.parametertree import parameterTypes, ParameterItem
2
+ from PySide6 import QtWidgets
3
+
4
+
5
+ class StrictParameterItem(ParameterItem):
6
+ def __init__(self, param, depth):
7
+ super().__init__(param, depth)
8
+
9
+
10
+ class StrictParameter(parameterTypes.SimpleParameter):
11
+ def __init__(self, *args, **kwargs):
12
+ super().__init__(**kwargs)
13
+
14
+ def setValue(self, value, block_signal=None):
15
+ print(self.opts.get('type'), self.opts['type'])
16
+ if self.opts['type'] == int and not isinstance(value, int):
17
+ raise ValueError(f"Invalid value type: expected int, got {type(value).__name__}")
18
+ elif self.opts['type'] == float and not isinstance(value, float):
19
+ raise ValueError(f"Invalid value type: expected float, got {type(value).__name__}")
20
+ elif self.opts['type'] == str and not isinstance(value, str):
21
+ raise ValueError(f"Invalid value type: expected str, got {type(value).__name__}")
22
+ elif self.opts['type'] == list and not isinstance(value, list):
23
+ raise ValueError(f"Invalid value type: expected list, got {type(value).__name__}")
24
+ super().setValue(value, block_signal)
25
+
26
+ @property
27
+ def itemClass(self):
28
+ return StrictParameterItem
@@ -0,0 +1,131 @@
1
+ #from typing import Optional
2
+ import os
3
+ import collections
4
+ import numpy as np
5
+ #from HDF5DataModel.Model.h5model import H5DataModel
6
+ from HDF5DataModel.Model.attrsclasses import DatasetAttrs, AcquisitionAtrrs, AcqSigAttrs, GenSigAttrs, AcqTraceAttrs
7
+
8
+ from pyseg2.rawseg2 import write_raw_seg2
9
+
10
+
11
+ class Dataset:
12
+ def __init__(self, name='default', parent: "H5DataModel"=None):
13
+ self.name = name
14
+ self.attrs = DatasetAttrs()
15
+ self.acquisitions = collections.OrderedDict()
16
+ self.parent = parent # the parent H5DataModel of this dataset
17
+
18
+ def add_acquisition(self, name):
19
+ self.acquisitions[name] = Acquisition()
20
+ return self.acquisitions[name]
21
+
22
+ def to_hdf5_file(self, h5file):
23
+ """Save the experiment to a HDF5 file"""
24
+ experiment_group = h5file.create_group(self.name)
25
+ experiment_group.attrs.update(self.attrs.__dict__)
26
+ for acq_name, acquisition in self.acquisitions.items():
27
+ acquisition_group = experiment_group.create_group(acq_name)
28
+ acquisition_group.attrs.update(acquisition.attrs.__dict__)
29
+ for sig_name, acq_sig in acquisition.acq_sigs.items():
30
+ acq_sig_group = acquisition_group.create_group(sig_name)
31
+ acq_sig_group.attrs.update(acq_sig.attrs.__dict__)
32
+ for trace_name, trace in acq_sig.traces.items():
33
+ trace_group = acq_sig_group.create_group(trace_name)
34
+ trace_group.attrs.update(trace.attrs.__dict__)
35
+ trace_group.create_dataset('signal', data=trace.data)
36
+ for gen_name, gen_sig in acquisition.gen_sigs.items():
37
+ gen_sig_group = acquisition_group.create_group(gen_name)
38
+ gen_sig_group.attrs.update(gen_sig.attrs.__dict__)
39
+ gen_sig_group.create_dataset('signal', data=gen_sig.signal)
40
+
41
+ def from_h5(self, h5file, experiment_name):
42
+ """Load the experiment from a HDF5 file"""
43
+ self.name = experiment_name
44
+ experiment_group = h5file[experiment_name]
45
+ self.attrs = DatasetAttrs()
46
+ self.attrs.set_attrs_from_dict(dict(experiment_group.attrs))
47
+ for acq_name in experiment_group:
48
+ acquisition_group = experiment_group[acq_name]
49
+ self.add_acquisition(acq_name)
50
+ self.acquisitions[acq_name].attrs = AcquisitionAtrrs()
51
+ self.acquisitions[acq_name].attrs.set_attrs_from_dict(dict(acquisition_group.attrs))
52
+ for sig_name in acquisition_group:
53
+ if acquisition_group[sig_name].attrs['type'] == 'Acquisition attributes':
54
+ self.acquisitions[acq_name].add_acq_sig(sig_name)
55
+ acq_sig_group = acquisition_group[sig_name]
56
+ self.acquisitions[acq_name].acq_sigs[sig_name].attrs = AcqSigAttrs()
57
+ self.acquisitions[acq_name].acq_sigs[sig_name].attrs.set_attrs_from_dict(dict(acq_sig_group.attrs))
58
+ for trace_name in acq_sig_group:
59
+ trace_group = acq_sig_group[trace_name]
60
+ self.acquisitions[acq_name].acq_sigs[sig_name].add_trace(trace_name)
61
+ self.acquisitions[acq_name].acq_sigs[sig_name].traces[trace_name].attrs = AcqTraceAttrs()
62
+ self.acquisitions[acq_name].acq_sigs[sig_name].traces[trace_name].attrs.set_attrs_from_dict(dict(trace_group.attrs))
63
+ self.acquisitions[acq_name].acq_sigs[sig_name].traces[trace_name].data = np.array(trace_group['signal'])
64
+ elif acquisition_group[sig_name].attrs['type'] == 'Generation attributes':
65
+ self.acquisitions[acq_name].add_gen_sig(sig_name)
66
+ gen_sig_group = acquisition_group[sig_name]
67
+ self.acquisitions[acq_name].gen_sigs[sig_name].attrs = GenSigAttrs()
68
+ self.acquisitions[acq_name].gen_sigs[sig_name].attrs.set_attrs_from_dict(dict(gen_sig_group.attrs))
69
+ self.acquisitions[acq_name].gen_sigs[sig_name].signal = np.array(gen_sig_group['signal'])
70
+
71
+
72
+ class Acquisition:
73
+ """An acquisition is a set of one generation signal and multiple acquisition signals with the sample and config"""
74
+ def __init__(self, parent: "Dataset"=None):
75
+ self.attrs = AcquisitionAtrrs()
76
+ self.acq_sigs = collections.OrderedDict()
77
+ self.gen_sigs = collections.OrderedDict()
78
+ self.parent = parent # the Parent Acquisition of self
79
+
80
+ def add_acq_sig(self, name):
81
+ self.acq_sigs[name] = AcqSig()
82
+ return self.acq_sigs[name]
83
+
84
+ def add_gen_sig(self, name):
85
+ self.gen_sigs[name] = GenSig()
86
+ return self.gen_sigs[name]
87
+
88
+
89
+ class AcqSig:
90
+ def __init__(self, parent: "Acquisition"=None):
91
+ self.attrs = AcqSigAttrs()
92
+ self.traces = collections.OrderedDict()
93
+ self.parent = parent
94
+
95
+ def add_trace(self, name):
96
+ self.traces[name] = AcqTrace()
97
+ return self.traces[name]
98
+
99
+ def to_seg2(self, filename: str, allow_overwrite: bool=False, include_type_names: bool=False):
100
+
101
+ trace_header_and_data = []
102
+ for trace in self.traces.values():
103
+ trace: AcqTrace
104
+
105
+ # FILL THE MANDATRY ATTRIBUTES
106
+ trace.attrs.SAMPLE_INTERVAL = 1. / trace.attrs.sampling_freq
107
+ # ...
108
+
109
+ trace_header_and_data.append((trace.attrs.__dict__, trace.data))
110
+
111
+ write_raw_seg2(
112
+ filename=filename,
113
+ file_header=self.attrs.__dict__,
114
+ trace_header_and_data=trace_header_and_data,
115
+ allow_overwrite=allow_overwrite,
116
+ include_type_names=include_type_names,
117
+ )
118
+
119
+
120
+ class GenSig:
121
+ def __init__(self, parent: "Acquisition"=None):
122
+ self.attrs = GenSigAttrs()
123
+ self.signal = np.zeros(1)
124
+ self.parent = parent # the parent Acquisition of self
125
+
126
+
127
+ class AcqTrace:
128
+ def __init__(self, parent: "AcqSig, GenSig"=None):
129
+ self.data = np.zeros(10)
130
+ self.attrs = AcqTraceAttrs()
131
+ self.parent = parent
File without changes