swcgeom 0.15.0__py3-none-any.whl → 0.17.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 (42) hide show
  1. swcgeom/_version.py +2 -2
  2. swcgeom/analysis/__init__.py +1 -3
  3. swcgeom/analysis/feature_extractor.py +3 -3
  4. swcgeom/analysis/{node_features.py → features.py} +105 -3
  5. swcgeom/analysis/lmeasure.py +821 -0
  6. swcgeom/analysis/sholl.py +31 -2
  7. swcgeom/core/__init__.py +4 -0
  8. swcgeom/core/branch.py +9 -4
  9. swcgeom/core/{segment.py → compartment.py} +14 -9
  10. swcgeom/core/node.py +0 -8
  11. swcgeom/core/path.py +21 -6
  12. swcgeom/core/population.py +47 -7
  13. swcgeom/core/swc_utils/assembler.py +12 -1
  14. swcgeom/core/swc_utils/base.py +12 -5
  15. swcgeom/core/swc_utils/checker.py +12 -2
  16. swcgeom/core/tree.py +34 -37
  17. swcgeom/core/tree_utils.py +4 -0
  18. swcgeom/images/augmentation.py +6 -1
  19. swcgeom/images/contrast.py +107 -0
  20. swcgeom/images/folder.py +71 -14
  21. swcgeom/images/io.py +74 -88
  22. swcgeom/transforms/__init__.py +2 -0
  23. swcgeom/transforms/image_preprocess.py +100 -0
  24. swcgeom/transforms/image_stack.py +1 -4
  25. swcgeom/transforms/images.py +176 -5
  26. swcgeom/transforms/mst.py +5 -5
  27. swcgeom/transforms/neurolucida_asc.py +495 -0
  28. swcgeom/transforms/tree.py +5 -1
  29. swcgeom/utils/__init__.py +1 -0
  30. swcgeom/utils/neuromorpho.py +425 -300
  31. swcgeom/utils/numpy_helper.py +14 -4
  32. swcgeom/utils/plotter_2d.py +130 -0
  33. swcgeom/utils/renderer.py +28 -139
  34. swcgeom/utils/sdf.py +5 -1
  35. {swcgeom-0.15.0.dist-info → swcgeom-0.17.0.dist-info}/METADATA +3 -3
  36. swcgeom-0.17.0.dist-info/RECORD +65 -0
  37. {swcgeom-0.15.0.dist-info → swcgeom-0.17.0.dist-info}/WHEEL +1 -1
  38. swcgeom/analysis/branch_features.py +0 -67
  39. swcgeom/analysis/path_features.py +0 -37
  40. swcgeom-0.15.0.dist-info/RECORD +0 -62
  41. {swcgeom-0.15.0.dist-info → swcgeom-0.17.0.dist-info}/LICENSE +0 -0
  42. {swcgeom-0.15.0.dist-info → swcgeom-0.17.0.dist-info}/top_level.txt +0 -0
swcgeom/_version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.15.0'
16
- __version_tuple__ = version_tuple = (0, 15, 0)
15
+ __version__ = version = '0.17.0'
16
+ __version_tuple__ = version_tuple = (0, 17, 0)
@@ -1,9 +1,7 @@
1
1
  """Analysis for neuron trees."""
2
2
 
3
- from swcgeom.analysis.branch_features import *
4
3
  from swcgeom.analysis.feature_extractor import *
5
- from swcgeom.analysis.node_features import *
6
- from swcgeom.analysis.path_features import *
4
+ from swcgeom.analysis.features import *
7
5
  from swcgeom.analysis.sholl import *
8
6
  from swcgeom.analysis.trunk import *
9
7
  from swcgeom.analysis.visualization import *
@@ -17,13 +17,13 @@ import numpy.typing as npt
17
17
  import seaborn as sns
18
18
  from matplotlib.axes import Axes
19
19
 
