You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
80 lines
2.7 KiB
80 lines
2.7 KiB
""" Sensospot Data Parser |
|
|
|
Parsing the numerical output from Sensovations Sensospot image analysis. |
|
""" |
|
|
|
from pathlib import Path |
|
from collections import namedtuple |
|
|
|
import numpy |
|
from defusedxml import ElementTree |
|
|
|
from .columns import ( |
|
COL_NAME_EXPOSURE_ID, |
|
COL_NAME_PARAMETERS_TIME, |
|
COL_NAME_PARAMETERS_CHANNEL, |
|
) |
|
|
|
ExposureInfo = namedtuple("ExposureInfo", ["channel", "time"]) |
|
|
|
|
|
def _search_measurement_params_file(folder): |
|
""" searches for a exposure settings file in a folder """ |
|
folder_path = Path(folder) |
|
params_folder = folder_path / "Parameters" |
|
if not params_folder.is_dir(): |
|
return None |
|
param_files = list(params_folder.glob("**/*.svexp")) |
|
if len(param_files) == 1: |
|
return param_files[0] |
|
else: |
|
return None |
|
|
|
|
|
def _parse_measurement_params(params_file): |
|
""" parses the cannel informations from a settings file """ |
|
file_path = Path(params_file) |
|
with file_path.open("r") as file_handle: |
|
tree = ElementTree.parse(file_handle) |
|
result = {} |
|
for child in tree.find("Channels"): |
|
# child.tag == "ChannelConfig1" |
|
exposure = int(child.tag[-1]) |
|
channel_description = child.attrib["Description"] |
|
# channel_description == "[Cy3|Cy5] Green" |
|
channel = channel_description.rsplit(" ", 1)[-1] |
|
time = float(child.attrib["ExposureTimeMs"]) |
|
result[exposure] = ExposureInfo(channel.lower(), time) |
|
return result |
|
|
|
|
|
def _get_measurement_params(folder): |
|
""" returns measurement parameters """ |
|
params_file = _search_measurement_params_file(folder) |
|
if params_file is not None: |
|
return _parse_measurement_params(params_file) |
|
return None |
|
|
|
|
|
def _add_measurement_params(data_frame, params): |
|
""" adds measurement parameters to a data frame """ |
|
for exposure_id, info in params.items(): |
|
mask = data_frame[COL_NAME_EXPOSURE_ID] == exposure_id |
|
data_frame.loc[mask, COL_NAME_PARAMETERS_CHANNEL] = info.channel |
|
data_frame.loc[mask, COL_NAME_PARAMETERS_TIME] = info.time |
|
data_frame[COL_NAME_PARAMETERS_CHANNEL] = data_frame[ |
|
COL_NAME_PARAMETERS_CHANNEL |
|
].astype("category") |
|
return data_frame |
|
|
|
|
|
def add_optional_measurement_parameters(data_frame, folder): |
|
""" adds measurement params to the data frame, if they could be parsed """ |
|
data_frame[COL_NAME_PARAMETERS_CHANNEL] = numpy.nan |
|
data_frame[COL_NAME_PARAMETERS_TIME] = numpy.nan |
|
params = _get_measurement_params(folder) |
|
if params: |
|
available_exposures = set(data_frame[COL_NAME_EXPOSURE_ID].unique()) |
|
if available_exposures == set(params.keys()): |
|
return _add_measurement_params(data_frame, params) |
|
return data_frame
|
|
|