LineageTree 1.5.1__py3-none-any.whl → 1.6.0__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 +1 -1
- LineageTree/lineageTree.py +176 -855
- LineageTree/loaders.py +654 -0
- LineageTree/tree_styles.py +6 -10
- LineageTree/utils.py +84 -137
- {LineageTree-1.5.1.dist-info → LineageTree-1.6.0.dist-info}/METADATA +1 -1
- LineageTree-1.6.0.dist-info/RECORD +11 -0
- LineageTree-1.5.1.dist-info/RECORD +0 -10
- {LineageTree-1.5.1.dist-info → LineageTree-1.6.0.dist-info}/LICENSE +0 -0
- {LineageTree-1.5.1.dist-info → LineageTree-1.6.0.dist-info}/WHEEL +0 -0
- {LineageTree-1.5.1.dist-info → LineageTree-1.6.0.dist-info}/top_level.txt +0 -0
LineageTree/utils.py
CHANGED
@@ -2,7 +2,6 @@ import csv
|
|
2
2
|
import random
|
3
3
|
import warnings
|
4
4
|
|
5
|
-
import networkx as nx
|
6
5
|
|
7
6
|
from LineageTree import lineageTree
|
8
7
|
|
@@ -14,133 +13,14 @@ except ImportError:
|
|
14
13
|
)
|
15
14
|
|
16
15
|
|
17
|
-
def hierarchy_pos(
|
18
|
-
G,
|
19
|
-
a,
|
20
|
-
root=None,
|
21
|
-
width=2000.0,
|
22
|
-
vert_gap=0.5,
|
23
|
-
vert_loc=0,
|
24
|
-
xcenter=0,
|
25
|
-
):
|
26
|
-
"""
|
27
|
-
From Joel's answer at https://stackoverflow.com/a/29597209/2966723.
|
28
|
-
Licensed under Creative Commons Attribution-Share Alike
|
29
|
-
|
30
|
-
If the graph is a tree this will return the positions to plot this in a
|
31
|
-
hierarchical layout.
|
32
|
-
|
33
|
-
|
34
|
-
#The graph represents the lifetimes of cells, so there is no new point for each timepoint.
|
35
|
-
#Each lifetime is represented by length.
|
36
|
-
|
37
|
-
G: the graph (must be a tree)
|
38
|
-
|
39
|
-
root: the root node of current branch
|
40
|
-
- if the tree is directed and this is not given,
|
41
|
-
|
42
|
-
root: the root node of current branch
|
43
|
-
- if the tree is directed and this is not given,
|
44
|
-
the root will be found and used
|
45
|
-
- if the tree is directed and this is given, then
|
46
|
-
- if the tree is directed and this is given, then
|
47
|
-
the positions will be just for the descendants of this node.
|
48
|
-
- if the tree is undirected and not given,
|
49
|
-
then a random choice will be used.
|
50
|
-
|
51
|
-
|
52
|
-
width: horizontal space allocated for this branch - avoids overlap with other branches
|
53
|
-
|
54
|
-
|
55
|
-
vert_gap: gap between levels of hierarchy
|
56
|
-
|
57
|
-
|
58
|
-
vert_loc: vertical location of root
|
59
|
-
|
60
|
-
|
61
|
-
xcenter: horizontal location of root
|
62
|
-
"""
|
63
|
-
if not nx.is_tree(G):
|
64
|
-
raise TypeError(
|
65
|
-
"cannot use hierarchy_pos on a graph that is not a tree"
|
66
|
-
)
|
67
|
-
|
68
|
-
if root is None:
|
69
|
-
if isinstance(G, nx.DiGraph):
|
70
|
-
root = next(
|
71
|
-
iter(nx.topological_sort(G))
|
72
|
-
) # allows back compatibility with nx version 1.11
|
73
|
-
else:
|
74
|
-
root = random.choice(list(G.nodes))
|
75
|
-
|
76
|
-
def lengths(cell):
|
77
|
-
succ = a.successor.get(cell, [])
|
78
|
-
if len(succ) < 2:
|
79
|
-
if list(G.neighbors(cell)) == []:
|
80
|
-
return 0
|
81
|
-
if list(G.neighbors(cell))[0] in a.get_cycle(cell):
|
82
|
-
return (
|
83
|
-
len(a.get_successors(cell))
|
84
|
-
- len(a.get_successors(list(G.neighbors(cell))[0]))
|
85
|
-
- 1
|
86
|
-
)
|
87
|
-
return len(a.get_successors(cell))
|
88
|
-
else:
|
89
|
-
return 0.7
|
90
|
-
|
91
|
-
def _hierarchy_pos(
|
92
|
-
G,
|
93
|
-
root,
|
94
|
-
width=2.0,
|
95
|
-
a=a,
|
96
|
-
vert_gap=0.5,
|
97
|
-
vert_loc=0,
|
98
|
-
xcenter=0.5,
|
99
|
-
pos=None,
|
100
|
-
parent=None,
|
101
|
-
):
|
102
|
-
"""
|
103
|
-
see hierarchy_pos docstring for most arguments
|
104
|
-
|
105
|
-
pos: a dict saying where all nodes go if they have been assigned
|
106
|
-
parent: parent of this branch. - only affects it if non-directed
|
107
|
-
|
108
|
-
"""
|
109
|
-
if pos is None:
|
110
|
-
pos = {root: (xcenter, vert_loc)}
|
111
|
-
elif not a.predecessor.get(a.get_predecessors(root)[0]):
|
112
|
-
vert_loc = vert_loc - len(a.get_predecessors(root))
|
113
|
-
pos[root] = (xcenter, vert_loc)
|
114
|
-
else:
|
115
|
-
pos[root] = (xcenter, vert_loc)
|
116
|
-
children = list(G.neighbors(root))
|
117
|
-
|
118
|
-
if not isinstance(G, nx.DiGraph) and parent is not None:
|
119
|
-
children.remove(parent)
|
120
|
-
if len(children) != 0:
|
121
|
-
dx = width / len(children)
|
122
|
-
nextx = xcenter - width / 2 - dx / 2
|
123
|
-
for child in children:
|
124
|
-
nextx += dx
|
125
|
-
pos = _hierarchy_pos(
|
126
|
-
G,
|
127
|
-
child,
|
128
|
-
width=dx,
|
129
|
-
vert_gap=lengths(child),
|
130
|
-
vert_loc=vert_loc - vert_gap,
|
131
|
-
xcenter=nextx,
|
132
|
-
pos=pos,
|
133
|
-
a=a,
|
134
|
-
parent=root,
|
135
|
-
)
|
136
|
-
return pos
|
137
|
-
|
138
|
-
return _hierarchy_pos(G, root, width, a, vert_gap, vert_loc, xcenter)
|
139
|
-
|
140
|
-
|
141
16
|
def to_motile(
|
142
17
|
lT: lineageTree, crop: int = None, max_dist=200, max_skip_frames=1
|
143
18
|
):
|
19
|
+
try:
|
20
|
+
import networkx as nx
|
21
|
+
except:
|
22
|
+
raise Warning("Please install networkx")
|
23
|
+
|
144
24
|
fmt = nx.DiGraph()
|
145
25
|
if not crop:
|
146
26
|
crop = lT.t_e
|
@@ -192,20 +72,87 @@ def write_csv_from_lT_to_lineaja(
|
|
192
72
|
)
|
193
73
|
|
194
74
|
|
195
|
-
def
|
196
|
-
"""
|
75
|
+
def create_links_and_cycles(lT: lineageTree, roots=None):
|
76
|
+
"""Generates a dictionary containing the links and the lengths of each branch.
|
77
|
+
Similar to simple tree, mainly used for tree manip app.
|
78
|
+
|
79
|
+
Args:
|
80
|
+
roots (Union[list,set,int]): The roots from which the tree will be generated.
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
dict: A dictionary with keys "links" and "times" which contains the connections all cells and their branch
|
84
|
+
length.
|
85
|
+
"""
|
86
|
+
if roots is None:
|
87
|
+
to_do = set(lT.roots)
|
88
|
+
elif isinstance(roots, list):
|
89
|
+
to_do = set(roots)
|
90
|
+
else:
|
91
|
+
to_do = {int(roots)}
|
92
|
+
times = {}
|
93
|
+
links = {}
|
94
|
+
while to_do:
|
95
|
+
curr = to_do.pop()
|
96
|
+
cyc = lT.get_successors(curr)
|
97
|
+
last = cyc[-1]
|
98
|
+
times[curr] = len(cyc)
|
99
|
+
if last != curr:
|
100
|
+
links[curr] = [cyc[-1]]
|
101
|
+
else:
|
102
|
+
links[curr] = []
|
103
|
+
succ = lT.successor.get(last)
|
104
|
+
if succ:
|
105
|
+
times[cyc[-1]] = 0
|
106
|
+
to_do.update(succ)
|
107
|
+
links[last] = succ
|
108
|
+
return {"links": links, "times": times, "root": roots}
|
109
|
+
|
110
|
+
|
111
|
+
def hierarchical_pos(
|
112
|
+
lnks_tms: dict, root, width=1000, vert_gap=2, xcenter=0, ycenter=0
|
113
|
+
):
|
114
|
+
"""Calculates the position of each node on te tree graph.
|
197
115
|
|
198
116
|
Args:
|
199
|
-
|
117
|
+
lnks_tms (dict): a dictionary created by create_links_and_cycles.
|
118
|
+
root (_type_): The id of the node, usually it exists inside lnks_tms dictionary, however you may use your own root.
|
119
|
+
width (int, optional): Max width, will not change the graph but the interacting with the graph takes this distance into account. Defaults to 1000.
|
120
|
+
vert_gap (int, optional): How far downwards each timepoint will go. Defaults to 2.
|
121
|
+
xcenter (int, optional): Where the root will be placed on the x axis. Defaults to 0.
|
122
|
+
ycenter (int, optional): Where the root will be placed on the y axis. Defaults to 0.
|
200
123
|
|
201
124
|
Returns:
|
202
|
-
|
125
|
+
_type_: _description_
|
203
126
|
"""
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
)
|
211
|
-
|
127
|
+
to_do = [root]
|
128
|
+
if root not in lnks_tms["times"]:
|
129
|
+
return None
|
130
|
+
pos_node = {root: [xcenter, ycenter]}
|
131
|
+
prev_width = {root: width / 2}
|
132
|
+
while to_do:
|
133
|
+
curr = to_do.pop()
|
134
|
+
succ = lnks_tms["links"].get(curr, [])
|
135
|
+
if len(succ) == 0:
|
136
|
+
continue
|
137
|
+
elif len(succ) == 1:
|
138
|
+
pos_node[succ[0]] = [
|
139
|
+
pos_node[curr][0],
|
140
|
+
pos_node[curr][1] - lnks_tms["times"].get(curr, 0),
|
141
|
+
]
|
142
|
+
to_do.extend(succ)
|
143
|
+
prev_width[succ[0]] = prev_width[curr]
|
144
|
+
elif len(succ) == 2:
|
145
|
+
pos_node[succ[0]] = [
|
146
|
+
pos_node[curr][0] - prev_width[curr] / 2,
|
147
|
+
pos_node[curr][1] - vert_gap,
|
148
|
+
]
|
149
|
+
pos_node[succ[1]] = [
|
150
|
+
pos_node[curr][0] + prev_width[curr] / 2,
|
151
|
+
pos_node[curr][1] - vert_gap,
|
152
|
+
]
|
153
|
+
to_do.extend(succ)
|
154
|
+
prev_width[succ[0]], prev_width[succ[1]] = (
|
155
|
+
prev_width[curr] / 2,
|
156
|
+
prev_width[curr] / 2,
|
157
|
+
)
|
158
|
+
return pos_node
|
@@ -0,0 +1,11 @@
|
|
1
|
+
LineageTree/__init__.py,sha256=P4WGjjokRD5ugh27WC263Pwll1PmMdLgHyshMVLNvIc,155
|
2
|
+
LineageTree/lineageTree.py,sha256=srhZ8UI4iBsKmSEIVhn0OpKuTSyrE6npEMxjj4v666M,102657
|
3
|
+
LineageTree/lineageTreeManager.py,sha256=tQMNmxAvUEd4fNLJViB-9DGItpgCRnSF-bS2_IdebMo,5566
|
4
|
+
LineageTree/loaders.py,sha256=hKd-69d_csjcsV0zabSTEOyy0NhprFqvnRAI18tYa9w,23718
|
5
|
+
LineageTree/tree_styles.py,sha256=IUEq8RHfwXTv3WXylpLVa5XoThaWt1i1cRsgZGXdd50,10634
|
6
|
+
LineageTree/utils.py,sha256=kC90fi8TFm8Pz7oom_bDsq7HPPKnFdJ6wI-x36fLvHE,4962
|
7
|
+
LineageTree-1.6.0.dist-info/LICENSE,sha256=IKncNCNpq93Kq7Ywg1V4I9Bu_99VMK-mX1EJyjTKLyc,1068
|
8
|
+
LineageTree-1.6.0.dist-info/METADATA,sha256=XlCCU5B8WqbKT0EiGqgf-kvVFH5D2aSWQzygUCc3YT4,4195
|
9
|
+
LineageTree-1.6.0.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
10
|
+
LineageTree-1.6.0.dist-info/top_level.txt,sha256=CCqPCTX76zPTEUagUgTWbLaZun8752n59iOOwfUlvxs,12
|
11
|
+
LineageTree-1.6.0.dist-info/RECORD,,
|
@@ -1,10 +0,0 @@
|
|
1
|
-
LineageTree/__init__.py,sha256=9nFMRvaUfOOjmlQa_wULLdgtNx8qKnajSRWBrRiiYJo,155
|
2
|
-
LineageTree/lineageTree.py,sha256=DrJRj6uZt9P2mdZGPTTIcX8RJM7zipgfuX_aoLUFA5A,127181
|
3
|
-
LineageTree/lineageTreeManager.py,sha256=tQMNmxAvUEd4fNLJViB-9DGItpgCRnSF-bS2_IdebMo,5566
|
4
|
-
LineageTree/tree_styles.py,sha256=cDrGZaHz-1d_bp1hAhvAtBmVcSbNeTcY5YHPyaJ4g3w,10690
|
5
|
-
LineageTree/utils.py,sha256=cWJVSETN2npEoP1Ud86e17aXT-0dwf2gWsf5DMpxV9k,5993
|
6
|
-
LineageTree-1.5.1.dist-info/LICENSE,sha256=IKncNCNpq93Kq7Ywg1V4I9Bu_99VMK-mX1EJyjTKLyc,1068
|
7
|
-
LineageTree-1.5.1.dist-info/METADATA,sha256=gY9oz2iSQdbfjZ1RKBpnBj16383bAa3kSUXwpTHvFvE,4195
|
8
|
-
LineageTree-1.5.1.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
9
|
-
LineageTree-1.5.1.dist-info/top_level.txt,sha256=CCqPCTX76zPTEUagUgTWbLaZun8752n59iOOwfUlvxs,12
|
10
|
-
LineageTree-1.5.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|