swcgeom 0.14.0__py3-none-any.whl → 0.16.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.
Potentially problematic release.
This version of swcgeom might be problematic. Click here for more details.
- swcgeom/_version.py +2 -2
- swcgeom/analysis/lmeasure.py +821 -0
- swcgeom/analysis/sholl.py +31 -2
- swcgeom/core/__init__.py +4 -0
- swcgeom/core/branch.py +9 -4
- swcgeom/core/branch_tree.py +2 -3
- swcgeom/core/{segment.py → compartment.py} +14 -9
- swcgeom/core/node.py +0 -8
- swcgeom/core/path.py +21 -6
- swcgeom/core/population.py +42 -3
- swcgeom/core/swc_utils/assembler.py +20 -138
- swcgeom/core/swc_utils/base.py +12 -5
- swcgeom/core/swc_utils/checker.py +12 -2
- swcgeom/core/swc_utils/subtree.py +2 -2
- swcgeom/core/tree.py +53 -49
- swcgeom/core/tree_utils.py +27 -5
- swcgeom/core/tree_utils_impl.py +22 -6
- swcgeom/images/augmentation.py +6 -1
- swcgeom/images/contrast.py +107 -0
- swcgeom/images/folder.py +111 -29
- swcgeom/images/io.py +79 -40
- swcgeom/transforms/__init__.py +2 -0
- swcgeom/transforms/base.py +41 -21
- swcgeom/transforms/branch.py +5 -5
- swcgeom/transforms/geometry.py +42 -18
- swcgeom/transforms/image_preprocess.py +100 -0
- swcgeom/transforms/image_stack.py +46 -28
- swcgeom/transforms/images.py +76 -6
- swcgeom/transforms/mst.py +10 -18
- swcgeom/transforms/neurolucida_asc.py +495 -0
- swcgeom/transforms/population.py +2 -2
- swcgeom/transforms/tree.py +12 -14
- swcgeom/transforms/tree_assembler.py +85 -19
- swcgeom/utils/__init__.py +1 -0
- swcgeom/utils/neuromorpho.py +425 -300
- swcgeom/utils/numpy_helper.py +14 -4
- swcgeom/utils/plotter_2d.py +130 -0
- swcgeom/utils/renderer.py +28 -139
- swcgeom/utils/sdf.py +5 -1
- {swcgeom-0.14.0.dist-info → swcgeom-0.16.0.dist-info}/METADATA +3 -3
- swcgeom-0.16.0.dist-info/RECORD +67 -0
- {swcgeom-0.14.0.dist-info → swcgeom-0.16.0.dist-info}/WHEEL +1 -1
- swcgeom-0.14.0.dist-info/RECORD +0 -62
- {swcgeom-0.14.0.dist-info → swcgeom-0.16.0.dist-info}/LICENSE +0 -0
- {swcgeom-0.14.0.dist-info → swcgeom-0.16.0.dist-info}/top_level.txt +0 -0
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
"""Assemble a tree."""
|
|
2
2
|
|
|
3
|
+
from copy import copy
|
|
3
4
|
from typing import Iterable, List, Optional, Tuple
|
|
4
5
|
|
|
6
|
+
import numpy as np
|
|
5
7
|
import pandas as pd
|
|
6
8
|
|
|
7
9
|
from swcgeom.core import Tree
|
|
8
|
-
from swcgeom.core.swc_utils import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
from swcgeom.core.swc_utils import (
|
|
11
|
+
SWCNames,
|
|
12
|
+
get_names,
|
|
13
|
+
link_roots_to_nearest_,
|
|
14
|
+
sort_nodes_,
|
|
12
15
|
)
|
|
13
16
|
from swcgeom.transforms.base import Transform
|
|
14
17
|
|
|
18
|
+
EPS = 1e-5
|
|
19
|
+
|
|
15
20
|
|
|
16
21
|
class LinesToTree(Transform[List[pd.DataFrame], Tree]):
|
|
17
22
|
"""Assemble lines to swc."""
|
|
@@ -35,11 +40,12 @@ class LinesToTree(Transform[List[pd.DataFrame], Tree]):
|
|
|
35
40
|
):
|
|
36
41
|
return self.assemble(lines, names=names)
|
|
37
42
|
|
|
38
|
-
def __repr__(self) -> str:
|
|
39
|
-
return f"LinesToTree-thre-{self.thre}-{'undirected' if self.undirected else 'directed'}"
|
|
40
|
-
|
|
41
43
|
def assemble(
|
|
42
|
-
self,
|
|
44
|
+
self,
|
|
45
|
+
lines: Iterable[pd.DataFrame],
|
|
46
|
+
*,
|
|
47
|
+
undirected: bool = True,
|
|
48
|
+
names: Optional[SWCNames] = None,
|
|
43
49
|
) -> pd.DataFrame:
|
|
44
50
|
"""Assemble lines to a tree.
|
|
45
51
|
|
|
@@ -51,6 +57,8 @@ class LinesToTree(Transform[List[pd.DataFrame], Tree]):
|
|
|
51
57
|
lines : List of ~pd.DataFrame
|
|
52
58
|
An array of tables containing a line, columns should follwing
|
|
53
59
|
the swc.
|
|
60
|
+
undirected : bool, default `True`
|
|
61
|
+
Forwarding to `self.try_assemble`.
|
|
54
62
|
names : SWCNames, optional
|
|
55
63
|
Forwarding to `self.try_assemble`.
|
|
56
64
|
|
|
@@ -60,17 +68,33 @@ class LinesToTree(Transform[List[pd.DataFrame], Tree]):
|
|
|
60
68
|
|
|
61
69
|
See Also
|
|
62
70
|
--------
|
|
63
|
-
self.
|
|
71
|
+
self.try_assemble
|
|
64
72
|
"""
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
|
|
74
|
+
tree, lines = self.try_assemble(
|
|
75
|
+
lines, sort_nodes=False, undirected=undirected, names=names
|
|
67
76
|
)
|
|
77
|
+
while len(lines) > 0:
|
|
78
|
+
t, lines = self.try_assemble(
|
|
79
|
+
lines,
|
|
80
|
+
id_offset=len(tree),
|
|
81
|
+
sort_nodes=False,
|
|
82
|
+
undirected=undirected,
|
|
83
|
+
names=names,
|
|
84
|
+
)
|
|
85
|
+
tree = pd.concat([tree, t])
|
|
86
|
+
|
|
87
|
+
tree = tree.reset_index()
|
|
88
|
+
link_roots_to_nearest_(tree)
|
|
89
|
+
sort_nodes_(tree)
|
|
90
|
+
return tree
|
|
68
91
|
|
|
69
92
|
def try_assemble(
|
|
70
93
|
self,
|
|
71
94
|
lines: Iterable[pd.DataFrame],
|
|
72
95
|
*,
|
|
73
96
|
id_offset: int = 0,
|
|
97
|
+
undirected: bool = True,
|
|
74
98
|
sort_nodes: bool = True,
|
|
75
99
|
names: Optional[SWCNames] = None,
|
|
76
100
|
) -> Tuple[pd.DataFrame, List[pd.DataFrame]]:
|
|
@@ -88,6 +112,9 @@ class LinesToTree(Transform[List[pd.DataFrame], Tree]):
|
|
|
88
112
|
the swc.
|
|
89
113
|
id_offset : int, default `0`
|
|
90
114
|
The offset of the line node id.
|
|
115
|
+
undirected : bool, default `True`
|
|
116
|
+
Both ends of a line can be considered connection point. If
|
|
117
|
+
`False`, only the starting point.
|
|
91
118
|
sort_nodes : bool, default `True`
|
|
92
119
|
sort nodes of subtree.
|
|
93
120
|
names : SWCNames, optional
|
|
@@ -97,11 +124,50 @@ class LinesToTree(Transform[List[pd.DataFrame], Tree]):
|
|
|
97
124
|
tree : ~pandas.DataFrame
|
|
98
125
|
remaining_lines : List of ~pandas.DataFrame
|
|
99
126
|
"""
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
127
|
+
|
|
128
|
+
names = get_names(names)
|
|
129
|
+
lines = copy(list(lines))
|
|
130
|
+
|
|
131
|
+
tree = lines[0]
|
|
132
|
+
tree[names.id] = id_offset + np.arange(len(tree))
|
|
133
|
+
tree[names.pid] = tree[names.id] - 1
|
|
134
|
+
tree.at[0, names.pid] = -1
|
|
135
|
+
del lines[0]
|
|
136
|
+
|
|
137
|
+
while True:
|
|
138
|
+
for i, line in enumerate(lines):
|
|
139
|
+
for p in [0, -1] if undirected else [0]:
|
|
140
|
+
xyz = [names.x, names.y, names.z]
|
|
141
|
+
vs = tree[xyz] - line.iloc[p][xyz]
|
|
142
|
+
dis = np.linalg.norm(vs, axis=1)
|
|
143
|
+
ind = np.argmin(dis)
|
|
144
|
+
if dis[ind] > self.thre:
|
|
145
|
+
continue
|
|
146
|
+
|
|
147
|
+
if dis[ind] < EPS:
|
|
148
|
+
line = line.drop((p + len(line)) % len(line)).reset_index(
|
|
149
|
+
drop=True
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
line[names.id] = id_offset + len(tree) + np.arange(len(line))
|
|
153
|
+
line[names.pid] = line[names.id] + (-1 if p == 0 else 1)
|
|
154
|
+
line.at[(p + len(line)) % len(line), names.pid] = tree.iloc[ind][
|
|
155
|
+
names.id
|
|
156
|
+
]
|
|
157
|
+
tree = pd.concat([tree, line])
|
|
158
|
+
del lines[i]
|
|
159
|
+
break
|
|
160
|
+
else:
|
|
161
|
+
continue
|
|
162
|
+
|
|
163
|
+
break
|
|
164
|
+
else:
|
|
165
|
+
break
|
|
166
|
+
|
|
167
|
+
if sort_nodes:
|
|
168
|
+
sort_nodes_(tree)
|
|
169
|
+
|
|
170
|
+
return tree, lines
|
|
171
|
+
|
|
172
|
+
def extra_repr(self):
|
|
173
|
+
return f"thre={self.thre}, undirected={self.undirected}"
|
swcgeom/utils/__init__.py
CHANGED
|
@@ -6,6 +6,7 @@ from swcgeom.utils.ellipse import *
|
|
|
6
6
|
from swcgeom.utils.file import *
|
|
7
7
|
from swcgeom.utils.neuromorpho import *
|
|
8
8
|
from swcgeom.utils.numpy_helper import *
|
|
9
|
+
from swcgeom.utils.plotter_2d import *
|
|
9
10
|
from swcgeom.utils.renderer import *
|
|
10
11
|
from swcgeom.utils.sdf import *
|
|
11
12
|
from swcgeom.utils.solid_geometry import *
|