Holger Frey
4 years ago
7 changed files with 249 additions and 38 deletions
@ -0,0 +1,74 @@ |
|||||||
|
""" 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 |
||||||
|
|
||||||
|
MeasurementParams = namedtuple("MeasurementParams", ["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 = int(child.attrib["ExposureTimeMs"]) |
||||||
|
result[exposure] = MeasurementParams(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["Exposure.Id"] == exposure_id |
||||||
|
data_frame.loc[mask, "Parameters.Channel"] = info.channel |
||||||
|
data_frame.loc[mask, "Parameters.Time"] = info.time |
||||||
|
data_frame["Parameters.Channel"] = data_frame["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["Parameters.Channel"] = numpy.nan |
||||||
|
data_frame["Parameters.Time"] = numpy.nan |
||||||
|
params = _get_measurement_params(folder) |
||||||
|
if params: |
||||||
|
available_exposures = set(data_frame["Exposure.Id"].unique()) |
||||||
|
if available_exposures == set(params.keys()): |
||||||
|
return _add_measurement_params(data_frame, params) |
||||||
|
return data_frame |
@ -0,0 +1,37 @@ |
|||||||
|
""" test fixtures """ |
||||||
|
|
||||||
|
from pathlib import Path |
||||||
|
|
||||||
|
import pytest |
||||||
|
|
||||||
|
EXAMPLE_DIR_WO_PARAMS = "mtp_wo_parameters" |
||||||
|
EXAMPLE_DIR_WITH_PARAMS = "mtp_with_parameters" |
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture |
||||||
|
def example_dir(request): |
||||||
|
root_dir = Path(request.config.rootdir) |
||||||
|
yield root_dir / "example_data" |
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture |
||||||
|
def example_file(example_dir): |
||||||
|
data_dir = example_dir / EXAMPLE_DIR_WO_PARAMS |
||||||
|
yield data_dir / "160218_SG2-013-001_Regen1_Cy3-100_1_A1_1.csv" |
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture |
||||||
|
def exposure_df(): |
||||||
|
from pandas import DataFrame |
||||||
|
|
||||||
|
yield DataFrame(data={"Exposure.Id": [1, 2, 3]}) |
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture |
||||||
|
def dir_for_caching(tmpdir, example_file): |
||||||
|
import shutil |
||||||
|
|
||||||
|
temp_path = Path(tmpdir) |
||||||
|
dest = temp_path / example_file.name |
||||||
|
shutil.copy(example_file, dest) |
||||||
|
yield temp_path |
@ -0,0 +1,125 @@ |
|||||||
|
from .conftest import EXAMPLE_DIR_WO_PARAMS, EXAMPLE_DIR_WITH_PARAMS |
||||||
|
|
||||||
|
|
||||||
|
def test_search_measurement_params_file_ok(example_dir): |
||||||
|
from sensospot_data.parameters import _search_measurement_params_file |
||||||
|
|
||||||
|
result = _search_measurement_params_file( |
||||||
|
example_dir / EXAMPLE_DIR_WITH_PARAMS |
||||||
|
) |
||||||
|
|
||||||
|
assert result.suffix == ".svexp" |
||||||
|
|
||||||
|
|
||||||
|
def test_search_measurement_params_file_no_parameters_folder(example_dir): |
||||||
|
from sensospot_data.parameters import _search_measurement_params_file |
||||||
|
|
||||||
|
result = _search_measurement_params_file( |
||||||
|
example_dir / EXAMPLE_DIR_WO_PARAMS |
||||||
|
) |
||||||
|
|
||||||
|
assert result is None |
||||||
|
|
||||||
|
|
||||||
|
def test_ssearch_measurement_params_file_parameters_file(tmpdir): |
||||||
|
from sensospot_data.parameters import _search_measurement_params_file |
||||||
|
|
||||||
|
params_dir = tmpdir / "Parameters" |
||||||
|
params_dir.mkdir() |
||||||
|
|
||||||
|
result = _search_measurement_params_file(tmpdir) |
||||||
|
|
||||||
|
assert result is None |
||||||
|
|
||||||
|
|
||||||
|
def test_parse_channel_info(example_dir): |
||||||
|
from sensospot_data.parameters import ( |
||||||
|
_search_measurement_params_file, |
||||||
|
_parse_measurement_params, |
||||||
|
) |
||||||
|
|
||||||
|
params = _search_measurement_params_file( |
||||||
|
example_dir / EXAMPLE_DIR_WITH_PARAMS |
||||||
|
) |
||||||
|
result = _parse_measurement_params(params) |
||||||
|
|
||||||
|
assert set(result.keys()) == {1, 2, 3} |
||||||
|
assert result[1] == ("green", 100) |
||||||
|
assert result[2] == ("red", 150) |
||||||
|
assert result[3] == ("red", 15) |
||||||
|
|
||||||
|
|
||||||
|
def test_get_measurement_params_file_found(example_dir): |
||||||
|
from sensospot_data.parameters import _get_measurement_params |
||||||
|
|
||||||
|
result = _get_measurement_params(example_dir / EXAMPLE_DIR_WITH_PARAMS) |
||||||
|
|
||||||
|
assert set(result.keys()) == {1, 2, 3} |
||||||
|
assert result[1] == ("green", 100) |
||||||
|
assert result[2] == ("red", 150) |
||||||
|
assert result[3] == ("red", 15) |
||||||
|
|
||||||
|
|
||||||
|
def test_get_measurement_params_file_not_found(example_dir): |
||||||
|
from sensospot_data.parameters import _get_measurement_params |
||||||
|
|
||||||
|
result = _get_measurement_params(example_dir / EXAMPLE_DIR_WO_PARAMS) |
||||||
|
|
||||||
|
assert result is None |
||||||
|
|
||||||
|
|
||||||
|
def test_add_measurement_params(exposure_df): |
||||||
|
from sensospot_data.parameters import ( |
||||||
|
_add_measurement_params, |
||||||
|
MeasurementParams, |
||||||
|
) |
||||||
|
|
||||||
|
params = { |
||||||
|
1: MeasurementParams("red", 10), |
||||||
|
2: MeasurementParams("green", 20), |
||||||
|
3: MeasurementParams("blue", 50), |
||||||
|
} |
||||||
|
|
||||||
|
result = _add_measurement_params(exposure_df, params) |
||||||
|
|
||||||
|
assert result["Exposure.Id"][0] == 1 |
||||||
|
assert result["Parameters.Channel"][0] == "red" |
||||||
|
assert result["Parameters.Time"][0] == 10 |
||||||
|
assert result["Exposure.Id"][1] == 2 |
||||||
|
assert result["Parameters.Channel"][1] == "green" |
||||||
|
assert result["Parameters.Time"][1] == 20 |
||||||
|
assert result["Exposure.Id"][2] == 3 |
||||||
|
assert result["Parameters.Channel"][2] == "blue" |
||||||
|
assert result["Parameters.Time"][2] == 50 |
||||||
|
|
||||||
|
|
||||||
|
def test_add_optional_measurement_parameters_with_params_file( |
||||||
|
exposure_df, example_dir |
||||||
|
): |
||||||
|
from sensospot_data.parameters import add_optional_measurement_parameters |
||||||
|
|
||||||
|
folder = example_dir / EXAMPLE_DIR_WITH_PARAMS |
||||||
|
add_optional_measurement_parameters(exposure_df, folder) |
||||||
|
|
||||||
|
expected = [(1, "green", 100), (2, "red", 150), (3, "red", 15)] |
||||||
|
for exposure_id, channel, time in expected: |
||||||
|
mask = exposure_df["Exposure.Id"] == exposure_id |
||||||
|
example_row = exposure_df.loc[mask].iloc[0] |
||||||
|
assert example_row["Parameters.Channel"] == channel |
||||||
|
assert example_row["Parameters.Time"] == time |
||||||
|
|
||||||
|
|
||||||
|
def test_add_optional_measurement_parameters_without_params_file( |
||||||
|
exposure_df, example_dir |
||||||
|
): |
||||||
|
from sensospot_data.parameters import add_optional_measurement_parameters |
||||||
|
from pandas import isnull |
||||||
|
|
||||||
|
folder = example_dir / EXAMPLE_DIR_WO_PARAMS |
||||||
|
add_optional_measurement_parameters(exposure_df, folder) |
||||||
|
|
||||||
|
for exposure_id in range(1, 4): |
||||||
|
mask = exposure_df["Exposure.Id"] == exposure_id |
||||||
|
example_row = exposure_df.loc[mask].iloc[0] |
||||||
|
assert isnull(example_row["Parameters.Channel"]) |
||||||
|
assert isnull(example_row["Parameters.Time"]) |
Loading…
Reference in new issue