pychemstation 0.8.4__py3-none-any.whl → 0.9.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.
- pychemstation/__init__.py +1 -1
- pychemstation/analysis/__init__.py +4 -1
- pychemstation/analysis/base_spectrum.py +4 -4
- pychemstation/{utils → analysis}/chromatogram.py +4 -7
- pychemstation/analysis/process_report.py +118 -71
- pychemstation/control/README.md +22 -46
- pychemstation/control/__init__.py +5 -0
- pychemstation/control/controllers/__init__.py +2 -0
- pychemstation/control/controllers/comm.py +39 -18
- pychemstation/control/controllers/devices/device.py +27 -14
- pychemstation/control/controllers/devices/injector.py +33 -89
- pychemstation/control/controllers/tables/method.py +266 -111
- pychemstation/control/controllers/tables/ms.py +7 -4
- pychemstation/control/controllers/tables/sequence.py +171 -82
- pychemstation/control/controllers/tables/table.py +192 -116
- pychemstation/control/hplc.py +117 -83
- pychemstation/generated/__init__.py +0 -2
- pychemstation/generated/dad_method.py +1 -1
- pychemstation/generated/pump_method.py +15 -19
- pychemstation/utils/injector_types.py +1 -1
- pychemstation/utils/macro.py +12 -11
- pychemstation/utils/method_types.py +3 -2
- pychemstation/{analysis/utils.py → utils/num_utils.py} +2 -2
- pychemstation/utils/parsing.py +1 -11
- pychemstation/utils/sequence_types.py +4 -5
- pychemstation/{analysis → utils}/spec_utils.py +1 -2
- pychemstation/utils/table_types.py +10 -9
- pychemstation/utils/tray_types.py +48 -38
- {pychemstation-0.8.4.dist-info → pychemstation-0.9.0.dist-info}/METADATA +63 -24
- pychemstation-0.9.0.dist-info/RECORD +37 -0
- pychemstation-0.8.4.dist-info/RECORD +0 -37
- {pychemstation-0.8.4.dist-info → pychemstation-0.9.0.dist-info}/WHEEL +0 -0
- {pychemstation-0.8.4.dist-info → pychemstation-0.9.0.dist-info}/licenses/LICENSE +0 -0
pychemstation/control/hplc.py
CHANGED
@@ -4,47 +4,47 @@ Module to provide API for higher-level HPLC actions.
|
|
4
4
|
Authors: Lucy Hao
|
5
5
|
"""
|
6
6
|
|
7
|
-
from
|
7
|
+
from __future__ import annotations
|
8
8
|
|
9
|
-
from
|
10
|
-
|
11
|
-
from
|
12
|
-
|
13
|
-
|
9
|
+
from typing import Dict, List, Optional, Tuple, Union
|
10
|
+
|
11
|
+
from pychemstation.analysis.chromatogram import (
|
12
|
+
AgilentHPLCChromatogram,
|
13
|
+
)
|
14
|
+
|
15
|
+
from ..analysis.process_report import AgilentReport, ReportType
|
16
|
+
from ..control.controllers import (
|
17
|
+
CommunicationController,
|
18
|
+
MethodController,
|
19
|
+
SequenceController,
|
20
|
+
)
|
21
|
+
from pychemstation.analysis.chromatogram import AgilentChannelChromatogramData
|
14
22
|
from ..utils.macro import Command, Response, Status
|
15
23
|
from ..utils.method_types import MethodDetails
|
16
24
|
from ..utils.sequence_types import SequenceTable
|
17
25
|
from ..utils.table_types import Table
|
26
|
+
from .controllers.devices.injector import InjectorController
|
18
27
|
|
19
28
|
|
20
29
|
class HPLCController:
|
21
30
|
# tables
|
22
|
-
METHOD_TIMETABLE = Table(
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
name="SprayChamber"
|
40
|
-
)
|
41
|
-
|
42
|
-
def __init__(self,
|
43
|
-
comm_dir: str,
|
44
|
-
method_dir: str,
|
45
|
-
sequence_dir: str,
|
46
|
-
data_dirs: List[str],
|
47
|
-
offline: bool = False):
|
31
|
+
METHOD_TIMETABLE = Table(register="RCPMP1Method[1]", name="Timetable")
|
32
|
+
|
33
|
+
SEQUENCE_TABLE = Table(register="_sequence[1]", name="SeqTable1")
|
34
|
+
|
35
|
+
INJECTOR_TABLE = Table(register="RCWLS1Pretreatment[1]", name="InstructionTable")
|
36
|
+
|
37
|
+
MSD_TABLE = Table(register="MSACQINFO[1]", name="SprayChamber")
|
38
|
+
|
39
|
+
def __init__(
|
40
|
+
self,
|
41
|
+
comm_dir: str,
|
42
|
+
method_dir: str,
|
43
|
+
sequence_dir: str,
|
44
|
+
data_dirs: List[str],
|
45
|
+
offline: bool = False,
|
46
|
+
debug: bool = False,
|
47
|
+
):
|
48
48
|
"""Initialize HPLC controller. The `hplc_talk.mac` macro file must be loaded in the Chemstation software.
|
49
49
|
`comm_dir` must match the file path in the macro file. All file paths are normal strings, with the left slash
|
50
50
|
double escaped: "C:\\my_folder\\"
|
@@ -56,21 +56,29 @@ class HPLCController:
|
|
56
56
|
:param sequence_dir: Name of directory where sequence files are stored.
|
57
57
|
:raises FileNotFoundError: If either `data_dir`, `method_dir`, `sequence_dir`, `sequence_data_dir`or `comm_dir` is not a valid directory.
|
58
58
|
"""
|
59
|
-
self.comm =
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
59
|
+
self.comm = (
|
60
|
+
CommunicationController(comm_dir=comm_dir, debug=debug)
|
61
|
+
if not offline
|
62
|
+
else None
|
63
|
+
)
|
64
|
+
self.method_controller = MethodController(
|
65
|
+
controller=self.comm,
|
66
|
+
src=method_dir,
|
67
|
+
data_dirs=data_dirs,
|
68
|
+
table=self.METHOD_TIMETABLE,
|
69
|
+
offline=offline,
|
70
|
+
injector_controller=InjectorController(
|
71
|
+
controller=self.comm, table=self.INJECTOR_TABLE, offline=offline
|
72
|
+
),
|
73
|
+
)
|
74
|
+
self.sequence_controller = SequenceController(
|
75
|
+
controller=self.comm,
|
76
|
+
src=sequence_dir,
|
77
|
+
data_dirs=data_dirs,
|
78
|
+
table=self.SEQUENCE_TABLE,
|
79
|
+
method_controller=self.method_controller,
|
80
|
+
offline=offline,
|
81
|
+
)
|
74
82
|
|
75
83
|
def send(self, cmd: Union[Command, str]):
|
76
84
|
"""
|
@@ -80,29 +88,32 @@ class HPLCController:
|
|
80
88
|
"""
|
81
89
|
if not self.comm:
|
82
90
|
raise RuntimeError(
|
83
|
-
"Communication controller must be initialized before sending command. It is currently in offline mode."
|
91
|
+
"Communication controller must be initialized before sending command. It is currently in offline mode."
|
92
|
+
)
|
84
93
|
self.comm.send(cmd)
|
85
94
|
|
86
95
|
def receive(self) -> Response:
|
87
96
|
"""
|
88
97
|
Get the most recent response from Chemstation.
|
89
98
|
|
90
|
-
:
|
99
|
+
:return: most recent response from a macro that returned a response.
|
91
100
|
"""
|
92
101
|
if not self.comm:
|
93
102
|
raise RuntimeError(
|
94
|
-
"Communication controller must be initialized before sending command. It is currently in offline mode."
|
103
|
+
"Communication controller must be initialized before sending command. It is currently in offline mode."
|
104
|
+
)
|
95
105
|
return self.comm.receive().value
|
96
106
|
|
97
107
|
def status(self) -> Status:
|
98
108
|
"""
|
99
109
|
Get the current status of the HPLC machine.
|
100
110
|
|
101
|
-
:
|
111
|
+
:return: current status of the HPLC machine; Status types can be found in `pychemstation.utils.macro`
|
102
112
|
"""
|
103
113
|
if not self.comm:
|
104
114
|
raise RuntimeError(
|
105
|
-
"Communication controller must be initialized before sending command. It is currently in offline mode."
|
115
|
+
"Communication controller must be initialized before sending command. It is currently in offline mode."
|
116
|
+
)
|
106
117
|
return self.comm.get_status()
|
107
118
|
|
108
119
|
def switch_method(self, method_name: str):
|
@@ -126,7 +137,12 @@ class HPLCController:
|
|
126
137
|
"""
|
127
138
|
self.sequence_controller.switch(sequence_name)
|
128
139
|
|
129
|
-
def run_method(
|
140
|
+
def run_method(
|
141
|
+
self,
|
142
|
+
experiment_name: str,
|
143
|
+
add_timestamp: bool = True,
|
144
|
+
stall_while_running: bool = True,
|
145
|
+
):
|
130
146
|
"""
|
131
147
|
This is the preferred method to trigger a run.
|
132
148
|
Starts the currently selected method, storing data
|
@@ -137,9 +153,11 @@ class HPLCController:
|
|
137
153
|
:param stall_while_running: whether to return or stall while HPLC runs.
|
138
154
|
:param add_timestamp: whether to append a timestamp in '%Y-%m-%d-%H-%M' format to end of experiment name.
|
139
155
|
"""
|
140
|
-
self.method_controller.run(
|
141
|
-
|
142
|
-
|
156
|
+
self.method_controller.run(
|
157
|
+
experiment_name=experiment_name,
|
158
|
+
stall_while_running=stall_while_running,
|
159
|
+
add_timestamp=add_timestamp,
|
160
|
+
)
|
143
161
|
|
144
162
|
def stop_method(self):
|
145
163
|
"""Stops the current running method, manual intervention may be needed."""
|
@@ -159,7 +177,7 @@ class HPLCController:
|
|
159
177
|
"""
|
160
178
|
Check if the currently running method (if any) is done.
|
161
179
|
|
162
|
-
:returns
|
180
|
+
:returns the percent of the method run completed, and whether the run is complete.
|
163
181
|
"""
|
164
182
|
return self.method_controller.check_hplc_run_finished()
|
165
183
|
|
@@ -167,7 +185,7 @@ class HPLCController:
|
|
167
185
|
"""
|
168
186
|
Check if the currently running sequence (if any) is done.
|
169
187
|
|
170
|
-
:
|
188
|
+
:return: the percent of the sequence run completed, and whether the run is complete.
|
171
189
|
"""
|
172
190
|
return self.sequence_controller.check_hplc_run_finished()
|
173
191
|
|
@@ -188,47 +206,67 @@ class HPLCController:
|
|
188
206
|
"""
|
189
207
|
self.sequence_controller.edit(updated_sequence)
|
190
208
|
|
191
|
-
def get_last_run_method_report(
|
192
|
-
|
193
|
-
|
209
|
+
def get_last_run_method_report(
|
210
|
+
self,
|
211
|
+
custom_path: Optional[str] = None,
|
212
|
+
report_type: ReportType = ReportType.CSV,
|
213
|
+
) -> AgilentReport:
|
194
214
|
"""
|
195
215
|
Return data contained in the REPORT files. Use `aghplctools` if you want more report processing utility.
|
216
|
+
|
196
217
|
:param custom_path: path to sequence folder
|
197
218
|
:param report_type: read either the TXT or CSV version
|
198
|
-
:
|
219
|
+
:return: report data for method
|
199
220
|
"""
|
200
|
-
return self.method_controller.get_report(
|
221
|
+
return self.method_controller.get_report(
|
222
|
+
custom_path=custom_path, report_type=report_type
|
223
|
+
)[0]
|
201
224
|
|
202
|
-
def get_last_run_method_data(
|
203
|
-
|
225
|
+
def get_last_run_method_data(
|
226
|
+
self, read_uv: bool = False, custom_path: Optional[str] = None
|
227
|
+
) -> Dict[str, AgilentHPLCChromatogram] | AgilentChannelChromatogramData:
|
204
228
|
"""
|
205
229
|
Returns the last run method data.
|
206
230
|
|
207
|
-
:param
|
231
|
+
:param custom_path: If you want to just load method data but from a file path. This file path must be the complete file path.
|
208
232
|
:param read_uv: whether to also read the UV file
|
209
233
|
"""
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
234
|
+
if read_uv:
|
235
|
+
return self.method_controller.get_data_uv(custom_path=custom_path)
|
236
|
+
else:
|
237
|
+
return self.method_controller.get_data(custom_path=custom_path)
|
238
|
+
|
239
|
+
def get_last_run_sequence_reports(
|
240
|
+
self,
|
241
|
+
custom_path: Optional[str] = None,
|
242
|
+
report_type: ReportType = ReportType.CSV,
|
243
|
+
) -> List[AgilentReport]:
|
215
244
|
"""
|
216
245
|
Return data contained in the REPORT files. Use `aghplctools` if you want more report processing utility.
|
246
|
+
|
217
247
|
:param custom_path: path to sequence folder
|
218
248
|
:param report_type: read either the TXT or CSV version
|
219
|
-
:
|
249
|
+
:return: list of reports for each row
|
220
250
|
"""
|
221
|
-
return self.sequence_controller.get_report(
|
222
|
-
|
223
|
-
|
224
|
-
|
251
|
+
return self.sequence_controller.get_report(
|
252
|
+
custom_path=custom_path, report_type=report_type
|
253
|
+
)
|
254
|
+
|
255
|
+
def get_last_run_sequence_data(
|
256
|
+
self, read_uv: bool = False, custom_path: Optional[str] = None
|
257
|
+
) -> (
|
258
|
+
List[Dict[int, AgilentHPLCChromatogram]] | List[AgilentChannelChromatogramData]
|
259
|
+
):
|
225
260
|
"""
|
226
261
|
Returns data for all rows in the last run sequence data.
|
227
262
|
|
228
|
-
:param
|
263
|
+
:param custom_path: If you want to just load sequence data but from a file path. This file path must be the complete file path.
|
229
264
|
:param read_uv: whether to also read the UV file
|
230
265
|
"""
|
231
|
-
|
266
|
+
if read_uv:
|
267
|
+
return self.sequence_controller.get_data_uv(custom_path=custom_path)
|
268
|
+
else:
|
269
|
+
return self.sequence_controller.get_data(custom_path=custom_path)
|
232
270
|
|
233
271
|
def check_loaded_sequence(self) -> str:
|
234
272
|
"""Returns the name of the currently loaded sequence."""
|
@@ -238,10 +276,6 @@ class HPLCController:
|
|
238
276
|
"""Returns the name of the currently loaded method."""
|
239
277
|
return self.method_controller.check()
|
240
278
|
|
241
|
-
def load_injector_program(self) -> InjectorTable:
|
242
|
-
"""Returns all details of the injector program for the currently loaded method."""
|
243
|
-
return self.method_controller.injector_controller.load()
|
244
|
-
|
245
279
|
def load_method(self) -> MethodDetails:
|
246
280
|
"""Returns details of the currently loaded method, such as its starting modifier conditions and timetable."""
|
247
281
|
return self.method_controller.load()
|
@@ -255,7 +289,7 @@ class HPLCController:
|
|
255
289
|
self.send(Command.STANDBY_CMD)
|
256
290
|
|
257
291
|
def preprun(self):
|
258
|
-
"""
|
292
|
+
"""Prepares all modules for run. All lamps and pumps are switched on."""
|
259
293
|
self.send(Command.PREPRUN_CMD)
|
260
294
|
|
261
295
|
def lamp_on(self):
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from dataclasses import dataclass, field
|
2
|
-
from typing import
|
2
|
+
from typing import List, Optional
|
3
3
|
from xml.etree.ElementTree import QName
|
4
4
|
|
5
5
|
|
@@ -313,25 +313,21 @@ class SolventElement:
|
|
313
313
|
"required": True,
|
314
314
|
},
|
315
315
|
)
|
316
|
-
channel1_extended_solvent_type: Optional[Channel1ExtendedSolventType] = (
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
},
|
324
|
-
)
|
316
|
+
channel1_extended_solvent_type: Optional[Channel1ExtendedSolventType] = field(
|
317
|
+
default=None,
|
318
|
+
metadata={
|
319
|
+
"name": "Channel1ExtendedSolventType",
|
320
|
+
"type": "Element",
|
321
|
+
"required": True,
|
322
|
+
},
|
325
323
|
)
|
326
|
-
channel2_extended_solvent_type: Optional[Channel2ExtendedSolventType] = (
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
},
|
334
|
-
)
|
324
|
+
channel2_extended_solvent_type: Optional[Channel2ExtendedSolventType] = field(
|
325
|
+
default=None,
|
326
|
+
metadata={
|
327
|
+
"name": "Channel2ExtendedSolventType",
|
328
|
+
"type": "Element",
|
329
|
+
"required": True,
|
330
|
+
},
|
335
331
|
)
|
336
332
|
|
337
333
|
|
pychemstation/utils/macro.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from enum import Enum
|
4
|
-
from typing import Union
|
5
3
|
from dataclasses import dataclass
|
4
|
+
from enum import Enum
|
5
|
+
from typing import Union, Any, Type
|
6
6
|
|
7
7
|
|
8
8
|
@dataclass
|
@@ -15,7 +15,7 @@ class Response:
|
|
15
15
|
# See https://www.agilent.com/cs/library/usermanuals/Public/MACROS.PDF
|
16
16
|
class Command(Enum):
|
17
17
|
def __str__(self):
|
18
|
-
return
|
18
|
+
return "%s" % self.value
|
19
19
|
|
20
20
|
GET_NUM_VAL_CMD = "response_num = {cmd}"
|
21
21
|
GET_TEXT_VAL_CMD = "response$ = {cmd}"
|
@@ -37,17 +37,17 @@ class Command(Enum):
|
|
37
37
|
# Method and Sequence Related
|
38
38
|
GET_METHOD_CMD = "response$ = _MethFile$"
|
39
39
|
GET_ROWS_CMD = 'response_num = TabHdrVal({register}, "{table_name}", "{col_name}")'
|
40
|
-
SWITCH_METHOD_CMD =
|
40
|
+
SWITCH_METHOD_CMD = "LoadMethod _MethPath$, _MethFile$"
|
41
41
|
SWITCH_METHOD_CMD_SPECIFIC = 'LoadMethod "{method_dir}", "{method_name}.M"'
|
42
42
|
START_METHOD_CMD = "StartMethod"
|
43
43
|
RUN_METHOD_CMD = 'RunMethod "{data_dir}",, "{experiment_name}"'
|
44
44
|
STOP_METHOD_CMD = "StopMethod"
|
45
|
-
UPDATE_METHOD_CMD =
|
46
|
-
SWITCH_SEQUENCE_CMD =
|
47
|
-
SAVE_SEQUENCE_CMD =
|
45
|
+
UPDATE_METHOD_CMD = "UpdateMethod"
|
46
|
+
SWITCH_SEQUENCE_CMD = "LoadSequence _SeqPath$, _SeqFile$"
|
47
|
+
SAVE_SEQUENCE_CMD = "SaveSequence _SeqPath$, _SeqFile$"
|
48
48
|
SAVE_METHOD_CMD = 'SaveMethod _MethPath$, _MethFile$, "{commit_msg}"'
|
49
|
-
GET_SEQUENCE_CMD =
|
50
|
-
RUN_SEQUENCE_CMD =
|
49
|
+
GET_SEQUENCE_CMD = "response$ = _SeqFile$"
|
50
|
+
RUN_SEQUENCE_CMD = "RunSequence"
|
51
51
|
|
52
52
|
|
53
53
|
class HPLCRunningStatus(Enum):
|
@@ -76,7 +76,6 @@ class HPLCAvailStatus(Enum):
|
|
76
76
|
|
77
77
|
|
78
78
|
class HPLCErrorStatus(Enum):
|
79
|
-
|
80
79
|
@classmethod
|
81
80
|
def has_member_key(cls, key):
|
82
81
|
return key in cls.__members__
|
@@ -87,7 +86,9 @@ class HPLCErrorStatus(Enum):
|
|
87
86
|
MALFORMED = "MALFORMED"
|
88
87
|
|
89
88
|
|
90
|
-
def str_to_status(
|
89
|
+
def str_to_status(
|
90
|
+
status: str,
|
91
|
+
) -> Type[HPLCRunningStatus[Any] | HPLCErrorStatus[Any] | HPLCAvailStatus[Any]]:
|
91
92
|
if HPLCErrorStatus.has_member_key(status):
|
92
93
|
return HPLCErrorStatus[status]
|
93
94
|
if HPLCRunningStatus.has_member_key(status):
|
@@ -2,11 +2,11 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
from dataclasses import dataclass
|
4
4
|
from enum import Enum
|
5
|
-
from typing import
|
5
|
+
from typing import Any, Optional, Union
|
6
6
|
|
7
|
+
from ..generated import Signal
|
7
8
|
from .injector_types import InjectorTable
|
8
9
|
from .table_types import RegisterFlag
|
9
|
-
from ..generated import Signal
|
10
10
|
|
11
11
|
|
12
12
|
class PType(Enum):
|
@@ -47,6 +47,7 @@ class MethodDetails:
|
|
47
47
|
:attribute params: the organic modifier (pump B) and flow rate displayed for the method (the time 0 settings)
|
48
48
|
:attribute dad_wavelengthes:
|
49
49
|
"""
|
50
|
+
|
50
51
|
name: str
|
51
52
|
params: HPLCMethodParams
|
52
53
|
timetable: list[TimeTableEntry]
|
@@ -11,7 +11,7 @@ def find_nearest_value_index(array, value) -> Tuple[float, int]:
|
|
11
11
|
:param value: Target value.
|
12
12
|
:type value: float
|
13
13
|
|
14
|
-
:
|
14
|
+
:return: Nearest value in array and its index.
|
15
15
|
"""
|
16
16
|
|
17
17
|
index_ = np.argmin(np.abs(array - value))
|
@@ -34,7 +34,7 @@ def interpolate_to_index(array, ids, precision: int = 100) -> np.array:
|
|
34
34
|
:type ids: np.array[float]
|
35
35
|
:param precision: Desired presion.
|
36
36
|
|
37
|
-
:
|
37
|
+
:return: New array with interpolated values according to provided indexes "ids".
|
38
38
|
|
39
39
|
Example:
|
40
40
|
>>> interpolate_to_index(np.array([1.5]), np.array([1,2,3], 100))
|
pychemstation/utils/parsing.py
CHANGED
@@ -13,6 +13,7 @@ I use it for file with version 130, genereted by an Agilent LC.
|
|
13
13
|
|
14
14
|
import struct
|
15
15
|
from struct import unpack
|
16
|
+
|
16
17
|
import numpy as np
|
17
18
|
|
18
19
|
# Constants used for binary file parsing
|
@@ -26,7 +27,6 @@ UINT32 = ENDIAN + "I"
|
|
26
27
|
|
27
28
|
|
28
29
|
def fread(fid, nelements, dtype):
|
29
|
-
|
30
30
|
"""Equivalent to Matlab fread function"""
|
31
31
|
|
32
32
|
if dtype is str:
|
@@ -41,7 +41,6 @@ def fread(fid, nelements, dtype):
|
|
41
41
|
|
42
42
|
|
43
43
|
def parse_utf16_string(file_, encoding="UTF16"):
|
44
|
-
|
45
44
|
"""Parse a pascal type UTF16 encoded string from a binary file object"""
|
46
45
|
|
47
46
|
# First read the expected number of CHARACTERS
|
@@ -52,7 +51,6 @@ def parse_utf16_string(file_, encoding="UTF16"):
|
|
52
51
|
|
53
52
|
|
54
53
|
class cached_property(object):
|
55
|
-
|
56
54
|
"""A property that is only computed once per instance and then replaces
|
57
55
|
itself with an ordinary attribute. Deleting the attribute resets the
|
58
56
|
property.
|
@@ -72,7 +70,6 @@ class cached_property(object):
|
|
72
70
|
|
73
71
|
|
74
72
|
class CHFile(object):
|
75
|
-
|
76
73
|
"""Class that implementats the Agilent .ch file format version
|
77
74
|
130. Warning: Not all aspects of the file header is understood,
|
78
75
|
so there may and probably is information that is not parsed. See
|
@@ -121,7 +118,6 @@ class CHFile(object):
|
|
121
118
|
supported_versions = {130}
|
122
119
|
|
123
120
|
def __init__(self, filepath):
|
124
|
-
|
125
121
|
self.filepath = filepath
|
126
122
|
self.metadata = {}
|
127
123
|
with open(self.filepath, "rb") as file_:
|
@@ -129,7 +125,6 @@ class CHFile(object):
|
|
129
125
|
self.values = self._parse_data(file_)
|
130
126
|
|
131
127
|
def _parse_header(self, file_):
|
132
|
-
|
133
128
|
"""Parse the header"""
|
134
129
|
|
135
130
|
# Parse and check version
|
@@ -153,7 +148,6 @@ class CHFile(object):
|
|
153
148
|
]
|
154
149
|
|
155
150
|
def _parse_header_status(self):
|
156
|
-
|
157
151
|
"""Print known and unknown parts of the header"""
|
158
152
|
|
159
153
|
file_ = open(self.filepath, "rb")
|
@@ -233,7 +227,6 @@ class CHFile(object):
|
|
233
227
|
file_.close()
|
234
228
|
|
235
229
|
def _parse_data(self, file_):
|
236
|
-
|
237
230
|
"""Parse the data. Decompress the delta-encoded data, and scale them
|
238
231
|
with y-scaling"""
|
239
232
|
|
@@ -251,7 +244,6 @@ class CHFile(object):
|
|
251
244
|
buff = [0, 0, 0, 0]
|
252
245
|
|
253
246
|
while file_.tell() < stop:
|
254
|
-
|
255
247
|
buff[0] = fread(file_, 1, INT16)[0][0]
|
256
248
|
buff[1] = buff[3]
|
257
249
|
|
@@ -259,7 +251,6 @@ class CHFile(object):
|
|
259
251
|
break
|
260
252
|
|
261
253
|
for i in range(buff[0] & 4095):
|
262
|
-
|
263
254
|
buff[2] = fread(file_, 1, INT16)[0][0]
|
264
255
|
|
265
256
|
if buff[2] != -32768:
|
@@ -278,7 +269,6 @@ class CHFile(object):
|
|
278
269
|
|
279
270
|
@cached_property
|
280
271
|
def times(self):
|
281
|
-
|
282
272
|
"""The time values (x-value) for the data set in minutes"""
|
283
273
|
|
284
274
|
return np.linspace(
|
@@ -1,17 +1,16 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from dataclasses import dataclass
|
4
3
|
from enum import Enum
|
5
|
-
from typing import Optional,
|
6
|
-
|
7
|
-
from pychemstation.utils.tray_types import
|
4
|
+
from typing import Optional, List
|
5
|
+
from dataclasses import dataclass, field
|
6
|
+
from pychemstation.utils.tray_types import Tray
|
8
7
|
|
9
8
|
|
10
9
|
@dataclass
|
11
10
|
class SequenceDataFiles:
|
12
11
|
sequence_name: str
|
13
12
|
dir: str
|
14
|
-
child_dirs:
|
13
|
+
child_dirs: List[str] = field(default_factory=list)
|
15
14
|
|
16
15
|
|
17
16
|
class SampleType(Enum):
|
@@ -6,7 +6,7 @@ analysis.
|
|
6
6
|
import numpy as np
|
7
7
|
import scipy
|
8
8
|
|
9
|
-
from .
|
9
|
+
from ..utils.num_utils import find_nearest_value_index
|
10
10
|
|
11
11
|
|
12
12
|
def create_binary_peak_map(data):
|
@@ -28,7 +28,6 @@ def create_binary_peak_map(data):
|
|
28
28
|
peak_map = np.full_like(data_c, False, dtype=bool)
|
29
29
|
|
30
30
|
for _ in range(100500): # shouldn't take more iterations
|
31
|
-
|
32
31
|
# looking for peaks
|
33
32
|
peaks_found = np.logical_or(
|
34
33
|
data_c > np.mean(data_c) + np.std(data_c) * 3,
|