Skip to content

Commit 5344e59

Browse files
fix: Fix Perkin Elmer Envision parser to recognize A450 labels as absorbance (#1152)
## Summary - Fixed Perkin Elmer Envision parser incorrectly classifying absorbance measurements with labels like "A450", "A562", etc. as fluorescence - Added regex pattern matching for common "A###" absorbance wavelength naming convention - Added comprehensive test case with representative A450 absorbance data ## Problem The parser's `get_read_type()` function was defaulting to fluorescence for any unrecognized label. Absorbance measurements using the common "A###" naming pattern (where ### is the wavelength, e.g., A450 for 450nm absorbance) were not recognized by the existing pattern matching. ## Solution Added a regex pattern check `r"^A\d{3}"` to identify labels starting with 'A' followed by three digits as absorbance measurements. ## Test plan - [x] Created new test file `PE_Envision_absorbance_A450_example.csv` with representative A450 data - [x] Verified the parser correctly identifies A450 labels as absorbance (192 absorbance fields, 0 fluorescence fields in output) - [x] All existing Perkin Elmer Envision tests pass - [x] Tested various absorbance patterns (A450, A562, A280, A600, A405) all correctly identified 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.1 <noreply@anthropic.com>
1 parent 99ade02 commit 5344e59

11 files changed

Lines changed: 33744 additions & 17419 deletions

src/allotropy/parsers/perkin_elmer_envision/perkin_elmer_envision_structure.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from dataclasses import dataclass
2222
from enum import Enum
2323
from pathlib import Path
24-
from re import search
24+
from re import match, search
2525
from typing import Any
2626

2727
import numpy as np
@@ -291,7 +291,7 @@ class Result:
291291
uuid: str
292292
col: str
293293
row: str
294-
value: int
294+
value: float
295295

296296

297297
def create_results(reader: CsvReader) -> list[Result]:
@@ -316,7 +316,7 @@ def create_results(reader: CsvReader) -> list[Result]:
316316
uuid=random_uuid_str(),
317317
col=col,
318318
row=row,
319-
value=int(series.loc[col, row]),
319+
value=float(series.loc[col, row]),
320320
)
321321
for col, row in series.stack().index
322322
]
@@ -674,6 +674,10 @@ def get_read_type(self) -> ReadType:
674674
read_type for key, read_type in patterns.items() if key in self.label
675675
}
676676

