fucciphase 0.0.1__py3-none-any.whl → 0.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fucciphase/__init__.py +7 -1
- fucciphase/__main__.py +12 -0
- fucciphase/fucci_phase.py +97 -51
- fucciphase/io.py +16 -12
- fucciphase/main_cli.py +263 -0
- fucciphase/napari/tracks_to_napari.py +14 -16
- fucciphase/phase.py +77 -74
- fucciphase/plot.py +238 -89
- fucciphase/sensor.py +31 -31
- fucciphase/tracking_utilities.py +63 -8
- fucciphase/utils/__init__.py +14 -1
- fucciphase/utils/checks.py +2 -5
- fucciphase/utils/dtw.py +2 -4
- fucciphase/utils/normalize.py +6 -8
- fucciphase/utils/simulator.py +1 -1
- fucciphase/utils/track_postprocessing.py +6 -8
- fucciphase/utils/trackmate.py +12 -12
- fucciphase-0.0.3.dist-info/METADATA +238 -0
- fucciphase-0.0.3.dist-info/RECORD +25 -0
- {fucciphase-0.0.1.dist-info → fucciphase-0.0.3.dist-info}/WHEEL +1 -1
- fucciphase-0.0.3.dist-info/entry_points.txt +3 -0
- fucciphase-0.0.1.dist-info/METADATA +0 -137
- fucciphase-0.0.1.dist-info/RECORD +0 -22
- {fucciphase-0.0.1.dist-info → fucciphase-0.0.3.dist-info}/licenses/LICENSE +0 -0
fucciphase/tracking_utilities.py
CHANGED
|
@@ -4,7 +4,30 @@ import pandas as pd
|
|
|
4
4
|
def get_feature_value_at_frame(
|
|
5
5
|
labels: pd.DataFrame, label_name: str, label: int, feature: str
|
|
6
6
|
) -> float:
|
|
7
|
-
"""
|
|
7
|
+
"""
|
|
8
|
+
Helper function to get the value of a feature for a given label.
|
|
9
|
+
|
|
10
|
+
Parameters
|
|
11
|
+
----------
|
|
12
|
+
labels : pandas.DataFrame
|
|
13
|
+
Dataframe containing at least the label and feature columns.
|
|
14
|
+
label_name : str
|
|
15
|
+
Column name containing label identifiers.
|
|
16
|
+
label : int
|
|
17
|
+
Label value to select.
|
|
18
|
+
feature : str
|
|
19
|
+
Column name of the feature whose value should be returned.
|
|
20
|
+
|
|
21
|
+
Returns
|
|
22
|
+
-------
|
|
23
|
+
float
|
|
24
|
+
The feature value corresponding to the specified label.
|
|
25
|
+
|
|
26
|
+
Raises
|
|
27
|
+
------
|
|
28
|
+
ValueError
|
|
29
|
+
If zero or multiple rows match the requested label.
|
|
30
|
+
"""
|
|
8
31
|
value = labels[labels[label_name] == label, feature].to_numpy()
|
|
9
32
|
assert len(value) == 1
|
|
10
33
|
return float(value[0])
|
|
@@ -18,21 +41,53 @@ def prepare_penalty_df(
|
|
|
18
41
|
label_name: str = "LABEL",
|
|
19
42
|
weight: float = 1.0,
|
|
20
43
|
) -> pd.DataFrame:
|
|
21
|
-
"""Prepare a
|
|
44
|
+
"""Prepare a dataframe with penalties for tracking.
|
|
45
|
+
|
|
46
|
+
This function is intended to construct a cost / penalty matrix for
|
|
47
|
+
linking detections between consecutive frames, inspired by the
|
|
48
|
+
formulations used in LapTrack and TrackMate.
|
|
22
49
|
|
|
23
50
|
Notes
|
|
24
51
|
-----
|
|
25
52
|
See more details here:
|
|
26
|
-
https://laptrack.readthedocs.io/en/stable/examples/custom_metric.html
|
|
53
|
+
- https://laptrack.readthedocs.io/en/stable/examples/custom_metric.html
|
|
54
|
+
- https://imagej.net/plugins/trackmate/trackers/lap-trackers#calculating-linking-costs
|
|
27
55
|
|
|
28
|
-
The penalty formulation is
|
|
29
|
-
see
|
|
30
|
-
https://imagej.net/plugins/trackmate/trackers/lap-trackers#calculating-linking-costs
|
|
31
|
-
The penalty is computed as:
|
|
56
|
+
The intended penalty formulation is:
|
|
32
57
|
P = 1 + sum(feature_penalties)
|
|
33
|
-
|
|
58
|
+
with each feature penalty of the form:
|
|
34
59
|
p = 3 * weight * abs(f1 - f2) / (f1 + f2)
|
|
35
60
|
|
|
61
|
+
**Current status:** this function is not yet stably implemented and will
|
|
62
|
+
raise ``NotImplementedError`` if called. The prototype implementation
|
|
63
|
+
below is kept for future development.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
df : pandas.DataFrame
|
|
68
|
+
Dataframe containing at least frame, label and feature columns.
|
|
69
|
+
feature_1 : str
|
|
70
|
+
Name of the first feature to use in the penalty.
|
|
71
|
+
feature_2 : str
|
|
72
|
+
Name of the second feature to use in the penalty.
|
|
73
|
+
frame_name : str, optional
|
|
74
|
+
Column name for frame indices. Default is ``"FRAME"``.
|
|
75
|
+
label_name : str, optional
|
|
76
|
+
Column name for object labels. Default is ``"LABEL"``.
|
|
77
|
+
weight : float, optional
|
|
78
|
+
Global scaling factor for feature penalties. Default is 1.0.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
pandas.DataFrame
|
|
83
|
+
Prototype would return a dataframe indexed by (frame, label1, label2)
|
|
84
|
+
with a ``penalty`` column.
|
|
85
|
+
|
|
86
|
+
Raises
|
|
87
|
+
------
|
|
88
|
+
NotImplementedError
|
|
89
|
+
This function is currently not stable and is intentionally disabled.
|
|
90
|
+
|
|
36
91
|
"""
|
|
37
92
|
raise NotImplementedError("This function is not yet stably implemented.")
|
|
38
93
|
|
fucciphase/utils/__init__.py
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""
|
|
2
|
+
Convenience functions for fucciphase - Utility submodule for FUCCIphase.
|
|
3
|
+
|
|
4
|
+
This package collects helper functions used throughout FUCCIphase, including:
|
|
5
|
+
- TrackMate XML parsing and rewriting
|
|
6
|
+
- Channel normalization
|
|
7
|
+
- Track splitting and postprocessing
|
|
8
|
+
- Motility and lineage visualizations
|
|
9
|
+
- Synthetic data generation
|
|
10
|
+
- DTW time-distortion utilities
|
|
11
|
+
|
|
12
|
+
Everything listed in ``__all__`` is considered part of the public FUCCIphase API.
|
|
13
|
+
|
|
14
|
+
"""
|
|
2
15
|
|
|
3
16
|
__all__ = [
|
|
4
17
|
"TrackMateXML",
|
fucciphase/utils/checks.py
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def check_channels(n_fluorophores: int, channels: List[str]) -> None:
|
|
1
|
+
def check_channels(n_fluorophores: int, channels: list[str]) -> None:
|
|
5
2
|
"""Check number of channels."""
|
|
6
3
|
if len(channels) != n_fluorophores:
|
|
7
4
|
raise ValueError(f"Need to provide {n_fluorophores} channel names.")
|
|
8
5
|
|
|
9
6
|
|
|
10
|
-
def check_thresholds(n_fluorophores: int, thresholds:
|
|
7
|
+
def check_thresholds(n_fluorophores: int, thresholds: list[float]) -> None:
|
|
11
8
|
"""Check correct format and range of thresholds."""
|
|
12
9
|
if len(thresholds) != n_fluorophores:
|
|
13
10
|
raise ValueError("Provide one threshold per channel.")
|
fucciphase/utils/dtw.py
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
from typing import List, Union
|
|
2
|
-
|
|
3
1
|
import numpy as np
|
|
4
2
|
|
|
5
3
|
|
|
6
4
|
def get_time_distortion_coefficient(
|
|
7
|
-
path:
|
|
5
|
+
path: np.ndarray | list[list[float]],
|
|
8
6
|
) -> tuple[np.ndarray, float, int, int]:
|
|
9
7
|
"""Compute distortion coefficient from warping path.
|
|
10
8
|
|
|
@@ -20,7 +18,7 @@ def get_time_distortion_coefficient(
|
|
|
20
18
|
lmbd = np.zeros(len(path) - 1)
|
|
21
19
|
alpha = 0
|
|
22
20
|
beta = 0
|
|
23
|
-
p:
|
|
21
|
+
p: np.ndarray | list[float]
|
|
24
22
|
for idx, p in enumerate(path):
|
|
25
23
|
# first index is skipped
|
|
26
24
|
if idx == 0:
|
fucciphase/utils/normalize.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import List, Optional, Tuple, Union
|
|
2
|
-
|
|
3
1
|
import numpy as np
|
|
4
2
|
import pandas as pd
|
|
5
3
|
from scipy import signal
|
|
@@ -37,7 +35,7 @@ def get_avg_channel_name(channel: str) -> str:
|
|
|
37
35
|
return f"{channel}_AVG"
|
|
38
36
|
|
|
39
37
|
|
|
40
|
-
def norm(vector:
|
|
38
|
+
def norm(vector: pd.Series | np.ndarray) -> pd.Series | np.ndarray:
|
|
41
39
|
"""Normalize a vector by subtracting the min and dividing by (max - min).
|
|
42
40
|
|
|
43
41
|
Parameters
|
|
@@ -63,13 +61,13 @@ def norm(vector: Union[pd.Series, np.ndarray]) -> Union[pd.Series, np.ndarray]:
|
|
|
63
61
|
# flake8: noqa: C901
|
|
64
62
|
def normalize_channels(
|
|
65
63
|
df: pd.DataFrame,
|
|
66
|
-
channels:
|
|
64
|
+
channels: str | list[str],
|
|
67
65
|
use_moving_average: bool = True,
|
|
68
66
|
moving_average_window: int = 7,
|
|
69
|
-
manual_min:
|
|
70
|
-
manual_max:
|
|
67
|
+
manual_min: list[float] | None = None,
|
|
68
|
+
manual_max: list[float] | None = None,
|
|
71
69
|
track_id_name: str = "TRACK_ID",
|
|
72
|
-
) ->
|
|
70
|
+
) -> list[str]:
|
|
73
71
|
"""Normalize channels, add in place the resulting columns to the
|
|
74
72
|
dataframe, and return the new columns' name.
|
|
75
73
|
|
|
@@ -173,7 +171,7 @@ def smooth_track(
|
|
|
173
171
|
channel: str,
|
|
174
172
|
track_id_name: str,
|
|
175
173
|
moving_average_window: int = 7,
|
|
176
|
-
) ->
|
|
174
|
+
) -> tuple[pd.Index, np.ndarray]:
|
|
177
175
|
"""Smooth intensity in one channel for a single track.
|
|
178
176
|
|
|
179
177
|
Parameters
|
fucciphase/utils/simulator.py
CHANGED
|
@@ -47,7 +47,7 @@ def simulate_single_track(track_id: float = 42, mean: float = 0.5) -> pd.DataFra
|
|
|
47
47
|
pd.DataFrame
|
|
48
48
|
Dataframe mocking a Trackmate single track import.
|
|
49
49
|
"""
|
|
50
|
-
#
|
|
50
|
+
# examples data
|
|
51
51
|
phase_percentages = [33.3, 33.3, 33.3]
|
|
52
52
|
center = [20.0, 55.0, 70.0, 95.0]
|
|
53
53
|
sigma = [5.0, 5.0, 10.0, 1.0]
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import List, Optional
|
|
2
|
-
|
|
3
1
|
import matplotlib.pyplot as plt
|
|
4
2
|
import numpy as np
|
|
5
3
|
import pandas as pd
|
|
@@ -157,7 +155,7 @@ def compute_motility_parameters(
|
|
|
157
155
|
|
|
158
156
|
|
|
159
157
|
def compute_displacements(
|
|
160
|
-
centroids_x: np.ndarray, centroids_y: np.ndarray, centroids_z:
|
|
158
|
+
centroids_x: np.ndarray, centroids_y: np.ndarray, centroids_z: np.ndarray | None
|
|
161
159
|
) -> np.ndarray:
|
|
162
160
|
"""Compute displacement w.r.t origin."""
|
|
163
161
|
N = len(centroids_x)
|
|
@@ -180,7 +178,7 @@ def compute_displacements(
|
|
|
180
178
|
|
|
181
179
|
|
|
182
180
|
def compute_velocities(
|
|
183
|
-
centroids_x: np.ndarray, centroids_y: np.ndarray, centroids_z:
|
|
181
|
+
centroids_x: np.ndarray, centroids_y: np.ndarray, centroids_z: np.ndarray | None
|
|
184
182
|
) -> np.ndarray:
|
|
185
183
|
"""Compute velocity."""
|
|
186
184
|
N = len(centroids_x)
|
|
@@ -205,7 +203,7 @@ def compute_velocities(
|
|
|
205
203
|
|
|
206
204
|
|
|
207
205
|
def compute_MSD(
|
|
208
|
-
centroids_x: np.ndarray, centroids_y: np.ndarray, centroids_z:
|
|
206
|
+
centroids_x: np.ndarray, centroids_y: np.ndarray, centroids_z: np.ndarray | None
|
|
209
207
|
) -> np.ndarray:
|
|
210
208
|
"""Compute mean-squared distance.
|
|
211
209
|
|
|
@@ -357,9 +355,9 @@ def split_trackmate_tracks(
|
|
|
357
355
|
def export_lineage_tree_to_svg(
|
|
358
356
|
df: pd.DataFrame,
|
|
359
357
|
trackmate_file: str,
|
|
360
|
-
node_color_column:
|
|
361
|
-
stroke_width:
|
|
362
|
-
) ->
|
|
358
|
+
node_color_column: str | None = None,
|
|
359
|
+
stroke_width: float | None = None,
|
|
360
|
+
) -> list[str]:
|
|
363
361
|
"""Write a lineage tree colored by FUCCI phases.
|
|
364
362
|
|
|
365
363
|
Parameters
|
fucciphase/utils/trackmate.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import re
|
|
2
2
|
import xml.etree.ElementTree as et
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
import pandas as pd
|
|
@@ -46,7 +46,7 @@ class TrackMateXML:
|
|
|
46
46
|
List of all features in the xml file, and whether they are integer features.
|
|
47
47
|
"""
|
|
48
48
|
|
|
49
|
-
def __init__(self, xml_path:
|
|
49
|
+
def __init__(self, xml_path: str | Path) -> None:
|
|
50
50
|
"""Initialize the TrackMateXML object.
|
|
51
51
|
|
|
52
52
|
The xml file is parsed and the model and all spots are imported.
|
|
@@ -61,12 +61,12 @@ class TrackMateXML:
|
|
|
61
61
|
self._root: et.Element | Any = self._tree.getroot()
|
|
62
62
|
|
|
63
63
|
# placeholders
|
|
64
|
-
self._model:
|
|
65
|
-
self._allspots:
|
|
64
|
+
self._model: et.Element | None = None
|
|
65
|
+
self._allspots: et.Element | None = None
|
|
66
66
|
|
|
67
67
|
self.nspots: int = 0 # number of spots
|
|
68
|
-
self.features:
|
|
69
|
-
self.spot_features:
|
|
68
|
+
self.features: dict[str, type] = {} # features and their types
|
|
69
|
+
self.spot_features: list[str] = [] # list of spot features
|
|
70
70
|
|
|
71
71
|
# import model and all spots
|
|
72
72
|
self._import_data()
|
|
@@ -74,7 +74,7 @@ class TrackMateXML:
|
|
|
74
74
|
def _get_spot_features(self) -> None:
|
|
75
75
|
"""Get the spot features from the tree."""
|
|
76
76
|
if self._allspots is not None:
|
|
77
|
-
spot_features:
|
|
77
|
+
spot_features: list[str] = []
|
|
78
78
|
for frame in self._allspots:
|
|
79
79
|
for spot in frame:
|
|
80
80
|
spot_features.extend(spot.attrib.keys())
|
|
@@ -249,7 +249,7 @@ class TrackMateXML:
|
|
|
249
249
|
for feature in new_features:
|
|
250
250
|
spot.attrib[feature] = str(spot_df[feature].values[0])
|
|
251
251
|
|
|
252
|
-
def save_xml(self, xml_path:
|
|
252
|
+
def save_xml(self, xml_path: str | Path) -> None:
|
|
253
253
|
"""Save the xml file.
|
|
254
254
|
|
|
255
255
|
Parameters
|
|
@@ -262,12 +262,12 @@ class TrackMateXML:
|
|
|
262
262
|
|
|
263
263
|
def get_full_tracks(
|
|
264
264
|
df: pd.DataFrame,
|
|
265
|
-
channels:
|
|
265
|
+
channels: list[str],
|
|
266
266
|
track_id_name: str = "UNIQUE_TRACK_ID",
|
|
267
267
|
spot_name: str = "name",
|
|
268
268
|
frame_name: str = "FRAME",
|
|
269
269
|
min_length: int = 40,
|
|
270
|
-
) ->
|
|
270
|
+
) -> tuple[list[pd.DataFrame], list[pd.DataFrame]]:
|
|
271
271
|
"""Locate all tracks that may describe a full cycle.
|
|
272
272
|
Tracks need to be auto-named by TrackMate.
|
|
273
273
|
For example, Track_1a, Track_1aa, Track_1b etc.
|
|
@@ -275,8 +275,8 @@ class TrackMateXML:
|
|
|
275
275
|
In addition, tracks longer than a certain minimum length can be selected.
|
|
276
276
|
"""
|
|
277
277
|
regex = "Track_[0-9]+.[a-z]+"
|
|
278
|
-
candidate_tracks:
|
|
279
|
-
save_tracks:
|
|
278
|
+
candidate_tracks: list[pd.DataFrame] = []
|
|
279
|
+
save_tracks: list[pd.DataFrame] = []
|
|
280
280
|
track_ids = df[track_id_name].unique()
|
|
281
281
|
for track_id in track_ids:
|
|
282
282
|
track = df[df[track_id_name] == track_id]
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fucciphase
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: Cell cycle analysis plugin.
|
|
5
|
+
Project-URL: homepage, https://github.com/nobias-ht/fucciphase
|
|
6
|
+
Project-URL: repository, https://github.com/nobias-ht/fucciphase
|
|
7
|
+
Author-email: Joran Deschamps <joran.deschamps@fht.org>
|
|
8
|
+
License: BSD-3-Clause
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Requires-Python: >=3.8
|
|
19
|
+
Requires-Dist: dtaidistance
|
|
20
|
+
Requires-Dist: lineagetree<1.5.0
|
|
21
|
+
Requires-Dist: matplotlib
|
|
22
|
+
Requires-Dist: monotonic-derivative
|
|
23
|
+
Requires-Dist: numpy
|
|
24
|
+
Requires-Dist: openpyxl
|
|
25
|
+
Requires-Dist: pandas
|
|
26
|
+
Requires-Dist: scipy
|
|
27
|
+
Requires-Dist: svgwrite
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: ipython; extra == 'dev'
|
|
30
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
31
|
+
Requires-Dist: pdbpp; extra == 'dev'
|
|
32
|
+
Requires-Dist: pre-commit; extra == 'dev'
|
|
33
|
+
Requires-Dist: rich; extra == 'dev'
|
|
34
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
35
|
+
Provides-Extra: doc
|
|
36
|
+
Requires-Dist: sphinx; extra == 'doc'
|
|
37
|
+
Provides-Extra: jupyter
|
|
38
|
+
Requires-Dist: jupyter; extra == 'jupyter'
|
|
39
|
+
Provides-Extra: napari
|
|
40
|
+
Requires-Dist: bioio; extra == 'napari'
|
|
41
|
+
Requires-Dist: bioio-ome-tiff; extra == 'napari'
|
|
42
|
+
Requires-Dist: bioio-tifffile; extra == 'napari'
|
|
43
|
+
Requires-Dist: napari; extra == 'napari'
|
|
44
|
+
Provides-Extra: test
|
|
45
|
+
Requires-Dist: pytest; extra == 'test'
|
|
46
|
+
Requires-Dist: pytest-cov; extra == 'test'
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
# fucciphase
|
|
50
|
+
|
|
51
|
+
[](https://github.com/Synthetic-Physiology-Lab/fucciphase/raw/main/LICENSE)
|
|
52
|
+
[](https://pypi.org/project/fucciphase)
|
|
53
|
+
[](https://python.org)
|
|
54
|
+
[](https://github.com/Synthetic-Physiology-Lab/fucciphase/actions/workflows/ci.yml)
|
|
55
|
+
[](https://codecov.io/gh/Synthetic-Physiology-Lab/fucciphase)
|
|
56
|
+
[](https://results.pre-commit.ci/latest/github/Synthetic-Physiology-Lab/fucciphase/main)
|
|
57
|
+
|
|
58
|
+
FUCCI cell cycle analysis plugin. Obtain cell cycle information from FUCCI fluorescence intensities.
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
The best way to run fucciphase is to install it in a virtual conda environment.
|
|
62
|
+
Make sure that git is installed and can be called from the command line.
|
|
63
|
+
|
|
64
|
+
To install from pip:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install fucciphase
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
If you wish to install it from source:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git clone https://github.com/Synthetic-Physiology-Lab/fucciphase
|
|
74
|
+
cd fucciphase
|
|
75
|
+
pip install -e .
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The installation should not take longer than a few seconds (depending on your internet connection).
|
|
79
|
+
|
|
80
|
+
A minimal environment for running the [notebooks](examples/notebooks) can be set up with:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install fucciphase jupyter matplotlib pandas
|
|
84
|
+
````
|
|
85
|
+
|
|
86
|
+
### Install Napari + movie reading support (optional)
|
|
87
|
+
|
|
88
|
+
FUCCIphase does not install Napari by default. For .ome.tif visualisation, install:
|
|
89
|
+
```bash
|
|
90
|
+
pip install napari bioio bioio-ome-tiff bioio-tifffile
|
|
91
|
+
```
|
|
92
|
+
or, if installing from source with extras:
|
|
93
|
+
```bash
|
|
94
|
+
pip install -e ".[napari]"
|
|
95
|
+
```
|
|
96
|
+
---
|
|
97
|
+
## What’s Inside This Repository
|
|
98
|
+
|
|
99
|
+
This repository is organized to support both **analysis workflows** and **reproducible usage examples** of FUCCIphase.
|
|
100
|
+
If you're new to the tool, this is where to start.
|
|
101
|
+
|
|
102
|
+
### 1 — `examples/notebooks/` [📁 notebooks](examples/notebooks)
|
|
103
|
+
|
|
104
|
+
Interactive Jupyter workflows demonstrating how to use FUCCIphase in practical scenarios.
|
|
105
|
+
|
|
106
|
+
| Notebook | Purpose |
|
|
107
|
+
| ---------------------------------- |----------------------------------------------------------------|
|
|
108
|
+
| `extract_calibration_data.ipynb` | Convert raw movies + TrackMate XML into FUCCI reference curves |
|
|
109
|
+
| `sensor_calibration.ipynb` | Build a FUCCI sensor model from calibration traces |
|
|
110
|
+
| `getting_started.ipynb` | Minimal end-to-end example of FUCCIphase usage |
|
|
111
|
+
| `example_estimated.ipynb` | Visualize fucciphase output tables |
|
|
112
|
+
| `percentage_reconstruction.ipynb` | Smooth and reconstruct %phase trajectories |
|
|
113
|
+
| `example_reconstruction.ipynb` | Recover incomplete/noisy fluorescence traces |
|
|
114
|
+
| `example_simulated.ipynb` | Generate synthetic FUCCI signals for testing |
|
|
115
|
+
| `color-tails-by-percentage.ipynb` | Visualize population-level phase composition |
|
|
116
|
+
| `explanation-dtw-alignment.ipynb` | How DTW alignment works internally |
|
|
117
|
+
| `phaselocking-workflow-lazy.ipynb` | Scalable phase-locking for large datasets |
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
### 2 — `examples/reproducibility/` [📁 reproducibility](examples/reproducibility)
|
|
121
|
+
|
|
122
|
+
This is a minimal workflow that uses the sample data. Navigate to the reproducibility directory, then run the following command in one step:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
fucciphase inputs/merged_linked.ome.xml `
|
|
126
|
+
-ref ../example_data/hacat_fucciphase_reference.csv `
|
|
127
|
+
-dt 0.25 `
|
|
128
|
+
-m MEAN_INTENSITY_CH1 `
|
|
129
|
+
-c MEAN_INTENSITY_CH2 `
|
|
130
|
+
--generate_unique_tracks true `
|
|
131
|
+
```
|
|
132
|
+
and to visualize results in napari:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
fucciphase-napari outputs/merged_linked.ome_processed.csv inputs/downscaled_hacat.ome.tif -m 0 -c 1 -s 2 --pixel_size 0.544
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Below a preview of the output generated by the reproducibility workflow:
|
|
139
|
+
|
|
140
|
+
[](outputs/video_downscaled_hacat.mp4)
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### 3 — `examples/example_data/` [📁 example_data](examples/example_data)
|
|
145
|
+
|
|
146
|
+
Reference-style FUCCI datasets used for **calibration & sensor building**.
|
|
147
|
+
|
|
148
|
+
Includes:
|
|
149
|
+
|
|
150
|
+
| File | Meaning |
|
|
151
|
+
| ------------------ | ------------------------------------------------- |
|
|
152
|
+
| `*_reference.csv` | FUCCI calibration traces used to learn the sensor |
|
|
153
|
+
| `*.json` | Saved sensor models usable via CLI or notebooks |
|
|
154
|
+
|
|
155
|
+
Use this folder if you want to train your own sensor or understand expected input format.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
## Basic usage
|
|
159
|
+
|
|
160
|
+
Fucci phase currently supports loading a
|
|
161
|
+
[TrackMate](https://imagej.net/plugins/trackmate/) XML file:
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from fucciphase import process_trackmate
|
|
165
|
+
from fucciphase.sensor import get_fuccisa_default_sensor
|
|
166
|
+
|
|
167
|
+
trackmate_xml = "path/to/trackmate.xml"
|
|
168
|
+
channel1 = "MEAN_INTENSITY_CH3"
|
|
169
|
+
channel2 = "MEAN_INTENSITY_CH4"
|
|
170
|
+
|
|
171
|
+
sensor = get_fuccisa_default_sensor()
|
|
172
|
+
|
|
173
|
+
df = process_trackmate(trackmate_xml,
|
|
174
|
+
channels=[channel1, channel2],
|
|
175
|
+
sensor=sensor,
|
|
176
|
+
thresholds=[0.1, 0.1])
|
|
177
|
+
print(df)
|
|
178
|
+
```
|
|
179
|
+
The TrackMate XML is converted to a [Pandas](https://pandas.pydata.org/) DataFrame.
|
|
180
|
+
Thus, in general data (e.g., stored in a CSV or XLSX file) that can be parsed into
|
|
181
|
+
a DataFrame is supported.
|
|
182
|
+
|
|
183
|
+
The runtime of the scripts depends on your datasize. 2D samples with a few hundred to a few thousand cells
|
|
184
|
+
can be processed in a few minutes. Visualization in Napari can take a bit longer.
|
|
185
|
+
Standard processing does not require a powerful computer.
|
|
186
|
+
Make sure that you have sufficient RAM to load videos for visualization in Napari.
|
|
187
|
+
|
|
188
|
+
### Using your own data
|
|
189
|
+
|
|
190
|
+
To process your own dataset:
|
|
191
|
+
|
|
192
|
+
1. Export tracking from Fiji/TrackMate as `.xml`
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
2. Build a reference CSV (minimum one full cell cycle):
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
percentage, time, cyan, magenta
|
|
199
|
+
```
|
|
200
|
+
For reference, check the example files available in the `example_data` folder.
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
3. Run:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
fucciphase your_tracks.xml -ref your_reference.csv -dt <your timestep> -m <ch1> -c <ch2>
|
|
207
|
+
```
|
|
208
|
+
4. Visualize with:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
fucciphase-napari your_tracks_processed.csv your_video.ome.tif -m <ch1> -c <ch2> -s <mask>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
## Development
|
|
216
|
+
|
|
217
|
+
To develop fucciphase, clone the repository, install fucciphase in your environment
|
|
218
|
+
and install the pre-commit hooks:
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
git clone https://github.com/Synthetic-Physiology-Lab/fucciphase
|
|
222
|
+
cd fucciphase
|
|
223
|
+
pip install -e ".[test, dev]"
|
|
224
|
+
pre-commit install
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
If you want to build the documentation, replace the abovementioned pip install by:
|
|
228
|
+
```bash
|
|
229
|
+
pip install -e ".[test, dev, doc]"
|
|
230
|
+
```
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Cite us
|
|
234
|
+
|
|
235
|
+
Di Sante, M., Pezzotti, M., Zimmermann, J., Enrico, A., Deschamps, J., Balmas, E.,
|
|
236
|
+
Becca, S., Solito, S., Reali, A., Bertero, A., Jug, F. and Pasqualini, F.S., 2025.
|
|
237
|
+
CALIPERS: Cell cycle-aware live imaging for phenotyping experiments and regeneration studies.
|
|
238
|
+
bioRxiv, https://doi.org/10.1101/2024.12.19.629259
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
fucciphase/__init__.py,sha256=HkyHcSzLlTlEIz7E3bvuINGBqfnIL0s6oPU0EE_pQCs,545
|
|
2
|
+
fucciphase/__main__.py,sha256=lXUDkaeNRAZep5O7dNLj9RY4EclpPolruAll0FFC_jo,298
|
|
3
|
+
fucciphase/fucci_phase.py,sha256=aR50chW5JAs-56R2vezINnMX_QkNT1nwGgqYLVreDVQ,8237
|
|
4
|
+
fucciphase/io.py,sha256=oleF2KmW5uE_cV2PQx5bTka1Aw69kLIO-200ZQpuiAQ,2038
|
|
5
|
+
fucciphase/main_cli.py,sha256=3wh32o91BV8J4309CxhN5tW--MOYgFId8eQWkCjdXg8,8958
|
|
6
|
+
fucciphase/phase.py,sha256=uZNMK7Odd07kNh8SbmsrZpTolEGdRBGE0o2sGbocZhw,17684
|
|
7
|
+
fucciphase/plot.py,sha256=E04VF7ejAUb8uC1pVRGxw7sS9A9_uaO51h6bVvu1aWc,24148
|
|
8
|
+
fucciphase/py.typed,sha256=esB4cHc6c07uVkGtqf8at7ttEnprwRxwk8obY8Qumq4,187
|
|
9
|
+
fucciphase/sensor.py,sha256=LSIVC0MfJncMjovUriAiFRTaEmEnClbjnsxqIgId6FQ,14714
|
|
10
|
+
fucciphase/tracking_utilities.py,sha256=vnjCFGS2vArnCuxBlw7852eN2Xhd-FIo63bVWkHV0Lo,4548
|
|
11
|
+
fucciphase/napari/__init__.py,sha256=At9Shk6HfDf6obtQaM0yKG4NOZVO6YxD2-J1M2ZGm7w,198
|
|
12
|
+
fucciphase/napari/tracks_to_napari.py,sha256=_Dknd1wwXj9VJzo3y8Ry6lgJni9VokfZWVq_z98RlfE,4039
|
|
13
|
+
fucciphase/utils/__init__.py,sha256=YwgK2COtG44QJaXHVPYKu2-Ifm6GIG1ahykvJ4pr-MM,1408
|
|
14
|
+
fucciphase/utils/checks.py,sha256=o4mMGJMIE5wlaf0jtblnTD4JGTfjc5W7ZS4tYDIPlLo,625
|
|
15
|
+
fucciphase/utils/dtw.py,sha256=6RJ5wZ8jDFKSVmcYajsdTJ4tfe3E-wKROEA2rWyGRN4,1638
|
|
16
|
+
fucciphase/utils/normalize.py,sha256=xaZ_1Mgw6fd3RouuYkfwRGKr4DimSwmVq-ghRcTxFpc,5964
|
|
17
|
+
fucciphase/utils/phase_fit.py,sha256=Ht_dEyuLYonv6is9qQ-Xd95pQR7IR-8C8mv0ckDcp4E,1743
|
|
18
|
+
fucciphase/utils/simulator.py,sha256=fV-Pj6APms3QbYmiD9TjEYYkTqkIWk0uKDLCpz36HmA,2323
|
|
19
|
+
fucciphase/utils/track_postprocessing.py,sha256=lv7TLBaGF4lOqlJUsl80rt1Igue2lM7WfmxIZXKwk3E,14388
|
|
20
|
+
fucciphase/utils/trackmate.py,sha256=rbgARawfefSmvaRjfzmYF_XWqUPDZnBQCgU1s9Ev_00,10612
|
|
21
|
+
fucciphase-0.0.3.dist-info/METADATA,sha256=YeQuzOiDo64ltvCliaWgk6H_OJJ1aCQnYufl4U1cSvQ,9018
|
|
22
|
+
fucciphase-0.0.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
23
|
+
fucciphase-0.0.3.dist-info/entry_points.txt,sha256=B77Cm5QnxeQz6DEfqD6n7zDw48-HrlepWPwLbdVITMY,119
|
|
24
|
+
fucciphase-0.0.3.dist-info/licenses/LICENSE,sha256=pQGrOGpOTwikEzkZ8Zc9XLQwbaZ85TMJP-GaWCNZciw,1554
|
|
25
|
+
fucciphase-0.0.3.dist-info/RECORD,,
|