lineagetree 3.0.0__tar.gz
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-3.0.0/LICENSE +21 -0
- lineagetree-3.0.0/PKG-INFO +129 -0
- lineagetree-3.0.0/README.md +83 -0
- lineagetree-3.0.0/pyproject.toml +136 -0
- lineagetree-3.0.0/setup.cfg +4 -0
- lineagetree-3.0.0/src/LineageTree/__init__.py +30 -0
- lineagetree-3.0.0/src/LineageTree/_core/_modifier.py +207 -0
- lineagetree-3.0.0/src/LineageTree/_core/_navigation.py +498 -0
- lineagetree-3.0.0/src/LineageTree/_core/_properties.py +227 -0
- lineagetree-3.0.0/src/LineageTree/_core/utils.py +170 -0
- lineagetree-3.0.0/src/LineageTree/_core/validation.py +37 -0
- lineagetree-3.0.0/src/LineageTree/_io/_loaders.py +980 -0
- lineagetree-3.0.0/src/LineageTree/_io/_writers.py +484 -0
- lineagetree-3.0.0/src/LineageTree/_legacy/export_csv.py +70 -0
- lineagetree-3.0.0/src/LineageTree/_legacy/to_lineajea.py +30 -0
- lineagetree-3.0.0/src/LineageTree/_legacy/to_motile.py +36 -0
- lineagetree-3.0.0/src/LineageTree/_mixins/_methodize.py +190 -0
- lineagetree-3.0.0/src/LineageTree/_mixins/analysis_mixin.py +28 -0
- lineagetree-3.0.0/src/LineageTree/_mixins/io_mixin.py +17 -0
- lineagetree-3.0.0/src/LineageTree/_mixins/modifier_mixin.py +21 -0
- lineagetree-3.0.0/src/LineageTree/_mixins/navigation_mixin.py +33 -0
- lineagetree-3.0.0/src/LineageTree/_mixins/plot_mixin.py +21 -0
- lineagetree-3.0.0/src/LineageTree/_mixins/properties_mixin.py +41 -0
- lineagetree-3.0.0/src/LineageTree/_mixins/spatial_mixin.py +19 -0
- lineagetree-3.0.0/src/LineageTree/lineage_tree.py +314 -0
- lineagetree-3.0.0/src/LineageTree/lineage_tree_manager.py +885 -0
- lineagetree-3.0.0/src/LineageTree/measure/dynamic_time_warping.py +342 -0
- lineagetree-3.0.0/src/LineageTree/measure/spatial.py +224 -0
- lineagetree-3.0.0/src/LineageTree/measure/uted.py +655 -0
- lineagetree-3.0.0/src/LineageTree/plot.py +737 -0
- lineagetree-3.0.0/src/LineageTree/tree_approximation.py +492 -0
- lineagetree-3.0.0/src/LineageTree.egg-info/PKG-INFO +129 -0
- lineagetree-3.0.0/src/LineageTree.egg-info/SOURCES.txt +43 -0
- lineagetree-3.0.0/src/LineageTree.egg-info/dependency_links.txt +1 -0
- lineagetree-3.0.0/src/LineageTree.egg-info/requires.txt +22 -0
- lineagetree-3.0.0/src/LineageTree.egg-info/top_level.txt +1 -0
- lineagetree-3.0.0/tests/test_lineageTree.py +682 -0
- lineagetree-3.0.0/tests/test_uted.py +233 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 leoguignard
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lineagetree
|
|
3
|
+
Version: 3.0.0
|
|
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
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
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
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: scipy>=1.9
|
|
27
|
+
Requires-Dist: numpy>=1.23
|
|
28
|
+
Requires-Dist: matplotlib
|
|
29
|
+
Requires-Dist: edist
|
|
30
|
+
Requires-Dist: svgwrite
|
|
31
|
+
Requires-Dist: Micro-Mastodon-Reader
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
35
|
+
Requires-Dist: black; extra == "dev"
|
|
36
|
+
Requires-Dist: ruff; extra == "dev"
|
|
37
|
+
Requires-Dist: bumpver; extra == "dev"
|
|
38
|
+
Provides-Extra: doc
|
|
39
|
+
Requires-Dist: sphinx-rtd-theme; extra == "doc"
|
|
40
|
+
Requires-Dist: myst-parser; extra == "doc"
|
|
41
|
+
Requires-Dist: sphinx_book_theme; extra == "doc"
|
|
42
|
+
Provides-Extra: test
|
|
43
|
+
Requires-Dist: pytest; extra == "test"
|
|
44
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
# LineageTree
|
|
48
|
+
|
|
49
|
+
This library allows to import and work with cell (but not limited to cells) lineage trees.
|
|
50
|
+
With LineageTree you can read from:
|
|
51
|
+
|
|
52
|
+
- TGMM algorithm outputs described in [Amat et al. 2014](https://www.nature.com/articles/nmeth.3036)
|
|
53
|
+
- TrackMate files described in [Tinevez et al. 2017](https://doi.org/10.1016/j.ymeth.2016.09.016)
|
|
54
|
+
- MaMuT files described in [Wolff et al. 2018](https://doi.org/10.7554/eLife.34410)
|
|
55
|
+
- SVF algorithm outputs described in [McDole, Guignard et al. 2018](https://doi.org/10.1016/j.cell.2018.09.031)
|
|
56
|
+
- ASTEC algorithm outputs described in [Guignard, Fiuza et al. 2020](https://doi.org/10.1126/science.aar5663)
|
|
57
|
+
- 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)
|
|
58
|
+
- and few others
|
|
59
|
+
|
|
60
|
+
## Basic usage
|
|
61
|
+
|
|
62
|
+
Once installed the library can be called the following way (as an example):
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from lineagetree import LineageTree
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
and one can then load lineage trees the following way:
|
|
69
|
+
|
|
70
|
+
For `.lT` files:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
lT = LineageTree.load('path/to/file.lT')
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
For ASTEC data:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from lineagetree import read_from_ASTEC
|
|
80
|
+
lT = read_from_ASTEC('path/to/ASTEC.pkl')
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
For MaMuT or TrackMate:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from lineagetree import read_from_mamut_xml
|
|
87
|
+
lT = read_from_mamut_xml('path/to/MaMuT.xml')
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
For TGMM:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from lineagetree import read_from_tgmm_xml
|
|
94
|
+
lT = read_from_tgmm_xml('path/to/single_time_file{t:04d}.xml', tb=0, te=500)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
For Mastodon:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from lineagetree import read_from_mastodon
|
|
101
|
+
lT = read_from_mastodon('path/to/Mastodon.mastodon')
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
or, for Mastodon csv file:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from lineagetree import read_from_mastodon_csv
|
|
108
|
+
lT = read_from_mastodon_csv(['path/to/nodes.csv', 'path/to/links.csv'])
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Quick install
|
|
112
|
+
|
|
113
|
+
To quickly install the library together with its dependencies one can run:
|
|
114
|
+
|
|
115
|
+
```shell
|
|
116
|
+
pip install LineageTree
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
or, for the latest version if you have cloned the directory:
|
|
120
|
+
|
|
121
|
+
```shell
|
|
122
|
+
pip install .
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
or for the latest version wihtout cloning the directory
|
|
126
|
+
|
|
127
|
+
```shell
|
|
128
|
+
pip install git+https://github.com/leoguignard/LineageTree
|
|
129
|
+
```
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# LineageTree
|
|
2
|
+
|
|
3
|
+
This library allows to import and work with cell (but not limited to cells) lineage trees.
|
|
4
|
+
With LineageTree you can read from:
|
|
5
|
+
|
|
6
|
+
- TGMM algorithm outputs described in [Amat et al. 2014](https://www.nature.com/articles/nmeth.3036)
|
|
7
|
+
- TrackMate files described in [Tinevez et al. 2017](https://doi.org/10.1016/j.ymeth.2016.09.016)
|
|
8
|
+
- MaMuT files described in [Wolff et al. 2018](https://doi.org/10.7554/eLife.34410)
|
|
9
|
+
- SVF algorithm outputs described in [McDole, Guignard et al. 2018](https://doi.org/10.1016/j.cell.2018.09.031)
|
|
10
|
+
- ASTEC algorithm outputs described in [Guignard, Fiuza et al. 2020](https://doi.org/10.1126/science.aar5663)
|
|
11
|
+
- 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)
|
|
12
|
+
- and few others
|
|
13
|
+
|
|
14
|
+
## Basic usage
|
|
15
|
+
|
|
16
|
+
Once installed the library can be called the following way (as an example):
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from lineagetree import LineageTree
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
and one can then load lineage trees the following way:
|
|
23
|
+
|
|
24
|
+
For `.lT` files:
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
lT = LineageTree.load('path/to/file.lT')
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
For ASTEC data:
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from lineagetree import read_from_ASTEC
|
|
34
|
+
lT = read_from_ASTEC('path/to/ASTEC.pkl')
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For MaMuT or TrackMate:
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from lineagetree import read_from_mamut_xml
|
|
41
|
+
lT = read_from_mamut_xml('path/to/MaMuT.xml')
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
For TGMM:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from lineagetree import read_from_tgmm_xml
|
|
48
|
+
lT = read_from_tgmm_xml('path/to/single_time_file{t:04d}.xml', tb=0, te=500)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For Mastodon:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from lineagetree import read_from_mastodon
|
|
55
|
+
lT = read_from_mastodon('path/to/Mastodon.mastodon')
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
or, for Mastodon csv file:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from lineagetree import read_from_mastodon_csv
|
|
62
|
+
lT = read_from_mastodon_csv(['path/to/nodes.csv', 'path/to/links.csv'])
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Quick install
|
|
66
|
+
|
|
67
|
+
To quickly install the library together with its dependencies one can run:
|
|
68
|
+
|
|
69
|
+
```shell
|
|
70
|
+
pip install LineageTree
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
or, for the latest version if you have cloned the directory:
|
|
74
|
+
|
|
75
|
+
```shell
|
|
76
|
+
pip install .
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
or for the latest version wihtout cloning the directory
|
|
80
|
+
|
|
81
|
+
```shell
|
|
82
|
+
pip install git+https://github.com/leoguignard/LineageTree
|
|
83
|
+
```
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=42.0.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[tool.setuptools.packages.find]
|
|
6
|
+
where = ["src"]
|
|
7
|
+
|
|
8
|
+
[project]
|
|
9
|
+
authors = [
|
|
10
|
+
{ name = "Léo Guignard", email = "leo.guignard@univ-amu.fr"},
|
|
11
|
+
{ name = "Giannis Liaskas"},
|
|
12
|
+
{ name = "Christopher Mazzerbo"},
|
|
13
|
+
]
|
|
14
|
+
maintainers = [
|
|
15
|
+
{name = "Léo Guignard", email = "leo.guignard@univ-amu.fr"}
|
|
16
|
+
]
|
|
17
|
+
name = "lineagetree"
|
|
18
|
+
description = "Structure for Lineage Trees"
|
|
19
|
+
version = "3.0.0"
|
|
20
|
+
license = "MIT"
|
|
21
|
+
license-files = [ "LICENSE" ]
|
|
22
|
+
readme = {file = "README.md", content-type = "text/markdown"}
|
|
23
|
+
requires-python = ">= 3.10"
|
|
24
|
+
classifiers = [
|
|
25
|
+
"Development Status :: 4 - Beta",
|
|
26
|
+
"Intended Audience :: Developers",
|
|
27
|
+
"Operating System :: OS Independent",
|
|
28
|
+
"Programming Language :: Python",
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
31
|
+
"Programming Language :: Python :: 3.10",
|
|
32
|
+
"Programming Language :: Python :: 3.11",
|
|
33
|
+
"Programming Language :: Python :: 3.12",
|
|
34
|
+
"Programming Language :: Python :: 3.13",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
dependencies = [
|
|
38
|
+
"scipy>=1.9",
|
|
39
|
+
"numpy>=1.23",
|
|
40
|
+
"matplotlib",
|
|
41
|
+
"edist",
|
|
42
|
+
"svgwrite",
|
|
43
|
+
"Micro-Mastodon-Reader",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[project.optional-dependencies]
|
|
47
|
+
dev = [
|
|
48
|
+
"pytest",
|
|
49
|
+
"pytest-cov",
|
|
50
|
+
"black",
|
|
51
|
+
"ruff",
|
|
52
|
+
"bumpver",
|
|
53
|
+
]
|
|
54
|
+
doc = [
|
|
55
|
+
"sphinx-rtd-theme",
|
|
56
|
+
"myst-parser",
|
|
57
|
+
"sphinx_book_theme",
|
|
58
|
+
]
|
|
59
|
+
test = [
|
|
60
|
+
"pytest",
|
|
61
|
+
"pytest-cov",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[project.urls]
|
|
65
|
+
"Bug Tracker" = "https://github.com/GuignardLab/LineageTree/issues"
|
|
66
|
+
"Documentation" = "https://github.com/GuignardLab/LineageTree#README.md"
|
|
67
|
+
"Source Code" = "https://github.com/GuignardLab/LineageTree"
|
|
68
|
+
"User Support" = "https://github.com/GuignardLab/LineageTree/issues"
|
|
69
|
+
|
|
70
|
+
[tool.black]
|
|
71
|
+
line-length = 79
|
|
72
|
+
|
|
73
|
+
[tool.isort]
|
|
74
|
+
profile = "black"
|
|
75
|
+
line_length = 79
|
|
76
|
+
|
|
77
|
+
[tool.bumpver]
|
|
78
|
+
current_version = "3.0.0"
|
|
79
|
+
version_pattern = "MAJOR.MINOR.PATCH[-TAG]"
|
|
80
|
+
commit_message = "bump version {old_version} -> {new_version}"
|
|
81
|
+
commit = true
|
|
82
|
+
tag = true
|
|
83
|
+
push = false
|
|
84
|
+
|
|
85
|
+
[tool.bumpver.file_patterns]
|
|
86
|
+
"pyproject.toml" = [
|
|
87
|
+
'current_version = "{version}"',
|
|
88
|
+
'version = "{version}"',
|
|
89
|
+
]
|
|
90
|
+
"src/lineagetree/__init__.py" = [
|
|
91
|
+
'__version__ = "{version}"',
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
[tool.ruff]
|
|
95
|
+
line-length = 79
|
|
96
|
+
exclude = [
|
|
97
|
+
".bzr",
|
|
98
|
+
".direnv",
|
|
99
|
+
".eggs",
|
|
100
|
+
".git",
|
|
101
|
+
".mypy_cache",
|
|
102
|
+
".pants.d",
|
|
103
|
+
".ruff_cache",
|
|
104
|
+
".svn",
|
|
105
|
+
".tox",
|
|
106
|
+
".venv",
|
|
107
|
+
"__pypackages__",
|
|
108
|
+
"_build",
|
|
109
|
+
"buck-out",
|
|
110
|
+
"build",
|
|
111
|
+
"dist",
|
|
112
|
+
"node_modules",
|
|
113
|
+
"venv",
|
|
114
|
+
"*vendored*",
|
|
115
|
+
"*_vendor*",
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
target-version = "py313"
|
|
119
|
+
|
|
120
|
+
[tool.ty.environment]
|
|
121
|
+
root = ["./src", ]
|
|
122
|
+
|
|
123
|
+
[tool.ty.rules]
|
|
124
|
+
unresolved-import = "ignore"
|
|
125
|
+
|
|
126
|
+
[tool.coverage.run]
|
|
127
|
+
source = ["lineagetree"]
|
|
128
|
+
|
|
129
|
+
[tool.coverage.report]
|
|
130
|
+
omit = [
|
|
131
|
+
"*/test/*",
|
|
132
|
+
"*/.vscode/*",
|
|
133
|
+
"*/site-packages/*",
|
|
134
|
+
"*/_io/*",
|
|
135
|
+
"*/_methodize.py",
|
|
136
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
__version__ = "3.0.0"
|
|
2
|
+
from .lineage_tree import LineageTree
|
|
3
|
+
from ._io._loaders import (
|
|
4
|
+
read_from_ASTEC,
|
|
5
|
+
read_from_binary,
|
|
6
|
+
read_from_csv,
|
|
7
|
+
read_from_mamut_xml,
|
|
8
|
+
read_from_mastodon,
|
|
9
|
+
read_from_mastodon_csv,
|
|
10
|
+
read_from_tgmm_xml,
|
|
11
|
+
read_from_txt_for_celegans,
|
|
12
|
+
read_from_txt_for_celegans_BAO,
|
|
13
|
+
read_from_txt_for_celegans_CAO,
|
|
14
|
+
)
|
|
15
|
+
from .lineage_tree_manager import LineageTreeManager
|
|
16
|
+
|
|
17
|
+
__all__ = (
|
|
18
|
+
"LineageTree",
|
|
19
|
+
"LineageTreeManager",
|
|
20
|
+
"read_from_tgmm_xml",
|
|
21
|
+
"read_from_txt_for_celegans_BAO",
|
|
22
|
+
"read_from_ASTEC",
|
|
23
|
+
"read_from_binary",
|
|
24
|
+
"read_from_csv",
|
|
25
|
+
"read_from_mamut_xml",
|
|
26
|
+
"read_from_mastodon_csv",
|
|
27
|
+
"read_from_mastodon",
|
|
28
|
+
"read_from_txt_for_celegans",
|
|
29
|
+
"read_from_txt_for_celegans_CAO",
|
|
30
|
+
)
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Iterable
|
|
4
|
+
from functools import wraps
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from ..lineage_tree import LineageTree
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def modifier(wrapped_func):
|
|
12
|
+
@wraps(wrapped_func)
|
|
13
|
+
def raising_flag(self, *args, **kwargs):
|
|
14
|
+
should_reset = (
|
|
15
|
+
not hasattr(self, "_has_been_reset") or not self._has_been_reset
|
|
16
|
+
)
|
|
17
|
+
out_func = wrapped_func(self, *args, **kwargs)
|
|
18
|
+
if should_reset:
|
|
19
|
+
for prop in self._protected_dynamic_properties:
|
|
20
|
+
self.__dict__[prop] = None
|
|
21
|
+
self._has_been_reset = True
|
|
22
|
+
return out_func
|
|
23
|
+
|
|
24
|
+
return raising_flag
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
###TODO pos can be callable and stay motionless (copy the position of the succ node, use something like optical flow)
|
|
28
|
+
@modifier
|
|
29
|
+
def add_chain(
|
|
30
|
+
lT: LineageTree,
|
|
31
|
+
node: int,
|
|
32
|
+
length: int,
|
|
33
|
+
downstream: bool,
|
|
34
|
+
pos: Callable | None = None,
|
|
35
|
+
) -> int:
|
|
36
|
+
"""Adds a chain of specific length to a node either as a successor or as a predecessor.
|
|
37
|
+
If it is placed on top of a tree all the nodes will move timepoints #length down.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
node : int
|
|
42
|
+
Id of the successor (predecessor if `downstream==False`)
|
|
43
|
+
length : int
|
|
44
|
+
The length of the new chain.
|
|
45
|
+
downstream : bool, default=True
|
|
46
|
+
If `True` will create a chain that goes forwards in time otherwise backwards.
|
|
47
|
+
pos : np.ndarray, optional
|
|
48
|
+
The new position of the chain. Defaults to None.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
int
|
|
53
|
+
Id of the first node of the sublineage.
|
|
54
|
+
"""
|
|
55
|
+
if length == 0:
|
|
56
|
+
return node
|
|
57
|
+
if length < 1:
|
|
58
|
+
raise ValueError("Length cannot be <1")
|
|
59
|
+
if downstream:
|
|
60
|
+
for _ in range(int(length)):
|
|
61
|
+
old_node = node
|
|
62
|
+
node = lT._add_node(pred=[old_node])
|
|
63
|
+
lT._time[node] = lT._time[old_node] + 1
|
|
64
|
+
else:
|
|
65
|
+
if lT._predecessor[node]:
|
|
66
|
+
raise Warning("The node already has a predecessor.")
|
|
67
|
+
if lT._time[node] - length < lT.t_b:
|
|
68
|
+
raise Warning(
|
|
69
|
+
"A node cannot created outside the lower bound of the dataset. (It is possible to change it by lT.t_b = int(...))"
|
|
70
|
+
)
|
|
71
|
+
for _ in range(int(length)):
|
|
72
|
+
old_node = node
|
|
73
|
+
node = lT._add_node(succ=[old_node])
|
|
74
|
+
lT._time[node] = lT._time[old_node] - 1
|
|
75
|
+
return node
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@modifier
|
|
79
|
+
def add_root(lT: LineageTree, t: int, pos: list | None = None) -> int:
|
|
80
|
+
"""Adds a root to a specific timepoint.
|
|
81
|
+
|
|
82
|
+
Parameters
|
|
83
|
+
----------
|
|
84
|
+
lT : LineageTree
|
|
85
|
+
The LineageTree instance.
|
|
86
|
+
t :int
|
|
87
|
+
The timepoint the node is going to be added.
|
|
88
|
+
pos : list
|
|
89
|
+
The position of the new node.
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
int
|
|
93
|
+
The id of the new root.
|
|
94
|
+
"""
|
|
95
|
+
C_next = lT.get_next_id()
|
|
96
|
+
lT._successor[C_next] = ()
|
|
97
|
+
lT._predecessor[C_next] = ()
|
|
98
|
+
lT._time[C_next] = t
|
|
99
|
+
lT.pos[C_next] = pos if isinstance(pos, list) else []
|
|
100
|
+
lT._changed_roots = True
|
|
101
|
+
return C_next
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def get_next_id(lT) -> int:
|
|
105
|
+
"""Computes the next authorized id and assign it.
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
int
|
|
110
|
+
next authorized id
|
|
111
|
+
"""
|
|
112
|
+
if not hasattr(lT, "max_id") or (lT.max_id == -1 and lT.nodes):
|
|
113
|
+
lT.max_id = max(lT.nodes) if len(lT.nodes) else 0
|
|
114
|
+
if not hasattr(lT, "next_id") or lT.next_id == []:
|
|
115
|
+
lT.max_id += 1
|
|
116
|
+
return lT.max_id
|
|
117
|
+
else:
|
|
118
|
+
return lT.next_id.pop()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@modifier
|
|
122
|
+
def _add_node(
|
|
123
|
+
lT: LineageTree,
|
|
124
|
+
succ: list | None = None,
|
|
125
|
+
pred: list | None = None,
|
|
126
|
+
pos: Iterable | None = None,
|
|
127
|
+
nid: int | None = None,
|
|
128
|
+
) -> int:
|
|
129
|
+
"""Adds a node to the LineageTree object that is either a successor or a predecessor of another node.
|
|
130
|
+
Does not handle time! You cannot enter both a successor and a predecessor.
|
|
131
|
+
|
|
132
|
+
Parameters
|
|
133
|
+
----------
|
|
134
|
+
lT : LineageTree
|
|
135
|
+
The LineageTree instance.
|
|
136
|
+
succ : list
|
|
137
|
+
list of ids of the nodes the new node is a successor to
|
|
138
|
+
pred : list
|
|
139
|
+
list of ids of the nodes the new node is a predecessor to
|
|
140
|
+
pos : np.ndarray, optional
|
|
141
|
+
position of the new node
|
|
142
|
+
nid : int, optional
|
|
143
|
+
id value of the new node, to be used carefully,
|
|
144
|
+
if None is provided the new id is automatically computed.
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
int
|
|
149
|
+
id of the new node.
|
|
150
|
+
"""
|
|
151
|
+
if not succ and not pred:
|
|
152
|
+
raise Warning(
|
|
153
|
+
"Please enter a successor or a predecessor, otherwise use the add_roots() function."
|
|
154
|
+
)
|
|
155
|
+
C_next = lT.get_next_id() if nid is None else nid
|
|
156
|
+
if succ:
|
|
157
|
+
lT._successor[C_next] = succ
|
|
158
|
+
for suc in succ:
|
|
159
|
+
lT._predecessor[suc] = (C_next,)
|
|
160
|
+
else:
|
|
161
|
+
lT._successor[C_next] = ()
|
|
162
|
+
if pred:
|
|
163
|
+
lT._predecessor[C_next] = pred
|
|
164
|
+
lT._successor[pred[0]] = lT._successor.setdefault(pred[0], ()) + (
|
|
165
|
+
C_next,
|
|
166
|
+
)
|
|
167
|
+
else:
|
|
168
|
+
lT._predecessor[C_next] = ()
|
|
169
|
+
if isinstance(pos, list):
|
|
170
|
+
lT.pos[C_next] = pos
|
|
171
|
+
return C_next
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@modifier
|
|
175
|
+
def remove_nodes(lT: LineageTree, group: int | set | list) -> None:
|
|
176
|
+
"""Removes a group of nodes from the LineageTree
|
|
177
|
+
|
|
178
|
+
Parameters
|
|
179
|
+
----------
|
|
180
|
+
lT : LineageTree
|
|
181
|
+
The LineageTree instance.
|
|
182
|
+
group : set of int or list of int or int
|
|
183
|
+
One or more nodes that are to be removed.
|
|
184
|
+
"""
|
|
185
|
+
if isinstance(group, int | float):
|
|
186
|
+
group = {group}
|
|
187
|
+
if isinstance(group, list):
|
|
188
|
+
group = set(group)
|
|
189
|
+
group = lT.nodes.intersection(group)
|
|
190
|
+
for node in group:
|
|
191
|
+
for attr in lT.__dict__:
|
|
192
|
+
attr_value = lT.__getattribute__(attr)
|
|
193
|
+
if isinstance(attr_value, dict) and attr not in [
|
|
194
|
+
"successor",
|
|
195
|
+
"predecessor",
|
|
196
|
+
"_successor",
|
|
197
|
+
"_predecessor",
|
|
198
|
+
]:
|
|
199
|
+
attr_value.pop(node, ())
|
|
200
|
+
if lT._predecessor.get(node):
|
|
201
|
+
lT._successor[lT._predecessor[node][0]] = tuple(
|
|
202
|
+
set(lT._successor[lT._predecessor[node][0]]).difference(group)
|
|
203
|
+
)
|
|
204
|
+
for p_node in lT._successor.get(node, []):
|
|
205
|
+
lT._predecessor[p_node] = ()
|
|
206
|
+
lT._predecessor.pop(node, ())
|
|
207
|
+
lT._successor.pop(node, ())
|