Skip to content

Commit

Permalink
Error checker: allow filtering for dividing lineages
Browse files Browse the repository at this point in the history
In case you are not interested in correcting non-dividing lineages
  • Loading branch information
rutgerkok committed Oct 19, 2023
1 parent 2fb4b43 commit 83f792f
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 14 deletions.
5 changes: 5 additions & 0 deletions organoid_tracker/core/links.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ def get_duration_in_time_points(self) -> int:
"""Gets the time this track takes in time points. This is simply the number of recorded positions."""
return len(self._positions_by_time_point)

def will_divide(self) -> bool:
"""Checks whether there are at least two next tracks. Faster than calling len(track.get_next_tracks()) > 1,
since this method doesn't create a set."""
return len(self._next_tracks) > 1


class Links:
"""Represents all links between positions at different time points. This is used to follow particles over time. If a
Expand Down
1 change: 1 addition & 0 deletions organoid_tracker/gui/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class DisplaySettings:
image_channel: Optional[ImageChannel] # Set to None to use the default image channel
error_correction_min_time_point: Optional[TimePoint] = None
error_correction_max_time_point: Optional[TimePoint] = None
error_correction_min_divisions: int = 0

def __init__(self, *, show_next_time_point: bool = False, show_images: bool = True,
show_data_axes: bool = True, show_positions: bool = True):
Expand Down
21 changes: 12 additions & 9 deletions organoid_tracker/linking_analysis/lineage_error_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ def delete_problematic_lineages(experiment: Experiment):

def get_problematic_lineages(links: Links, position_data: PositionData, crumbs: AbstractSet[Position],
*, min_time_point: Optional[TimePoint] = None,
max_time_point: Optional[TimePoint] = None) -> List[LineageWithErrors]:
max_time_point: Optional[TimePoint] = None, min_divisions: int = 0
) -> List[LineageWithErrors]:
"""Gets a list of all lineages with warnings in the experiment. The provided "crumbs" are placed in the right
lineages, so that you can see to what lineages those cells belong."""
positions_with_errors = linking_markers.find_errored_positions(position_data, min_time_point=min_time_point,
Expand All @@ -73,16 +74,18 @@ def get_problematic_lineages(links: Links, position_data: PositionData, crumbs:
track_to_crumbs = _group_by_track(links, crumbs)

lineages_with_errors = list()
for track in links.find_starting_tracks():
lineage = LineageWithErrors(track)
lineage._add_errors(track_to_errors.get(track))
lineage._add_crumbs(track_to_crumbs.get(track))
for starting_track in links.find_starting_tracks():
divisions_in_lineage = 0
lineage = LineageWithErrors(starting_track)

for next_track in track.find_all_descending_tracks():
lineage._add_errors(track_to_errors.get(next_track))
lineage._add_crumbs(track_to_crumbs.get(next_track))
for track in starting_track.find_all_descending_tracks(include_self=True):
if track.will_divide():
divisions_in_lineage += 1

if len(lineage.errored_positions) > 0:
lineage._add_errors(track_to_errors.get(track))
lineage._add_crumbs(track_to_crumbs.get(track))

if len(lineage.errored_positions) > 0 and divisions_in_lineage >= min_divisions:
lineages_with_errors.append(lineage)

return lineages_with_errors
Expand Down
26 changes: 23 additions & 3 deletions organoid_tracker/visualizer/errors_visualizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ def __init__(self, window: Window, start_position: Optional[Position]):
display_settings = window.display_settings
self._problematic_lineages = lineage_error_finder.get_problematic_lineages(links, position_data, crumb_positions,
min_time_point=display_settings.error_correction_min_time_point,
max_time_point=display_settings.error_correction_max_time_point)
max_time_point=display_settings.error_correction_max_time_point,
min_divisions=display_settings.error_correction_min_divisions)
self._total_number_of_warnings = sum((len(lineage.errored_positions) for lineage in self._problematic_lineages))

super().__init__(window, chosen_position=start_position, all_positions=[])
Expand Down Expand Up @@ -68,8 +69,9 @@ def get_extra_menu_options(self) -> Dict[str, Any]:
"Edit//Errors-Recheck all errors": self._recheck_errors,
"Edit//Error settings-Change minimum allowed time in between divisions...": self._change_min_division_time,
"Edit//Error settings-Change maximum allowed movement per minute...": self._change_max_distance,
"Edit//Correction settings-Change minimum time point for correction...": self._change_min_time_point,
"Edit//Correction settings-Change maximum time point for correction...": self._change_max_time_point,
"Filter//Time-Change minimum time point for correction...": self._change_min_time_point,
"Filter//Time-Change maximum time point for correction...": self._change_max_time_point,
"Filter//Lineage-Ignore lineages with too few divisions...": self._change_min_divisions,
"Navigate//Lineage-Next lineage [Up]": self.__goto_next_lineage,
"Navigate//Lineage-Previous lineage [Down]": self.__goto_previous_lineage
}
Expand Down Expand Up @@ -138,6 +140,24 @@ def _change_max_time_point(self):
self._recalculate_errors()
self.update_status("Now checking errors up too and including time point " + str(answer) + ".")

def _change_min_divisions(self):
# Find the current value
current_min_divisions = self.get_window().display_settings.error_correction_min_divisions

# Update new value
answer = dialog.prompt_int("Error checking", "How many divisions must a lineage have in order to be included?",
default=current_min_divisions, minimum=0, maximum=100)
if answer is None:
return
self.get_window().display_settings.error_correction_min_divisions = answer
self._recalculate_errors()
if answer == 0:
self.update_status("Now including all lineages again.")
elif answer == 1:
self.update_status("Now only including lineages with at least 1 division.")
else:
self.update_status("Now only including lineages with at least " + str(answer) + " divisions.")

def _get_error_checking_time_points(self) -> Tuple[int, int]:
"""Gets the min and max time point used for error checking. If no positions are loaded, arbitrary values are
returned."""
Expand Down
3 changes: 2 additions & 1 deletion organoid_tracker/visualizer/lineage_errors_visualizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ def _calculate_time_point_metadata(self):
positions = self._experiment.positions.of_time_point(self._time_point)
lineages_with_errors = lineage_error_finder.get_problematic_lineages(links, position_data, positions,
min_time_point=self._display_settings.error_correction_min_time_point,
max_time_point=self._display_settings.error_correction_max_time_point)
max_time_point=self._display_settings.error_correction_max_time_point,
min_divisions=self._display_settings.error_correction_min_divisions)
verified_lineages = set()
for position in positions:
if not links.contains_position(position):
Expand Down
2 changes: 1 addition & 1 deletion organoid_tracker/visualizer/position_list_visualizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def _draw_connections(self, links: Links, main_position: Position, line_style:st
def _show_image(self):
current_position = self._position_list[self._current_position_index]
time_point = current_position.time_point()
image_2d = self.load_image(time_point, int(current_position.z), self._display_settings.show_next_time_point)
image_2d = self.load_image(time_point, int(round(current_position.z)), self._display_settings.show_next_time_point)
if image_2d is not None:
offset = self._experiment.images.offsets.of_time_point(time_point)
extent = (offset.x, offset.x + image_2d.shape[1], offset.y + image_2d.shape[0], offset.y)
Expand Down

0 comments on commit 83f792f

Please sign in to comment.