Skip to content

Commit

Permalink
store errors in AfidDistance object
Browse files Browse the repository at this point in the history
  • Loading branch information
kaitj committed Sep 18, 2023
1 parent 97f6474 commit 93b1ce4
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 37 deletions.
33 changes: 29 additions & 4 deletions afids_utils/afids.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,6 @@ class AfidPosition:
desc: str = attrs.field(validator=_validate_desc)

def __sub__(self, other: AfidPosition) -> tuple[float, float, float]:
# Check if computation performed on corresponding AFIDs
if not self.label == other.label or not self.desc == other.desc:
raise ValueError("Non-corresponding AFIDs")

# Compute distances
x_dist = self.x - other.x
y_dist = self.y - other.y
Expand All @@ -67,6 +63,35 @@ def __sub__(self, other: AfidPosition) -> tuple[float, float, float]:
return x_dist, y_dist, z_dist


@attrs.define(kw_only=True)
class AfidDistance(AfidPosition):
"""Extends the ``AfidPosition`` class to store distances between two
``AfidPosition`` objects
Parameters
----------
label
Unique label for AFID
x
Distance error along x-axis (in mm)
y
Distance error along y-axis (in mm)
z
Distance error along z-axis (in mm)
desc
Description for AFID (e.g. AC, PC)
euc
Euclidean distance between two AfidPositions
"""

euc: float = attrs.field()


def _validate_afids(
instance: AfidSet,
attribute: attrs.Attribute[list[AfidPosition]],
Expand Down
31 changes: 19 additions & 12 deletions afids_utils/metrics.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
"""Methods for computing various metrics pertaining to AFIDs"""
from __future__ import annotations

from afids_utils.afids import AfidPosition
from afids_utils.afids import AfidDistance, AfidPosition


def compute_AFLE(
def compute_distance(
afid_position: AfidPosition, template_position: AfidPosition
) -> tuple[float, float, float, float]:
"""Compute distance errors along each spatial dimension and
AFID localizaton error (AFLE)
) -> AfidDistance:
"""Compute distance between two AfidPositions, returning Euclidean
distance, as well as distances along each spatial dimension
Parameters
----------
Expand All @@ -17,16 +17,23 @@ def compute_AFLE(
(x, y, z)
template_position
Template AfidPosition to compute AFLE against
Template AfidPosition to compute distance against
Returns
-------
tuple[float, float, float, float]
Distance errors along each spatial dimension (x, y, z) and
AFLE respectively
AfidDistance
Object containing distances along each spatial dimension
(x, y, z) and Euclidean distance respectively
"""
# Compute distances and AFLE
# Compute distances
x_dist, y_dist, z_dist = afid_position - template_position
afle = (x_dist**2 + y_dist**2 + z_dist**2) ** 0.5
euc = (x_dist**2 + y_dist**2 + z_dist**2) ** 0.5

return x_dist, y_dist, z_dist, afle
return AfidDistance(
label=afid_position.label,
desc=afid_position.desc,
x=x_dist,
y=y_dist,
z=z_dist,
euc=euc,
)
11 changes: 1 addition & 10 deletions afids_utils/tests/test_afids.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,11 @@ class TestAfidPosition:
def test_valid_position(self, pos: AfidPosition):
"""Just checks that a hypothesis-generated AfidsPosition inits."""

@given(
pos1=af_st.afid_positions(label=1), pos2=af_st.afid_positions(label=1)
)
@given(pos1=af_st.afid_positions(), pos2=af_st.afid_positions())
def test_valid_distance(self, pos1: AfidPosition, pos2: AfidPosition):
"""Check that a subtraction between corresponding AFIDs possible"""
assert pos1 - pos2

@given(
pos1=af_st.afid_positions(label=1), pos2=af_st.afid_positions(label=2)
)
def test_invalid_distance(self, pos1: AfidPosition, pos2: AfidPosition):
with pytest.raises(ValueError, match=r"Non-corresponding .*"):
pos1 - pos2

@given(
label=st.integers().filter(lambda label: label not in range(1, 33)),
x=af_st.valid_position_coords(),
Expand Down
20 changes: 9 additions & 11 deletions afids_utils/tests/test_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@

import afids_utils.metrics as af_metrics
import afids_utils.tests.strategies as af_st
from afids_utils.afids import AfidPosition
from afids_utils.afids import AfidDistance, AfidPosition


class TestMetrics:
@given(
pos1=af_st.afid_positions(label=1), pos2=af_st.afid_positions(label=1)
)
@given(pos1=af_st.afid_positions(), pos2=af_st.afid_positions())
def test_compute_afle(self, pos1: AfidPosition, pos2: AfidPosition):
res = af_metrics.compute_AFLE(pos1, pos2)
assert isinstance(res, tuple) and list(map(type, res)) == [
float,
float,
float,
float,
]
res = af_metrics.compute_distance(pos1, pos2)
assert isinstance(res, AfidDistance)
# Check internals
assert isinstance(res.x, float)
assert isinstance(res.y, float)
assert isinstance(res.z, float)
assert isinstance(res.euc, float)
6 changes: 6 additions & 0 deletions docs/api/afids.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
:exclude-members: label, desc, x, y, z
```

```{eval-rst}
.. autoclass:: afids_utils.afids.AfidDistance
:members:
:exclude-members: label, desc, x, y, z, euc
```

```{eval-rst}
.. autoclass:: afids_utils.afids.AfidVoxel
:members:
Expand Down

0 comments on commit 93b1ce4

Please sign in to comment.