LineageTree 1.6.1__py3-none-any.whl → 1.8.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.
@@ -1,3 +1,4 @@
1
+ import warnings
1
2
  from abc import ABC, abstractmethod
2
3
  from enum import Enum
3
4
 
@@ -7,14 +8,32 @@ from LineageTree import lineageTree
7
8
 
8
9
 
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
+
10
21
  def __init__(
11
- self, lT: lineageTree, root: int, node_length: int, end_time: int
22
+ self,
23
+ lT: lineageTree,
24
+ root: int,
25
+ downsample: int,
26
+ end_time: int = None,
27
+ time_scale: int = 1,
12
28
  ):
13
- self.lT = lT
14
- self.root = root
15
- self.node_length = node_length
16
- self.end_time = end_time
17
- self.tree = self.get_tree()
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()
18
37
  self.edist = self._edist_format(self.tree[0])
19
38
 
20
39
  @abstractmethod
@@ -124,7 +143,7 @@ class mini_tree(abstract_trees):
124
143
  cycle = cycle[cycle_times <= self.end_time]
125
144
  if cycle.size:
126
145
  _next = self.lT[cycle[-1]]
127
- if len(_next) > 1:
146
+ if 1 < len(_next):
128
147
  out_dict[current] = _next
129
148
  to_do.extend(_next)
130
149
  else:
@@ -177,86 +196,84 @@ class simple_tree(abstract_trees):
177
196
  to_do.extend(_next)
178
197
  else:
179
198
  out_dict[current] = []
180
- self.times[current] = len(
181
- cycle
182
- ) # * time_resolution will be fixed when working on registered trees.
199
+ self.times[current] = len(cycle) * self.time_scale
183
200
  return out_dict, self.times
184
201
 
185
202
  def delta(self, x, y, corres1, corres2, times1, times2):
186
203
  return super().delta(x, y, corres1, corres2, times1, times2)
187
204
 
188
205
  def get_norm(self):
189
- return len(self.lT.get_sub_tree(self.root, end_time=self.end_time))
206
+ return (
207
+ len(self.lT.get_sub_tree(self.root, end_time=self.end_time))
208
+ * self.time_scale
209
+ )
190
210
 
191
211
 
192
- class fragmented_tree(abstract_trees):
193
- """Similar idea to simple tree, but tries to correct its flaws.
194
- Instead of having branches with length == life cycle of cell,nodes of specific length are added on the
195
- edges of the branch, providing both accuratr results and speed.
196
- It's the recommended method for calculating edit distances on developing embryos.
197
- """
212
+ class downsample_tree(abstract_trees):
213
+ """Downsamples a tree so every n nodes are being used as one."""
198
214
 
199
215
  def __init__(self, **kwargs):
200
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
+ )
201
224
 
202
225
  def get_tree(self):
203
- if self.end_time is None:
204
- self.end_time = self.lT.t_e
205
226
  self.out_dict = {}
206
227
  self.times = {}
207
228
  to_do = [self.root]
208
- if not isinstance(self.node_length, list):
209
- self.node_length = list(self.node_length)
210
229
  while to_do:
211
230
  current = to_do.pop()
