pychemstation 0.5.4__tar.gz → 0.5.6.dev1__tar.gz
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-0.5.4 → pychemstation-0.5.6.dev1}/PKG-INFO +10 -8
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/README.md +10 -8
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/control/__init__.py +0 -1
- {pychemstation-0.5.4/pychemstation/control/table → pychemstation-0.5.6.dev1/pychemstation/control/controllers}/__init__.py +1 -0
- {pychemstation-0.5.4/pychemstation/control → pychemstation-0.5.6.dev1/pychemstation/control/controllers}/comm.py +2 -2
- {pychemstation-0.5.4/pychemstation/control/table → pychemstation-0.5.6.dev1/pychemstation/control/controllers}/method.py +24 -14
- {pychemstation-0.5.4/pychemstation/control/table → pychemstation-0.5.6.dev1/pychemstation/control/controllers}/sequence.py +22 -19
- {pychemstation-0.5.4/pychemstation/control/table → pychemstation-0.5.6.dev1/pychemstation/control/controllers}/table_controller.py +35 -25
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/control/hplc.py +6 -7
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/chromatogram.py +8 -27
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/PKG-INFO +10 -8
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/SOURCES.txt +5 -5
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/setup.py +1 -1
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/tests/test_comb.py +2 -2
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/LICENSE +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/__init__.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/analysis/__init__.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/analysis/base_spectrum.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/analysis/spec_utils.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/analysis/utils.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/generated/__init__.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/generated/dad_method.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/generated/pump_method.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/__init__.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/macro.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/method_types.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/parsing.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/sequence_types.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/table_types.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/tray_types.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/dependency_links.txt +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/requires.txt +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/top_level.txt +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pyproject.toml +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/setup.cfg +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/tests/__init__.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/tests/constants.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/tests/test_comm.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/tests/test_method.py +0 -0
- {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/tests/test_sequence.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pychemstation
|
3
|
-
Version: 0.5.
|
3
|
+
Version: 0.5.6.dev1
|
4
4
|
Summary: Library to interact with Chemstation software, primarily used in Hein lab
|
5
5
|
Home-page: https://gitlab.com/heingroup/device-api/pychemstation
|
6
6
|
Author: Lucy Hao
|
@@ -41,7 +41,7 @@ pip install pychemstation
|
|
41
41
|
where you will put your
|
42
42
|
MACRO file(s).
|
43
43
|
3. Download the [
|
44
|
-
`hplc_talk.mac`](https://
|
44
|
+
`hplc_talk.mac`](https://gitlab.com/heingroup/device-api/pychemstation/-/blob/main/tests/hplc_talk.mac).
|
45
45
|
- On line 69, change the path name up to `\cmd` and `\reply`. For instance, you should have:
|
46
46
|
`MonitorFile "[my path]\cmd", "[my path]\reply"`
|
47
47
|
- and then add this file to the folder from the previous step.
|
@@ -78,13 +78,12 @@ hplc_controller = HPLCController(data_dir=DATA_DIR,
|
|
78
78
|
hplc_controller.preprun()
|
79
79
|
hplc_controller.switch_method(method_name=DEFAULT_METHOD)
|
80
80
|
hplc_controller.run_method(experiment_name="Run 10")
|
81
|
-
|
81
|
+
chrom = hplc_controller.get_last_run_method_data()
|
82
82
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
chromatogram_data.to_csv("Run 10.csv", index=False)
|
83
|
+
# afterwards, save, analyze or plot the data!
|
84
|
+
values = {"x": chrom.A.x, "y": chrom.A.y}
|
85
|
+
chromatogram_data = pd.DataFrame.from_dict(values)
|
86
|
+
chromatogram_data.to_csv("Run 10.csv", index=False)
|
88
87
|
```
|
89
88
|
|
90
89
|
## Adding your own MACROs
|
@@ -103,3 +102,6 @@ Lucy Hao
|
|
103
102
|
|
104
103
|
- Adapted from [**AnalyticalLabware**](https://github.com/croningp/analyticallabware), created by members in the Cronin
|
105
104
|
Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
|
105
|
+
- Adapted from the [MACROS](https://github.com/Bourne-Group/HPLCMethodOptimisationGUI)
|
106
|
+
used in [**Operator-free HPLC automated method development guided by Bayesian optimization**](https://pubs.rsc.org/en/content/articlelanding/2024/dd/d4dd00062e),
|
107
|
+
created by members in the Bourne Group. Copyright © Bourne Group, used under the [MIT](https://opensource.org/license/mit) license.
|
@@ -25,7 +25,7 @@ pip install pychemstation
|
|
25
25
|
where you will put your
|
26
26
|
MACRO file(s).
|
27
27
|
3. Download the [
|
28
|
-
`hplc_talk.mac`](https://
|
28
|
+
`hplc_talk.mac`](https://gitlab.com/heingroup/device-api/pychemstation/-/blob/main/tests/hplc_talk.mac).
|
29
29
|
- On line 69, change the path name up to `\cmd` and `\reply`. For instance, you should have:
|
30
30
|
`MonitorFile "[my path]\cmd", "[my path]\reply"`
|
31
31
|
- and then add this file to the folder from the previous step.
|
@@ -62,13 +62,12 @@ hplc_controller = HPLCController(data_dir=DATA_DIR,
|
|
62
62
|
hplc_controller.preprun()
|
63
63
|
hplc_controller.switch_method(method_name=DEFAULT_METHOD)
|
64
64
|
hplc_controller.run_method(experiment_name="Run 10")
|
65
|
-
|
65
|
+
chrom = hplc_controller.get_last_run_method_data()
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
chromatogram_data.to_csv("Run 10.csv", index=False)
|
67
|
+
# afterwards, save, analyze or plot the data!
|
68
|
+
values = {"x": chrom.A.x, "y": chrom.A.y}
|
69
|
+
chromatogram_data = pd.DataFrame.from_dict(values)
|
70
|
+
chromatogram_data.to_csv("Run 10.csv", index=False)
|
72
71
|
```
|
73
72
|
|
74
73
|
## Adding your own MACROs
|
@@ -86,4 +85,7 @@ our [GitLab](https://gitlab.com/heingroup/device-api/pychemstation)!
|
|
86
85
|
Lucy Hao
|
87
86
|
|
88
87
|
- Adapted from [**AnalyticalLabware**](https://github.com/croningp/analyticallabware), created by members in the Cronin
|
89
|
-
Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
|
88
|
+
Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
|
89
|
+
- Adapted from the [MACROS](https://github.com/Bourne-Group/HPLCMethodOptimisationGUI)
|
90
|
+
used in [**Operator-free HPLC automated method development guided by Bayesian optimization**](https://pubs.rsc.org/en/content/articlelanding/2024/dd/d4dd00062e),
|
91
|
+
created by members in the Bourne Group. Copyright © Bourne Group, used under the [MIT](https://opensource.org/license/mit) license.
|
@@ -1,13 +1,13 @@
|
|
1
1
|
import os
|
2
2
|
import time
|
3
|
-
from typing import Optional
|
3
|
+
from typing import Optional
|
4
4
|
|
5
5
|
from xsdata.formats.dataclass.parsers import XmlParser
|
6
6
|
|
7
|
-
from
|
8
|
-
from ...control.
|
7
|
+
from ...control.controllers.table_controller import TableController
|
8
|
+
from ...control.controllers.comm import CommunicationController
|
9
9
|
from ...generated import PumpMethod, DadMethod, SolventElement
|
10
|
-
from ...utils.chromatogram import TIME_FORMAT,
|
10
|
+
from ...utils.chromatogram import TIME_FORMAT, AgilentChannelChromatogramData
|
11
11
|
from ...utils.macro import Command
|
12
12
|
from ...utils.method_types import PType, TimeTableEntry, Param, MethodTimetable, HPLCMethodParams
|
13
13
|
from ...utils.table_types import RegisterFlag, TableOperation, Table
|
@@ -51,9 +51,10 @@ class MethodController(TableController):
|
|
51
51
|
rows = self.get_num_rows()
|
52
52
|
if rows.is_ok():
|
53
53
|
timetable_rows = [self.get_row(r + 1) for r in range(int(rows.ok_value.num_response))]
|
54
|
-
|
54
|
+
self.table_state = MethodTimetable(
|
55
55
|
first_row=self.get_method_params(),
|
56
56
|
subsequent_rows=timetable_rows)
|
57
|
+
return self.table_state
|
57
58
|
else:
|
58
59
|
raise RuntimeError(rows.err_value)
|
59
60
|
|
@@ -88,6 +89,7 @@ class MethodController(TableController):
|
|
88
89
|
if res.is_ok():
|
89
90
|
parsed_response = res.ok_value.string_response
|
90
91
|
assert parsed_response == f"{method_name}.M", "Switching Methods failed."
|
92
|
+
self.table_state = None
|
91
93
|
|
92
94
|
def load_from_disk(self, method_name: str) -> MethodTimetable:
|
93
95
|
"""
|
@@ -118,7 +120,7 @@ class MethodController(TableController):
|
|
118
120
|
elif solvent.channel == "Channel_B":
|
119
121
|
organic_modifier = solvent
|
120
122
|
|
121
|
-
|
123
|
+
self.table_state = MethodTimetable(
|
122
124
|
first_row=HPLCMethodParams(
|
123
125
|
organic_modifier=organic_modifier.percentage,
|
124
126
|
flow=method.flow,
|
@@ -135,6 +137,7 @@ class MethodController(TableController):
|
|
135
137
|
organic_modifier=organic_modifier,
|
136
138
|
modifier_a=aq_modifier
|
137
139
|
)
|
140
|
+
return self.table_state
|
138
141
|
else:
|
139
142
|
raise FileNotFoundError
|
140
143
|
|
@@ -242,7 +245,7 @@ class MethodController(TableController):
|
|
242
245
|
"""
|
243
246
|
self.send(Command.STOP_METHOD_CMD)
|
244
247
|
|
245
|
-
def run(self, experiment_name: str):
|
248
|
+
def run(self, experiment_name: str, stall_while_running: bool = True):
|
246
249
|
"""
|
247
250
|
This is the preferred method to trigger a run.
|
248
251
|
Starts the currently selected method, storing data
|
@@ -261,14 +264,21 @@ class MethodController(TableController):
|
|
261
264
|
folder_name = f"{experiment_name}_{timestamp}.D"
|
262
265
|
self.data_files.append(os.path.join(self.data_dir, folder_name))
|
263
266
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
267
|
+
if stall_while_running:
|
268
|
+
run_completed = self.check_hplc_done_running(method=self.table_state)
|
269
|
+
if run_completed.is_ok():
|
270
|
+
self.data_files[-1] = run_completed.value
|
271
|
+
else:
|
272
|
+
raise RuntimeError("Run error has occurred.")
|
273
|
+
else:
|
274
|
+
self.data_files[-1].dir = self.fuzzy_match_most_recent_folder(folder_name).ok_value
|
268
275
|
|
269
276
|
def retrieve_recent_data_files(self) -> str:
|
270
277
|
return self.data_files[-1]
|
271
278
|
|
272
|
-
def get_data(self
|
273
|
-
|
274
|
-
|
279
|
+
def get_data(self, custom_path: Optional[str] = None) -> AgilentChannelChromatogramData:
|
280
|
+
if not custom_path:
|
281
|
+
self.get_spectrum(self.data_files[-1])
|
282
|
+
else:
|
283
|
+
self.get_spectrum(custom_path)
|
284
|
+
return AgilentChannelChromatogramData(**self.spectra)
|
@@ -1,17 +1,15 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import Optional
|
2
2
|
|
3
|
-
from copy import deepcopy
|
4
3
|
|
5
4
|
import os
|
6
5
|
import time
|
7
6
|
|
8
|
-
from .table_controller import TableController
|
9
|
-
from ...control import CommunicationController
|
10
|
-
from ...utils.chromatogram import SEQUENCE_TIME_FORMAT,
|
7
|
+
from ...control.controllers.table_controller import TableController
|
8
|
+
from ...control.controllers.comm import CommunicationController
|
9
|
+
from ...utils.chromatogram import SEQUENCE_TIME_FORMAT, AgilentChannelChromatogramData
|
11
10
|
from ...utils.macro import Command
|
12
11
|
from ...utils.sequence_types import SequenceTable, SequenceEntry, SequenceDataFiles, InjectionSource, SampleType
|
13
12
|
from ...utils.table_types import TableOperation, RegisterFlag, Table
|
14
|
-
from ...utils.tray_types import TenColumn
|
15
13
|
|
16
14
|
|
17
15
|
class SequenceController(TableController):
|
@@ -29,9 +27,10 @@ class SequenceController(TableController):
|
|
29
27
|
seq_name = self.receive()
|
30
28
|
|
31
29
|
if rows.is_ok() and seq_name.is_ok():
|
32
|
-
|
30
|
+
self.table_state = SequenceTable(
|
33
31
|
name=seq_name.ok_value.string_response.partition(".S")[0],
|
34
32
|
rows=[self.get_row(r + 1) for r in range(int(rows.ok_value.num_response))])
|
33
|
+
return self.table_state
|
35
34
|
raise RuntimeError(rows.err_value)
|
36
35
|
|
37
36
|
def get_row(self, row: int) -> SequenceEntry:
|
@@ -65,6 +64,7 @@ class SequenceController(TableController):
|
|
65
64
|
parsed_response = self.receive().value.string_response
|
66
65
|
|
67
66
|
assert parsed_response == f"{seq_name}.S", "Switching sequence failed."
|
67
|
+
self.table_state = None
|
68
68
|
|
69
69
|
def edit(self, sequence_table: SequenceTable):
|
70
70
|
"""
|
@@ -171,7 +171,7 @@ class SequenceController(TableController):
|
|
171
171
|
|
172
172
|
self.send(Command.SAVE_SEQUENCE_CMD)
|
173
173
|
|
174
|
-
def run(self):
|
174
|
+
def run(self, stall_while_running: bool = True):
|
175
175
|
"""
|
176
176
|
Starts the currently loaded sequence, storing data
|
177
177
|
under the <data_dir>/<sequence table name> folder.
|
@@ -186,25 +186,28 @@ class SequenceController(TableController):
|
|
186
186
|
self.data_files.append(SequenceDataFiles(dir=folder_name,
|
187
187
|
sequence_name=seq_table.name))
|
188
188
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
189
|
+
if stall_while_running:
|
190
|
+
run_completed = self.check_hplc_done_running(sequence=seq_table)
|
191
|
+
if run_completed.is_ok():
|
192
|
+
self.data_files[-1].dir = run_completed.value
|
193
|
+
else:
|
194
|
+
raise RuntimeError("Run error has occurred.")
|
195
|
+
else:
|
196
|
+
self.data_files[-1].dir = self.fuzzy_match_most_recent_folder(folder_name).ok_value
|
195
197
|
|
196
198
|
def retrieve_recent_data_files(self):
|
197
199
|
sequence_data_files: SequenceDataFiles = self.data_files[-1]
|
198
200
|
return sequence_data_files.dir
|
199
201
|
|
200
|
-
def get_data(self) -> list[
|
201
|
-
parent_dir = self.data_files[-1].dir
|
202
|
+
def get_data(self, custom_path:Optional[str] = None ) -> list[AgilentChannelChromatogramData]:
|
203
|
+
parent_dir = self.data_files[-1].dir if not custom_path else custom_path
|
202
204
|
subdirs = [x[0] for x in os.walk(self.data_dir)]
|
203
205
|
potential_folders = sorted(list(filter(lambda d: parent_dir in d, subdirs)))
|
204
|
-
self.data_files[-1].child_dirs = [f for f in potential_folders if
|
206
|
+
self.data_files[-1].child_dirs = [f for f in potential_folders if
|
207
|
+
parent_dir in f and ".M" not in f and ".D" in f]
|
205
208
|
|
206
|
-
spectra: list[
|
209
|
+
spectra: list[AgilentChannelChromatogramData] = []
|
207
210
|
for row in self.data_files[-1].child_dirs:
|
208
211
|
self.get_spectrum(row)
|
209
|
-
spectra.append(
|
212
|
+
spectra.append(AgilentChannelChromatogramData(**self.spectra))
|
210
213
|
return spectra
|
@@ -6,14 +6,13 @@ Authors: Lucy Hao
|
|
6
6
|
|
7
7
|
import abc
|
8
8
|
import os
|
9
|
-
import time
|
10
9
|
from typing import Union, Optional
|
11
10
|
|
12
11
|
import polling
|
13
12
|
from result import Result, Ok, Err
|
14
13
|
|
15
|
-
from ...control import CommunicationController
|
16
|
-
from ...utils.chromatogram import AgilentHPLCChromatogram
|
14
|
+
from ...control.controllers.comm import CommunicationController
|
15
|
+
from ...utils.chromatogram import AgilentHPLCChromatogram, AgilentChannelChromatogramData
|
17
16
|
from ...utils.macro import Command, HPLCRunningStatus, Response
|
18
17
|
from ...utils.method_types import MethodTimetable
|
19
18
|
from ...utils.sequence_types import SequenceDataFiles, SequenceTable
|
@@ -25,6 +24,7 @@ class TableController(abc.ABC):
|
|
25
24
|
def __init__(self, controller: CommunicationController, src: str, data_dir: str, table: Table):
|
26
25
|
self.controller = controller
|
27
26
|
self.table = table
|
27
|
+
self.table_state : Optional[TableController] = None
|
28
28
|
|
29
29
|
if os.path.isdir(src):
|
30
30
|
self.src: str = src
|
@@ -120,7 +120,7 @@ class TableController(abc.ABC):
|
|
120
120
|
self.send(TableOperation.CREATE_TABLE.value.format(register=self.table.register,
|
121
121
|
table_name=self.table.name))
|
122
122
|
|
123
|
-
def get_num_rows(self) -> Result[
|
123
|
+
def get_num_rows(self) -> Result[Response, str]:
|
124
124
|
self.send(TableOperation.GET_NUM_ROWS.value.format(register=self.table.register,
|
125
125
|
table_name=self.table.name,
|
126
126
|
col_name=RegisterFlag.NUM_ROWS))
|
@@ -139,8 +139,8 @@ class TableController(abc.ABC):
|
|
139
139
|
def check_hplc_is_running(self) -> bool:
|
140
140
|
started_running = polling.poll(
|
141
141
|
lambda: isinstance(self.controller.get_status(), HPLCRunningStatus),
|
142
|
-
step=
|
143
|
-
max_tries=
|
142
|
+
step=5,
|
143
|
+
max_tries=100)
|
144
144
|
return started_running
|
145
145
|
|
146
146
|
def check_hplc_done_running(self,
|
@@ -154,7 +154,7 @@ class TableController(abc.ABC):
|
|
154
154
|
"""
|
155
155
|
timeout = 10 * 60
|
156
156
|
if method:
|
157
|
-
timeout = ((method.first_row.maximum_run_time +
|
157
|
+
timeout = ((method.first_row.maximum_run_time + 5) * 60)
|
158
158
|
if sequence:
|
159
159
|
timeout *= len(sequence.rows)
|
160
160
|
|
@@ -162,32 +162,42 @@ class TableController(abc.ABC):
|
|
162
162
|
finished_run = polling.poll(
|
163
163
|
lambda: self.controller.check_if_running(),
|
164
164
|
timeout=timeout,
|
165
|
-
step=
|
166
|
-
|
167
|
-
|
168
|
-
if finished_run:
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
split_folder = path.split(os.sep)
|
178
|
-
if most_recent_folder in split_folder[-1]:
|
179
|
-
parent_dirs.append(folder)
|
180
|
-
parent_dir = sorted(parent_dirs, reverse=True)[0]
|
181
|
-
return Ok(parent_dir)
|
165
|
+
step=18)
|
166
|
+
|
167
|
+
check_folder = self.fuzzy_match_most_recent_folder(most_recent_folder)
|
168
|
+
if check_folder.is_ok() and finished_run:
|
169
|
+
return check_folder
|
170
|
+
elif check_folder.is_ok():
|
171
|
+
finished_run = polling.poll(
|
172
|
+
lambda: self.controller.check_if_running(),
|
173
|
+
timeout=timeout,
|
174
|
+
step=12)
|
175
|
+
if finished_run:
|
176
|
+
return check_folder
|
182
177
|
else:
|
183
178
|
return Err("Run did not complete as expected")
|
184
179
|
|
180
|
+
def fuzzy_match_most_recent_folder(self, most_recent_folder) -> Result[str, str]:
|
181
|
+
if os.path.exists(most_recent_folder):
|
182
|
+
return Ok(most_recent_folder)
|
183
|
+
|
184
|
+
subdirs = [x[0] for x in os.walk(self.data_dir)]
|
185
|
+
potential_folders = sorted(list(filter(lambda d: most_recent_folder in d, subdirs)))
|
186
|
+
parent_dirs = []
|
187
|
+
for folder in potential_folders:
|
188
|
+
path = os.path.normpath(folder)
|
189
|
+
split_folder = path.split(os.sep)
|
190
|
+
if most_recent_folder in split_folder[-1]:
|
191
|
+
parent_dirs.append(folder)
|
192
|
+
parent_dir = sorted(parent_dirs, reverse=True)[0]
|
193
|
+
return Ok(parent_dir)
|
194
|
+
|
185
195
|
@abc.abstractmethod
|
186
196
|
def retrieve_recent_data_files(self):
|
187
197
|
pass
|
188
198
|
|
189
199
|
@abc.abstractmethod
|
190
|
-
def get_data(self) ->
|
200
|
+
def get_data(self) -> Union[list[AgilentChannelChromatogramData], AgilentChannelChromatogramData]:
|
191
201
|
pass
|
192
202
|
|
193
203
|
def get_spectrum(self, data_file: str):
|
@@ -6,9 +6,8 @@ Authors: Lucy Hao
|
|
6
6
|
|
7
7
|
from typing import Union, Optional
|
8
8
|
|
9
|
-
from ..control import CommunicationController
|
10
|
-
from ..
|
11
|
-
from ..utils.chromatogram import AgilentHPLCChromatogram
|
9
|
+
from ..control.controllers import MethodController, SequenceController, CommunicationController
|
10
|
+
from ..utils.chromatogram import AgilentHPLCChromatogram, AgilentChannelChromatogramData
|
12
11
|
from ..utils.macro import Command, HPLCRunningStatus, HPLCAvailStatus, HPLCErrorStatus, Response
|
13
12
|
from ..utils.method_types import MethodTimetable
|
14
13
|
from ..utils.sequence_types import SequenceTable, SequenceEntry
|
@@ -65,8 +64,8 @@ class HPLCController:
|
|
65
64
|
only 'General-Poroshell' is needed.
|
66
65
|
|
67
66
|
:param method_name: any available method in Chemstation method directory
|
68
|
-
:
|
69
|
-
:
|
67
|
+
:raises IndexError: Response did not have expected format. Try again.
|
68
|
+
:raises AssertionError: The desired method is not selected. Try again.
|
70
69
|
"""
|
71
70
|
self.method_controller.switch(method_name)
|
72
71
|
|
@@ -127,13 +126,13 @@ class HPLCController:
|
|
127
126
|
"""
|
128
127
|
self.sequence_controller.edit_row(row, num)
|
129
128
|
|
130
|
-
def get_last_run_method_data(self) ->
|
129
|
+
def get_last_run_method_data(self) -> AgilentChannelChromatogramData:
|
131
130
|
"""
|
132
131
|
Returns the last run method data.
|
133
132
|
"""
|
134
133
|
return self.method_controller.get_data()
|
135
134
|
|
136
|
-
def get_last_run_sequence_data(self) -> list[
|
135
|
+
def get_last_run_sequence_data(self) -> list[AgilentChannelChromatogramData]:
|
137
136
|
"""
|
138
137
|
Returns data for all rows in the last run sequence data.
|
139
138
|
"""
|
@@ -1,17 +1,14 @@
|
|
1
1
|
"""Module for HPLC chromatogram data loading and manipulating"""
|
2
2
|
|
3
3
|
import os
|
4
|
-
import logging
|
5
4
|
import time
|
5
|
+
from dataclasses import dataclass
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
|
9
9
|
from .parsing import CHFile
|
10
10
|
from ..analysis import AbstractSpectrum
|
11
11
|
|
12
|
-
# Chemstation data path
|
13
|
-
DATA_DIR = r"C:\Chem32\1\Data"
|
14
|
-
|
15
12
|
# standard filenames for spectral data
|
16
13
|
CHANNELS = {"A": "01", "B": "02", "C": "03", "D": "04"}
|
17
14
|
|
@@ -19,7 +16,7 @@ ACQUISITION_PARAMETERS = "acq.txt"
|
|
19
16
|
|
20
17
|
# format used in acquisition parameters
|
21
18
|
TIME_FORMAT = "%Y-%m-%d %H-%M-%S"
|
22
|
-
SEQUENCE_TIME_FORMAT = "%Y-%m-%d %H"
|
19
|
+
SEQUENCE_TIME_FORMAT = "%Y-%m-%d %H-%M"
|
23
20
|
|
24
21
|
|
25
22
|
class AgilentHPLCChromatogram(AbstractSpectrum):
|
@@ -105,26 +102,10 @@ class AgilentHPLCChromatogram(AbstractSpectrum):
|
|
105
102
|
np.savez_compressed(npz_file, times=data.times, values=data.values)
|
106
103
|
return np.array(data.times), np.array(data.values)
|
107
104
|
|
108
|
-
def extract_peakarea(self, experiment_dir: str):
|
109
|
-
"""
|
110
|
-
Reads processed data from Chemstation report files.
|
111
105
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
# return data
|
119
|
-
pass
|
120
|
-
|
121
|
-
def default_processing(self):
|
122
|
-
"""
|
123
|
-
Processes the chromatogram in place.
|
124
|
-
"""
|
125
|
-
# trim first 5 min and last 3 min of run
|
126
|
-
self.trim(5, 25)
|
127
|
-
# parameters found to work best for chromatogram data
|
128
|
-
self.correct_baseline(lmbd=1e5, p=0.0001, n_iter=10)
|
129
|
-
# get all peaks in processed chromatogram
|
130
|
-
self.find_peaks()
|
106
|
+
@dataclass
|
107
|
+
class AgilentChannelChromatogramData:
|
108
|
+
A: AgilentHPLCChromatogram
|
109
|
+
B: AgilentHPLCChromatogram
|
110
|
+
C: AgilentHPLCChromatogram
|
111
|
+
D: AgilentHPLCChromatogram
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pychemstation
|
3
|
-
Version: 0.5.
|
3
|
+
Version: 0.5.6.dev1
|
4
4
|
Summary: Library to interact with Chemstation software, primarily used in Hein lab
|
5
5
|
Home-page: https://gitlab.com/heingroup/device-api/pychemstation
|
6
6
|
Author: Lucy Hao
|
@@ -41,7 +41,7 @@ pip install pychemstation
|
|
41
41
|
where you will put your
|
42
42
|
MACRO file(s).
|
43
43
|
3. Download the [
|
44
|
-
`hplc_talk.mac`](https://
|
44
|
+
`hplc_talk.mac`](https://gitlab.com/heingroup/device-api/pychemstation/-/blob/main/tests/hplc_talk.mac).
|
45
45
|
- On line 69, change the path name up to `\cmd` and `\reply`. For instance, you should have:
|
46
46
|
`MonitorFile "[my path]\cmd", "[my path]\reply"`
|
47
47
|
- and then add this file to the folder from the previous step.
|
@@ -78,13 +78,12 @@ hplc_controller = HPLCController(data_dir=DATA_DIR,
|
|
78
78
|
hplc_controller.preprun()
|
79
79
|
hplc_controller.switch_method(method_name=DEFAULT_METHOD)
|
80
80
|
hplc_controller.run_method(experiment_name="Run 10")
|
81
|
-
|
81
|
+
chrom = hplc_controller.get_last_run_method_data()
|
82
82
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
chromatogram_data.to_csv("Run 10.csv", index=False)
|
83
|
+
# afterwards, save, analyze or plot the data!
|
84
|
+
values = {"x": chrom.A.x, "y": chrom.A.y}
|
85
|
+
chromatogram_data = pd.DataFrame.from_dict(values)
|
86
|
+
chromatogram_data.to_csv("Run 10.csv", index=False)
|
88
87
|
```
|
89
88
|
|
90
89
|
## Adding your own MACROs
|
@@ -103,3 +102,6 @@ Lucy Hao
|
|
103
102
|
|
104
103
|
- Adapted from [**AnalyticalLabware**](https://github.com/croningp/analyticallabware), created by members in the Cronin
|
105
104
|
Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
|
105
|
+
- Adapted from the [MACROS](https://github.com/Bourne-Group/HPLCMethodOptimisationGUI)
|
106
|
+
used in [**Operator-free HPLC automated method development guided by Bayesian optimization**](https://pubs.rsc.org/en/content/articlelanding/2024/dd/d4dd00062e),
|
107
|
+
created by members in the Bourne Group. Copyright © Bourne Group, used under the [MIT](https://opensource.org/license/mit) license.
|
@@ -13,12 +13,12 @@ pychemstation/analysis/base_spectrum.py
|
|
13
13
|
pychemstation/analysis/spec_utils.py
|
14
14
|
pychemstation/analysis/utils.py
|
15
15
|
pychemstation/control/__init__.py
|
16
|
-
pychemstation/control/comm.py
|
17
16
|
pychemstation/control/hplc.py
|
18
|
-
pychemstation/control/
|
19
|
-
pychemstation/control/
|
20
|
-
pychemstation/control/
|
21
|
-
pychemstation/control/
|
17
|
+
pychemstation/control/controllers/__init__.py
|
18
|
+
pychemstation/control/controllers/comm.py
|
19
|
+
pychemstation/control/controllers/method.py
|
20
|
+
pychemstation/control/controllers/sequence.py
|
21
|
+
pychemstation/control/controllers/table_controller.py
|
22
22
|
pychemstation/generated/__init__.py
|
23
23
|
pychemstation/generated/dad_method.py
|
24
24
|
pychemstation/generated/pump_method.py
|
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
|
|
5
5
|
|
6
6
|
setuptools.setup(
|
7
7
|
name="pychemstation",
|
8
|
-
version="0.5.
|
8
|
+
version="0.5.6.dev1",
|
9
9
|
author="Lucy Hao",
|
10
10
|
author_email="lhao03@student.ubc.ca",
|
11
11
|
description="Library to interact with Chemstation software, primarily used in Hein lab",
|
@@ -28,14 +28,14 @@ class TestCombinations(unittest.TestCase):
|
|
28
28
|
first_row=HPLCMethodParams(
|
29
29
|
organic_modifier=5,
|
30
30
|
flow=0.65,
|
31
|
-
maximum_run_time=
|
31
|
+
maximum_run_time=1),
|
32
32
|
subsequent_rows=[
|
33
33
|
TimeTableEntry(
|
34
34
|
start_time=0.10,
|
35
35
|
organic_modifer=5,
|
36
36
|
flow=0.34),
|
37
37
|
TimeTableEntry(
|
38
|
-
start_time=
|
38
|
+
start_time=0.5,
|
39
39
|
organic_modifer=98,
|
40
40
|
flow=0.55)])
|
41
41
|
self.hplc_controller.edit_method(rand_method, save=True)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|