Skip to content

Commit f8a4aa4

Browse files
authored
feat: Molecular Devices SoftMax Pro - add support for spectral TimeFormat measurements (#1026)
1 parent ab3b7e7 commit f8a4aa4

4 files changed

Lines changed: 97652 additions & 4 deletions

File tree

src/allotropy/parsers/lines_reader.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,14 @@ def pop_as_series(self, sep: str = " ") -> pd.Series[str] | None:
181181
line = self.pop()
182182
return None if line is None else pd.Series(line.split(sep))
183183

184+
def pop_line_as_df(
185+
self, sep: str = " ", empty_pat: str = EMPTY_STR_PATTERN
186+
) -> pd.DataFrame | None:
187+
self.drop_empty(empty_pat)
188+
line = self.pop()
189+
self.drop_empty(empty_pat)
190+
return None if line is None else pd.DataFrame([line.split(sep)])
191+
184192
def lines_as_df(
185193
self,
186194
lines: list[str],

src/allotropy/parsers/moldev_softmax_pro/softmax_pro_structure.py

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,37 @@ def create(
709709
)
710710
set_columns(data, columns)
711711

712+
measurement_data = [
713+
TimeMeasurementData.create(header, wavelength, row)
714+
for _, row in data.iterrows()
715+
]
716+
712717
return TimeWavelengthData(
718+
wavelength=wavelength,
719+
measurement_data=measurement_data,
720+
)
721+
722+
723+
@dataclass(frozen=True)
724+
class SpectrumTimeWavelengthData:
725+
wavelength: float
726+
measurement_data: list[TimeMeasurementData]
727+
728+
@staticmethod
729+
def create(
730+
reader: CsvReader,
731+
header: PlateHeader,
732+
wavelength: float,
733+
columns: pd.Series[str],
734+
) -> SpectrumTimeWavelengthData:
735+
data = assert_not_none(
736+
reader.pop_line_as_df(sep="\t"),
737+
msg="unable to find raw data from time block for Spectrum read type.",
738+
)
739+
740+
set_columns(data, columns)
741+
742+
return SpectrumTimeWavelengthData(
713743
wavelength=wavelength,
714744
measurement_data=[
715745
TimeMeasurementData.create(header, wavelength, row)
@@ -742,6 +772,29 @@ def create(reader: CsvReader, header: PlateHeader) -> TimeRawData:
742772
)
743773

744774

775+
@dataclass(frozen=True)
776+
class TimeSpectrumRawData:
777+
wavelength_data: list[SpectrumTimeWavelengthData]
778+
779+
@staticmethod
780+
def create(reader: CsvReader, header: PlateHeader) -> TimeSpectrumRawData:
781+
columns = assert_not_none(
782+
reader.pop_as_series(sep="\t"),
783+
msg="unable to find data columns for time block raw data.",
784+
)
785+
wavelength_data = [
786+
SpectrumTimeWavelengthData.create(
787+
reader,
788+
header,
789+
wavelength,
790+
columns,
791+
)
792+
for wavelength in header.wavelengths
793+
]
794+
795+
return TimeSpectrumRawData(wavelength_data=wavelength_data)
796+
797+
745798
@dataclass(frozen=True)
746799
class TimeReducedData:
747800
data: list[ReducedDataElement]
@@ -773,20 +826,23 @@ def create(reader: CsvReader, header: PlateHeader) -> TimeReducedData:
773826

774827
@dataclass(frozen=True)
775828
class TimeData:
776-
raw_data: TimeRawData
829+
raw_data: TimeRawData | TimeSpectrumRawData
777830
reduced_data: TimeReducedData | None
778831

779832
@staticmethod
780833
def create(
781834
reader: CsvReader,
782835
header: PlateHeader,
783836
) -> TimeData:
784-
raw_data = None
785837
reduced_data = None
838+
raw_data: TimeRawData | TimeSpectrumRawData | None = None
786839

787840
# Read raw data if data_type is RAW or BOTH
788841
if header.data_type in (DataType.RAW.value, DataType.BOTH.value):
789-
raw_data = TimeRawData.create(reader, header)
842+
if header.read_type == ReadType.SPECTRUM.value:
843+
raw_data = TimeSpectrumRawData.create(reader, header)
844+
else:
845+
raw_data = TimeRawData.create(reader, header)
790846
# For REDUCED only, create synthetic raw data with error message
791847
else:
792848
raw_data = TimeData._create_synthetic_raw_data(header)
@@ -803,8 +859,8 @@ def create(
803859
@staticmethod
804860
def _create_synthetic_raw_data(header: PlateHeader) -> TimeRawData:
805861
"""Create synthetic raw data with error messages when only reduced data is available."""
806-
synthetic_wavelength_data = []
807862

863+
synthetic_wavelength_data = []
808864
for wavelength in header.wavelengths:
809865
# For each position in the plate, create a data element with an error document
810866
num_cols = header.num_columns

0 commit comments

Comments
 (0)