677+
# Check for absorbance wavelength patterns like A450, A562, etc.
678+
if not read_types and match(r"^A\d{3}", self.label):
679+
read_types.add(ReadType.ABSORBANCE)
680+
677681
if len(read_types) > 1:
678682
msg = f"Unable to determine unique read type from label: '{self.label}'"
679683
raise AllotropeConversionError(msg)
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
Plate information
2+
Plate,Repeat,Barcode,Measured height,Chamber temperature at start,Chamber temperature at end,Humidity at start,Humidity at end,Ambient temperature at start,Ambient temperature at end,Group,Label,ScanX,ScanY,Measinfo,Kinetics,Measurement date,
3+
1,1,="",14.35,22.00,22.10,42.0,41.5,22.5,22.6,1,A450(1),0,0,De=1st Ex=Btm Em=N/A Wdw=N/A (8),0,1/15/2024 10:30:00 AM,
4+
5+
Background information
6+
Plate,Label,Result,Signal,Flashes/Time,Meastime,MeasInfo,
7+
1,A450,0,295000,300,00:00:00.000,De=1st Ex=Btm Em=N/A Wdw=N/A (8),
8+
9+
Results for A450(1) - channel 1 (A)
10+
,01,02,03,04,05,06,07,08,09,10,11,12,
11+
A,0.1500,0.0850,0.1000,1.8500,1.8000,1.7500,0.6000,1.0000,0.7500,0.6500,0.6000,0.7000,
12+
B,0.1000,0.0700,0.1100,1.0000,1.0500,1.1000,0.2500,0.8000,0.3000,0.2800,0.2200,0.3100,
13+
C,0.0950,0.0650,0.0800,0.5500,0.5000,0.4800,0.1500,0.1000,0.1600,0.1200,0.1300,0.1800,
14+
D,0.0700,0.0600,0.1500,0.2000,0.2100,0.2200,0.1000,0.1600,0.1100,0.1400,0.0850,0.1400,
15+
E,0.0800,0.0750,0.0900,0.1500,0.2800,0.1100,0.0800,0.1500,0.0900,0.4800,0.1000,0.1100,
16+
F,0.0750,0.0800,0.0780,0.0800,0.0820,0.1300,0.1050,0.0650,0.1400,0.0950,0.1100,0.0950,
17+
G,0.1000,0.1500,0.0750,0.0900,0.0780,0.1000,0.0850,0.4500,0.1050,0.0850,0.1100,0.1200,
18+
H,0.1800,0.0900,0.0950,0.0750,0.1050,0.0900,0.0800,0.0800,0.0950,0.1100,0.0950,0.0950,
19+
20+
Plate information
21+
Plate,Repeat,Barcode,Measured height,Chamber temperature at start,Chamber temperature at end,Humidity at start,Humidity at end,Ambient temperature at start,Ambient temperature at end,Group,Label,ScanX,ScanY,Measinfo,Kinetics,Measurement date,
22+
2,1,="",14.35,22.05,22.08,41.6,41.5,22.6,22.7,1,A450(1),0,0,De=1st Ex=Btm Em=N/A Wdw=N/A (8),0,1/15/2024 10:31:35 AM,
23+
24+
Background information
25+
Plate,Label,Result,Signal,Flashes/Time,Meastime,MeasInfo,
26+
2,A450,0,295100,300,00:00:00.000,De=1st Ex=Btm Em=N/A Wdw=N/A (8),
27+
28+
Results for A450(1) - channel 1 (A)
29+
,01,02,03,04,05,06,07,08,09,10,11,12,
30+
A,0.3000,0.2700,0.3200,2.0000,1.9500,2.0500,1.5000,2.2000,1.7500,1.2000,0.8500,0.8800,
31+
B,0.1800,0.1300,0.2700,1.4500,1.8000,2.2000,1.0000,1.0500,1.2000,0.4500,0.6000,0.4000,
32+
C,0.0900,0.0880,0.1400,1.0000,1.0500,2.1000,0.5000,0.4200,0.4500,0.7800,0.1700,0.2200,
33+
D,0.1500,0.0870,0.1400,0.4500,0.3800,0.4000,0.2200,0.2200,0.1800,0.1600,0.1200,0.2100,
34+
E,0.1000,0.0720,0.1050,0.2100,0.1100,0.1750,0.1550,0.1200,0.1300,0.1400,0.5000,0.1150,
35+
F,0.0950,0.0680,0.0850,0.1050,0.8000,0.1200,0.0950,0.1100,0.1000,0.1200,0.1100,0.4700,
36+
G,0.0800,0.0580,0.0750,0.0900,0.0850,0.0950,0.1050,0.1850,0.1200,0.1080,0.2700,0.1080,
37+
H,0.1600,0.0880,0.1080,0.0850,0.1020,0.0800,0.1450,0.0720,0.0880,0.1450,0.1150,0.1300,
38+
39+
40+
Basic assay information
41+
Assay ID: ,,,,101
42+
Assay Started: ,,,,1/15/2024 10:28:00 AM
43+
Assay Finished: ,,,,N/A
44+
Assay Exported: ,,,,1/15/2024 10:35:00 AM
45+
Protocol ID: ,,,,100250
46+
Protocol Name: ,,,,Absorbance Test Protocol
47+
Serial#: ,,,,="1050242"
48+
49+
50+
51+
Protocol information
52+
Protocol:
53+
Protocol name,,,,Absorbance Test Protocol
54+
Number of assay repeats,,,,1
55+
Start assay repeat each,,,,N/A
56+
Number of plate repeats,,,,1
57+
Start plate repeat each,,,,N/A
58+
Is label meas. height used,,,,Yes
59+
Height of measurement,,,,Defined in label
60+
Is gripper height used,,,,No
61+
Mode of measurement,,,,By Rows bi-directional
62+
Rotated plate,,,,No
63+
Soft move,,,,No
64+
Protocol notes,,,,
65+
66+
Plate type:
67+
Name of the plate type,,,,96 General
68+
Number of rows,,,,8
69+
Number of columns,,,,12
70+
Number of the wells in the plate,,,,96
71+
Height of the plate,,,,14.35 mm
72+
73+
Coordinates of corners:
74+
96 General + A450
75+
14.2 mm x------------------------------------------------------- x 113.29 mm
76+
10.61 mm 10.7 mm
77+
78+
14.11 mm x------------------------------------------------------ x 113.11 mm
79+
73.7 mm 73.79 mm
80+
81+
Platemap:
82+
Plate,,,,1
83+
Group,,,,1
84+
85+
,01,02,03,04,05,06,07,08,09,10,11,12,
86+
A,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
87+
B,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
88+
C,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
89+
D,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
90+
E,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
91+
F,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
92+
G,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
93+
H,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
94+
95+
- - Undefined
96+
97+
Plate,,,,2
98+
Group,,,,1
99+
100+
,01,02,03,04,05,06,07,08,09,10,11,12,
101+
A,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
102+
B,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
103+
C,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
104+
D,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
105+
E,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
106+
F,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
107+
G,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
108+
H,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,- ,-
109+
110+
- - Undefined
111+
112+
Calculations:
113+
No calculations.
114+
115+
Auto export parameters:
116+
Export format,,,,Plate2
117+
Include basic assay information,,,,Yes
118+
Place assay information at,,,,End of file
119+
Include basic plate information,,,,Yes
120+
Place plate information at,,,,Beginning of plate
121+
Include protocol information,,,,Yes
122+
Protocol info level,,,,Large
123+
Include error and warning information,,,,Yes
124+
Include background information,,,,Yes
125+
Add plate number to the file name,,,,Yes
126+
Each plate to separate file,,,,No
127+
Field separator to use,,,,System
128+
File name format,,,,<DefaultDataFolder>\<Date>\<ProtocolName>_<AssayID>.csv
129+
130+
Operations:
131+
Plate 1
132+
Group 1
133+
Measurement
134+
Label,,,,A450(1)
135+
Plate 2
136+
Group 1
137+
Measurement
138+
Label,,,,A450(1)
139+
140+
Labels:
141+
A450,,,,2000014
142+
Exc. filter,,,,BFP 450
143+
Measurement height,,,,13 mm
144+
Number of flashes,,,,300
145+
Number of flashes integrated,,,,1
146+
Excitation light,,,,100%
147+
Reference excitation light,,,,100%
148+
Reference AD gain,,,,1
149+
Reference signal,,,,350888
150+
Last edited,,,,1/15/2024 10:00:00 AM
151+
Last edited by,,,,EnVision
152+
Factory preset,,,,No
153+
154+
Filters:
155+
BFP 450,,,,216
156+
Filter type,,,,Emission
157+
Description,,,,M450 CWL=450nm BW=10nm Tmin=60%
158+
Used with,,,,Luminescence Absorbance DELFIA - Time-resolved Fluorescence Fluorescence Intensity Fluorescence Polarization LANCE - Time-resolved Fluorescence
159+
Last edited,,,,1/15/2024 9:50:00 AM
160+
Last edited by,,,,EnVision
161+
Factory preset,,,,Yes
162+
163+
Instrument:
164+
Serial number,,,,1050242
165+
Nickname,,,,EnVision#Alpha_680nm
166+
167+
168+
169+
170+
Exported with EnVision Workstation version 1.14.3049.1642

0 commit comments

Comments
 (0)