LineageTree 1.8.0__py3-none-any.whl → 2.0.1__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.
- LineageTree/__init__.py +27 -2
- LineageTree/legacy/export_csv.py +70 -0
- LineageTree/legacy/to_lineajea.py +30 -0
- LineageTree/legacy/to_motile.py +36 -0
- LineageTree/lineageTree.py +2268 -1467
- LineageTree/lineageTreeManager.py +749 -70
- LineageTree/loaders.py +942 -864
- LineageTree/test/test_lineageTree.py +634 -0
- LineageTree/test/test_uted.py +233 -0
- LineageTree/tree_approximation.py +488 -0
- LineageTree/utils.py +103 -103
- {LineageTree-1.8.0.dist-info → lineagetree-2.0.1.dist-info}/METADATA +30 -34
- lineagetree-2.0.1.dist-info/RECORD +16 -0
- {LineageTree-1.8.0.dist-info → lineagetree-2.0.1.dist-info}/WHEEL +1 -1
- LineageTree/tree_styles.py +0 -334
- LineageTree-1.8.0.dist-info/RECORD +0 -11
- {LineageTree-1.8.0.dist-info → lineagetree-2.0.1.dist-info/licenses}/LICENSE +0 -0
- {LineageTree-1.8.0.dist-info → lineagetree-2.0.1.dist-info}/top_level.txt +0 -0
LineageTree/utils.py
CHANGED
@@ -1,122 +1,88 @@
|
|
1
|
-
import
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
pos=lT.pos[time_node],
|
32
|
-
score=1,
|
33
|
-
)
|
34
|
-
|
35
|
-
motile.add_cand_edges(fmt, max_dist, max_skip_frames=max_skip_frames)
|
36
|
-
|
37
|
-
return fmt
|
38
|
-
|
39
|
-
|
40
|
-
def write_csv_from_lT_to_lineaja(
|
41
|
-
lT, path_to, start: int = 0, finish: int = 300
|
42
|
-
):
|
43
|
-
csv_dict = {}
|
44
|
-
for time in range(start, finish):
|
45
|
-
for node in lT.time_nodes[time]:
|
46
|
-
csv_dict[node] = {"pos": lT.pos[node], "t": time}
|
47
|
-
with open(path_to, "w", newline="\n") as file:
|
48
|
-
fieldnames = [
|
49
|
-
"time",
|
50
|
-
"positions_x",
|
51
|
-
"positions_y",
|
52
|
-
"positions_z",
|
53
|
-
"id",
|
54
|
-
]
|
55
|
-
writer = csv.DictWriter(file, fieldnames=fieldnames)
|
56
|
-
writer.writeheader()
|
57
|
-
for node in csv_dict:
|
58
|
-
writer.writerow(
|
59
|
-
{
|
60
|
-
"time": csv_dict[node]["t"],
|
61
|
-
"positions_z": csv_dict[node]["pos"][0],
|
62
|
-
"positions_y": csv_dict[node]["pos"][1],
|
63
|
-
"positions_x": csv_dict[node]["pos"][2],
|
64
|
-
"id": node,
|
65
|
-
}
|
66
|
-
)
|
67
|
-
|
68
|
-
|
69
|
-
def create_links_and_cycles(lT: lineageTree, roots=None):
|
70
|
-
"""Generates a dictionary containing the links and the lengths of each branch.
|
71
|
-
Similar to simple tree, mainly used for tree manip app.
|
72
|
-
|
73
|
-
Args:
|
74
|
-
roots (Union[list,set,int]): The roots from which the tree will be generated.
|
75
|
-
|
76
|
-
Returns:
|
77
|
-
dict: A dictionary with keys "links" and "times" which contains the connections all cells and their branch
|
78
|
-
length.
|
1
|
+
from collections.abc import Iterable
|
2
|
+
|
3
|
+
from LineageTree import lineageTree, tree_approximation
|
4
|
+
|
5
|
+
|
6
|
+
def create_links_and_chains(
|
7
|
+
lT: lineageTree,
|
8
|
+
roots: int | Iterable | None = None,
|
9
|
+
end_time: int | None = None,
|
10
|
+
) -> dict[str, dict]:
|
11
|
+
"""Generates a dictionary containing all the edges (from start of lifetime to end not the intermediate timepoints)
|
12
|
+
of a subtree spawned by node/s and their duration
|
13
|
+
|
14
|
+
|
15
|
+
Parameters
|
16
|
+
----------
|
17
|
+
lT : lineageTree
|
18
|
+
The lineagetree that the user is working on
|
19
|
+
roots : int or Iterable, optional
|
20
|
+
The root/s from which the tree/s will be generated, if 'None' all the roots will be selected.
|
21
|
+
end_time : int, optional
|
22
|
+
The last timepoint to be considered, if 'None' the last timepoint of the dataset (t_e) is considered, by default None.
|
23
|
+
|
24
|
+
Returns
|
25
|
+
-------
|
26
|
+
dict mapping str to set or dict mapping int to list or int
|
27
|
+
A dictionary that contains:
|
28
|
+
- "links": The dictionary that contains the hierarchy of the nodes (only start and end of each chain)
|
29
|
+
- "times": The time distance between the start and the end of a chain
|
30
|
+
- "roots": The roots used
|
79
31
|
"""
|
80
32
|
if roots is None:
|
81
33
|
to_do = set(lT.roots)
|
82
|
-
elif isinstance(roots,
|
34
|
+
elif isinstance(roots, Iterable):
|
83
35
|
to_do = set(roots)
|
84
36
|
else:
|
85
37
|
to_do = {int(roots)}
|
38
|
+
if end_time is None:
|
39
|
+
end_time = lT.t_e
|
86
40
|
times = {}
|
87
41
|
links = {}
|
88
42
|
while to_do:
|
89
43
|
curr = to_do.pop()
|
90
|
-
cyc = lT.get_successors(curr)
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
44
|
+
cyc = lT.get_successors(curr, end_time=end_time)
|
45
|
+
if cyc[-1] != curr or lT.time[cyc[-1]] <= end_time:
|
46
|
+
last = cyc[-1]
|
47
|
+
times[curr] = len(cyc)
|
48
|
+
if last != curr:
|
49
|
+
links[curr] = [last]
|
50
|
+
else:
|
51
|
+
links[curr] = []
|
52
|
+
succ = lT._successor.get(last)
|
53
|
+
if succ:
|
54
|
+
times[cyc[-1]] = 0
|
55
|
+
to_do.update(succ)
|
101
56
|
links[last] = succ
|
102
57
|
return {"links": links, "times": times, "root": roots}
|
103
58
|
|
104
59
|
|
105
60
|
def hierarchical_pos(
|
106
61
|
lnks_tms: dict, root, width=1000, vert_gap=2, xcenter=0, ycenter=0
|
107
|
-
):
|
108
|
-
"""Calculates the position of each node on
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
62
|
+
) -> dict[int, list[float]] | None:
|
63
|
+
"""Calculates the position of each node on the tree graph.
|
64
|
+
|
65
|
+
Parameters
|
66
|
+
----------
|
67
|
+
lnks_tms : dict
|
68
|
+
a dictionary created by create_links_and_chains.
|
69
|
+
root : _type_
|
70
|
+
The id of the node, usually it exists inside lnks_tms dictionary, however you may use your own root.
|
71
|
+
width : int, optional
|
72
|
+
Max width, will not change the graph but interacting with the graph takes this distance into account, by default 1000
|
73
|
+
vert_gap : int, optional
|
74
|
+
How far downwards each timepoint will go, by default 2
|
75
|
+
xcenter : int, optional
|
76
|
+
Where the root will be placed on the x axis, by default 0
|
77
|
+
ycenter : int, optional
|
78
|
+
Where the root will be placed on the y axis, by default 0
|
79
|
+
|
80
|
+
Returns
|
81
|
+
-------
|
82
|
+
dict mapping int to list of float
|
83
|
+
Provides a dictionary that contains the id of each node as keys and its 2-d position on the
|
84
|
+
tree graph as values.
|
85
|
+
If the root requested does not exists, None is then returned
|
120
86
|
"""
|
121
87
|
to_do = [root]
|
122
88
|
if root not in lnks_tms["times"]:
|
@@ -152,3 +118,37 @@ def hierarchical_pos(
|
|
152
118
|
prev_width[curr] / 2,
|
153
119
|
)
|
154
120
|
return pos_node
|
121
|
+
|
122
|
+
|
123
|
+
def convert_style_to_number(
|
124
|
+
style: str | tree_approximation.TreeApproximationTemplate,
|
125
|
+
downsample: int | None,
|
126
|
+
) -> int:
|
127
|
+
"""Converts tree_style and downsampling to a single number.
|
128
|
+
|
129
|
+
Parameters
|
130
|
+
----------
|
131
|
+
style : str
|
132
|
+
the tree style
|
133
|
+
downsample : int
|
134
|
+
the downsampling factor
|
135
|
+
|
136
|
+
Returns
|
137
|
+
-------
|
138
|
+
int
|
139
|
+
A number which serves as ID if the tree style and downsampling used.
|
140
|
+
"""
|
141
|
+
style_dict = {
|
142
|
+
"full": 0,
|
143
|
+
"simple": -1,
|
144
|
+
"normalized_simple": -2,
|
145
|
+
"mini": -1000,
|
146
|
+
}
|
147
|
+
if style == "downsampled" and downsample is not None:
|
148
|
+
return downsample
|
149
|
+
elif not isinstance(style, str) and issubclass(
|
150
|
+
style, tree_approximation.TreeApproximationTemplate
|
151
|
+
):
|
152
|
+
return hash(style.__name__)
|
153
|
+
else:
|
154
|
+
return style_dict[style]
|
@@ -1,53 +1,49 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: LineageTree
|
3
|
-
Version:
|
4
|
-
Summary: Lineage
|
5
|
-
|
6
|
-
Author: Léo Guignard
|
7
|
-
|
8
|
-
License: MIT
|
9
|
-
Project-URL: Bug Tracker, https://github.com/
|
10
|
-
Project-URL: Documentation, https://github.com/
|
11
|
-
Project-URL: Source Code, https://github.com/
|
12
|
-
Project-URL: User Support, https://github.com/
|
13
|
-
Classifier: Development Status ::
|
3
|
+
Version: 2.0.1
|
4
|
+
Summary: Structure for Lineage Trees
|
5
|
+
Author: Giannis Liaskas, Christopher Mazzerbo
|
6
|
+
Author-email: Léo Guignard <leo.guignard@univ-amu.fr>
|
7
|
+
Maintainer-email: Léo Guignard <leo.guignard@univ-amu.fr>
|
8
|
+
License-Expression: MIT
|
9
|
+
Project-URL: Bug Tracker, https://github.com/GuignardLab/LineageTree/issues
|
10
|
+
Project-URL: Documentation, https://github.com/GuignardLab/LineageTree#README.md
|
11
|
+
Project-URL: Source Code, https://github.com/GuignardLab/LineageTree
|
12
|
+
Project-URL: User Support, https://github.com/GuignardLab/LineageTree/issues
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
14
14
|
Classifier: Intended Audience :: Developers
|
15
|
-
Classifier: License :: OSI Approved :: MIT License
|
16
15
|
Classifier: Operating System :: OS Independent
|
17
16
|
Classifier: Programming Language :: Python
|
18
17
|
Classifier: Programming Language :: Python :: 3
|
19
18
|
Classifier: Programming Language :: Python :: 3 :: Only
|
20
|
-
Classifier: Programming Language :: Python :: 3.8
|
21
|
-
Classifier: Programming Language :: Python :: 3.9
|
22
19
|
Classifier: Programming Language :: Python :: 3.10
|
23
|
-
Classifier:
|
24
|
-
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
23
|
+
Requires-Python: >=3.10
|
25
24
|
Description-Content-Type: text/markdown
|
26
25
|
License-File: LICENSE
|
27
26
|
Requires-Dist: scipy>=1.9
|
28
27
|
Requires-Dist: numpy>=1.23
|
29
28
|
Requires-Dist: mastodon-reader
|
30
29
|
Requires-Dist: matplotlib
|
31
|
-
|
32
|
-
Requires-Dist: svgwrite
|
33
|
-
|
30
|
+
Requires-Dist: edist
|
31
|
+
Requires-Dist: svgwrite
|
32
|
+
Provides-Extra: dev
|
33
|
+
Requires-Dist: pytest; extra == "dev"
|
34
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
35
|
+
Requires-Dist: tox; extra == "dev"
|
36
|
+
Requires-Dist: black; extra == "dev"
|
37
|
+
Requires-Dist: ruff; extra == "dev"
|
38
|
+
Requires-Dist: bumpver; extra == "dev"
|
39
|
+
Provides-Extra: doc
|
40
|
+
Requires-Dist: sphinx-rtd-theme; extra == "doc"
|
41
|
+
Requires-Dist: myst-parser; extra == "doc"
|
42
|
+
Requires-Dist: sphinx_book_theme; extra == "doc"
|
34
43
|
Provides-Extra: test
|
35
|
-
Requires-Dist: svgwrite; extra == "test"
|
36
|
-
Requires-Dist: matplotlib; extra == "test"
|
37
|
-
Requires-Dist: tox; extra == "test"
|
38
44
|
Requires-Dist: pytest; extra == "test"
|
39
45
|
Requires-Dist: pytest-cov; extra == "test"
|
40
|
-
|
41
|
-
Provides-Extra: treeedit
|
42
|
-
Requires-Dist: edist; extra == "treeedit"
|
43
|
-
Provides-Extra: all
|
44
|
-
Requires-Dist: svgwrite; extra == "all"
|
45
|
-
Requires-Dist: matplotlib; extra == "all"
|
46
|
-
Requires-Dist: tox; extra == "all"
|
47
|
-
Requires-Dist: pytest; extra == "all"
|
48
|
-
Requires-Dist: pytest-cov; extra == "all"
|
49
|
-
Requires-Dist: edist; extra == "all"
|
50
|
-
Requires-Dist: mastodon-reader; extra == "all"
|
46
|
+
Dynamic: license-file
|
51
47
|
|
52
48
|
# LineageTree
|
53
49
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
LineageTree/__init__.py,sha256=Mkxh44uNuGueMMHEnOWpEchFefwMS6rht_EqHShIYew,749
|
2
|
+
LineageTree/lineageTree.py,sha256=dWpGuQ_h4JMvTzOBaMg_dC4mkPwIR2Rb3EvDKowcVxM,125146
|
3
|
+
LineageTree/lineageTreeManager.py,sha256=25QWNbj3Ep7itQKd6LrddICG457BEp1DlfKWgVHlx5I,31753
|
4
|
+
LineageTree/loaders.py,sha256=rjLHSaukBI23oxndkqrkK_6UBjmzU4LUkr_lgOaZqvM,30189
|
5
|
+
LineageTree/tree_approximation.py,sha256=61Omn0gUaRiNTDcIucDM4DUPBW5voXRxCZQ0uYGRDSg,16170
|
6
|
+
LineageTree/utils.py,sha256=EOH2MGlBH3cFs8DVOX-3fJRwoj0ZmiE_nPkAjzWXK48,5124
|
7
|
+
LineageTree/legacy/export_csv.py,sha256=cJ1R3GCGEy9Oey73jbFhoKRGTonNbqg229fVnGm_FuU,2009
|
8
|
+
LineageTree/legacy/to_lineajea.py,sha256=iZyZTsrvWYHkGJ8npf91lQPrXPgKouiy7Zrywx5Lkkw,926
|
9
|
+
LineageTree/legacy/to_motile.py,sha256=4AC9BmGa-hpqt8_x6HTR_XqCrTERlKo9WwYHUFtheM0,860
|
10
|
+
LineageTree/test/test_lineageTree.py,sha256=d5uucokzE7OWQirsW7XxaGEgeRszQ5KICbAYhriXEQo,16492
|
11
|
+
LineageTree/test/test_uted.py,sha256=Vl7uNGZp57XUD3v3SHRJtXhb0Lte8mDjpOtEKp_dxt0,6496
|
12
|
+
lineagetree-2.0.1.dist-info/licenses/LICENSE,sha256=IKncNCNpq93Kq7Ywg1V4I9Bu_99VMK-mX1EJyjTKLyc,1068
|
13
|
+
lineagetree-2.0.1.dist-info/METADATA,sha256=UwtX1LWAG-s-7aaGkss_UTpourt3InBk5ab5x-4W4i0,4300
|
14
|
+
lineagetree-2.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
15
|
+
lineagetree-2.0.1.dist-info/top_level.txt,sha256=CCqPCTX76zPTEUagUgTWbLaZun8752n59iOOwfUlvxs,12
|
16
|
+
lineagetree-2.0.1.dist-info/RECORD,,
|
LineageTree/tree_styles.py
DELETED
@@ -1,334 +0,0 @@
|
|
1
|
-
import warnings
|
2
|
-
from abc import ABC, abstractmethod
|
3
|
-
from enum import Enum
|
4
|
-
|
5
|
-
import numpy as np
|
6
|
-
|
7
|
-
from LineageTree import lineageTree
|
8
|
-
|
9
|
-
|
10
|
-
class abstract_trees(ABC):
|
11
|
-
"""Template class to produce different techniques to comapare lineageTrees.
|
12
|
-
To add a new technique you need to iherit this class or one of its children
|
13
|
-
and add them to the tree_style enum.
|
14
|
-
For a class to be valid you need a
|
15
|
-
- tree constructor (get_tree) that produces one dictionary that contains
|
16
|
-
arbitary unique labels and one dictionary that contains the duration of each node.
|
17
|
-
- delta function: A function that handles the cost of comparing nodes to each other.
|
18
|
-
- normalization function, a function that returns the length of the tree or any interger.
|
19
|
-
"""
|
20
|
-
|
21
|
-
def __init__(
|
22
|
-
self,
|
23
|
-
lT: lineageTree,
|
24
|
-
root: int,
|
25
|
-
downsample: int,
|
26
|
-
end_time: int = None,
|
27
|
-
time_scale: int = 1,
|
28
|
-
):
|
29
|
-
self.lT: lineageTree = lT
|
30
|
-
self.root: int = root
|
31
|
-
self.downsample: int = downsample
|
32
|
-
self.end_time: int = end_time if end_time else self.lT.t_e
|
33
|
-
self.time_scale: int = int(time_scale) if time_scale else 1
|
34
|
-
if time_scale <= 0:
|
35
|
-
raise Exception("Please used a valid time_scale (Larger than 0)")
|
36
|
-
self.tree: tuple = self.get_tree()
|
37
|
-
self.edist = self._edist_format(self.tree[0])
|
38
|
-
|
39
|
-
@abstractmethod
|
40
|
-
def get_tree(self):
|
41
|
-
"""
|
42
|
-
Get a tree version of the tree spawned by the node `r`
|
43
|
-
|
44
|
-
Args:
|
45
|
-
r (int): root of the tree to spawn
|
46
|
-
end_time (int): the last time point to consider
|
47
|
-
time_resolution (float): the time between two consecutive time points
|
48
|
-
|
49
|
-
Returns:
|
50
|
-
(dict) {m (int): [d1 (int), d2 (int)]}: an adjacency dictionnary
|
51
|
-
where the ids are the ids of the cells in the original tree
|
52
|
-
at their first time point (except for the cell `r` if it was
|
53
|
-
not the first time point).
|
54
|
-
(dict) {m (int): duration (float)}: life time duration of the cell `m`
|
55
|
-
"""
|
56
|
-
|
57
|
-
@abstractmethod
|
58
|
-
def delta(self, x, y, corres1, corres2, times1, times2):
|
59
|
-
"""The distance of two nodes inside a tree. Behaves like a staticmethod.
|
60
|
-
The corres1/2 and time1/2 should always be provided and will be handled accordingly by the specific
|
61
|
-
delta of each tree style.
|
62
|
-
|
63
|
-
Args:
|
64
|
-
x (int): The first node to compare, takes the names provided by the edist.
|
65
|
-
y (int): The second node to compare, takes the names provided by the edist
|
66
|
-
corres1 (dict): Correspondance between node1 and its name in the real tree.
|
67
|
-
corres2 (dict): Correspondance between node2 and its name in the real tree.
|
68
|
-
times1 (dict): The dictionary of the branch lengths of the tree that n1 is spawned from.
|
69
|
-
times2 (dict): The dictionary of the branch lengths of the tree that n2 is spawned from.
|
70
|
-
|
71
|
-
Returns:
|
72
|
-
(int|float): The diatance between these 2 nodes.
|
73
|
-
"""
|
74
|
-
if x is None and y is None:
|
75
|
-
return 0
|
76
|
-
if x is None:
|
77
|
-
return times2[corres2[y]]
|
78
|
-
if y is None:
|
79
|
-
return times1[corres1[x]]
|
80
|
-
len_x = times1[corres1[x]]
|
81
|
-
len_y = times2[corres2[y]]
|
82
|
-
return np.abs(len_x - len_y)
|
83
|
-
|
84
|
-
@abstractmethod
|
85
|
-
def get_norm(self):
|
86
|
-
"""
|
87
|
-
Returns the valid value for normalizing the edit distance.
|
88
|
-
Returns:
|
89
|
-
(int|float): The number of nodes of each tree according to each style.
|
90
|
-
"""
|
91
|
-
|
92
|
-
def _edist_format(self, adj_dict: dict):
|
93
|
-
"""Formating the custom tree style to the format needed by edist.
|
94
|
-
SHOULD NOT BE CHANGED.
|
95
|
-
|
96
|
-
Args:
|
97
|
-
adj_dict (dict): _description_
|
98
|
-
|
99
|
-
Returns:
|
100
|
-
_type_: _description_
|
101
|
-
"""
|
102
|
-
inv_adj = {vi: k for k, v in adj_dict.items() for vi in v}
|
103
|
-
roots = set(adj_dict).difference(inv_adj)
|
104
|
-
nid2list = {}
|
105
|
-
list2nid = {}
|
106
|
-
nodes = []
|
107
|
-
adj_list = []
|
108
|
-
curr_id = 0
|
109
|
-
for r in roots:
|
110
|
-
to_do = [r]
|
111
|
-
while to_do:
|
112
|
-
curr = to_do.pop(0)
|
113
|
-
nid2list[curr] = curr_id
|
114
|
-
list2nid[curr_id] = curr
|
115
|
-
nodes.append(curr_id)
|
116
|
-
to_do = adj_dict.get(curr, []) + to_do
|
117
|
-
curr_id += 1
|
118
|
-
adj_list = [
|
119
|
-
[nid2list[d] for d in adj_dict.get(list2nid[_id], [])]
|
120
|
-
for _id in nodes
|
121
|
-
]
|
122
|
-
return nodes, adj_list, list2nid
|
123
|
-
|
124
|
-
|
125
|
-
class mini_tree(abstract_trees):
|
126
|
-
"""Each branch is converted to a node of length 1, it is useful for comparing synchronous developing cells, extremely fast.
|
127
|
-
Mainly used for testing.
|
128
|
-
"""
|
129
|
-
|
130
|
-
def __init__(self, **kwargs):
|
131
|
-
super().__init__(**kwargs)
|
132
|
-
|
133
|
-
def get_tree(self):
|
134
|
-
if self.end_time is None:
|
135
|
-
self.end_time = self.lT.t_e
|
136
|
-
out_dict = {}
|
137
|
-
self.times = {}
|
138
|
-
to_do = [self.root]
|
139
|
-
while to_do:
|
140
|
-
current = to_do.pop()
|
141
|
-
cycle = np.array(self.lT.get_successors(current))
|
142
|
-
cycle_times = np.array([self.lT.time[c] for c in cycle])
|
143
|
-
cycle = cycle[cycle_times <= self.end_time]
|
144
|
-
if cycle.size:
|
145
|
-
_next = self.lT[cycle[-1]]
|
146
|
-
if 1 < len(_next):
|
147
|
-
out_dict[current] = _next
|
148
|
-
to_do.extend(_next)
|
149
|
-
else:
|
150
|
-
out_dict[current] = []
|
151
|
-
self.length = len(out_dict)
|
152
|
-
return out_dict, None
|
153
|
-
|
154
|
-
def get_norm(self):
|
155
|
-
return len(
|
156
|
-
self.lT.get_all_branches_of_node(self.root, end_time=self.end_time)
|
157
|
-
)
|
158
|
-
|
159
|
-
def _edist_format(self, adj_dict: dict):
|
160
|
-
return super()._edist_format(adj_dict)
|
161
|
-
|
162
|
-
def delta(self, x, y, corres1, corres2, times1, times2):
|
163
|
-
if x is None and y is None:
|
164
|
-
return 0
|
165
|
-
if x is None:
|
166
|
-
return 1
|
167
|
-
if y is None:
|
168
|
-
return 1
|
169
|
-
return 0
|
170
|
-
|
171
|
-
|
172
|
-
class simple_tree(abstract_trees):
|
173
|
-
"""Each branch is converted to one node with length the same as the life cycle of the cell.
|
174
|
-
This method is fast, but imprecise, especialy for small trees (recommended height of the trees should be 100 at least).
|
175
|
-
Use with CAUTION.
|
176
|
-
"""
|
177
|
-
|
178
|
-
def __init__(self, **kwargs):
|
179
|
-
super().__init__(**kwargs)
|
180
|
-
|
181
|
-
def get_tree(self):
|
182
|
-
if self.end_time is None:
|
183
|
-
self.end_time = self.lT.t_e
|
184
|
-
out_dict = {}
|
185
|
-
self.times = {}
|
186
|
-
to_do = [self.root]
|
187
|
-
while to_do:
|
188
|
-
current = to_do.pop()
|
189
|
-
cycle = np.array(self.lT.get_successors(current))
|
190
|
-
cycle_times = np.array([self.lT.time[c] for c in cycle])
|
191
|
-
cycle = cycle[cycle_times <= self.end_time]
|
192
|
-
if cycle.size:
|
193
|
-
_next = self.lT[cycle[-1]]
|
194
|
-
if len(_next) > 1 and self.lT.time[cycle[-1]] < self.end_time:
|
195
|
-
out_dict[current] = _next
|
196
|
-
to_do.extend(_next)
|
197
|
-
else:
|
198
|
-
out_dict[current] = []
|
199
|
-
self.times[current] = len(cycle) * self.time_scale
|
200
|
-
return out_dict, self.times
|
201
|
-
|
202
|
-
def delta(self, x, y, corres1, corres2, times1, times2):
|
203
|
-
return super().delta(x, y, corres1, corres2, times1, times2)
|
204
|
-
|
205
|
-
def get_norm(self):
|
206
|
-
return (
|
207
|
-
len(self.lT.get_sub_tree(self.root, end_time=self.end_time))
|
208
|
-
* self.time_scale
|
209
|
-
)
|
210
|
-
|
211
|
-
|
212
|
-
class downsample_tree(abstract_trees):
|
213
|
-
"""Downsamples a tree so every n nodes are being used as one."""
|
214
|
-
|
215
|
-
def __init__(self, **kwargs):
|
216
|
-
super().__init__(**kwargs)
|
217
|
-
if self.downsample == 0:
|
218
|
-
raise Exception("Please use a valid downsampling rate")
|
219
|
-
if self.downsample == 1:
|
220
|
-
warnings.warn(
|
221
|
-
"Downsampling rate of 1 is identical to the full tree.",
|
222
|
-
stacklevel=1,
|
223
|
-
)
|
224
|
-
|
225
|
-
def get_tree(self):
|
226
|
-
self.out_dict = {}
|
227
|
-
self.times = {}
|
228
|
-
to_do = [self.root]
|
229
|
-
while to_do:
|
230
|
-
current = to_do.pop()
|
231
|
-
_next = self.lT.get_cells_at_t_from_root(
|
232
|
-
current,
|
233
|
-
self.lT.time[current] + (self.downsample / self.time_scale),
|
234
|
-
)
|
235
|
-
if _next == [current]:
|
236
|
-
_next = None
|
237
|
-
if _next and self.lT.time[_next[0]] <= self.end_time:
|
238
|
-
self.out_dict[current] = _next
|
239
|
-
to_do.extend(_next)
|
240
|
-
else:
|
241
|
-
self.out_dict[current] = []
|
242
|
-
self.times[current] = 1 # self.downsample
|
243
|
-
return self.out_dict, self.times
|
244
|
-
|
245
|
-
def get_norm(self):
|
246
|
-
return len(self.times.values()) * self.downsample / self.time_scale
|
247
|
-
|
248
|
-
def delta(self, x, y, corres1, corres2, times1, times2):
|
249
|
-
if x is None and y is None:
|
250
|
-
return 0
|
251
|
-
if x is None:
|
252
|
-
return self.downsample
|
253
|
-
if y is None:
|
254
|
-
return self.downsample
|
255
|
-
return 0
|
256
|
-
|
257
|
-
|
258
|
-
class normalized_simple_tree(simple_tree):
|
259
|
-
def __init__(self, **kwargs):
|
260
|
-
super().__init__(**kwargs)
|
261
|
-
|
262
|
-
def delta(self, x, y, corres1, corres2, times1, times2):
|
263
|
-
if x is None and y is None:
|
264
|
-
return 0
|
265
|
-
if x is None:
|
266
|
-
return 1
|
267
|
-
if y is None:
|
268
|
-
return 1
|
269
|
-
return abs(times1[corres1[x]] - times2[corres2[y]]) / (
|
270
|
-
times1[corres1[x]] + times2[corres2[y]]
|
271
|
-
)
|
272
|
-
|
273
|
-
def get_norm(self):
|
274
|
-
return len(
|
275
|
-
self.lT.get_all_branches_of_node(self.root, end_time=self.end_time)
|
276
|
-
)
|
277
|
-
|
278
|
-
|
279
|
-
class full_tree(abstract_trees):
|
280
|
-
"""No approximations the whole tree is used here. Perfect accuracy, but heavy on ram and speed.
|
281
|
-
Not recommended to use on napari.
|
282
|
-
|
283
|
-
"""
|
284
|
-
|
285
|
-
def __init__(self, **kwargs):
|
286
|
-
super().__init__(**kwargs)
|
287
|
-
|
288
|
-
def get_tree(self) -> dict:
|
289
|
-
self.out_dict = {}
|
290
|
-
self.times = {}
|
291
|
-
to_do = [self.root]
|
292
|
-
while to_do:
|
293
|
-
current = to_do.pop()
|
294
|
-
_next = self.lT.successor.get(current, [])
|
295
|
-
if _next and self.lT.time[_next[0]] <= self.end_time:
|
296
|
-
if self.time_scale > 1:
|
297
|
-
for _ in range(self.time_scale - 1):
|
298
|
-
next_id = self.lT.get_next_id()
|
299
|
-
self.out_dict[current] = [next_id]
|
300
|
-
current = next_id
|
301
|
-
self.out_dict[current] = _next
|
302
|
-
to_do.extend(_next)
|
303
|
-
else:
|
304
|
-
for _ in range(self.time_scale - 1):
|
305
|
-
next_id = self.lT.get_next_id()
|
306
|
-
self.out_dict[current] = [next_id]
|
307
|
-
current = next_id
|
308
|
-
self.out_dict[current] = []
|
309
|
-
self.times[current] = 1
|
310
|
-
return self.out_dict, self.times
|
311
|
-
|
312
|
-
def get_norm(self):
|
313
|
-
return len(self.times) * self.time_scale
|
314
|
-
|
315
|
-
def delta(self, x, y, corres1, corres2, times1, times2):
|
316
|
-
if x is None and y is None:
|
317
|
-
return 0
|
318
|
-
if x is None:
|
319
|
-
return 1
|
320
|
-
if y is None:
|
321
|
-
return 1
|
322
|
-
return 0
|
323
|
-
|
324
|
-
|
325
|
-
class tree_style(Enum):
|
326
|
-
mini = mini_tree
|
327
|
-
simple = simple_tree
|
328
|
-
normalized_simple = normalized_simple_tree
|
329
|
-
downsampled = downsample_tree
|
330
|
-
full = full_tree
|
331
|
-
|
332
|
-
@classmethod
|
333
|
-
def list_names(self):
|
334
|
-
return [style.name for style in self]
|
@@ -1,11 +0,0 @@
|
|
1
|
-
LineageTree/__init__.py,sha256=888vRBgs18oExOHp7Q87HSH1GL60m-YLLjkMWYnZcBI,155
|
2
|
-
LineageTree/lineageTree.py,sha256=SoxLcYXhr5wzuX9ZXMDsK5fePd_6_Boq-y4HVJ6mBBI,102326
|
3
|
-
LineageTree/lineageTreeManager.py,sha256=bBhJrCUmLa6D6cZ95jT4hTnNfG7q-l_FiqOf2oaBc2o,6458
|
4
|
-
LineageTree/loaders.py,sha256=eStgVrqYeUlYQ-r7EByCZo2t5cgn-mXARTWBzLSN12Q,32778
|
5
|
-
LineageTree/tree_styles.py,sha256=ZEj0HcoEaWk8zyObboXW-qoM3uzKAQgiNzX2-UUa0cg,11337
|
6
|
-
LineageTree/utils.py,sha256=sFIj1eDid1EKP09g_jrSgqk4NLdNVf7KjC5UwN0Fihc,4878
|
7
|
-
LineageTree-1.8.0.dist-info/LICENSE,sha256=IKncNCNpq93Kq7Ywg1V4I9Bu_99VMK-mX1EJyjTKLyc,1068
|
8
|
-
LineageTree-1.8.0.dist-info/METADATA,sha256=X9UUm6EP44N_O3Uv0JN4Bu9wXU9kXAB9Nh-lHkjHoEs,4469
|
9
|
-
LineageTree-1.8.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
10
|
-
LineageTree-1.8.0.dist-info/top_level.txt,sha256=CCqPCTX76zPTEUagUgTWbLaZun8752n59iOOwfUlvxs,12
|
11
|
-
LineageTree-1.8.0.dist-info/RECORD,,
|