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
@@ -11,7 +11,7 @@ __all__ = ["padding1d", "numpy_err"]
11
11
 
12
12
  def padding1d(
13
13
  n: int,
14
- v: npt.NDArray | None,
14
+ v: npt.ArrayLike | None,
15
15
  padding_value: Any = 0,
16
16
  dtype: npt.DTypeLike | None = None,
17
17
  ) -> npt.NDArray:
@@ -31,9 +31,19 @@ def padding1d(
31
31
  x will used, otherwise defaults to `~numpy.float32`.
32
32
  """
33
33
 
34
- dtype = dtype or (v is not None and v.dtype) or np.float32
35
- v = np.zeros(n, dtype=dtype) if v is None else v
36
- v = v.astype(dtype) if v.dtype != dtype else v
34
+ if not isinstance(v, np.ndarray):
35
+ dtype = dtype or np.float32
36
+ if v is not None:
37
+ v = np.array(v, dtype=dtype)
38
+ else:
39
+ v = np.zeros(n, dtype=dtype)
40
+
41
+ if dtype is None:
42
+ dtype = v.dtype
43
+
44
+ if v.dtype != dtype:
45
+ v = v.astype(dtype)
46
+
37
47
  assert v.ndim == 1
38
48
 
39
49
  if v.shape[0] >= n:
@@ -0,0 +1,130 @@
1
+ """Rendering related utils."""
2
+
3
+ from typing import Optional, Tuple
4
+
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+ import numpy.typing as npt
8
+ from matplotlib import cm
9
+ from matplotlib.axes import Axes
10
+ from matplotlib.collections import LineCollection, PatchCollection
11
+ from matplotlib.colors import Colormap, Normalize
12
+ from matplotlib.figure import Figure
13
+ from matplotlib.patches import Circle
14
+
15
+ from swcgeom.utils.renderer import Camera
16
+ from swcgeom.utils.transforms import to_homogeneous, translate3d
17
+
18
+ __all__ = ["draw_lines", "draw_direction_indicator", "draw_circles", "get_fig_ax"]
19
+
20
+
21
+ def draw_lines(
22
+ ax: Axes, lines: npt.NDArray[np.floating], camera: Camera, **kwargs
23
+ ) -> LineCollection:
24
+ """Draw lines.
25
+
26
+ Parameters
27
+ ----------
28
+ ax : ~matplotlib.axes.Axes
29
+ lines : A collection of coords of lines
30
+ Excepting a ndarray of shape (N, 2, 3), the axis-2 holds two points,
31
+ and the axis-3 holds the coordinates (x, y, z).
32
+ camera : Camera
33
+ Camera position.
34
+ **kwargs : dict[str, Unknown]
35
+ Forwarded to `~matplotlib.collections.LineCollection`.
36
+ """
37
+
38
+ T = camera.MVP
39
+ T = translate3d(*camera.position).dot(T) # keep origin
40
+
41
+ starts, ends = lines[:, 0], lines[:, 1]
42
+ starts, ends = to_homogeneous(starts, 1), to_homogeneous(ends, 1)
43
+ starts, ends = np.dot(T, starts.T).T[:, 0:2], np.dot(T, ends.T).T[:, 0:2]
44
+
45
+ edges = np.stack([starts, ends], axis=1)
46
+ return ax.add_collection(LineCollection(edges, **kwargs)) # type: ignore
47
+
48
+
49
+ def draw_direction_indicator(
50
+ ax: Axes, camera: Camera, loc: Tuple[float, float]
51
+ ) -> None:
52
+ x, y = loc
53
+ direction = camera.MV.dot(
54
+ [
55
+ [1, 0, 0, 1],
56
+ [0, 1, 0, 1],
57
+ [0, 0, 1, 1],
58
+ [0, 0, 0, 1],
59
+ ]
60
+ )
61
+
62
+ arrow_length, text_offset = 0.05, 0.05 # TODO: may still overlap
63
+ text_colors = [["x", "red"], ["y", "green"], ["z", "blue"]]
64
+ for (dx, dy, dz, _), (text, color) in zip(direction, text_colors):
65
+ if 1 - abs(dz) < 1e-5:
66
+ continue
67
+
68
+ ax.arrow(
69
+ x,
70
+ y,
71
+ arrow_length * dx,
72
+ arrow_length * dy,
73
+ head_length=0.02,
74
+ head_width=0.01,
75
+ color=color,
76
+ transform=ax.transAxes,
77
+ )
78
+
79
+ ax.text(
80
+ x + (arrow_length + text_offset) * dx,
81
+ y + (arrow_length + text_offset) * dy,
82
+ text,
83
+ color=color,
84
+ transform=ax.transAxes,
85
+ horizontalalignment="center",
86
+ verticalalignment="center",
87
+ )
88
+
89
+
90
+ def draw_circles(
91
+ ax: Axes,
92
+ x: npt.NDArray,
93
+ y: npt.NDArray,
94
+ *,
95
+ y_min: Optional[float] = None,
96
+ y_max: Optional[float] = None,
97
+ cmap: str | Colormap = "viridis",
98
+ ) -> PatchCollection:
99
+ """Draw a sequential of circles."""
100
+
101
+ y_min = y.min() if y_min is None else y_min
102
+ y_max = y.max() if y_max is None else y_max
103
+ norm = Normalize(y_min, y_max)
104
+
105
+ color_map = cmap if isinstance(cmap, Colormap) else cm.get_cmap(name=cmap)
106
+ colors = color_map(norm(y))
107
+
108
+ circles = [
109
+ Circle((0, 0), xi, color=color) for xi, color in reversed(list(zip(x, colors)))
110
+ ]
111
+ patches = PatchCollection(circles, match_original=True)
112
+ patches.set_cmap(color_map)
113
+ patches.set_norm(norm)
114
+ patches: PatchCollection = ax.add_collection(patches) # type: ignore
115
+
116
+ ax.set_aspect(1)
117
+ ax.autoscale()
118
+ return patches
119
+
120
+
121
+ def get_fig_ax(
122
+ fig: Optional[Figure] = None, ax: Optional[Axes] = None
123
+ ) -> Tuple[Figure, Axes]:
124
+ if fig is None and ax is not None:
125
+ fig = ax.get_figure()
126
+ assert fig is not None, "expecting a figure from the axes"
127
+
128
+ fig = fig or plt.gcf()
129
+ ax = ax or plt.gca()
130
+ return fig, ax
swcgeom/utils/renderer.py CHANGED
@@ -1,36 +1,19 @@
1
1
  """Rendering related utils."""
2
2
 
3
3
  from functools import cached_property
4
- from typing import Dict, Literal, Optional, Tuple, cast
4
+ from typing import Dict, Literal, Tuple, cast
5
5
 
6
- import matplotlib.pyplot as plt
7
6
  import numpy as np
8
7
  import numpy.typing as npt
9
- from matplotlib import cm
10
- from matplotlib.axes import Axes
11
- from matplotlib.collections import LineCollection, PatchCollection
12
- from matplotlib.colors import Colormap, Normalize
13
- from matplotlib.figure import Figure
14
- from matplotlib.patches import Circle
15
8
  from typing_extensions import Self
16
9
 
17
10
  from swcgeom.utils.transforms import (
18
11
  Vec3f,
19
12
  model_view_transformation,
20
13
  orthographic_projection_simple,
21
- to_homogeneous,
22
- translate3d,
23
14
  )
24
15
 
25
- __all__ = [
26
- "CameraOptions",
27
- "SimpleCamera",
28
- "palette",
29
- "draw_lines",
30
- "draw_direction_indicator",
31
- "draw_circles",
32
- "get_fig_ax",
33
- ]
16
+ __all__ = ["CameraOptions", "Camera", "SimpleCamera", "palette"]
34
17
 
35
18
  CameraOption = Vec3f | Tuple[Vec3f, Vec3f] | Tuple[Vec3f, Vec3f, Vec3f]
36
19
  CameraPreset = Literal["xy", "yz", "zx", "yx", "zy", "xz"]
@@ -45,13 +28,35 @@ CameraPresets: Dict[CameraPreset, Tuple[Vec3f, Vec3f, Vec3f]] = {
45
28
  CameraOptions = CameraOption | CameraPreset
46
29
 
47
30
 
48
- class SimpleCamera:
31
+ class Camera:
32
+ _position: Vec3f
33
+ _look_at: Vec3f
34
+ _up: Vec3f
35
+
36
+ # fmt: off
37
+ @property
38
+ def position(self) -> Vec3f: return self._position
39
+ @property
40
+ def look_at(self) -> Vec3f: return self._look_at
41
+ @property
42
+ def up(self) -> Vec3f: return self._up
43
+
44
+ @property
45
+ def MV(self) -> npt.NDArray[np.float32]: raise NotImplementedError()
46
+ @property
47
+ def P(self) -> npt.NDArray[np.float32]: raise NotImplementedError()
48
+ @property
49
+ def MVP(self) -> npt.NDArray[np.float32]: return self.P.dot(self.MV)
50
+ # fmt: on
51
+
52
+
53
+ class SimpleCamera(Camera):
49
54
  """Simplest camera."""
50
55
 
51
56
  def __init__(self, position: Vec3f, look_at: Vec3f, up: Vec3f):
52
- self.position = position
53
- self.look_at = look_at
54
- self.up = up
57
+ self._position = position
58
+ self._look_at = look_at
59
+ self._up = up
55
60
 
56
61
  @cached_property
57
62
  def MV(self) -> npt.NDArray[np.float32]: # pylint: disable=invalid-name
@@ -61,10 +66,6 @@ class SimpleCamera:
61
66
  def P(self) -> npt.NDArray[np.float32]: # pylint: disable=invalid-name
62
67
  return orthographic_projection_simple()
63
68
 
64
- @cached_property
65
- def MVP(self) -> npt.NDArray[np.float32]: # pylint: disable=invalid-name
66
- return self.P.dot(self.MV)
67
-
68
69
  @classmethod
69
70
  def from_options(cls, camera: CameraOptions) -> Self:
70
71
  if isinstance(camera, str):
@@ -130,115 +131,3 @@ class Palette:
130
131
 
131
132
 
132
133
  palette = Palette()
133
-
134
-
135
- def draw_lines(
136
- ax: Axes, lines: npt.NDArray[np.floating], camera: SimpleCamera, **kwargs
137
- ) -> LineCollection:
138
- """Draw lines.
139
-
140
- Parameters
141
- ----------
142
- ax : ~matplotlib.axes.Axes
143
- lines : A collection of coords of lines
144
- Excepting a ndarray of shape (N, 2, 3), the axis-2 holds two points,
145
- and the axis-3 holds the coordinates (x, y, z).
146
- camera : Camera
147
- Camera position.
148
- **kwargs : dict[str, Unknown]
149
- Forwarded to `~matplotlib.collections.LineCollection`.
150
- """
151
-
152
- T = camera.MVP
153
- T = translate3d(*camera.position).dot(T) # keep origin
154
-
155
- starts, ends = lines[:, 0], lines[:, 1]
156
- starts, ends = to_homogeneous(starts, 1), to_homogeneous(ends, 1)
157
- starts, ends = np.dot(T, starts.T).T[:, 0:2], np.dot(T, ends.T).T[:, 0:2]
158
-
159
- edges = np.stack([starts, ends], axis=1)
160
- return ax.add_collection(LineCollection(edges, **kwargs)) # type: ignore
161
-
162
-
163
- def draw_direction_indicator(
164
- ax: Axes, camera: SimpleCamera, loc: Tuple[float, float]
165
- ) -> None:
166
- x, y = loc
167
- direction = camera.MV.dot(
168
- [
169
- [1, 0, 0, 1],
170
- [0, 1, 0, 1],
171
- [0, 0, 1, 1],
172
- [0, 0, 0, 1],
173
- ]
174
- )
175
-
176
- arrow_length, text_offset = 0.05, 0.05 # TODO: may still overlap
177
- text_colors = [["x", "red"], ["y", "green"], ["z", "blue"]]
178
- for (dx, dy, dz, _), (text, color) in zip(direction, text_colors):
179
- if 1 - abs(dz) < 1e-5:
180
- continue
181
-
182
- ax.arrow(
183
- x,
184
- y,
185
- arrow_length * dx,
186
- arrow_length * dy,
187
- head_length=0.02,
188
- head_width=0.01,
189
- color=color,
190
- transform=ax.transAxes,
191
- )
192
-
193
- ax.text(
194
- x + (arrow_length + text_offset) * dx,
195
- y + (arrow_length + text_offset) * dy,
196
- text,
197
- color=color,
198
- transform=ax.transAxes,
199
- horizontalalignment="center",
200
- verticalalignment="center",
201
- )
202
-
203
-
204
- def draw_circles(
205
- ax: Axes,
206
- x: npt.NDArray,
207
- y: npt.NDArray,
208
- *,
209
- y_min: Optional[float] = None,
210
- y_max: Optional[float] = None,
211
- cmap: str | Colormap = "viridis",
212
- ) -> PatchCollection:
213
- """Draw a sequential of circles."""
214
-
215
- y_min = y.min() if y_min is None else y_min
216
- y_max = y.max() if y_max is None else y_max
217
- norm = Normalize(y_min, y_max)
218
-
219
- color_map = cmap if isinstance(cmap, Colormap) else cm.get_cmap(name=cmap)
220
- colors = color_map(norm(y))
221
-
222
- circles = [
223
- Circle((0, 0), xi, color=color) for xi, color in reversed(list(zip(x, colors)))
224
- ]
225
- patches = PatchCollection(circles, match_original=True)
226
- patches.set_cmap(color_map)
227
- patches.set_norm(norm)
228
- patches: PatchCollection = ax.add_collection(patches) # type: ignore
229
-
230
- ax.set_aspect(1)
231
- ax.autoscale()
232
- return patches
233
-
234
-
235
- def get_fig_ax(
236
- fig: Figure | None = None, ax: Axes | None = None
237
- ) -> Tuple[Figure, Axes]:
238
- if fig is None:
239
- fig = plt.gcf() if ax is None else ax.get_figure()
240
-
241
- if ax is None:
242
- ax = fig.gca()
243
-
244
- return fig, ax
swcgeom/utils/sdf.py CHANGED
@@ -174,7 +174,11 @@ class SDFDifference(SDF):
174
174
 
175
175
 
176
176
  class SDFCompose(SDFUnion):
177
- """Compose multiple SDFs."""
177
+ """Compose multiple SDFs.
178
+
179
+ .. deprecated:: 0.14.0
180
+ Use :cls:`SDFUnion` instead.
181
+ """
178
182
 
179
183
  def __init__(self, sdfs: Iterable[SDF]) -> None:
180
184
  warnings.warn(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: swcgeom
3
- Version: 0.15.0
3
+ Version: 0.17.0
4
4
  Summary: Neuron geometry library for swc format
5
5
  Author-email: yzx9 <yuan.zx@outlook.com>
6
6
  License: Apache-2.0
@@ -19,14 +19,14 @@ Requires-Dist: sdflit >=0.2.1
19
19
  Requires-Dist: seaborn >=0.12.0
20
20
  Requires-Dist: tifffile >=2022.8.12
21
21
  Requires-Dist: typing-extensions >=4.4.0
22
+ Requires-Dist: tqdm >=4.46.1
22
23
  Requires-Dist: v3d-py-helper >=0.1.0
23
24
  Provides-Extra: all
24
25
  Requires-Dist: beautifulsoup4 >=4.11.1 ; extra == 'all'
25
26
  Requires-Dist: certifi >=2023.5.7 ; extra == 'all'
26
27
  Requires-Dist: chardet >=5.2.0 ; extra == 'all'
27
28
  Requires-Dist: lmdb >=1.4.1 ; extra == 'all'
28
- Requires-Dist: pycurl >=7.0.0 ; extra == 'all'
29
- Requires-Dist: tqdm >=4.46.1 ; extra == 'all'
29
+ Requires-Dist: requests >=2.0.0 ; extra == 'all'
30
30
  Requires-Dist: urllib3 >=1.26.0 ; extra == 'all'
31
31
 
32
32
  # SWCGEOM
@@ -0,0 +1,65 @@
1
+ swcgeom/__init__.py,sha256=z88Zwcjv-ii7c7dYd9QPg9XrUVorQjtrgGbQCsEnQhc,265
2
+ swcgeom/_version.py,sha256=kBQrirg2HABnJUda1U0a6ZmIqeCqRLaPZOws884sTW8,413
3
+ swcgeom/analysis/__init__.py,sha256=NurxIAyjsxjYv9rbzNf65y2sv-iBcGTmLap645hYq9Y,280
4
+ swcgeom/analysis/feature_extractor.py,sha256=MBhnE6JbgCMhfTO8jEXqbLkVIiQh2WvVH2C4JR0IcpI,13948
5
+ swcgeom/analysis/features.py,sha256=meUXUOIqV1PgiRtgYQdFrVuTmyPYQRSJ0C1Ll97XDhU,5965
6
+ swcgeom/analysis/lmeasure.py,sha256=GI5HoIXkRp_GEDHd_JXJOMeAtZ26HP6lbSfF_0L-2r8,27559
7
+ swcgeom/analysis/sholl.py,sha256=KeUyEXLatHjmn4hOSs8y_0o8UKDq9VoIufJ_81SOtgw,7249
8
+ swcgeom/analysis/trunk.py,sha256=L2tjUIUmrRQpah_W3ZETGWd16bDXJ5F8Sk2XBNGms0Q,5558
9
+ swcgeom/analysis/visualization.py,sha256=mKOpzTPkLpr1ggGL1MZPZRTG92GEg4idLT4eN5z5KOs,5654
10
+ swcgeom/analysis/volume.py,sha256=nWPR7wGOk3Wl5eh97YMws0X-2jk8K7lmFp4-03wL3lY,4628
11
+ swcgeom/core/__init__.py,sha256=BEfFBnpaKnJOBID5G5kpGcL7_E1Fj0eZZDITDVwvmRY,445
12
+ swcgeom/core/branch.py,sha256=NchxRgXpFv_ImShvQBPU_9xNzufTrPMvEYmx7d46JNA,4162
13
+ swcgeom/core/branch_tree.py,sha256=Ece6q1VNCRLLMj29N_MjXmmlHT8h4tpWCuDE0uSgKJo,1873
14
+ swcgeom/core/compartment.py,sha256=-2EYkGfqN12he2dsrtO1afC52Bk_fMD5aRLO_useGCQ,3248
15
+ swcgeom/core/node.py,sha256=Kwqoh_WMBLIt2WNDwF-7EwS-C8lONG5krGPmmdHwhvY,3329
16
+ swcgeom/core/path.py,sha256=mxexT7eEHpRaCapE4t0dzfQGgW_zPPzn6N1MkD-jLgI,4579
17
+ swcgeom/core/population.py,sha256=MVVAgGki9SQYMuEJpWyG0eBX4ImR2wpfvWxMqAnXRa8,9824
18
+ swcgeom/core/swc.py,sha256=lSYxAa25l6O8WZ9JtSSET-RZMr6EA1Tq_aXL_x0H9Rc,6795
19
+ swcgeom/core/tree.py,sha256=fQM_Z5-bWsh55hS1pde52tSjKE9-aZY75wbKmDOOQcQ,12195
20
+ swcgeom/core/tree_utils.py,sha256=WWh7uizkyG0u7Zs6ZmkSLPYBsU4XC-gqPeOiVGyaqGE,7749
21
+ swcgeom/core/tree_utils_impl.py,sha256=kN2ByjqqQtZUfmC_ac25tXOaE-CMiV2lP58VxFphLEU,1616
22
+ swcgeom/core/swc_utils/__init__.py,sha256=qghRxjtzvq5KKfN4HhvLpZNsGPfZQu-Jj2x62_5-TbQ,575
23
+ swcgeom/core/swc_utils/assembler.py,sha256=XtjEWz_iAOMpQzLnErCiCjbnqrbB7JA4t2-LLi2R4rQ,889
24
+ swcgeom/core/swc_utils/base.py,sha256=6jNf1EeMz7yJQr3rYSi5EuU2ZPjeefB9vIRFaY53PbA,4788
25
+ swcgeom/core/swc_utils/checker.py,sha256=yuLPRoSt9c7No4GGePa05kxjGFCs0zYS7oB1HadNeMI,2852
26
+ swcgeom/core/swc_utils/io.py,sha256=6_--Qoe8kDja4PWsjwqRAvPJZNMFILFgauHaeWeGikU,6444
27
+ swcgeom/core/swc_utils/normalizer.py,sha256=_Ysi8bSJ2JBnIGB8o6BvAg2mcz6xuJp9rgNLZqpLuR8,5083
28
+ swcgeom/core/swc_utils/subtree.py,sha256=43QITYvgXu3b_kfIod2Irrj3dSfrA-gTFev5VxzRafI,1995
29
+ swcgeom/images/__init__.py,sha256=QBP1ZGGo2nWAcV7Krz-vbvW_jN4ChqXrrpoScXcUURs,96
30
+ swcgeom/images/augmentation.py,sha256=cV4k4KR_WcsRajyr0DuhHVDRRZcN4FQ7OIzB_rb2FUo,4173
31
+ swcgeom/images/contrast.py,sha256=ViZVW6XI-l2sLVTODLRLtHinv_7lVgtH-xZmaw1nQLw,2160
32
+ swcgeom/images/folder.py,sha256=YY9YjF17nDwOQEXhzFe-Dj0zPTcG0WP1-gisscImmYg,6674
33
+ swcgeom/images/io.py,sha256=05VlDcrtt3Un7M2hFddV0aWopgj55TuukSBjHLYwLHg,20704
34
+ swcgeom/transforms/__init__.py,sha256=1rr4X--qY_lBi7l7_NHyvvkoWpQOQOqkioRT8I20olI,562
35
+ swcgeom/transforms/base.py,sha256=gN5Iqi-OHkYrsjllSOdxI6Yzav3jJGoi6kUPy-38FAs,4101
36
+ swcgeom/transforms/branch.py,sha256=R0rVti--u70IiUKyHSx6MsDYJyy6zSCf18Uia2Cmh28,5410
37
+ swcgeom/transforms/geometry.py,sha256=XR73fO_8T7otUFIllqKOWW0OnrsXBc7yA01oDT99yMc,7385
38
+ swcgeom/transforms/image_preprocess.py,sha256=ZVPpRoO69dmLF5K7CWsGaQJXB2G5gxdvA-FcDmfz4yQ,3662
39
+ swcgeom/transforms/image_stack.py,sha256=RIldGAOI3QeoeBtr0VKeBKJVg-fWSmzWll63SvsaTfI,5775
40
+ swcgeom/transforms/images.py,sha256=3j8X8L9q0nSMJ_fP-73jL-zYtgi3fn3Erti9Ej1UZYo,5760
41
+ swcgeom/transforms/mst.py,sha256=Oc_HnaXjg5EXC7ZnOPneHX0-rXizDAEUcjq63GTj-ac,6251
42
+ swcgeom/transforms/neurolucida_asc.py,sha256=O4fK1OMropPnIEVdMenbyT_sV39gEGIv_6vIl6yUOVg,14146
43
+ swcgeom/transforms/path.py,sha256=Gk2iunGQMX7vE83bdo8xoDO-KAT1Vvep0iZs7oFLzFQ,1089
44
+ swcgeom/transforms/population.py,sha256=EmZ6ntuOKe8mXJxMW7nCUA-w2DVlEVe2n0IOVz49tCY,833
45
+ swcgeom/transforms/tree.py,sha256=YzLvKUwTOj92286jHah0CtRYQIxHiNiMGKcgsc_dB0E,6333
46
+ swcgeom/transforms/tree_assembler.py,sha256=vi_X9CNo5IxHP5J7bRl2z91PWufU6HmYlz1iyfdPUxE,5121
47
+ swcgeom/utils/__init__.py,sha256=LXL0wqq6-ggNweZrftp2lrNHCmVJ6LHIto3DuwlYz3c,466
48
+ swcgeom/utils/debug.py,sha256=qay2qJpViLX82mzxdndxQFn-pi1vaEj9CbLGuGt8Y9k,465
49
+ swcgeom/utils/download.py,sha256=By2qZezo6h1Ke_4YpSIhDgcisOrpjVqRmNzbhynC2xs,2834
50
+ swcgeom/utils/dsu.py,sha256=3aCbtpnl_D0OXnowTS8-kuwnCS4BKBYL5ECiFQ1fUW8,1435
51
+ swcgeom/utils/ellipse.py,sha256=LB3q5CIy75GEUdTauIpKySwIHaDrwXzzkBhOCnjJ8Vw,3259
52
+ swcgeom/utils/file.py,sha256=1hchQDsPgn-i-Vz5OQtcogxav_ajCQ_OaEZCLmqczRg,2515
53
+ swcgeom/utils/neuromorpho.py,sha256=xfQ5npDsI_3UHMFbzrBNU453ZG6C6Y271NvU6cExfuc,19107
54
+ swcgeom/utils/numpy_helper.py,sha256=xuvXpZgP-ZeuwTvPFD3DIxwJ5BK4fMCU7k5_5fUHaWE,1425
55
+ swcgeom/utils/plotter_2d.py,sha256=R34_cLfcx_ycPuXS4D0n6ERse7mmzcnhMlkz8KU4yk4,3740
56
+ swcgeom/utils/renderer.py,sha256=yGEu2SBvUQCVwsU8MT273HHgQ9uk5R0Pmo_bJaTN5yU,4233
57
+ swcgeom/utils/sdf.py,sha256=zNDgwXKRNIVcV4ORMmDXup6Bhf_vlHqwa-b3WZn6KhE,10684
58
+ swcgeom/utils/solid_geometry.py,sha256=TV02jhcoCLCqtYA9hfE50LFD_VRfixMiOSiHB5Jb2_U,2431
59
+ swcgeom/utils/transforms.py,sha256=PmP5fL_iVguq4GR2aqXhM0TeCsiFVnrPZMZG6zLohrE,6983
60
+ swcgeom/utils/volumetric_object.py,sha256=DVRGGmQrAL0oaW6hbNtp5TStbic9DfyJdCzsv2FNw2c,15134
61
+ swcgeom-0.17.0.dist-info/LICENSE,sha256=JPtohhZ4XURqoKI0ZqnMYb7dobCOoZR_n5EpnaLTp3E,11344
62
+ swcgeom-0.17.0.dist-info/METADATA,sha256=wtsF7F3P38QJtBXm0wpsAQRofs2sjXAbNHrlrFDLM-4,2332
63
+ swcgeom-0.17.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
64
+ swcgeom-0.17.0.dist-info/top_level.txt,sha256=hmLyUXWS61Gxl07haswFEKKefYPBVJYlUlol8ghNkjY,8
65
+ swcgeom-0.17.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,67 +0,0 @@
1
- """Branch anlysis of tree."""
2
-
3
- from functools import cached_property
4
- from typing import List, TypeVar
5
-
6
- import numpy as np
7
- import numpy.typing as npt
8
-
9
- from swcgeom.core import Branch, Tree
10
-
11
- __all__ = ["BranchFeatures"]
12
-
13
- T = TypeVar("T", bound=Branch)
14
-
15
-
16
- class BranchFeatures:
17
- """Analysis bransh of tree."""
18
-
19
- tree: Tree
20
-
21
- def __init__(self, tree: Tree) -> None:
22
- self.tree = tree
23
-
24
- def get_count(self) -> int:
25
- return len(self._branches)
26
-
27
- def get_length(self) -> npt.NDArray[np.float32]:
28
- """Get length of branches."""
29
- length = [br.length() for br in self._branches]
30
- return np.array(length, dtype=np.float32)
31
-
32
- def get_tortuosity(self) -> npt.NDArray[np.float32]:
33
- """Get tortuosity of path."""
34
- return np.array([br.tortuosity() for br in self._branches], dtype=np.float32)
35
-
36
- def get_angle(self, eps: float = 1e-7) -> npt.NDArray[np.float32]:
37
- """Get agnle between branches.
38
-
39
- Returns
40
- -------
41
- angle : npt.NDArray[np.float32]
42
- An array of shape (N, N), which N is length of branches.
43
- """
44
-
45
- return self.calc_angle(self._branches, eps=eps)
46
-
47
- @staticmethod
48
- def calc_angle(branches: List[T], eps: float = 1e-7) -> npt.NDArray[np.float32]:
49
- """Calc agnle between branches.
50
-
51
- Returns
52
- -------
53
- angle : npt.NDArray[np.float32]
54
- An array of shape (N, N), which N is length of branches.
55
- """
56
-
57
- vector = np.array([br[-1].xyz() - br[0].xyz() for br in branches])
58
- vector_dot = np.matmul(vector, vector.T)
59
- vector_norm = np.linalg.norm(vector, ord=2, axis=1, keepdims=True)
60
- vector_norm_dot = np.matmul(vector_norm, vector_norm.T) + eps
61
- arccos = np.clip(vector_dot / vector_norm_dot, -1, 1)
62
- angle = np.arccos(arccos)
63
- return angle
64
-
65
- @cached_property
66
- def _branches(self) -> List[Tree.Branch]:
67
- return self.tree.get_branches()
@@ -1,37 +0,0 @@
1
- """Depth distribution of tree."""
2
-
3
-
4
- from functools import cached_property
5
- from typing import List
6
-
7
- import numpy as np
8
- import numpy.typing as npt
9
-
10
- from swcgeom.core import Tree
11
-
12
- __all__ = ["PathFeatures"]
13
-
14
-
15
- class PathFeatures:
16
- """Path analysis of tree."""
17
-
18
- tree: Tree
19
-
20
- def __init__(self, tree: Tree) -> None:
21
- self.tree = tree
22
-
23
- def get_count(self) -> int:
24
- return len(self._paths)
25
-
26
- def get_length(self) -> npt.NDArray[np.float32]:
27
- """Get length of paths."""
28
- length = [path.length() for path in self._paths]
29
- return np.array(length, dtype=np.float32)
30
-
31
- def get_tortuosity(self) -> npt.NDArray[np.float32]:
32
- """Get tortuosity of path."""
33
- return np.array([path.tortuosity() for path in self._paths], dtype=np.float32)
34
-
35
- @cached_property
36
- def _paths(self) -> List[Tree.Path]:
37
- return self.tree.get_paths()
@@ -1,62 +0,0 @@
1
- swcgeom/__init__.py,sha256=z88Zwcjv-ii7c7dYd9QPg9XrUVorQjtrgGbQCsEnQhc,265
2
- swcgeom/_version.py,sha256=oHv-EAjiXbJma3jZ0Tq6UPimiWYyyw2Ao9S8zdq9uWs,413
3
- swcgeom/analysis/__init__.py,sha256=esL_poW8u-_bmp7vR9ldcumX3_xodtaVfM1USqxQo5w,377
4
- swcgeom/analysis/branch_features.py,sha256=s6PTMwwvxrVtZXRZlQbUSIw4M9-1IG63kf-Nxc0tMB0,1958
5
- swcgeom/analysis/feature_extractor.py,sha256=coe07_bJau96BkimcnXzuf4KqjY5_QRLwqaumFsu_tQ,14031
6
- swcgeom/analysis/node_features.py,sha256=fevnyrF-t4PX39ifLypiDW6EUWB8i-a3PpBnQZU3VOc,3407
7
- swcgeom/analysis/path_features.py,sha256=iE21HBxAoGLxk_qK7MBwQhyUOBqNPcnk4urVHr9SVqk,889
8
- swcgeom/analysis/sholl.py,sha256=9hSW8rZm1gvSIgcEZg8IVPT8kzBgBfwqbwP4E8R7L44,6390
9
- swcgeom/analysis/trunk.py,sha256=L2tjUIUmrRQpah_W3ZETGWd16bDXJ5F8Sk2XBNGms0Q,5558
10
- swcgeom/analysis/visualization.py,sha256=mKOpzTPkLpr1ggGL1MZPZRTG92GEg4idLT4eN5z5KOs,5654
11
- swcgeom/analysis/volume.py,sha256=nWPR7wGOk3Wl5eh97YMws0X-2jk8K7lmFp4-03wL3lY,4628
12
- swcgeom/core/__init__.py,sha256=ZUudZavxAIUU6Q0lBHrQ4ybmL5lBfvzyYsTtpuih9wg,332
13
- swcgeom/core/branch.py,sha256=uuJCxaByRu-OdDZVWEffSFcmZWY-6ZWUhHN1M2Awj1s,3980
14
- swcgeom/core/branch_tree.py,sha256=Ece6q1VNCRLLMj29N_MjXmmlHT8h4tpWCuDE0uSgKJo,1873
15
- swcgeom/core/node.py,sha256=HvfgsW4WU01hkRIPci8KF4bQMAkwtAxOGfUL4yUbuBs,3623
16
- swcgeom/core/path.py,sha256=CsEelHiDR0JPBP1dTvoCSRvX3kBlZxkQilosnncV4nQ,4188
17
- swcgeom/core/population.py,sha256=I9xSeGUveLhxkOg_5FWLcvf4yJVJ6j9_n03Hna3y_6w,8790
18
- swcgeom/core/segment.py,sha256=yabRdFj7KlkJP4V67jAlCIRzpHduNnq3bRBIRMuANfA,3158
19
- swcgeom/core/swc.py,sha256=lSYxAa25l6O8WZ9JtSSET-RZMr6EA1Tq_aXL_x0H9Rc,6795
20
- swcgeom/core/tree.py,sha256=K2k7o8OZ9r2YeMmIebT8_0qvkwJYtLLzFHECz3fmmts,12365
21
- swcgeom/core/tree_utils.py,sha256=3aCHghny5Z727sxkt6P8E2MMr34vK6irfPCelMn3vk4,7681
22
- swcgeom/core/tree_utils_impl.py,sha256=kN2ByjqqQtZUfmC_ac25tXOaE-CMiV2lP58VxFphLEU,1616
23
- swcgeom/core/swc_utils/__init__.py,sha256=qghRxjtzvq5KKfN4HhvLpZNsGPfZQu-Jj2x62_5-TbQ,575
24
- swcgeom/core/swc_utils/assembler.py,sha256=_ByaVFc61rfCS2p9QUw4g40uF4pZ6NJaDc--TcV4jWo,642
25
- swcgeom/core/swc_utils/base.py,sha256=huVxjuMLlTHbEb-KSEFDLgU0Ss3723t2Gr4Z_gQtl00,4737
26
- swcgeom/core/swc_utils/checker.py,sha256=E72GtLZ_1IqQQ7aWQGs0dZ3Z609__bw3EYQqeWrk-EI,2657
27
- swcgeom/core/swc_utils/io.py,sha256=6_--Qoe8kDja4PWsjwqRAvPJZNMFILFgauHaeWeGikU,6444
28
- swcgeom/core/swc_utils/normalizer.py,sha256=_Ysi8bSJ2JBnIGB8o6BvAg2mcz6xuJp9rgNLZqpLuR8,5083
29
- swcgeom/core/swc_utils/subtree.py,sha256=43QITYvgXu3b_kfIod2Irrj3dSfrA-gTFev5VxzRafI,1995
30
- swcgeom/images/__init__.py,sha256=QBP1ZGGo2nWAcV7Krz-vbvW_jN4ChqXrrpoScXcUURs,96
31
- swcgeom/images/augmentation.py,sha256=v9zluYXmBEbafaDBTpvJovi4_KWJmHZZSvcYHzG0oWo,4099
32
- swcgeom/images/folder.py,sha256=2REkrdNghLm1z8kZ2PDVvtsupzog8kARkeMjLuLiLFo,4955
33
- swcgeom/images/io.py,sha256=jUyKjtau8_5V-PN1kRsPHtP1OtueJi1zEf5-7PZ_tG8,21226
34
- swcgeom/transforms/__init__.py,sha256=Mi2mOgkQ50JbZ9LmgXgJIuAA5eio67oe2AOs2CCCxTQ,463
35
- swcgeom/transforms/base.py,sha256=gN5Iqi-OHkYrsjllSOdxI6Yzav3jJGoi6kUPy-38FAs,4101
36
- swcgeom/transforms/branch.py,sha256=R0rVti--u70IiUKyHSx6MsDYJyy6zSCf18Uia2Cmh28,5410
37
- swcgeom/transforms/geometry.py,sha256=XR73fO_8T7otUFIllqKOWW0OnrsXBc7yA01oDT99yMc,7385
38
- swcgeom/transforms/image_stack.py,sha256=KhZ26Ps88jk_7NkI9dkS2E7NZXUvMaN3Ln9WzJ-vPu0,5823
39
- swcgeom/transforms/images.py,sha256=l5Hx8x27zoClUz3s11j2oj0Lt9ROh5JJfjoIU_vd3H8,898
40
- swcgeom/transforms/mst.py,sha256=ceL_EWpCtoSy9zYD6wPP5zO68eNTrDl9JExoPLcE_Lw,6236
41
- swcgeom/transforms/path.py,sha256=Gk2iunGQMX7vE83bdo8xoDO-KAT1Vvep0iZs7oFLzFQ,1089
42
- swcgeom/transforms/population.py,sha256=EmZ6ntuOKe8mXJxMW7nCUA-w2DVlEVe2n0IOVz49tCY,833
43
- swcgeom/transforms/tree.py,sha256=Q45sVA7yi8pINV7ENOWPKz6DnEM3U5uJxwkFKNFS5VE,6262
44
- swcgeom/transforms/tree_assembler.py,sha256=vi_X9CNo5IxHP5J7bRl2z91PWufU6HmYlz1iyfdPUxE,5121
45
- swcgeom/utils/__init__.py,sha256=QfezYuQzgmPziNiWz2T1h77V-gjpuBoUi3mC-K-PZlI,427
46
- swcgeom/utils/debug.py,sha256=qay2qJpViLX82mzxdndxQFn-pi1vaEj9CbLGuGt8Y9k,465
47
- swcgeom/utils/download.py,sha256=By2qZezo6h1Ke_4YpSIhDgcisOrpjVqRmNzbhynC2xs,2834
48
- swcgeom/utils/dsu.py,sha256=3aCbtpnl_D0OXnowTS8-kuwnCS4BKBYL5ECiFQ1fUW8,1435
49
- swcgeom/utils/ellipse.py,sha256=LB3q5CIy75GEUdTauIpKySwIHaDrwXzzkBhOCnjJ8Vw,3259
50
- swcgeom/utils/file.py,sha256=1hchQDsPgn-i-Vz5OQtcogxav_ajCQ_OaEZCLmqczRg,2515
51
- swcgeom/utils/neuromorpho.py,sha256=CDK2tUM2pNwHv_lEserHhQs_VlY3Rn557-jtV63EFlk,14420
52
- swcgeom/utils/numpy_helper.py,sha256=A-F-eFdGktCHVAQ_HcXiFB3Y1YhhSNfAmtOl8483Dvo,1292
53
- swcgeom/utils/renderer.py,sha256=xHVZ06Z1MeKBPC3nKzuwA1HryzR0ga79y6johZA4-q0,7290
54
- swcgeom/utils/sdf.py,sha256=K-LSnwwNsGF85GW1kNBaqXAAVesxZAEsrn0nvOA2LcA,10614
55
- swcgeom/utils/solid_geometry.py,sha256=TV02jhcoCLCqtYA9hfE50LFD_VRfixMiOSiHB5Jb2_U,2431
56
- swcgeom/utils/transforms.py,sha256=PmP5fL_iVguq4GR2aqXhM0TeCsiFVnrPZMZG6zLohrE,6983
57
- swcgeom/utils/volumetric_object.py,sha256=DVRGGmQrAL0oaW6hbNtp5TStbic9DfyJdCzsv2FNw2c,15134
58
- swcgeom-0.15.0.dist-info/LICENSE,sha256=JPtohhZ4XURqoKI0ZqnMYb7dobCOoZR_n5EpnaLTp3E,11344
59
- swcgeom-0.15.0.dist-info/METADATA,sha256=VJX8KlMJWpYCZ-bMUYy_kL05sAHXmvHLMqUepQaKNTQ,2347
60
- swcgeom-0.15.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
61
- swcgeom-0.15.0.dist-info/top_level.txt,sha256=hmLyUXWS61Gxl07haswFEKKefYPBVJYlUlol8ghNkjY,8
62
- swcgeom-0.15.0.dist-info/RECORD,,