LineageTree 1.8.0__py3-none-any.whl → 2.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.
@@ -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,156 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: LineageTree
3
- Version: 1.8.0
4
- Summary: Lineage tree structure
5
- Home-page: https://github.com/leoguignard/LineageTree
6
- Author: Léo Guignard
7
- Author-email: leo.guignard@univ-amu.fr
8
- License: MIT
9
- Project-URL: Bug Tracker, https://github.com/leoguignard/LineageTree/issues
10
- Project-URL: Documentation, https://github.com/leoguignard/LineageTree#README.md
11
- Project-URL: Source Code, https://github.com/leoguignard/LineageTree
12
- Project-URL: User Support, https://github.com/leoguignard/LineageTree/issues
13
- Classifier: Development Status :: 2 - Pre-Alpha
14
- Classifier: Intended Audience :: Developers
15
- Classifier: License :: OSI Approved :: MIT License
16
- Classifier: Operating System :: OS Independent
17
- Classifier: Programming Language :: Python
18
- Classifier: Programming Language :: Python :: 3
19
- Classifier: Programming Language :: Python :: 3 :: Only
20
- Classifier: Programming Language :: Python :: 3.8
21
- Classifier: Programming Language :: Python :: 3.9
22
- Classifier: Programming Language :: Python :: 3.10
23
- Classifier: Topic :: Scientific/Engineering :: Image Processing
24
- Requires-Python: >=3.8
25
- Description-Content-Type: text/markdown
26
- License-File: LICENSE
27
- Requires-Dist: scipy>=1.9
28
- Requires-Dist: numpy>=1.23
29
- Requires-Dist: mastodon-reader
30
- Requires-Dist: matplotlib
31
- Provides-Extra: svg
32
- Requires-Dist: svgwrite; extra == "svg"
33
- Requires-Dist: matplotlib; extra == "svg"
34
- Provides-Extra: test
35
- Requires-Dist: svgwrite; extra == "test"
36
- Requires-Dist: matplotlib; extra == "test"
37
- Requires-Dist: tox; extra == "test"
38
- Requires-Dist: pytest; extra == "test"
39
- Requires-Dist: pytest-cov; extra == "test"
40
- Requires-Dist: mastodon-reader; extra == "test"
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"
51
-
52
- # LineageTree
53
-
54
- This library allows to import and work with cell (but not limited to cells) lineage trees.
55
- With LineageTree you can read from:
56
-
57
- - TGMM algorithm outputs described in [Fernando et al. 2014](https://www.nature.com/articles/nmeth.3036)
58
- - TrackMate files described in [Tinevez et al. 2017](https://doi.org/10.1016/j.ymeth.2016.09.016)
59
- - MaMuT files described in [Wolff et al. 2018](https://doi.org/10.7554/eLife.34410)
60
- - SVF algorithm outputs described in [McDole, Guignard et al. 2018](https://doi.org/10.1016/j.cell.2018.09.031)
61
- - ASTEC algorithm outputs described in [Guignard, Fiuza et al. 2020](https://doi.org/10.1126/science.aar5663)
62
- - Data from the [Digital development Database](http://digital-development.org/index.html) described in [Du et al. 2014](https://www.cell.com/fulltext/S0092-8674(13)01542-0) and [Du et al. 2015](https://www.sciencedirect.com/science/article/pii/S1534580715004876?via%3Dihub)
63
- - and few others
64
-
65
- ## Basic usage
66
-
67
- Once installed the library can be called the following way (as an example):
68
-
69
- ```python
70
- from LineageTree import lineageTree
71
- ```
72
-
73
- and one can then load lineage trees the following way:
74
-
75
- For `.lT` files:
76
-
77
- ```python
78
- lT = lineageTree('path/to/file.lT')
79
- ```
80
-
81
- For ASTEC data:
82
-
83
- ```python
84
- lT = lineageTree('path/to/ASTEC.pkl', file_type='ASTEC')
85
- ```
86
-
87
- or
88
-
89
- ```python
90
- lT = lineageTree('path/to/ASTEC.xml', file_type='ASTEC')
91
- ```
92
-
93
- For SVF:
94
-
95
- ```python
96
- lT = lineageTree('path/to/SVF.bin')
97
- ```
98
-
99
- For MaMuT:
100
-
101
- ```python
102
- lT = lineageTree('path/to/MaMuT.xml', file_type='MaMuT')
103
- ```
104
-
105
- For TrackMate:
106
-
107
- ```python
108
- lT = lineageTree('path/to/MaMuT.xml', file_type='TrackMate')
109
- ```
110
-
111
- For TGMM:
112
-
113
- ```python
114
- lT = lineageTree('path/to/single_time_file{t:04d}.xml', tb=0, te=500, file_type='TGMM')
115
- ```
116
-
117
- For Mastodon:
118
-
119
- ```python
120
- lT = lineageTree('path/to/Mastodon.mastodon', file_type='mastodon')
121
- ```
122
-
123
- or, for Mastodon csv file:
124
-
125
- ```python
126
- lT = lineageTree(['path/to/nodes.csv', 'path/to/links.csv'], file_type='mastodon')
127
- ```
128
-
129
- ## Dependencies
130
-
131
- Some dependecies are requiered:
132
-
133
- - general python dependecies:
134
- - numpy, scipy
135
- - specific dependency:
136
- - svgwrite if svg output is needed
137
-
138
- ## Quick install
139
-
140
- To quickly install the library together with its dependencies one can run:
141
-
142
- ```shell
143
- pip install LineageTree
144
- ```
145
-
146
- or, for the latest version if you have cloned the directory:
147
-
148
- ```shell
149
- pip install .
150
- ```
151
-
152
- or for the latest version wihtout cloning the directory
153
-
154
- ```shell
155
- pip install git+https://github.com/leoguignard/LineageTree
156
- ```
@@ -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,,