212
- cycle = np.array(
213
- self.lT.get_successors(current, end_time=self.end_time)
231
+ _next = self.lT.get_cells_at_t_from_root(
232
+ current,
233
+ self.lT.time[current] + (self.downsample / self.time_scale),
214
234
  )
215
- if cycle.size > 0:
216
- cumul_sum_of_nodes = np.cumsum(self.node_length) * 2 + 1
217
- max_number_fragments = len(
218
- cumul_sum_of_nodes[cumul_sum_of_nodes < len(cycle)]
219
- )
220
- if max_number_fragments > 0:
221
- current_node_lengths = self.node_length[
222
- :max_number_fragments
223
- ].copy()
224
- length_middle_node = (
225
- len(cycle) - sum(current_node_lengths) * 2
226
- )
227
- times_tmp = (
228
- current_node_lengths
229
- + [length_middle_node]
230
- + current_node_lengths[::-1]
231
- )
232
- pos_all_nodes = np.concatenate(
233
- [[0], np.cumsum(times_tmp[:-1])]
234
- )
235
- track = cycle[pos_all_nodes]
236
- self.out_dict.update(
237
- {k: [v] for k, v in zip(track[:-1], track[1:])}
238
- )
239
- self.times.update(zip(track, times_tmp))
240
- else:
241
- for i, cell in enumerate(cycle[:-1]):
242
- self.out_dict[cell] = [cycle[i + 1]]
243
- self.times[cell] = 1
244
- current = cycle[-1]
245
- _next = self.lT[current]
246
- self.times[current] = 1
247
- if _next and self.lT.time[_next[0]] <= self.end_time:
248
- to_do.extend(_next)
249
- self.out_dict[current] = _next
250
- else:
251
- self.out_dict[current] = []
252
-
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
253
243
  return self.out_dict, self.times
254
244
 
255
245
  def get_norm(self):
256
- return len(self.lT.get_sub_tree(self.root, end_time=self.end_time))
246
+ return len(self.times.values()) * self.downsample / self.time_scale
257
247
 
258
248
  def delta(self, x, y, corres1, corres2, times1, times2):
259
- return super().delta(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
+ )
260
277
 
261
278
 
262
279
  class full_tree(abstract_trees):
@@ -276,24 +293,40 @@ class full_tree(abstract_trees):
276
293
  current = to_do.pop()
277
294
  _next = self.lT.successor.get(current, [])
278
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
279
301
  self.out_dict[current] = _next
280
302
  to_do.extend(_next)
281
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
282
308
  self.out_dict[current] = []
283
309
  self.times[current] = 1
284
310
  return self.out_dict, self.times
285
311
 
286
312
  def get_norm(self):
287
- return len(self.lT.get_sub_tree(self.root, end_time=self.end_time))
313
+ return len(self.times) * self.time_scale
288
314
 
289
315
  def delta(self, x, y, corres1, corres2, times1, times2):
290
- return super().delta(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
291
323
 
292
324
 
293
325
  class tree_style(Enum):
294
326
  mini = mini_tree
295
327
  simple = simple_tree
296
- fragmented = fragmented_tree
328
+ normalized_simple = normalized_simple_tree
329
+ downsampled = downsample_tree
297
330
  full = full_tree
298
331
 
299
332
  @classmethod
LineageTree/utils.py CHANGED
@@ -1,15 +1,14 @@
1
1
  import csv
2
- import random
3
2
  import warnings
4
3
 
5
-
6
4
  from LineageTree import lineageTree
7
5
 
8
6
  try:
9
7
  import motile
10
8
  except ImportError:
11
9
  warnings.warn(
12
- "No motile installed therefore you will not be able to produce links with motile."
10
+ "No motile installed therefore you will not be able to produce links with motile.",
11
+ stacklevel=2,
13
12
  )
14
13
 
15
14
 
@@ -18,16 +17,13 @@ def to_motile(
18
17
  ):
19
18
  try:
20
19
  import networkx as nx
21
- except:
22
- raise Warning("Please install networkx")
20
+ except ImportError:
21
+ raise Warning("Please install networkx") # noqa: B904
23
22
 
24
23
  fmt = nx.DiGraph()
25
24
  if not crop:
26
25
  crop = lT.t_e
27
- # time_nodes = [
28
26
  for time in range(crop):
29
- # time_nodes += lT.time_nodes[time]
30
- # print(time_nodes)
31
27
  for time_node in lT.time_nodes[time]:
32
28
  fmt.add_node(
33
29
  time_node,
@@ -35,8 +31,6 @@ def to_motile(
35
31
  pos=lT.pos[time_node],
36
32
  score=1,
37
33
  )
38
- # for suc in lT.successor:
39
- # fmt.add_edge(time_node, suc, **{"score":0})
40
34
 
41
35
  motile.add_cand_edges(fmt, max_dist, max_skip_frames=max_skip_frames)
42
36
 
@@ -137,7 +131,9 @@ def hierarchical_pos(
137
131
  elif len(succ) == 1:
138
132
  pos_node[succ[0]] = [
139
133
  pos_node[curr][0],
140
- pos_node[curr][1] - lnks_tms["times"].get(curr, 0),
134
+ pos_node[curr][1]
135
+ - lnks_tms["times"].get(curr, 0)
136
+ + min(vert_gap, lnks_tms["times"].get(curr, 0)),
141
137
  ]
142
138
  to_do.extend(succ)
143
139
  prev_width[succ[0]] = prev_width[curr]
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: LineageTree
3
- Version: 1.6.1
3
+ Version: 1.8.0
4
4
  Summary: Lineage tree structure
5
5
  Home-page: https://github.com/leoguignard/LineageTree
6
6
  Author: Léo Guignard
@@ -28,14 +28,6 @@ Requires-Dist: scipy>=1.9
28
28
  Requires-Dist: numpy>=1.23
29
29
  Requires-Dist: mastodon-reader
30
30
  Requires-Dist: matplotlib
31
- Provides-Extra: all
32
- Requires-Dist: svgwrite; extra == "all"
33
- Requires-Dist: matplotlib; extra == "all"
34
- Requires-Dist: tox; extra == "all"
35
- Requires-Dist: pytest; extra == "all"
36
- Requires-Dist: pytest-cov; extra == "all"
37
- Requires-Dist: edist; extra == "all"
38
- Requires-Dist: mastodon-reader; extra == "all"
39
31
  Provides-Extra: svg
40
32
  Requires-Dist: svgwrite; extra == "svg"
41
33
  Requires-Dist: matplotlib; extra == "svg"
@@ -48,6 +40,14 @@ Requires-Dist: pytest-cov; extra == "test"
48
40
  Requires-Dist: mastodon-reader; extra == "test"
49
41
  Provides-Extra: treeedit
50
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
51
 
52
52
  # LineageTree
53
53
 
@@ -59,6 +59,7 @@ With LineageTree you can read from:
59
59
  - MaMuT files described in [Wolff et al. 2018](https://doi.org/10.7554/eLife.34410)
60
60
  - SVF algorithm outputs described in [McDole, Guignard et al. 2018](https://doi.org/10.1016/j.cell.2018.09.031)
61
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)
62
63
  - and few others
63
64
 
64
65
  ## Basic usage
@@ -0,0 +1,11 @@
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,11 +0,0 @@
1
- LineageTree/__init__.py,sha256=fIOwpoeHI19rwQShQ50iRXyRg4OXzVo_A4q_BUDBmsk,155
2
- LineageTree/lineageTree.py,sha256=lamlTaHtu3gPUCMKIvlCHQqGMbcQAHCvgS8MB6EHWTQ,102742
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.1.dist-info/LICENSE,sha256=IKncNCNpq93Kq7Ywg1V4I9Bu_99VMK-mX1EJyjTKLyc,1068
8
- LineageTree-1.6.1.dist-info/METADATA,sha256=eDkg_GjSQtFDXXjmyagn-gXRosFsDq2n8706srcixA8,4195
9
- LineageTree-1.6.1.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
10
- LineageTree-1.6.1.dist-info/top_level.txt,sha256=CCqPCTX76zPTEUagUgTWbLaZun8752n59iOOwfUlvxs,12
11
- LineageTree-1.6.1.dist-info/RECORD,,