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.

Files changed (45) hide show
  1. swcgeom/_version.py +2 -2
  2. swcgeom/analysis/lmeasure.py +821 -0
  3. swcgeom/analysis/sholl.py +31 -2
  4. swcgeom/core/__init__.py +4 -0
  5. swcgeom/core/branch.py +9 -4
  6. swcgeom/core/branch_tree.py +2 -3
  7. swcgeom/core/{segment.py → compartment.py} +14 -9
  8. swcgeom/core/node.py +0 -8
  9. swcgeom/core/path.py +21 -6
  10. swcgeom/core/population.py +42 -3
  11. swcgeom/core/swc_utils/assembler.py +20 -138
  12. swcgeom/core/swc_utils/base.py +12 -5
  13. swcgeom/core/swc_utils/checker.py +12 -2
  14. swcgeom/core/swc_utils/subtree.py +2 -2
  15. swcgeom/core/tree.py +53 -49
  16. swcgeom/core/tree_utils.py +27 -5
  17. swcgeom/core/tree_utils_impl.py +22 -6
  18. swcgeom/images/augmentation.py +6 -1
  19. swcgeom/images/contrast.py +107 -0
  20. swcgeom/images/folder.py +111 -29
  21. swcgeom/images/io.py +79 -40
  22. swcgeom/transforms/__init__.py +2 -0
  23. swcgeom/transforms/base.py +41 -21
  24. swcgeom/transforms/branch.py +5 -5
  25. swcgeom/transforms/geometry.py +42 -18
  26. swcgeom/transforms/image_preprocess.py +100 -0
  27. swcgeom/transforms/image_stack.py +46 -28
  28. swcgeom/transforms/images.py +76 -6
  29. swcgeom/transforms/mst.py +10 -18
  30. swcgeom/transforms/neurolucida_asc.py +495 -0
  31. swcgeom/transforms/population.py +2 -2
  32. swcgeom/transforms/tree.py +12 -14
  33. swcgeom/transforms/tree_assembler.py +85 -19
  34. swcgeom/utils/__init__.py +1 -0
  35. swcgeom/utils/neuromorpho.py +425 -300
  36. swcgeom/utils/numpy_helper.py +14 -4
  37. swcgeom/utils/plotter_2d.py +130 -0
  38. swcgeom/utils/renderer.py +28 -139
  39. swcgeom/utils/sdf.py +5 -1
  40. {swcgeom-0.14.0.dist-info → swcgeom-0.16.0.dist-info}/METADATA +3 -3
  41. swcgeom-0.16.0.dist-info/RECORD +67 -0
  42. {swcgeom-0.14.0.dist-info → swcgeom-0.16.0.dist-info}/WHEEL +1 -1
  43. swcgeom-0.14.0.dist-info/RECORD +0 -62
  44. {swcgeom-0.14.0.dist-info → swcgeom-0.16.0.dist-info}/LICENSE +0 -0
  45. {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 SWCNames
9
- from swcgeom.core.swc_utils.assembler import (
10
- assemble_lines_impl,
11
- try_assemble_lines_impl,
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, lines: Iterable[pd.DataFrame], *, names: Optional[SWCNames] = None
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.try_assemble_lines
71
+ self.try_assemble
64
72
  """
65
- return assemble_lines_impl(
66
- lines, thre=self.thre, undirected=self.undirected, names=names
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
- return try_assemble_lines_impl(
101
- lines,
102
- undirected=self.undirected,
103
- thre=self.thre,
104
- id_offset=id_offset,
105
- sort_nodes=sort_nodes,
106
- names=names,
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 *