Skip to content

Commit cb5f80c

Browse files
feat: Thermo Fisher Scientific NanoDrop Eight - add unread data to asm (#1096)
<img width="1821" height="171" alt="image" src="https://github.com/user-attachments/assets/0f97fec0-7bbf-4f04-97b0-1dc923315548" />
1 parent 10a0683 commit cb5f80c

10 files changed

Lines changed: 347 additions & 39 deletions

File tree

src/allotropy/allotrope/converter.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
"@": "_AT_",
114114
"'": "_QUOTE_",
115115
",": "_COMMA_",
116+
"&": "_AMPERSAND_",
116117
# NOTE: this MUST be at the end, or it will break other key replacements.
117118
" ": "_",
118119
}

src/allotropy/parsers/thermo_fisher_nanodrop_eight/constants.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,14 @@
88
(260, 230),
99
]
1010

11-
CONCENTRATION_UNITS = ["ng/μL", "μg/mL", "μg/µL", "mg/mL", "μg,mL"]
11+
CONCENTRATION_UNITS = [
12+
"ng/μL",
13+
"ng/µL",
14+
"ng/μl",
15+
"ng/µl",
16+
"ng/âμl",
17+
"μg/mL",
18+
"μg/µL",
19+
"mg/mL",
20+
"μg,mL",
21+
]

src/allotropy/parsers/thermo_fisher_nanodrop_eight/nanodrop_eight_parser.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
create_metadata,
1818
SpectroscopyRow,
1919
)
20-
from allotropy.parsers.utils.pandas import map_rows
20+
from allotropy.parsers.utils.pandas import map_rows, SeriesData
2121
from allotropy.parsers.vendor_parser import VendorParser
2222

2323

@@ -40,7 +40,10 @@ def create_data(self, named_file_contents: NamedFileContents) -> Data:
4040
return Data(
4141
metadata=metadata,
4242
measurement_groups=[
43-
create_measurement_group(row, reader.header) for row in rows
43+
create_measurement_group(
44+
row, reader.header, SeriesData(reader.data.iloc[0])
45+
)
46+
for row in rows
4447
],
4548
# NOTE: in current implementation, calculated data is reported at global level for some reason.
4649
# TODO(nstender): should we move this inside of measurements?

src/allotropy/parsers/thermo_fisher_nanodrop_eight/nanodrop_eight_structure.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,16 @@ def create(data: SeriesData, header: SeriesData) -> SpectroscopyRow:
4949
)
5050
mass_concentration = get_first_not_none(
5151
lambda key: data.get(float, key),
52-
["conc.", "conc", "concentration"],
52+
["conc.", "conc", "concentration", "ng/âμl", "ng/μl", "ng/µL", "ng/µl"],
5353
)
5454
unit = get_first_not_none(
5555
lambda key: key if data.get(float, key.lower()) else None,
5656
constants.CONCENTRATION_UNITS,
5757
)
58+
# Normalize the unit to a standard format that ASM recognizes
59+
if unit and "ng/" in unit:
60+
# Normalize all variants to ng/µL (micro sign + uppercase L)
61+
unit = "ng/µL"
5862

5963
spectra_data_cube = None
6064
float_cols = [col for col in data.series.index if try_float_or_none(col)]
@@ -78,6 +82,26 @@ def create(data: SeriesData, header: SeriesData) -> SpectroscopyRow:
7882
str, ["sample id", "uid"], NOT_APPLICABLE, SeriesData.NOT_NAN
7983
)
8084
location_id = data.get(str, "location")
85+
86+
# Fields to skip from data as they're already captured elsewhere
87+
data_skip_fields = {
88+
"date",
89+
"date & time",
90+
"a260/a230",
91+
"a260/a280",
92+
"sample",
93+
"username",
94+
"weirdextra:",
95+
"andmore",
96+
}
97+
98+
# Fields to skip from header as they're already captured elsewhere
99+
header_skip_fields = {
100+
"serial number",
101+
"application",
102+
"user name",
103+
}
104+
81105
measurements: list[Measurement] = []
82106
for wavelength, absorbance in absorbances.items():
83107
if not absorbance:
@@ -103,6 +127,15 @@ def create(data: SeriesData, header: SeriesData) -> SpectroscopyRow:
103127
and mass_concentration
104128
and unit
105129
else None,
130+
sample_custom_info={
131+
"Sample Name": data.get(
132+
str, "sample name", validate=SeriesData.NOT_NAN
133+
)
134+
},
135+
custom_info={
136+
**data.get_unread(skip=data_skip_fields),
137+
**header.get_unread(skip=header_skip_fields),
138+
},
106139
)
107140
)
108141
if spectra_data_cube:
@@ -113,6 +146,10 @@ def create(data: SeriesData, header: SeriesData) -> SpectroscopyRow:
113146
data_cube=spectra_data_cube,
114147
sample_identifier=sample_id,
115148
location_identifier=location_id,
149+
custom_info={
150+
**data.get_unread(skip=data_skip_fields),
151+
**header.get_unread(skip=header_skip_fields),
152+
},
116153
)
117154
)
118155

