chromparser 0.1.0__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.
- chromparser-0.1.0/LICENSE +51 -0
- chromparser-0.1.0/PKG-INFO +162 -0
- chromparser-0.1.0/README.md +133 -0
- chromparser-0.1.0/pyproject.toml +113 -0
- chromparser-0.1.0/pyproject.toml.orig +84 -0
- chromparser-0.1.0/src/chromparser/__init__.py +183 -0
- chromparser-0.1.0/src/chromparser/__main__.py +7 -0
- chromparser-0.1.0/src/chromparser/_netcdf3.py +548 -0
- chromparser-0.1.0/src/chromparser/_util.py +98 -0
- chromparser-0.1.0/src/chromparser/cli.py +192 -0
- chromparser-0.1.0/src/chromparser/errors.py +49 -0
- chromparser-0.1.0/src/chromparser/hdf5.py +428 -0
- chromparser-0.1.0/src/chromparser/model.py +254 -0
- chromparser-0.1.0/src/chromparser/py.typed +0 -0
- chromparser-0.1.0/src/chromparser/sniff.py +80 -0
- chromparser-0.1.0/src/chromparser/vendors/__init__.py +55 -0
- chromparser-0.1.0/src/chromparser/vendors/agilent/__init__.py +17 -0
- chromparser-0.1.0/src/chromparser/vendors/agilent/ch.py +344 -0
- chromparser-0.1.0/src/chromparser/vendors/agilent/dot_d.py +69 -0
- chromparser-0.1.0/src/chromparser/vendors/agilent/dx.py +147 -0
- chromparser-0.1.0/src/chromparser/vendors/andi/__init__.py +15 -0
- chromparser-0.1.0/src/chromparser/vendors/andi/chrom.py +181 -0
- chromparser-0.1.0/src/chromparser/vendors/andi/common.py +232 -0
- chromparser-0.1.0/src/chromparser/vendors/andi/ms.py +358 -0
- chromparser-0.1.0/src/chromparser/vendors/andi/write.py +320 -0
- chromparser-0.1.0/src/chromparser/vendors/chromeleon/__init__.py +19 -0
- chromparser-0.1.0/src/chromparser/vendors/chromeleon/archive.py +310 -0
- chromparser-0.1.0/src/chromparser/vendors/chromeleon/raw.py +407 -0
- chromparser-0.1.0/src/chromparser/vendors/chromeleon/sequence.py +177 -0
- chromparser-0.1.0/src/chromparser/vendors/chromeleon/txt.py +319 -0
- chromparser-0.1.0/src/chromparser/vendors/shimadzu/__init__.py +8 -0
- chromparser-0.1.0/src/chromparser/vendors/shimadzu/gcd.py +146 -0
- chromparser-0.1.0/src/chromparser/vendors/shimadzu/ole.py +84 -0
- chromparser-0.1.0/src/chromparser/vendors/shimadzu/qgd.py +196 -0
- chromparser-0.1.0/src/chromparser/vendors/thermo/__init__.py +7 -0
- chromparser-0.1.0/src/chromparser/vendors/thermo/raw.py +377 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Sebastian Rejman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
--------------------------------------------------------------------------------
|
|
24
|
+
Third-party notice
|
|
25
|
+
|
|
26
|
+
The Agilent .ch decoders in src/chromparser/vendors/agilent/ch.py are adapted
|
|
27
|
+
from ImportAgilent.m in chemplexity/chromatography
|
|
28
|
+
(https://github.com/chemplexity/chromatography), which is distributed under the
|
|
29
|
+
following license:
|
|
30
|
+
|
|
31
|
+
The MIT License (MIT)
|
|
32
|
+
|
|
33
|
+
Copyright (c) 2014 James Dillon
|
|
34
|
+
|
|
35
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
36
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
37
|
+
in the Software without restriction, including without limitation the rights
|
|
38
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
39
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
40
|
+
furnished to do so, subject to the following conditions:
|
|
41
|
+
|
|
42
|
+
The above copyright notice and this permission notice shall be included in all
|
|
43
|
+
copies or substantial portions of the Software.
|
|
44
|
+
|
|
45
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
46
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
47
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
48
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
49
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
50
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
51
|
+
SOFTWARE.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chromparser
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Read chromatography raw files (Chromeleon, Thermo, Agilent, Shimadzu) into one data model and convert them to HDF5.
|
|
5
|
+
Keywords: chromatography,GC,GC-MS,HPLC,Chromeleon,Agilent,Shimadzu,Thermo,hdf5
|
|
6
|
+
Author: Sebastian Rejman
|
|
7
|
+
Author-email: Sebastian Rejman <s.rejman@uu.nl>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
19
|
+
Requires-Dist: numpy>=1.22
|
|
20
|
+
Requires-Dist: h5py>=3.0
|
|
21
|
+
Requires-Dist: olefile>=0.46
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Project-URL: homepage, https://github.com/MyonicS/chromparser
|
|
24
|
+
Project-URL: documentation, https://myonics.github.io/chromparser/
|
|
25
|
+
Project-URL: repository, https://github.com/MyonicS/chromparser
|
|
26
|
+
Project-URL: issues, https://github.com/MyonicS/chromparser/issues
|
|
27
|
+
Project-URL: changelog, https://github.com/MyonicS/chromparser/blob/main/CHANGELOG.md
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# chromparser
|
|
31
|
+
|
|
32
|
+
[](LICENSE)
|
|
33
|
+
[](pyproject.toml)
|
|
34
|
+
[](https://github.com/MyonicS/chromparser/actions/workflows/tests.yml)
|
|
35
|
+
[](https://myonics.github.io/chromparser/)
|
|
36
|
+
[](CHANGELOG.md)
|
|
37
|
+
[](https://github.com/astral-sh/ruff)
|
|
38
|
+
|
|
39
|
+
chromparser reads chromatography raw files (Chromeleon, Thermo, Agilent,
|
|
40
|
+
Shimadzu, ANDI netCDF) into one Python data model, and converts them to a
|
|
41
|
+
single HDF5 layout or to ANDI netCDF. Pure Python on numpy, h5py and olefile;
|
|
42
|
+
MIT licensed; every format is clean-room and documented.
|
|
43
|
+
|
|
44
|
+
## Supported formats
|
|
45
|
+
|
|
46
|
+
| Vendor | Files | Reader | Format id |
|
|
47
|
+
| --- | --- | --- | --- |
|
|
48
|
+
| Thermo Chromeleon 7 | `.cmbx` archives (signals and embedded MS) | `read_cmbx` | `chromeleon-cmbx` |
|
|
49
|
+
| | raw signal files (`SignHdr`, from a data vault) | `read_chromeleon_raw` | `chromeleon-raw` |
|
|
50
|
+
| | text exports (`.txt`), 7.2 and 7.3, any locale | `read_chromeleon_txt` | `chromeleon-txt` |
|
|
51
|
+
| Thermo | `.raw` MS files (v66, centroid, single quad), e.g. extracted from `.cmbx` | `read_thermo_raw` | `thermo-raw` |
|
|
52
|
+
| Agilent | `.ch` (versions 8, 81, 179, 181) | `read_agilent_ch` | `agilent-ch` |
|
|
53
|
+
| | `.D` folders | `read_agilent_d` | `agilent-d` |
|
|
54
|
+
| | OpenLab `.dx` archives | `read_agilent_dx` | `agilent-dx` |
|
|
55
|
+
| Shimadzu GCMSsolution | `.qgd` (GC-MS, centroids) | `read_qgd` | `shimadzu-qgd` |
|
|
56
|
+
| | `.gcd` (GC/FID) | `read_gcd` | `shimadzu-gcd` |
|
|
57
|
+
| ANDI (netCDF) | ANDI-MS `.cdf` (GC-MS, centroids) | `read_andi_ms` | `andi-ms` |
|
|
58
|
+
| | ANDI chromatography / AIA `.cdf` (one signal) | `read_andi_chrom` | `andi-chrom` |
|
|
59
|
+
|
|
60
|
+
The format is detected from the content (magic bytes, OLE2 storages, zip
|
|
61
|
+
members, netCDF variables, folder contents), never from the extension.
|
|
62
|
+
Everything chromparser reads can also be written as ANDI files
|
|
63
|
+
(`write_andi`), which AMDIS, NIST MS Search, MZmine, OpenChrom, MS-DIAL and
|
|
64
|
+
XCMS read; ANDI loses metadata, HDF5 keeps everything
|
|
65
|
+
([`docs/formats/andi.md`](docs/formats/andi.md)).
|
|
66
|
+
|
|
67
|
+
> Chromeleon and Thermo are trademarks of Thermo Fisher Scientific, Agilent
|
|
68
|
+
> and OpenLab of Agilent Technologies, Shimadzu and GCMSsolution of Shimadzu
|
|
69
|
+
> Corporation. This project is not affiliated with or endorsed by them. The
|
|
70
|
+
> formats were reverse engineered for interoperability; see `docs/formats/`.
|
|
71
|
+
|
|
72
|
+
## Installation
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install chromparser # or: uv add chromparser
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Python 3.10 or newer.
|
|
79
|
+
|
|
80
|
+
## Usage
|
|
81
|
+
|
|
82
|
+
### Command line
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
chromparser info run.cmbx sample.qgd data.D # injections, channels, MS runs
|
|
86
|
+
chromparser convert run.cmbx # writes run.h5 (layout v3)
|
|
87
|
+
chromparser convert *.qgd --overwrite
|
|
88
|
+
chromparser convert 152612018.raw --signal-unit pA # unit is not in raw files
|
|
89
|
+
chromparser convert old.h5 # cmbx-reader v1/v2 -> old.v3.h5
|
|
90
|
+
chromparser convert run.cmbx --to andi -o out/ # one ANDI .cdf per signal / MS run
|
|
91
|
+
chromparser extract-ms run.cmbx -d out/ # the embedded Thermo .raw files
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`chromparser convert --no-ms` skips the MS data of `.cmbx` archives.
|
|
95
|
+
|
|
96
|
+
### Python
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
import chromparser
|
|
100
|
+
|
|
101
|
+
for injection in chromparser.read("run.cmbx"): # always a list
|
|
102
|
+
print(injection.name, injection.inject_time, injection.metadata)
|
|
103
|
+
for channel, signal in injection.signals.items():
|
|
104
|
+
signal.time, signal.values, signal.unit # minutes, as stored
|
|
105
|
+
for name, ms in injection.ms.items():
|
|
106
|
+
mz, intensity = ms.spectrum(ms.scan_number[0])
|
|
107
|
+
eic = ms.xic(57.0, tolerance=0.5) # one value per scan
|
|
108
|
+
|
|
109
|
+
injection = chromparser.read_one("FID1A.ch") # files with one injection
|
|
110
|
+
chromparser.sniff("mystery.dat") # e.g. "shimadzu-qgd"
|
|
111
|
+
chromparser.convert("sample.qgd", "sample.h5")
|
|
112
|
+
injections = chromparser.read_hdf5("sample.h5") # == chromparser.read("sample.qgd")
|
|
113
|
+
chromparser.write_andi(injections, "out/") # out/sample_MS.cdf, for AMDIS etc.
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Data model
|
|
117
|
+
|
|
118
|
+
See [`docs/model.md`](docs/model.md) for the data model and the reader
|
|
119
|
+
contract, and [`docs/hdf5.md`](docs/hdf5.md) for the HDF5 layout. In short:
|
|
120
|
+
|
|
121
|
+
* `Signal`: `time` (min, float64), `values` (dtype as stored), `unit`,
|
|
122
|
+
`acquisition_start` (UTC), `sampling_interval` (s), `metadata`.
|
|
123
|
+
* `MSData`: per scan `scan_number`, `retention_time` (min), `tic`, optional
|
|
124
|
+
`base_peak_*`, `filters`, `ms_level`; per peak `mz`, `intensity` (dtypes as
|
|
125
|
+
stored: float32 for Thermo, float64 m/z and uint32 intensity for Shimadzu)
|
|
126
|
+
and optional `flags` (bit 0 = saturated), CSR-indexed by `peak_offset`.
|
|
127
|
+
* `inject_time` is local time: timezone-aware when the file has the offset,
|
|
128
|
+
naive when it stores only the wall time (Agilent `.ch`, Chromeleon 7.2
|
|
129
|
+
text exports).
|
|
130
|
+
* Unsupported variants raise `UnsupportedVariant` saying what was found;
|
|
131
|
+
readers never return partial data silently. Recoverable oddities are
|
|
132
|
+
warnings, recorded in `metadata["warnings"]`.
|
|
133
|
+
|
|
134
|
+
## Scope and limitations
|
|
135
|
+
|
|
136
|
+
* Files and data types not in the table above are probably not supported
|
|
137
|
+
yet. chromparser then raises an error saying what it found; it does not
|
|
138
|
+
return partial data.
|
|
139
|
+
* Agilent `.ch` versions 8, 81 and 181 are implemented from the documented
|
|
140
|
+
encodings but have not been checked against real files yet; please share
|
|
141
|
+
a sample if you have one.
|
|
142
|
+
* Spectra are kept as centroids; binning to nominal m/z is left to the user
|
|
143
|
+
(`np.rint(ms.mz)`).
|
|
144
|
+
|
|
145
|
+
If a file fails to read, please open an issue; a sample file helps a lot.
|
|
146
|
+
|
|
147
|
+
## Development
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
uv sync # environment with the dev tools
|
|
151
|
+
uv run pytest # runs without local data
|
|
152
|
+
uv run ruff check . && uv run ruff format --check .
|
|
153
|
+
uv sync --group docs && uv run mkdocs serve # the documentation site
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Large local files make more tests run; see [`tests/README.md`](tests/README.md).
|
|
157
|
+
Contributor notes are in [`AGENTS.md`](AGENTS.md).
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
MIT. The Agilent `.ch` decoders are adapted from chemplexity/chromatography
|
|
162
|
+
(MIT, Copyright (c) 2014 James Dillon); see [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# chromparser
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](pyproject.toml)
|
|
5
|
+
[](https://github.com/MyonicS/chromparser/actions/workflows/tests.yml)
|
|
6
|
+
[](https://myonics.github.io/chromparser/)
|
|
7
|
+
[](CHANGELOG.md)
|
|
8
|
+
[](https://github.com/astral-sh/ruff)
|
|
9
|
+
|
|
10
|
+
chromparser reads chromatography raw files (Chromeleon, Thermo, Agilent,
|
|
11
|
+
Shimadzu, ANDI netCDF) into one Python data model, and converts them to a
|
|
12
|
+
single HDF5 layout or to ANDI netCDF. Pure Python on numpy, h5py and olefile;
|
|
13
|
+
MIT licensed; every format is clean-room and documented.
|
|
14
|
+
|
|
15
|
+
## Supported formats
|
|
16
|
+
|
|
17
|
+
| Vendor | Files | Reader | Format id |
|
|
18
|
+
| --- | --- | --- | --- |
|
|
19
|
+
| Thermo Chromeleon 7 | `.cmbx` archives (signals and embedded MS) | `read_cmbx` | `chromeleon-cmbx` |
|
|
20
|
+
| | raw signal files (`SignHdr`, from a data vault) | `read_chromeleon_raw` | `chromeleon-raw` |
|
|
21
|
+
| | text exports (`.txt`), 7.2 and 7.3, any locale | `read_chromeleon_txt` | `chromeleon-txt` |
|
|
22
|
+
| Thermo | `.raw` MS files (v66, centroid, single quad), e.g. extracted from `.cmbx` | `read_thermo_raw` | `thermo-raw` |
|
|
23
|
+
| Agilent | `.ch` (versions 8, 81, 179, 181) | `read_agilent_ch` | `agilent-ch` |
|
|
24
|
+
| | `.D` folders | `read_agilent_d` | `agilent-d` |
|
|
25
|
+
| | OpenLab `.dx` archives | `read_agilent_dx` | `agilent-dx` |
|
|
26
|
+
| Shimadzu GCMSsolution | `.qgd` (GC-MS, centroids) | `read_qgd` | `shimadzu-qgd` |
|
|
27
|
+
| | `.gcd` (GC/FID) | `read_gcd` | `shimadzu-gcd` |
|
|
28
|
+
| ANDI (netCDF) | ANDI-MS `.cdf` (GC-MS, centroids) | `read_andi_ms` | `andi-ms` |
|
|
29
|
+
| | ANDI chromatography / AIA `.cdf` (one signal) | `read_andi_chrom` | `andi-chrom` |
|
|
30
|
+
|
|
31
|
+
The format is detected from the content (magic bytes, OLE2 storages, zip
|
|
32
|
+
members, netCDF variables, folder contents), never from the extension.
|
|
33
|
+
Everything chromparser reads can also be written as ANDI files
|
|
34
|
+
(`write_andi`), which AMDIS, NIST MS Search, MZmine, OpenChrom, MS-DIAL and
|
|
35
|
+
XCMS read; ANDI loses metadata, HDF5 keeps everything
|
|
36
|
+
([`docs/formats/andi.md`](docs/formats/andi.md)).
|
|
37
|
+
|
|
38
|
+
> Chromeleon and Thermo are trademarks of Thermo Fisher Scientific, Agilent
|
|
39
|
+
> and OpenLab of Agilent Technologies, Shimadzu and GCMSsolution of Shimadzu
|
|
40
|
+
> Corporation. This project is not affiliated with or endorsed by them. The
|
|
41
|
+
> formats were reverse engineered for interoperability; see `docs/formats/`.
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install chromparser # or: uv add chromparser
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Python 3.10 or newer.
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
### Command line
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
chromparser info run.cmbx sample.qgd data.D # injections, channels, MS runs
|
|
57
|
+
chromparser convert run.cmbx # writes run.h5 (layout v3)
|
|
58
|
+
chromparser convert *.qgd --overwrite
|
|
59
|
+
chromparser convert 152612018.raw --signal-unit pA # unit is not in raw files
|
|
60
|
+
chromparser convert old.h5 # cmbx-reader v1/v2 -> old.v3.h5
|
|
61
|
+
chromparser convert run.cmbx --to andi -o out/ # one ANDI .cdf per signal / MS run
|
|
62
|
+
chromparser extract-ms run.cmbx -d out/ # the embedded Thermo .raw files
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`chromparser convert --no-ms` skips the MS data of `.cmbx` archives.
|
|
66
|
+
|
|
67
|
+
### Python
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
import chromparser
|
|
71
|
+
|
|
72
|
+
for injection in chromparser.read("run.cmbx"): # always a list
|
|
73
|
+
print(injection.name, injection.inject_time, injection.metadata)
|
|
74
|
+
for channel, signal in injection.signals.items():
|
|
75
|
+
signal.time, signal.values, signal.unit # minutes, as stored
|
|
76
|
+
for name, ms in injection.ms.items():
|
|
77
|
+
mz, intensity = ms.spectrum(ms.scan_number[0])
|
|
78
|
+
eic = ms.xic(57.0, tolerance=0.5) # one value per scan
|
|
79
|
+
|
|
80
|
+
injection = chromparser.read_one("FID1A.ch") # files with one injection
|
|
81
|
+
chromparser.sniff("mystery.dat") # e.g. "shimadzu-qgd"
|
|
82
|
+
chromparser.convert("sample.qgd", "sample.h5")
|
|
83
|
+
injections = chromparser.read_hdf5("sample.h5") # == chromparser.read("sample.qgd")
|
|
84
|
+
chromparser.write_andi(injections, "out/") # out/sample_MS.cdf, for AMDIS etc.
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Data model
|
|
88
|
+
|
|
89
|
+
See [`docs/model.md`](docs/model.md) for the data model and the reader
|
|
90
|
+
contract, and [`docs/hdf5.md`](docs/hdf5.md) for the HDF5 layout. In short:
|
|
91
|
+
|
|
92
|
+
* `Signal`: `time` (min, float64), `values` (dtype as stored), `unit`,
|
|
93
|
+
`acquisition_start` (UTC), `sampling_interval` (s), `metadata`.
|
|
94
|
+
* `MSData`: per scan `scan_number`, `retention_time` (min), `tic`, optional
|
|
95
|
+
`base_peak_*`, `filters`, `ms_level`; per peak `mz`, `intensity` (dtypes as
|
|
96
|
+
stored: float32 for Thermo, float64 m/z and uint32 intensity for Shimadzu)
|
|
97
|
+
and optional `flags` (bit 0 = saturated), CSR-indexed by `peak_offset`.
|
|
98
|
+
* `inject_time` is local time: timezone-aware when the file has the offset,
|
|
99
|
+
naive when it stores only the wall time (Agilent `.ch`, Chromeleon 7.2
|
|
100
|
+
text exports).
|
|
101
|
+
* Unsupported variants raise `UnsupportedVariant` saying what was found;
|
|
102
|
+
readers never return partial data silently. Recoverable oddities are
|
|
103
|
+
warnings, recorded in `metadata["warnings"]`.
|
|
104
|
+
|
|
105
|
+
## Scope and limitations
|
|
106
|
+
|
|
107
|
+
* Files and data types not in the table above are probably not supported
|
|
108
|
+
yet. chromparser then raises an error saying what it found; it does not
|
|
109
|
+
return partial data.
|
|
110
|
+
* Agilent `.ch` versions 8, 81 and 181 are implemented from the documented
|
|
111
|
+
encodings but have not been checked against real files yet; please share
|
|
112
|
+
a sample if you have one.
|
|
113
|
+
* Spectra are kept as centroids; binning to nominal m/z is left to the user
|
|
114
|
+
(`np.rint(ms.mz)`).
|
|
115
|
+
|
|
116
|
+
If a file fails to read, please open an issue; a sample file helps a lot.
|
|
117
|
+
|
|
118
|
+
## Development
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
uv sync # environment with the dev tools
|
|
122
|
+
uv run pytest # runs without local data
|
|
123
|
+
uv run ruff check . && uv run ruff format --check .
|
|
124
|
+
uv sync --group docs && uv run mkdocs serve # the documentation site
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Large local files make more tests run; see [`tests/README.md`](tests/README.md).
|
|
128
|
+
Contributor notes are in [`AGENTS.md`](AGENTS.md).
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
MIT. The Agilent `.ch` decoders are adapted from chemplexity/chromatography
|
|
133
|
+
(MIT, Copyright (c) 2014 James Dillon); see [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "chromparser"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Read chromatography raw files (Chromeleon, Thermo, Agilent, Shimadzu) into one data model and convert them to HDF5."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
keywords = [
|
|
9
|
+
"chromatography",
|
|
10
|
+
"GC",
|
|
11
|
+
"GC-MS",
|
|
12
|
+
"HPLC",
|
|
13
|
+
"Chromeleon",
|
|
14
|
+
"Agilent",
|
|
15
|
+
"Shimadzu",
|
|
16
|
+
"Thermo",
|
|
17
|
+
"hdf5",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 4 - Beta",
|
|
21
|
+
"Intended Audience :: Science/Research",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Programming Language :: Python :: 3.14",
|
|
28
|
+
"Topic :: Scientific/Engineering :: Chemistry",
|
|
29
|
+
]
|
|
30
|
+
requires-python = ">=3.10"
|
|
31
|
+
dependencies = [
|
|
32
|
+
"numpy>=1.22",
|
|
33
|
+
"h5py>=3.0",
|
|
34
|
+
"olefile>=0.46",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[[project.authors]]
|
|
38
|
+
name = "Sebastian Rejman"
|
|
39
|
+
email = "s.rejman@uu.nl"
|
|
40
|
+
|
|
41
|
+
[project.scripts]
|
|
42
|
+
chromparser = "chromparser.cli:main"
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
homepage = "https://github.com/MyonicS/chromparser"
|
|
46
|
+
documentation = "https://myonics.github.io/chromparser/"
|
|
47
|
+
repository = "https://github.com/MyonicS/chromparser"
|
|
48
|
+
issues = "https://github.com/MyonicS/chromparser/issues"
|
|
49
|
+
changelog = "https://github.com/MyonicS/chromparser/blob/main/CHANGELOG.md"
|
|
50
|
+
|
|
51
|
+
[dependency-groups]
|
|
52
|
+
dev = [
|
|
53
|
+
"pytest>=8.0",
|
|
54
|
+
"ruff>=0.6",
|
|
55
|
+
"scipy>=1.15.3",
|
|
56
|
+
]
|
|
57
|
+
docs = [
|
|
58
|
+
"matplotlib>=3.10.9",
|
|
59
|
+
"mkdocs-jupyter>=0.26.3",
|
|
60
|
+
"mkdocs-material>=9.7.7",
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
[build-system]
|
|
64
|
+
requires = ["uv_build>=0.10.9,<0.11.0"]
|
|
65
|
+
build-backend = "uv_build"
|
|
66
|
+
|
|
67
|
+
[tool.pytest.ini_options]
|
|
68
|
+
addopts = ["--import-mode=importlib"]
|
|
69
|
+
testpaths = ["tests"]
|
|
70
|
+
pythonpath = ["tests"]
|
|
71
|
+
|
|
72
|
+
[tool.ruff]
|
|
73
|
+
line-length = 88
|
|
74
|
+
target-version = "py310"
|
|
75
|
+
src = [
|
|
76
|
+
"src",
|
|
77
|
+
"tests",
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
[tool.ruff.lint]
|
|
81
|
+
select = [
|
|
82
|
+
"B",
|
|
83
|
+
"D",
|
|
84
|
+
"E",
|
|
85
|
+
"F",
|
|
86
|
+
"I",
|
|
87
|
+
"NPY",
|
|
88
|
+
"PT",
|
|
89
|
+
"RUF",
|
|
90
|
+
"SIM",
|
|
91
|
+
"UP",
|
|
92
|
+
"W",
|
|
93
|
+
]
|
|
94
|
+
ignore = [
|
|
95
|
+
"E501",
|
|
96
|
+
"D105",
|
|
97
|
+
"D107",
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
[tool.ruff.lint.per-file-ignores]
|
|
101
|
+
"tests/**" = ["D"]
|
|
102
|
+
"tools/**" = ["D"]
|
|
103
|
+
"docs/**/*.ipynb" = [
|
|
104
|
+
"D",
|
|
105
|
+
"I002",
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
[tool.ruff.lint.pydocstyle]
|
|
109
|
+
convention = "numpy"
|
|
110
|
+
|
|
111
|
+
[tool.ruff.lint.isort]
|
|
112
|
+
known-first-party = ["chromparser"]
|
|
113
|
+
required-imports = ["from __future__ import annotations"]
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "chromparser"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Read chromatography raw files (Chromeleon, Thermo, Agilent, Shimadzu) into one data model and convert them to HDF5."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
authors = [{ name = "Sebastian Rejman", email = "s.rejman@uu.nl" }]
|
|
9
|
+
keywords = [
|
|
10
|
+
"chromatography",
|
|
11
|
+
"GC",
|
|
12
|
+
"GC-MS",
|
|
13
|
+
"HPLC",
|
|
14
|
+
"Chromeleon",
|
|
15
|
+
"Agilent",
|
|
16
|
+
"Shimadzu",
|
|
17
|
+
"Thermo",
|
|
18
|
+
"hdf5",
|
|
19
|
+
]
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Development Status :: 4 - Beta",
|
|
22
|
+
"Intended Audience :: Science/Research",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.10",
|
|
25
|
+
"Programming Language :: Python :: 3.11",
|
|
26
|
+
"Programming Language :: Python :: 3.12",
|
|
27
|
+
"Programming Language :: Python :: 3.13",
|
|
28
|
+
"Programming Language :: Python :: 3.14",
|
|
29
|
+
"Topic :: Scientific/Engineering :: Chemistry",
|
|
30
|
+
]
|
|
31
|
+
requires-python = ">=3.10"
|
|
32
|
+
dependencies = ["numpy>=1.22", "h5py>=3.0", "olefile>=0.46"]
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
chromparser = "chromparser.cli:main"
|
|
36
|
+
|
|
37
|
+
[project.urls]
|
|
38
|
+
homepage = "https://github.com/MyonicS/chromparser"
|
|
39
|
+
documentation = "https://myonics.github.io/chromparser/"
|
|
40
|
+
repository = "https://github.com/MyonicS/chromparser"
|
|
41
|
+
issues = "https://github.com/MyonicS/chromparser/issues"
|
|
42
|
+
changelog = "https://github.com/MyonicS/chromparser/blob/main/CHANGELOG.md"
|
|
43
|
+
|
|
44
|
+
[dependency-groups]
|
|
45
|
+
dev = [
|
|
46
|
+
"pytest>=8.0",
|
|
47
|
+
"ruff>=0.6",
|
|
48
|
+
"scipy>=1.15.3",
|
|
49
|
+
]
|
|
50
|
+
docs = [
|
|
51
|
+
"matplotlib>=3.10.9",
|
|
52
|
+
"mkdocs-jupyter>=0.26.3",
|
|
53
|
+
"mkdocs-material>=9.7.7",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
[build-system]
|
|
57
|
+
requires = ["uv_build>=0.10.9,<0.11.0"]
|
|
58
|
+
build-backend = "uv_build"
|
|
59
|
+
|
|
60
|
+
[tool.pytest.ini_options]
|
|
61
|
+
addopts = ["--import-mode=importlib"]
|
|
62
|
+
testpaths = ["tests"]
|
|
63
|
+
pythonpath = ["tests"]
|
|
64
|
+
|
|
65
|
+
[tool.ruff]
|
|
66
|
+
line-length = 88
|
|
67
|
+
target-version = "py310"
|
|
68
|
+
src = ["src", "tests"]
|
|
69
|
+
|
|
70
|
+
[tool.ruff.lint]
|
|
71
|
+
select = ["B", "D", "E", "F", "I", "NPY", "PT", "RUF", "SIM", "UP", "W"]
|
|
72
|
+
ignore = ["E501", "D105", "D107"]
|
|
73
|
+
|
|
74
|
+
[tool.ruff.lint.per-file-ignores]
|
|
75
|
+
"tests/**" = ["D"]
|
|
76
|
+
"tools/**" = ["D"]
|
|
77
|
+
"docs/**/*.ipynb" = ["D", "I002"]
|
|
78
|
+
|
|
79
|
+
[tool.ruff.lint.pydocstyle]
|
|
80
|
+
convention = "numpy"
|
|
81
|
+
|
|
82
|
+
[tool.ruff.lint.isort]
|
|
83
|
+
known-first-party = ["chromparser"]
|
|
84
|
+
required-imports = ["from __future__ import annotations"]
|