Skip to content

Commit f0b0562

Browse files
authored
feat: CTL ImmunoSpot - use proper units in data processing document (#1098)
1 parent 167a1eb commit f0b0562

8 files changed

Lines changed: 5481 additions & 2818 deletions

File tree

src/allotropy/allotrope/models/shared/definitions/custom.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
SeimensPerMeter,
7373
SquareCentimetersPerGram,
7474
SquareCentimetersPerMole,
75+
SquareMillimeter,
7576
SquareResponseUnit,
7677
TODO,
7778
Unitless,
@@ -821,6 +822,16 @@ class TNullableQuantityValueSquareCentimetersPerMole(
821822
pass
822823

823824

825+
@dataclass(frozen=True, kw_only=True)
826+
class TQuantityValueSquareMillimeter(SquareMillimeter, TQuantityValue):
827+
pass
828+
829+
830+
@dataclass(frozen=True, kw_only=True)
831+
class TNullableQuantityValueSquareMillimeter(SquareMillimeter, TNullableQuantityValue):
832+
pass
833+
834+
824835
@dataclass(frozen=True, kw_only=True)
825836
class TQuantityValueSquareResponseUnit(SquareResponseUnit, TQuantityValue):
826837
pass

src/allotropy/allotrope/models/shared/definitions/units.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,11 @@ class SquareCentimetersPerMole(HasUnit):
339339
unit: str = "cm^2/mol"
340340

341341

342+
@dataclass(frozen=True, kw_only=True)
343+
class SquareMillimeter(HasUnit):
344+
unit: str = "mm^2"
345+
346+
342347
@dataclass(frozen=True, kw_only=True)
343348
class SquareResponseUnit(HasUnit):
344349
unit: str = "RU^2"

src/allotropy/allotrope/schemas/shared/definitions/custom.json

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,7 +1199,7 @@
11991199
}
12001200
]
12011201
},
1202-
"TQuantityValueResponseUnit": {
1202+
"tQuantityValueResponseUnit": {
12031203
"allOf": [
12041204
{
12051205
"$ref": "#/$defs/tQuantityValue"
@@ -1219,7 +1219,7 @@
12191219
}
12201220
]
12211221
},
1222-
"TQuantityValueResponseUnitPerSecond": {
1222+
"tQuantityValueResponseUnitPerSecond": {
12231223
"allOf": [
12241224
{
12251225
"$ref": "#/$defs/tQuantityValue"
@@ -1319,6 +1319,26 @@
13191319
}
13201320
]
13211321
},
1322+
"tQuantityValueSquareMillimeter": {
1323+
"allOf": [
1324+
{
1325+
"$ref": "#/$defs/tQuantityValue"
1326+
},
1327+
{
1328+
"$ref": "#/$defs/SquareMillimeter"
1329+
}
1330+
]
1331+
},
1332+
"tNullableQuantityValueSquareMillimeter": {
1333+
"allOf": [
1334+
{
1335+
"$ref": "#/$defs/tNullableQuantityValue"
1336+
},
1337+
{
1338+
"$ref": "#/$defs/SquareMillimeter"
1339+
}
1340+
]
1341+
},
13221342
"tQuantityValueSquareResponseUnit": {
13231343
"allOf": [
13241344
{
@@ -1399,4 +1419,4 @@
13991419
}
14001420
]
14011421
}
1402-
}
1422+
}

src/allotropy/allotrope/schemas/shared/definitions/units.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,18 @@
791791
"unit"
792792
]
793793
},
794+
"SquareMillimeter": {
795+
"properties": {
796+
"unit": {
797+
"type": "string",
798+
"const": "mm^2",
799+
"$asm.unit-iri": "http://qudt.org/vocab/unit#SquareMillimeter"
800+
}
801+
},
802+
"required": [
803+
"unit"
804+
]
805+
},
794806
"SquareResponseUnit": {
795807
"properties": {
796808
"unit": {

src/allotropy/parsers/ctl_immunospot/ctl_immunospot_structure.py

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
import pandas as pd
77

8+
from allotropy.allotrope.models.shared.definitions.custom import (
9+
TQuantityValueSquareMillimeter,
10+
TQuantityValueUnitless,
11+
)
812
from allotropy.allotrope.models.shared.definitions.definitions import (
913
FieldComponentDatatype,
1014
)
@@ -24,6 +28,8 @@
2428
from allotropy.parsers.utils.uuids import random_uuid_str
2529
from allotropy.parsers.utils.values import (
2630
assert_not_none,
31+
quantity_or_none,
32+
try_float_or_none,
2733
)
2834

2935

@@ -35,11 +41,26 @@ def _create_measurement(
3541
histograms: dict[str, tuple[list[float], list[float]]],
3642
header_data: dict[str, float | str | None],
3743
) -> Measurement:
44+
def get_value_or_none(
45+
data: dict[str, float | str | None], name: str
46+
) -> float | None:
47+
value = str(data.pop(name, None)).split()[0]
48+
return try_float_or_none(value)
49+
3850
location_identifier = f"{well_row}{well_col}"
3951
data_processing_document = {
40-
"Min. SpotSize": header_data.pop("Min. SpotSize", None),
41-
"Max. SpotSize": header_data.pop("Max. SpotSize", None),
42-
"Spot Separation": header_data.pop("Spot Separation", None),
52+
"Min. SpotSize": quantity_or_none(
53+
TQuantityValueSquareMillimeter,
54+
get_value_or_none(header_data, "Min. SpotSize"),
55+
),
56+
"Max. SpotSize": quantity_or_none(
57+
TQuantityValueSquareMillimeter,
58+
get_value_or_none(header_data, "Max. SpotSize"),
59+
),
60+
"Spot Separation": quantity_or_none(
61+
TQuantityValueUnitless,
62+
get_value_or_none(header_data, "Spot Separation"),
63+
),
4364
}
4465
has_data = any(
4566
value is not None and str(value).strip() != ""
@@ -65,29 +86,31 @@ def _create_measurement(
6586
for name, data in plate_data.items()
6687
],
6788
),
68-
custom_data_cubes=[
69-
DataCube(
70-
label="spot count histogram",
71-
structure_dimensions=[
72-
DataCubeComponent(
73-
concept="spot size",
74-
type_=FieldComponentDatatype.double,
75-
unit=UNITLESS,
76-
)
77-
],
78-
structure_measures=[
79-
DataCubeComponent(
80-
concept="spot count",
81-
type_=FieldComponentDatatype.double,
82-
unit="Number",
83-
)
84-
],
85-
dimensions=[histograms[location_identifier][0]],
86-
measures=[histograms[location_identifier][1]],
87-
)
88-
]
89-
if histograms and location_identifier in histograms
90-
else None,
89+
custom_data_cubes=(
90+
[
91+
DataCube(
92+
label="spot count histogram",
93+
structure_dimensions=[
94+
DataCubeComponent(
95+
concept="spot size",
96+
type_=FieldComponentDatatype.double,
97+
unit=UNITLESS,
98+
)
99+
],
100+
structure_measures=[
101+
DataCubeComponent(
102+
concept="spot count",
103+
type_=FieldComponentDatatype.double,
104+
unit="Number",
105+
)
106+
],
107+
dimensions=[histograms[location_identifier][0]],
108+
measures=[histograms[location_identifier][1]],
109+
)
110+
]
111+
if histograms and location_identifier in histograms
112+
else None
113+
),
91114
device_control_custom_info=header_data,
92115
)
93116

0 commit comments

Comments
 (0)