Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions tests/test_phasor.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,3 +382,116 @@ def test_phasor_settings_are_served(serve_state):
assert payload['values']['phasor_filter'] == 'none'
keys = [entry['key'] for entry in payload['schema']]
assert 'phasor_filter' in keys and 'irf' in keys


def test_a_polygon_selects_one_population(two_populations):
real, imag, mean = two_populations

masks = phasor.cursor_masks(
real, imag, mean,
cursors=[{'id': 'p1', 'type': 'polygon',
'vertices': [[0.25, 0.35], [0.35, 0.35],
[0.35, 0.45], [0.25, 0.45]]}],
min_photons=1.0)

mask = masks['p1']
assert mask[:8].all()
assert not mask[8:].any()


def test_a_polygon_and_an_ellipse_share_one_request(two_populations):
real, imag, mean = two_populations

masks = phasor.cursor_masks(
real, imag, mean,
cursors=[
{'id': 'p1', 'type': 'polygon',
'vertices': [[0.25, 0.35], [0.35, 0.35],
[0.35, 0.45], [0.25, 0.45]]},
{'id': 'e1', 'center_g': 0.70, 'center_s': 0.35, 'radius': 0.05},
],
min_photons=1.0)

assert masks['p1'].sum() == 128
assert masks['e1'].sum() == 128
assert not (masks['p1'] & masks['e1']).any()


def test_a_polygon_drops_low_photon_pixels(two_populations):
real, imag, mean = two_populations
mean = mean.copy()
mean[0, :] = 0.0

masks = phasor.cursor_masks(
real, imag, mean,
cursors=[{'id': 'p1', 'type': 'polygon',
'vertices': [[0.25, 0.35], [0.35, 0.35],
[0.35, 0.45], [0.25, 0.45]]}],
min_photons=10.0)

assert not masks['p1'][0].any()
assert masks['p1'][1:8].all()


def test_a_polygon_needs_three_vertices(two_populations):
real, imag, mean = two_populations

with pytest.raises(ValueError, match='three vertices'):
phasor.cursor_masks(
real, imag, mean,
cursors=[{'id': 'p1', 'type': 'polygon',
'vertices': [[0.25, 0.35], [0.35, 0.45]]}],
min_photons=1.0)


def test_a_polygon_with_no_vertices_is_rejected(two_populations):
real, imag, mean = two_populations

with pytest.raises(ValueError, match='three vertices'):
phasor.cursor_masks(
real, imag, mean,
cursors=[{'id': 'p1', 'type': 'polygon'}],
min_photons=1.0)


def test_an_unknown_cursor_type_is_rejected(two_populations):
real, imag, mean = two_populations

with pytest.raises(ValueError, match='unknown cursor type'):
phasor.cursor_masks(
real, imag, mean,
cursors=[{'id': 'x1', 'type': 'freehand'}],
min_photons=1.0)


def test_a_polygon_gets_its_own_label(two_populations):
real, imag, mean = two_populations

labels = phasor.label_image(
real, imag, mean,
cursors=[
{'id': 'e1', 'center_g': 0.70, 'center_s': 0.35, 'radius': 0.05},
{'id': 'p1', 'type': 'polygon',
'vertices': [[0.25, 0.35], [0.35, 0.35],
[0.35, 0.45], [0.25, 0.45]]},
],
min_photons=1.0)

assert set(np.unique(labels)) == {1, 2}
assert (labels[8:] == 1).all()
assert (labels[:8] == 2).all()


def test_a_polygon_reports_lifetimes_like_an_ellipse(two_populations):
real, imag, mean = two_populations
cursors = [{'id': 'p1', 'type': 'polygon',
'vertices': [[0.25, 0.35], [0.35, 0.35],
[0.35, 0.45], [0.25, 0.45]]}]

masks = phasor.cursor_masks(real, imag, mean, cursors, min_photons=1.0)
found = phasor.cursor_stats(real, imag, mean, masks, 80.0)

assert len(found) == 1
assert found[0]['n_pixels'] == 128
assert found[0]['tau_phi_ns'] > 0
assert found[0]['mean_g'] == pytest.approx(0.30, abs=0.01)
81 changes: 81 additions & 0 deletions tests/test_phasor_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,84 @@ def test_mask_options_ride_on_the_body(dataset):
})

assert payload['options']['phasor_filter'] == 'median'


FULL_PLANE = [[-5.0, -5.0], [5.0, -5.0], [5.0, 5.0], [-5.0, 5.0]]
LEFT_HALF = [[-5.0, -5.0], [0.5, -5.0], [0.5, 5.0], [-5.0, 5.0]]
RIGHT_HALF = [[0.5, -5.0], [5.0, -5.0], [5.0, 5.0], [0.5, 5.0]]


def _mask(url, ident, cursors, min_photons=1.0, output=None):
body = {'cursors': cursors, 'min_photons': min_photons}
if output:
body['output'] = output
return _call(url, f'/v1/datasets/{ident}/phasor/mask', 'POST', body)


def test_a_polygon_covering_everything_selects_every_valid_pixel(dataset):
url, ident = dataset
points = _call(url, f'/v1/datasets/{ident}/phasor/points?bins=64&min_photons=1.0')

payload = _mask(url, ident, [
{'id': 'p1', 'type': 'polygon', 'vertices': FULL_PLANE}])

assert payload['cursors'][0]['n_pixels'] == points['n_valid']


def test_two_polygons_partition_the_valid_pixels(dataset):
url, ident = dataset
points = _call(url, f'/v1/datasets/{ident}/phasor/points?bins=64&min_photons=1.0')

payload = _mask(url, ident, [
{'id': 'left', 'type': 'polygon', 'vertices': LEFT_HALF},
{'id': 'right', 'type': 'polygon', 'vertices': RIGHT_HALF}])

counts = {entry['id']: entry['n_pixels'] for entry in payload['cursors']}
assert counts['left'] + counts['right'] == points['n_valid']


def test_a_polygon_reports_a_lifetime(dataset):
url, ident = dataset

payload = _mask(url, ident, [
{'id': 'p1', 'type': 'polygon', 'vertices': FULL_PLANE}])

entry = payload['cursors'][0]
assert entry['n_pixels'] > 0
assert entry['tau_phi_ns'] is not None
assert entry['photons'] > 0


def test_a_polygon_becomes_a_label_image(dataset):
url, ident = dataset

payload = _mask(url, ident, [
{'id': 'p1', 'type': 'polygon', 'vertices': FULL_PLANE}],
output='labels')

labels = np.frombuffer(base64.b64decode(payload['labels']), dtype=np.uint8)
assert labels.size == payload['width'] * payload['height']
assert int((labels == 1).sum()) == payload['cursors'][0]['n_pixels']


def test_a_polygon_and_an_ellipse_are_labelled_apart(dataset):
url, ident = dataset

payload = _mask(url, ident, [
{'id': 'e1', 'center_g': 0.5, 'center_s': 0.3, 'radius': 0.1},
{'id': 'p1', 'type': 'polygon', 'vertices': FULL_PLANE}],
output='labels')

labels = np.frombuffer(base64.b64decode(payload['labels']), dtype=np.uint8)
assert set(np.unique(labels)) <= {0, 1, 2}
assert int((labels == 1).sum()) == payload['cursors'][0]['n_pixels']


def test_a_polygon_with_two_vertices_is_a_client_error(dataset):
url, ident = dataset

with pytest.raises(HTTPError) as raised:
_mask(url, ident, [
{'id': 'p1', 'type': 'polygon', 'vertices': [[0.2, 0.3], [0.4, 0.5]]}])

assert raised.value.code == 400
Loading