Skip to content

Commit

Permalink
Refactor to use an intermediate Experiment object
Browse files Browse the repository at this point in the history
  • Loading branch information
rutgerkok committed Jul 15, 2024
1 parent 9ab9bfb commit de2c914
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 63 deletions.
47 changes: 47 additions & 0 deletions src/napari_organoidtracker/_experiment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from typing import List, Tuple, Dict

import numpy

from napari_organoidtracker._links import Links


class Experiment:
links: Links

def __init__(self):
self.links = Links()


def experiment_to_napari(experiment: Experiment) -> List[Tuple[numpy.ndarray, Dict, str]]:
"""Convert an Experiment object to the Napari format.
The track layer format of Napari is documented at https://napari.org/stable/howtos/layers/tracks.html .
"""

links = experiment.links
positions_table = [] # Each row is [track_id, t, z, y, z], ordered by track_id and then t
linking_graph = {}
for track_id, track in links.find_all_tracks_and_ids():
for position in track.positions():
positions_table.append(
[
track_id,
position.time_point_number(),
position.z,
position.y,
position.x,
]
)

previous_track_ids = [
links.get_track_id(previous_track)
for previous_track in track.get_previous_tracks()
]
linking_graph[track_id] = previous_track_ids

# Move all time points so that we start at time point 0 (OrganoidTracker can start at any time point number, but
# Napari always starts at 0)
positions_table = numpy.array(positions_table, dtype=numpy.float32)
positions_table[:, 1] -= positions_table[:, 1].min()

return [(positions_table, {"graph": linking_graph}, "tracks")]
2 changes: 1 addition & 1 deletion src/napari_organoidtracker/_links.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Any, Dict, Iterable, List, Optional, Set, Tuple

from napari_organoidtracker._basics import DataType, TimePoint
from napari_organoidtracker._positions import Position
from napari_organoidtracker._position import Position


class LinkingTrack:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


class Position:
"""A detected position. Only the 3D + time position is stored here, see the PositionShape class for the shape.
"""A detected position. Only the 3D + time position is stored here.
The position is immutable."""

__slots__ = [
Expand Down
81 changes: 20 additions & 61 deletions src/napari_organoidtracker/_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
import json
from typing import Any, Dict, List, Tuple

from napari_organoidtracker import _experiment
from napari_organoidtracker._experiment import Experiment
from napari_organoidtracker._links import Links
from napari_organoidtracker._positions import Position
from napari_organoidtracker._position import Position


def napari_get_reader(path):
Expand Down Expand Up @@ -68,18 +70,15 @@ def reader_function(input_path):

return_list = []
for path in paths:
tracking_data, add_kwargs = _read_organoidtracker_file(path)

layer_type = "tracks"
return_list.append((tracking_data, add_kwargs, layer_type))
experiment = _read_organoidtracker_file(path)
return_list += _experiment.experiment_to_napari(experiment)
return return_list


def _read_organoidtracker_file(filepath) -> Tuple[List, Dict]:
"""Read a .aut file and return the data in Napari format.
The file format of Napari is documented at https://napari.org/stable/howtos/layers/tracks.html .
def _read_organoidtracker_file(filepath) -> Experiment:
"""Read a .aut file and return the data as a parsed Experiment object.
"""
experiment = Experiment()

with open(filepath) as handle:
data = json.load(handle)
Expand All @@ -88,16 +87,13 @@ def _read_organoidtracker_file(filepath) -> Tuple[List, Dict]:
# We don't have a general data file, but a specialized one
raise ValueError(
"Unknown file format",
"This plugin is not able to load this AUT file: it is missing the"
" version tag.",
"This plugin is not able to load this AUT file: it is missing the version tag.",
)

if data.get("version", "v1") != "v1":
raise ValueError(
"Unknown data version",
"This plugin is not able to load data of version "
+ str(data["version"])
+ ".",
"This plugin is not able to load data of version " + str(data["version"]) + ".",
)

# if "shapes" in data:
Expand All @@ -107,56 +103,21 @@ def _read_organoidtracker_file(filepath) -> Tuple[List, Dict]:
# _parse_position_format(experiment, data["positions"], min_time_point, max_time_point)

if "links" in data:
tracking_data, linking_graph = _parse_links_format(data["links"])
elif (
"links_scratch" in data
): # Deprecated, was used back when experiments could hold multiple linking sets
tracking_data, linking_graph = _parse_links_format(
data["links_scratch"]
)
elif (
"links_baseline" in data
): # Deprecated, was used back when experiments could hold multiple linking sets
tracking_data, linking_graph = _parse_links_format(
data["links_baseline"]
)
else:
tracking_data = []
linking_graph = {}
_parse_links_format(experiment, data["links"])
elif "links_scratch" in data: # Deprecated, was used back when experiments could hold multiple linking sets
_parse_links_format(experiment, data["links_scratch"])
elif "links_baseline" in data: # Deprecated, was used back when experiments could hold multiple linking sets
_parse_links_format(experiment, data["links_baseline"])

return tracking_data, {"graph": linking_graph}
return experiment


def _parse_links_format(links_json: Dict[str, Any]) -> Tuple[List, Dict]:
def _parse_links_format(experiment: Experiment, links_json: Dict[str, Any]):
"""Parses a node_link_graph and adds all links and positions to the experiment."""
links = Links()
_add_d3_data(links, links_json)

links.sort_tracks_by_x()

positions_table = (
[]
) # Each row is [track_id, t, z, y, z], ordered by track_id and then t
linking_graph = {}
for track_id, track in links.find_all_tracks_and_ids():
for position in track.positions():
positions_table.append(
[
track_id,
position.time_point_number(),
position.z,
position.y,
position.x,
]
)

previous_track_ids = [
links.get_track_id(previous_track)
for previous_track in track.get_previous_tracks()
]
linking_graph[track_id] = previous_track_ids

return positions_table, linking_graph
experiment.links = links


def _add_d3_data(links: Links, links_json: Dict):
Expand All @@ -174,7 +135,7 @@ def _add_d3_data(links: Links, links_json: Dict):
# Lineage metadata, store it
links.set_lineage_data(
links.get_track(source),
data_key[len("__lineage_") :],
data_key[len("__lineage_"):],
data_value,
)

Expand All @@ -187,6 +148,4 @@ def _parse_position(json_structure: Dict[str, Any]) -> Position:
json_structure["z"],
time_point_number=json_structure["_time_point_number"],
)
return Position(
json_structure["x"], json_structure["y"], json_structure["z"]
)
return Position(json_structure["x"], json_structure["y"], json_structure["z"])

0 comments on commit de2c914

Please sign in to comment.