@@ -138,11 +175,13 @@ def create_metadata(data: SeriesData, file_path: str) -> Metadata:
138175

139176

140177
def create_measurement_group(
141-
row: SpectroscopyRow, header: SeriesData
178+
row: SpectroscopyRow, header: SeriesData, data: SeriesData
142179
) -> MeasurementGroup:
180+
analyst = header.get(str, "user name") or data.get(str, "username")
181+
data.get_unread()
143182
return MeasurementGroup(
144183
measurement_time=row.timestamp,
145-
analyst=header.get(str, "user name"),
184+
analyst=analyst,
146185
experiment_type=row.experiment_type,
147186
measurements=row.measurements,
148187
)

tests/parsers/thermo_fisher_nanodrop_eight/testdata/thermo_nanodrop_eight_RNA.json

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@
2525
"absorbance": {
2626
"value": 17.62,
2727
"unit": "mAU"
28+
},
29+
"processed data aggregate document": {
30+
"processed data document": [
31+
{
32+
"mass concentration": {
33+
"value": 704.986,
34+
"unit": "ng/µL"
35+
}
36+
}
37+
]
2838
}
2939
},
3040
{
@@ -50,7 +60,8 @@
5060
}
5161
],
5262
"experiment type": "RNA"
53-
}
63+
},
64+
"analyst": "GN104564"
5465
},
5566
{
5667
"measurement aggregate document": {
@@ -75,6 +86,16 @@
7586
"absorbance": {
7687
"value": 17.16,
7788
"unit": "mAU"
89+
},
90+
"processed data aggregate document": {
91+
"processed data document": [
92+
{
93+
"mass concentration": {
94+
"value": 686.535,
95+
"unit": "ng/µL"
96+
}
97+
}
98+
]
7899
}
79100
},
80101
{
@@ -100,7 +121,8 @@
100121
}
101122
],
102123
"experiment type": "RNA"
103-
}
124+
},
125+
"analyst": "GN104564"
104126
},
105127
{
106128
"measurement aggregate document": {
@@ -125,6 +147,16 @@
125147
"absorbance": {
126148
"value": 17.75,
127149
"unit": "mAU"
150+
},
151+
"processed data aggregate document": {
152+
"processed data document": [
153+
{
154+
"mass concentration": {
155+
"value": 710.13,
156+
"unit": "ng/µL"
157+
}
158+
}
159+
]
128160
}
129161
},
130162
{
@@ -150,7 +182,8 @@
150182
}
151183
],
152184
"experiment type": "RNA"
153-
}
185+
},
186+
"analyst": "GN104564"
154187
}
155188
],
156189
"device system document": {
@@ -162,7 +195,7 @@
162195
"file name": "thermo_nanodrop_eight_RNA.txt",
163196
"UNC path": "tests/parsers/thermo_fisher_nanodrop_eight/testdata/thermo_nanodrop_eight_RNA.txt",
164197
"ASM converter name": "allotropy_thermo_fisher_scientific_nanodrop_eight",
165-
"ASM converter version": "0.1.62"
198+
"ASM converter version": "0.1.106"
166199
},
167200
"calculated data aggregate document": {
168201
"calculated data document": [

0 commit comments

Comments
 (0)