20
- from swcgeom.analysis.branch_features import BranchFeatures
21
- from swcgeom.analysis.node_features import (
20
+ from swcgeom.analysis.features import (
22
21
  BifurcationFeatures,
22
+ BranchFeatures,
23
23
  NodeFeatures,
24
+ PathFeatures,
24
25
  TipFeatures,
25
26
  )
26
- from swcgeom.analysis.path_features import PathFeatures
27
27
  from swcgeom.analysis.sholl import Sholl
28
28
  from swcgeom.analysis.volume import get_volume
29
29
  from swcgeom.core import Population, Populations, Tree
@@ -1,15 +1,26 @@
1
- """Depth distribution of tree."""
1
+ """Feature anlysis of tree."""
2
2
 
3
3
  from abc import ABC, abstractmethod
4
4
  from functools import cached_property
5
+ from typing import List, TypeVar
5
6
 
6
7
  import numpy as np
7
8
  import numpy.typing as npt
8
9
  from typing_extensions import Self
9
10
 
10
- from swcgeom.core import BranchTree, Tree
11
+ from swcgeom.core import Branch, BranchTree, Tree
11
12
 
12
- __all__ = ["NodeFeatures", "BifurcationFeatures", "TipFeatures"]
13
+ __all__ = [
14
+ "NodeFeatures",
15
+ "BifurcationFeatures",
16
+ "TipFeatures",
17
+ "PathFeatures",
18
+ "BranchFeatures",
19
+ ]
20
+
21
+ T = TypeVar("T", bound=Branch)
22
+
23
+ # Node Level
13
24
 
14
25
 
15
26
  class NodeFeatures:
@@ -31,6 +42,7 @@ class NodeFeatures:
31
42
  -------
32
43
  count : array of shape (1,)
33
44
  """
45
+
34
46
  return np.array([self.tree.number_of_nodes()], dtype=np.float32)
35
47
 
36
48
  def get_radial_distance(self) -> npt.NDArray[np.float32]:
@@ -41,6 +53,7 @@ class NodeFeatures:
41
53
  radial_distance : npt.NDArray[np.float32]
42
54
  Array of shape (N,).
43
55
  """
56
+
44
57
  xyz = self.tree.xyz() - self.tree.soma().xyz()
45
58
  radial_distance = np.linalg.norm(xyz, axis=1)
46
59
  return radial_distance
@@ -58,6 +71,7 @@ class NodeFeatures:
58
71
  order : npt.NDArray[np.int32]
59
72
  Array of shape (N,), which k is the number of branchs.
60
73
  """
74
+
61
75
  order = np.zeros_like(self._branch_tree.id(), dtype=np.int32)
62
76
 
63
77
  def assign_depth(n: Tree.Node, pre_depth: int | None) -> int:
@@ -88,6 +102,7 @@ class _SubsetNodesFeatures(ABC):
88
102
  count : npt.NDArray[np.float32]
89
103
  Array of shape (1,).
90
104
  """
105
+
91
106
  return np.array([np.count_nonzero(self.nodes)], dtype=np.float32)
92
107
 
93
108
  def get_radial_distance(self) -> npt.NDArray[np.float32]:
@@ -98,6 +113,7 @@ class _SubsetNodesFeatures(ABC):
98
113
  radial_distance : npt.NDArray[np.float32]
99
114
  Array of shape (N,).
100
115
  """
116
+
101
117
  return self._features.get_radial_distance()[self.nodes]
102
118
 
103
119
  @classmethod
@@ -119,3 +135,89 @@ class TipFeatures(_SubsetNodesFeatures):
119
135
  @cached_property
120
136
  def nodes(self) -> npt.NDArray[np.bool_]:
121
137
  return np.array([n.is_tip() for n in self._features.tree])
138
+
139
+
140
+ # Path Level
141
+
142
+
143
+ class PathFeatures:
144
+ """Path analysis of tree."""
145
+
146
+ tree: Tree
147
+
148
+ def __init__(self, tree: Tree) -> None:
149
+ self.tree = tree
150
+
151
+ def get_count(self) -> int:
152
+ return len(self._paths)
153
+
154
+ def get_length(self) -> npt.NDArray[np.float32]:
155
+ """Get length of paths."""
156
+
157
+ length = [path.length() for path in self._paths]
158
+ return np.array(length, dtype=np.float32)
159
+
160
+ def get_tortuosity(self) -> npt.NDArray[np.float32]:
161
+ """Get tortuosity of path."""
162
+
163
+ return np.array([path.tortuosity() for path in self._paths], dtype=np.float32)
164
+
165
+ @cached_property
166
+ def _paths(self) -> List[Tree.Path]:
167
+ return self.tree.get_paths()
168
+
169
+
170
+ class BranchFeatures:
171
+ """Analysis bransh of tree."""
172
+
173
+ tree: Tree
174
+
175
+ def __init__(self, tree: Tree) -> None:
176
+ self.tree = tree
177
+
178
+ def get_count(self) -> int:
179
+ return len(self._branches)
180
+
181
+ def get_length(self) -> npt.NDArray[np.float32]:
182
+ """Get length of branches."""
183
+
184
+ length = [br.length() for br in self._branches]
185
+ return np.array(length, dtype=np.float32)
186
+
187
+ def get_tortuosity(self) -> npt.NDArray[np.float32]:
188
+ """Get tortuosity of path."""
189
+
190
+ return np.array([br.tortuosity() for br in self._branches], dtype=np.float32)
191
+
192
+ def get_angle(self, eps: float = 1e-7) -> npt.NDArray[np.float32]:
193
+ """Get agnle between branches.
194
+
195
+ Returns
196
+ -------
197
+ angle : npt.NDArray[np.float32]
198
+ An array of shape (N, N), which N is length of branches.
199
+ """
200
+
201
+ return self.calc_angle(self._branches, eps=eps)
202
+
203
+ @staticmethod
204
+ def calc_angle(branches: List[T], eps: float = 1e-7) -> npt.NDArray[np.float32]:
205
+ """Calc agnle between branches.
206
+
207
+ Returns
208
+ -------
209
+ angle : npt.NDArray[np.float32]
210
+ An array of shape (N, N), which N is length of branches.
211
+ """
212
+
213
+ vector = np.array([br[-1].xyz() - br[0].xyz() for br in branches])
214
+ vector_dot = np.matmul(vector, vector.T)
215
+ vector_norm = np.linalg.norm(vector, ord=2, axis=1, keepdims=True)
216
+ vector_norm_dot = np.matmul(vector_norm, vector_norm.T) + eps
217
+ arccos = np.clip(vector_dot / vector_norm_dot, -1, 1)
218
+ angle = np.arccos(arccos)
219
+ return angle
220
+
221
+ @cached_property
222
+ def _branches(self) -> List[Tree.Branch]:
223
+ return self.tree.get_branches()