swcgeom 0.18.1__py3-none-any.whl → 0.19.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/__init__.py +12 -1
- swcgeom/analysis/__init__.py +6 -6
- swcgeom/analysis/feature_extractor.py +22 -24
- swcgeom/analysis/features.py +18 -40
- swcgeom/analysis/lmeasure.py +227 -323
- swcgeom/analysis/sholl.py +17 -23
- swcgeom/analysis/trunk.py +23 -28
- swcgeom/analysis/visualization.py +37 -44
- swcgeom/analysis/visualization3d.py +16 -25
- swcgeom/analysis/volume.py +33 -47
- swcgeom/core/__init__.py +12 -13
- swcgeom/core/branch.py +10 -17
- swcgeom/core/branch_tree.py +3 -2
- swcgeom/core/compartment.py +1 -1
- swcgeom/core/node.py +3 -6
- swcgeom/core/path.py +11 -16
- swcgeom/core/population.py +32 -51
- swcgeom/core/swc.py +25 -16
- swcgeom/core/swc_utils/__init__.py +10 -12
- swcgeom/core/swc_utils/assembler.py +5 -12
- swcgeom/core/swc_utils/base.py +40 -31
- swcgeom/core/swc_utils/checker.py +3 -8
- swcgeom/core/swc_utils/io.py +32 -47
- swcgeom/core/swc_utils/normalizer.py +17 -23
- swcgeom/core/swc_utils/subtree.py +13 -20
- swcgeom/core/tree.py +61 -51
- swcgeom/core/tree_utils.py +36 -49
- swcgeom/core/tree_utils_impl.py +4 -6
- swcgeom/images/__init__.py +2 -2
- swcgeom/images/augmentation.py +23 -39
- swcgeom/images/contrast.py +22 -46
- swcgeom/images/folder.py +32 -34
- swcgeom/images/io.py +80 -121
- swcgeom/transforms/__init__.py +13 -13
- swcgeom/transforms/base.py +28 -19
- swcgeom/transforms/branch.py +31 -41
- swcgeom/transforms/branch_tree.py +3 -1
- swcgeom/transforms/geometry.py +13 -4
- swcgeom/transforms/image_preprocess.py +2 -0
- swcgeom/transforms/image_stack.py +40 -35
- swcgeom/transforms/images.py +31 -24
- swcgeom/transforms/mst.py +27 -40
- swcgeom/transforms/neurolucida_asc.py +13 -13
- swcgeom/transforms/path.py +4 -0
- swcgeom/transforms/population.py +4 -0
- swcgeom/transforms/tree.py +16 -11
- swcgeom/transforms/tree_assembler.py +37 -54
- swcgeom/utils/__init__.py +12 -12
- swcgeom/utils/download.py +7 -14
- swcgeom/utils/dsu.py +12 -0
- swcgeom/utils/ellipse.py +26 -14
- swcgeom/utils/file.py +8 -13
- swcgeom/utils/neuromorpho.py +78 -92
- swcgeom/utils/numpy_helper.py +15 -12
- swcgeom/utils/plotter_2d.py +10 -16
- swcgeom/utils/plotter_3d.py +7 -9
- swcgeom/utils/renderer.py +16 -8
- swcgeom/utils/sdf.py +12 -23
- swcgeom/utils/solid_geometry.py +58 -2
- swcgeom/utils/transforms.py +164 -100
- swcgeom/utils/volumetric_object.py +29 -53
- {swcgeom-0.18.1.dist-info → swcgeom-0.19.0.dist-info}/METADATA +7 -6
- swcgeom-0.19.0.dist-info/RECORD +67 -0
- {swcgeom-0.18.1.dist-info → swcgeom-0.19.0.dist-info}/WHEEL +1 -1
- swcgeom/_version.py +0 -16
- swcgeom-0.18.1.dist-info/RECORD +0 -68
- {swcgeom-0.18.1.dist-info → swcgeom-0.19.0.dist-info/licenses}/LICENSE +0 -0
- {swcgeom-0.18.1.dist-info → swcgeom-0.19.0.dist-info}/top_level.txt +0 -0
swcgeom/utils/transforms.py
CHANGED
|
@@ -36,26 +36,56 @@ Vec3f = tuple[float, float, float]
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
def angle(a: npt.ArrayLike, b: npt.ArrayLike) -> float:
|
|
39
|
-
"""Get the angle
|
|
39
|
+
"""Get the signed angle between two vectors.
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
The angle is positive if the rotation from a to b is counter-clockwise, and
|
|
42
|
+
negative if clockwise.
|
|
43
|
+
|
|
44
|
+
>>> angle([1, 0, 0], [1, 0, 0]) # identical
|
|
45
|
+
0.0
|
|
46
|
+
>>> angle([1, 0, 0], [0, 1, 0]) # 90 degrees counter-clockwise
|
|
47
|
+
1.5707963267948966
|
|
48
|
+
>>> angle([1, 0, 0], [0, -1, 0]) # 90 degrees clockwise
|
|
49
|
+
-1.5707963267948966
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
angle: Angle in radians between -π and π.
|
|
45
53
|
"""
|
|
46
|
-
a, b = np.array(a), np.array(b)
|
|
47
|
-
costheta = np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
|
|
48
|
-
theta = np.arccos(costheta)
|
|
49
|
-
return theta if np.cross(a, b) > 0 else -theta
|
|
50
54
|
|
|
55
|
+
a = np.asarray(a)
|
|
56
|
+
b = np.asarray(b)
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
# Normalize vectors
|
|
59
|
+
a_norm = a / np.linalg.norm(a)
|
|
60
|
+
b_norm = b / np.linalg.norm(b)
|
|
61
|
+
|
|
62
|
+
# Calculate cosine of angle
|
|
63
|
+
cos_theta = np.dot(a_norm, b_norm)
|
|
64
|
+
cos_theta = np.clip(cos_theta, -1.0, 1.0) # Ensure within valid range
|
|
65
|
+
theta = np.arccos(cos_theta)
|
|
66
|
+
|
|
67
|
+
# Determine sign using cross product
|
|
68
|
+
cross = np.cross(a_norm, b_norm)
|
|
69
|
+
sign = np.sign(cross[2]) # Use z-component for 3D
|
|
70
|
+
return float(sign * theta)
|
|
54
71
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
|
|
73
|
+
def scale3d(sx: float, sy: float, sz: float) -> npt.NDArray[np.float32]:
|
|
74
|
+
"""Get the 3D scale transformation matrix.
|
|
75
|
+
|
|
76
|
+
>>> np.allclose(
|
|
77
|
+
... scale3d(2, 3, 4),
|
|
78
|
+
... [
|
|
79
|
+
... [2.0, 0.0, 0.0, 0.0],
|
|
80
|
+
... [0.0, 3.0, 0.0, 0.0],
|
|
81
|
+
... [0.0, 0.0, 4.0, 0.0],
|
|
82
|
+
... [0.0, 0.0, 0.0, 1.0],
|
|
83
|
+
... ],
|
|
84
|
+
... )
|
|
85
|
+
True
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
T: The homogeneous transformation matrix, shape (4, 4).
|
|
59
89
|
"""
|
|
60
90
|
return np.array(
|
|
61
91
|
[
|
|
@@ -69,12 +99,21 @@ def scale3d(sx: float, sy: float, sz: float) -> npt.NDArray[np.float32]:
|
|
|
69
99
|
|
|
70
100
|
|
|
71
101
|
def translate3d(tx: float, ty: float, tz: float) -> npt.NDArray[np.float32]:
|
|
72
|
-
"""Get the 3D translate
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
102
|
+
"""Get the 3D translate transformation matrix.
|
|
103
|
+
|
|
104
|
+
>>> np.allclose(
|
|
105
|
+
... translate3d(1, 2, 3),
|
|
106
|
+
... [
|
|
107
|
+
... [1.0, 0.0, 0.0, 1.0],
|
|
108
|
+
... [0.0, 1.0, 0.0, 2.0],
|
|
109
|
+
... [0.0, 0.0, 1.0, 3.0],
|
|
110
|
+
... [0.0, 0.0, 0.0, 1.0],
|
|
111
|
+
... ],
|
|
112
|
+
... )
|
|
113
|
+
True
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
T: The homogeneous transformation matrix, shape (4, 4).
|
|
78
117
|
"""
|
|
79
118
|
return np.array(
|
|
80
119
|
[
|
|
@@ -88,10 +127,10 @@ def translate3d(tx: float, ty: float, tz: float) -> npt.NDArray[np.float32]:
|
|
|
88
127
|
|
|
89
128
|
|
|
90
129
|
def rotate3d(n: npt.ArrayLike, theta: float) -> npt.NDArray[np.float32]:
|
|
91
|
-
r"""Get the 3D rotation
|
|
130
|
+
r"""Get the 3D rotation transformation matrix.
|
|
92
131
|
|
|
93
|
-
Rotate v with axis n by an angle theta according to the right hand rule,
|
|
94
|
-
|
|
132
|
+
Rotate v with axis n by an angle theta according to the right hand rule, follow
|
|
133
|
+
rodrigues' rotation formula.
|
|
95
134
|
|
|
96
135
|
.. math::
|
|
97
136
|
|
|
@@ -105,17 +144,12 @@ def rotate3d(n: npt.ArrayLike, theta: float) -> npt.NDArray[np.float32]:
|
|
|
105
144
|
-n_y & n_x & 0
|
|
106
145
|
\end{pmatrix}
|
|
107
146
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
Returns
|
|
116
|
-
-------
|
|
117
|
-
T : np.NDArray
|
|
118
|
-
The homogeneous transfomation matrix, shape (4, 4).
|
|
147
|
+
Args:
|
|
148
|
+
n: Rotation axis.
|
|
149
|
+
theta: Rotation angle in radians.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
T: The homogeneous transformation matrix, shape (4, 4).
|
|
119
153
|
"""
|
|
120
154
|
|
|
121
155
|
n = np.array(n)
|
|
@@ -138,20 +172,28 @@ def rotate3d(n: npt.ArrayLike, theta: float) -> npt.NDArray[np.float32]:
|
|
|
138
172
|
|
|
139
173
|
|
|
140
174
|
def rotate3d_x(theta: float) -> npt.NDArray[np.float32]:
|
|
141
|
-
"""Get the 3D rotation
|
|
175
|
+
"""Get the 3D rotation transformation matrix.
|
|
142
176
|
|
|
143
177
|
Rotate 3D vector `v` with `x`-axis by an angle theta according to the right
|
|
144
178
|
hand rule.
|
|
145
179
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
180
|
+
>>> np.allclose(
|
|
181
|
+
... rotate3d_x(np.pi / 2), # 90 degree rotation
|
|
182
|
+
... [
|
|
183
|
+
... [+1.0, +0.0, +0.0, +0.0],
|
|
184
|
+
... [+0.0, +0.0, -1.0, +0.0],
|
|
185
|
+
... [+0.0, +1.0, +0.0, +0.0],
|
|
186
|
+
... [+0.0, +0.0, +0.0, +1.0],
|
|
187
|
+
... ],
|
|
188
|
+
... )
|
|
189
|
+
True
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
theta: float
|
|
193
|
+
Rotation angle in radians.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
T: The homogeneous transformation matrix, shape (4, 4).
|
|
155
197
|
"""
|
|
156
198
|
|
|
157
199
|
return np.array(
|
|
@@ -166,20 +208,27 @@ def rotate3d_x(theta: float) -> npt.NDArray[np.float32]:
|
|
|
166
208
|
|
|
167
209
|
|
|
168
210
|
def rotate3d_y(theta: float) -> npt.NDArray[np.float32]:
|
|
169
|
-
"""Get the 3D rotation
|
|
211
|
+
"""Get the 3D rotation transformation matrix.
|
|
170
212
|
|
|
171
213
|
Rotate 3D vector `v` with `y`-axis by an angle theta according to the right
|
|
172
214
|
hand rule.
|
|
173
215
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
216
|
+
>>> np.allclose(
|
|
217
|
+
... rotate3d_y(np.pi / 2), # 90 degree rotation
|
|
218
|
+
... [
|
|
219
|
+
... [+0.0, +0.0, +1.0, +0.0],
|
|
220
|
+
... [+0.0, +1.0, +0.0, +0.0],
|
|
221
|
+
... [-1.0, +0.0, +0.0, +0.0],
|
|
222
|
+
... [+0.0, +0.0, +0.0, +1.0],
|
|
223
|
+
... ],
|
|
224
|
+
... )
|
|
225
|
+
True
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
theta: Rotation angle in radians.
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
T: The homogeneous transformation matrix, shape (4, 4).
|
|
183
232
|
"""
|
|
184
233
|
return np.array(
|
|
185
234
|
[
|
|
@@ -193,20 +242,29 @@ def rotate3d_y(theta: float) -> npt.NDArray[np.float32]:
|
|
|
193
242
|
|
|
194
243
|
|
|
195
244
|
def rotate3d_z(theta: float) -> npt.NDArray[np.float32]:
|
|
196
|
-
"""Get the 3D rotation
|
|
197
|
-
|
|
198
|
-
Rotate 3D vector `v` with `z`-axis by an angle theta according to the right
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
245
|
+
"""Get the 3D rotation transformation matrix.
|
|
246
|
+
|
|
247
|
+
Rotate 3D vector `v` with `z`-axis by an angle theta according to the right hand
|
|
248
|
+
rule.
|
|
249
|
+
|
|
250
|
+
>>> np.allclose(
|
|
251
|
+
... rotate3d_z(np.pi / 2), # 90 degree rotation
|
|
252
|
+
... [
|
|
253
|
+
... [+0.0, -1.0, +0.0, +0.0],
|
|
254
|
+
... [+1.0, +0.0, +0.0, +0.0],
|
|
255
|
+
... [+0.0, +0.0, +1.0, +0.0],
|
|
256
|
+
... [+0.0, +0.0, +0.0, +1.0],
|
|
257
|
+
... ],
|
|
258
|
+
... )
|
|
259
|
+
True
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
theta: float
|
|
263
|
+
Rotation angle in radians.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
T: np.NDArray
|
|
267
|
+
The homogeneous transformation matrix, shape (4, 4).
|
|
210
268
|
"""
|
|
211
269
|
return np.array(
|
|
212
270
|
[
|
|
@@ -222,17 +280,20 @@ def rotate3d_z(theta: float) -> npt.NDArray[np.float32]:
|
|
|
222
280
|
def to_homogeneous(xyz: npt.ArrayLike, w: float) -> npt.NDArray[np.float32]:
|
|
223
281
|
"""Fill xyz to homogeneous coordinates.
|
|
224
282
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
283
|
+
>>> np.allclose(to_homogeneous([1, 2, 3], 1), [1.0, 2.0, 3.0, 1.0])
|
|
284
|
+
True
|
|
285
|
+
>>> np.allclose(
|
|
286
|
+
... to_homogeneous([[1, 2, 3], [4, 5, 6]], 0),
|
|
287
|
+
... [[1.0, 2.0, 3.0, 0.0], [4.0, 5.0, 6.0, 0.0]],
|
|
288
|
+
... )
|
|
289
|
+
True
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
xyz: Coordinate of shape (..., 3)
|
|
293
|
+
w: w of homogeneous coordinate, 1 for dot, 0 for vector.
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
xyz4: Array of shape (..., 4)
|
|
236
297
|
"""
|
|
237
298
|
xyz = np.array(xyz)
|
|
238
299
|
if xyz.ndim == 1:
|
|
@@ -247,17 +308,12 @@ def to_homogeneous(xyz: npt.ArrayLike, w: float) -> npt.NDArray[np.float32]:
|
|
|
247
308
|
def _to_homogeneous(xyz: npt.NDArray, w: float) -> npt.NDArray[np.float32]:
|
|
248
309
|
"""Fill xyz to homogeneous coordinates.
|
|
249
310
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
Returns
|
|
258
|
-
-------
|
|
259
|
-
xyz4 : npt.NDArray[np.float32]
|
|
260
|
-
Array of shape (N, 4)
|
|
311
|
+
Args:
|
|
312
|
+
xyz: Coordinate of shape (N, 3)
|
|
313
|
+
w: w of homogeneous coordinate, 1 for dot, 0 for vector.
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
xyz4: Array of shape (N, 4)
|
|
261
317
|
"""
|
|
262
318
|
if xyz.shape[1] == 4:
|
|
263
319
|
return xyz
|
|
@@ -273,14 +329,10 @@ def model_view_transformation(
|
|
|
273
329
|
) -> npt.NDArray[np.float32]:
|
|
274
330
|
r"""Play model/view transformation.
|
|
275
331
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
Camera
|
|
280
|
-
look_at: Tuple[float, float, float]
|
|
281
|
-
Camera look-at \vec{g}.
|
|
282
|
-
up: Tuple[float, float, float]
|
|
283
|
-
Camera up direction \vec{t}.
|
|
332
|
+
Args:
|
|
333
|
+
position: Camera position \vec{e}.
|
|
334
|
+
look_at: Camera look-at \vec{g}.
|
|
335
|
+
up: Camera up direction \vec{t}.
|
|
284
336
|
"""
|
|
285
337
|
|
|
286
338
|
e = np.array(position, dtype=np.float32)
|
|
@@ -301,7 +353,19 @@ def model_view_transformation(
|
|
|
301
353
|
|
|
302
354
|
|
|
303
355
|
def orthographic_projection_simple() -> npt.NDArray[np.float32]:
|
|
304
|
-
"""Simple orthographic projection by drop z-axis
|
|
356
|
+
"""Simple orthographic projection by drop z-axis
|
|
357
|
+
|
|
358
|
+
>>> np.allclose(
|
|
359
|
+
... orthographic_projection_simple(),
|
|
360
|
+
... [
|
|
361
|
+
... [1.0, 0.0, 0.0, 0.0],
|
|
362
|
+
... [0.0, 1.0, 0.0, 0.0],
|
|
363
|
+
... [0.0, 0.0, 0.0, 0.0],
|
|
364
|
+
... [0.0, 0.0, 0.0, 0.0],
|
|
365
|
+
... ],
|
|
366
|
+
... )
|
|
367
|
+
True
|
|
368
|
+
"""
|
|
305
369
|
return np.array(
|
|
306
370
|
[
|
|
307
371
|
[1, 0, 0, 0],
|
|
@@ -31,7 +31,7 @@ computations.
|
|
|
31
31
|
|
|
32
32
|
import warnings
|
|
33
33
|
from abc import ABC, abstractmethod
|
|
34
|
-
from typing import Generic,
|
|
34
|
+
from typing import Generic, TypeVar
|
|
35
35
|
|
|
36
36
|
import numpy as np
|
|
37
37
|
import numpy.typing as npt
|
|
@@ -98,7 +98,7 @@ class VolMCObject(VolObject, ABC):
|
|
|
98
98
|
cache_volume: float | None = None
|
|
99
99
|
cache_volume_n_samples: int = 0
|
|
100
100
|
|
|
101
|
-
def __init__(self, *, n_samples:
|
|
101
|
+
def __init__(self, *, n_samples: int | None = None) -> None:
|
|
102
102
|
super().__init__()
|
|
103
103
|
if n_samples is not None:
|
|
104
104
|
warnings.warn(
|
|
@@ -113,17 +113,12 @@ class VolMCObject(VolObject, ABC):
|
|
|
113
113
|
def sample(self, n: int) -> tuple[npt.NDArray[np.float32], float]:
|
|
114
114
|
"""Sample points.
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
-------
|
|
123
|
-
points : ndarray
|
|
124
|
-
Sampled points.
|
|
125
|
-
volume : float
|
|
126
|
-
Volume of the sample range.
|
|
116
|
+
Args:
|
|
117
|
+
n: Number of points to sample.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
points: Sampled points.
|
|
121
|
+
volume: Volume of the sample range.
|
|
127
122
|
"""
|
|
128
123
|
raise NotImplementedError()
|
|
129
124
|
|
|
@@ -135,21 +130,17 @@ class VolMCObject(VolObject, ABC):
|
|
|
135
130
|
def is_in(self, p: npt.NDArray[np.float32]) -> npt.NDArray[np.bool_]:
|
|
136
131
|
"""Is p in the object.
|
|
137
132
|
|
|
138
|
-
Returns
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
Array of shape (N,), if bounding box is `None`, `True` will
|
|
142
|
-
be returned.
|
|
133
|
+
Returns:
|
|
134
|
+
is_in: Array of shape (N,).
|
|
135
|
+
If bounding box is `None`, `True` will be returned.
|
|
143
136
|
"""
|
|
144
137
|
return np.array([self.inside(pp) for pp in p])
|
|
145
138
|
|
|
146
|
-
def _get_volume(self, *, n_samples:
|
|
139
|
+
def _get_volume(self, *, n_samples: int | None = None) -> float:
|
|
147
140
|
"""Get volume by Monte Carlo integration.
|
|
148
141
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
n_samples : int, default 1_000_000
|
|
152
|
-
Number of samples
|
|
142
|
+
Args:
|
|
143
|
+
n_samples: Number of samples, default 1_000_000
|
|
153
144
|
"""
|
|
154
145
|
|
|
155
146
|
# legacy
|
|
@@ -178,9 +169,7 @@ class VolMCObject(VolObject, ABC):
|
|
|
178
169
|
class VolSDFObject(VolMCObject):
|
|
179
170
|
"""Volumetric SDF Object.
|
|
180
171
|
|
|
181
|
-
|
|
182
|
-
-----
|
|
183
|
-
SDF must has a bounding box.
|
|
172
|
+
NOTE: SDF must has a bounding box.
|
|
184
173
|
"""
|
|
185
174
|
|
|
186
175
|
def __init__(self, sdf: SDF, **kwargs) -> None:
|
|
@@ -294,10 +283,8 @@ class VolSphere(VolSDFObject):
|
|
|
294
283
|
V = \frac{4}{3} * π * r^3
|
|
295
284
|
\end{equation}
|
|
296
285
|
|
|
297
|
-
Returns
|
|
298
|
-
|
|
299
|
-
volume : float
|
|
300
|
-
Volume.
|
|
286
|
+
Returns:
|
|
287
|
+
volume: volume of sphere.
|
|
301
288
|
"""
|
|
302
289
|
return 4 / 3 * np.pi * radius**3
|
|
303
290
|
|
|
@@ -309,17 +296,12 @@ class VolSphere(VolSDFObject):
|
|
|
309
296
|
V = π * h^2 * (3r - h) / 3
|
|
310
297
|
\end{equation}
|
|
311
298
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
Returns
|
|
320
|
-
-------
|
|
321
|
-
volume : float
|
|
322
|
-
volume of the spherical cap
|
|
299
|
+
Args:
|
|
300
|
+
r: radius of the sphere
|
|
301
|
+
h: height of the spherical cap
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
volume: volume of the spherical cap
|
|
323
305
|
"""
|
|
324
306
|
return np.pi * h**2 * (3 * r - h) / 3
|
|
325
307
|
|
|
@@ -361,10 +343,8 @@ class VolFrustumCone(VolSDFObject):
|
|
|
361
343
|
V = \frac{1}{3} * π * h * (r^2 + r * R + R^2)
|
|
362
344
|
\end{equation}
|
|
363
345
|
|
|
364
|
-
Returns
|
|
365
|
-
|
|
366
|
-
volume : float
|
|
367
|
-
Volume.
|
|
346
|
+
Returns:
|
|
347
|
+
volume: volume of frustum.
|
|
368
348
|
"""
|
|
369
349
|
return (1 / 3) * np.pi * height * (r1**2 + r1 * r2 + r2**2)
|
|
370
350
|
|
|
@@ -386,10 +366,8 @@ class VolSphere2Intersection(VolSDFIntersection[VolSphere, VolSphere]):
|
|
|
386
366
|
V = \frac{\pi}{12d} * (r_1 + r_2 - d)^2 (d^2 + 2d r_1 - 3r_1^2 + 2d r_2 - 3r_2^2 + 6 r_1r_2)
|
|
387
367
|
\end{equation}
|
|
388
368
|
|
|
389
|
-
Returns
|
|
390
|
-
|
|
391
|
-
volume : float
|
|
392
|
-
Intersect volume.
|
|
369
|
+
Returns:
|
|
370
|
+
volume: Intersect volume.
|
|
393
371
|
"""
|
|
394
372
|
|
|
395
373
|
r1, r2 = obj1.radius, obj2.radius
|
|
@@ -440,10 +418,8 @@ class VolSphereFrustumConeIntersection(VolSDFIntersection[VolSphere, VolFrustumC
|
|
|
440
418
|
) -> float:
|
|
441
419
|
r"""Calculate intersect volume of sphere and frustum cone.
|
|
442
420
|
|
|
443
|
-
Returns
|
|
444
|
-
|
|
445
|
-
volume : float
|
|
446
|
-
Intersect volume.
|
|
421
|
+
Returns:
|
|
422
|
+
volume: Intersect volume.
|
|
447
423
|
"""
|
|
448
424
|
|
|
449
425
|
h = frustum_cone.height()
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: swcgeom
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.19.0
|
|
4
4
|
Summary: Neuron geometry library for swc format
|
|
5
|
-
Author-email: yzx9 <
|
|
5
|
+
Author-email: yzx9 <pypi@yzx9.xyz>
|
|
6
6
|
License: Apache-2.0
|
|
7
7
|
Project-URL: repository, https://github.com/yzx9/swcgeom
|
|
8
8
|
Keywords: neuronscience,neuron,neuroanatomy,neuron-morphology
|
|
@@ -15,12 +15,12 @@ Requires-Dist: numpy>=1.22.3
|
|
|
15
15
|
Requires-Dist: pandas>=1.4.2
|
|
16
16
|
Requires-Dist: pynrrd>=1.1.0
|
|
17
17
|
Requires-Dist: scipy>=1.9.1
|
|
18
|
-
Requires-Dist: sdflit>=0.2.
|
|
18
|
+
Requires-Dist: sdflit>=0.2.6
|
|
19
19
|
Requires-Dist: seaborn>=0.12.0
|
|
20
20
|
Requires-Dist: tifffile>=2022.8.12
|
|
21
|
-
Requires-Dist:
|
|
21
|
+
Requires-Dist: typing-extensions>=4.4.0
|
|
22
22
|
Requires-Dist: tqdm>=4.46.1
|
|
23
|
-
Requires-Dist: v3d-py-helper
|
|
23
|
+
Requires-Dist: v3d-py-helper>=0.4.1
|
|
24
24
|
Provides-Extra: all
|
|
25
25
|
Requires-Dist: beautifulsoup4>=4.11.1; extra == "all"
|
|
26
26
|
Requires-Dist: certifi>=2023.5.7; extra == "all"
|
|
@@ -28,6 +28,7 @@ Requires-Dist: chardet>=5.2.0; extra == "all"
|
|
|
28
28
|
Requires-Dist: lmdb>=1.4.1; extra == "all"
|
|
29
29
|
Requires-Dist: requests>=2.0.0; extra == "all"
|
|
30
30
|
Requires-Dist: urllib3>=1.26.0; extra == "all"
|
|
31
|
+
Dynamic: license-file
|
|
31
32
|
|
|
32
33
|
# SWCGEOM
|
|
33
34
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
swcgeom/__init__.py,sha256=7Hjtjg2r_dRP-oUmNX_Zza1NqV6703L0XnpuhKQ3wcs,939
|
|
2
|
+
swcgeom/analysis/__init__.py,sha256=1Bp93CxYzKqnTLzRdy8GpnhhBf6t8S2sgpEIhOJOj6w,945
|
|
3
|
+
swcgeom/analysis/feature_extractor.py,sha256=kCrsH5Df6KdocD8hKH_5SeLwdvEuWP09CbLUPaoFGdM,14787
|
|
4
|
+
swcgeom/analysis/features.py,sha256=vn_4sbwTY2muCXJqYEbQilxzSFhugaDlhips_Tt2vE8,6585
|
|
5
|
+
swcgeom/analysis/lmeasure.py,sha256=5B4ltZGvIJCHe1KDkxIvGWv2Ar4_oC5F67Q8n87CnOg,27840
|
|
6
|
+
swcgeom/analysis/sholl.py,sha256=6k7Ek6VxWJcGuTan98Ib18cjtpAzKulEeZds2kzyN6M,7043
|
|
7
|
+
swcgeom/analysis/trunk.py,sha256=q_Rdh0v-aimZKp1krji6B1lynZ7Rc9hYJhESGiLjFDY,5944
|
|
8
|
+
swcgeom/analysis/visualization.py,sha256=MXlBZG5mmoXwjHVcJfERVEYZveSkwTNweKBAIOb1dFM,6029
|
|
9
|
+
swcgeom/analysis/visualization3d.py,sha256=0PRhUOdYPl071xK5PaTl5HFrkOXfwyfHw-d3RD0W1zs,2932
|
|
10
|
+
swcgeom/analysis/volume.py,sha256=mUZRCY8KUdWZiMqZvP6_BlETLsb2_dotxC8vqu50450,5074
|
|
11
|
+
swcgeom/core/__init__.py,sha256=_iC91Q0nU7pUqydHON9hbelf4WY68uhNTRlAzS__CYk,1152
|
|
12
|
+
swcgeom/core/branch.py,sha256=xqGHtoZodId3lREaDHuHgpZruGsOddqA8hPMmlXmcLk,4651
|
|
13
|
+
swcgeom/core/branch_tree.py,sha256=uNkzcg5q99n-Wg3H7eCJQfOE6DP9m-FucCXaFCmBsdc,2443
|
|
14
|
+
swcgeom/core/compartment.py,sha256=QABZiXELtSnsg5u2M2yTOD-9aosg2KB3wRVQvm1ccpY,3851
|
|
15
|
+
swcgeom/core/node.py,sha256=HEFS7pTmGP7xlP0DfvOxbFPAGY87H7uW1exdKKeB6os,4302
|
|
16
|
+
swcgeom/core/path.py,sha256=tkYJttFv_mke9hc_2eqnPC5WJMicQC103W4-Xalo13I,5023
|
|
17
|
+
swcgeom/core/population.py,sha256=IhSZn_2ZKE8nqxpPhVGQU5hedcnkQMBCOCQnfTn5K9Q,10696
|
|
18
|
+
swcgeom/core/swc.py,sha256=AM-KQqVopVTnCpDfVRz6MsjT9Vr8wTEHeqz1aUXGq10,7416
|
|
19
|
+
swcgeom/core/tree.py,sha256=04_HM2lAI-sxQKmarSmXN0obHSD4WHaAPZr0f6nwI5E,13158
|
|
20
|
+
swcgeom/core/tree_utils.py,sha256=tfVDrhxbvGPNOzI4NifWNTzE7ckPWgCziStvYg2hU2A,7859
|
|
21
|
+
swcgeom/core/tree_utils_impl.py,sha256=XK86XX2rX6kq2x_gEjX2uIKHBuAq762C10blWiK2-MA,2156
|
|
22
|
+
swcgeom/core/swc_utils/__init__.py,sha256=oPXmYeFrlDm-rBXhU-5Y4TeKuq_2jbNWqh0_1v7pM3c,1233
|
|
23
|
+
swcgeom/core/swc_utils/assembler.py,sha256=4DahkrtqJKNyFhvrxQVLam1dwjznQ2anAl9X31Hd6LQ,1440
|
|
24
|
+
swcgeom/core/swc_utils/base.py,sha256=98J9R7rAZO685pzIJWfC66T8cfWzepf405cYXWzuuHQ,5273
|
|
25
|
+
swcgeom/core/swc_utils/checker.py,sha256=jCSGEgK9OuVV4ErOq2FStq4AJC4uFDAsnoYHwq-5a6A,3141
|
|
26
|
+
swcgeom/core/swc_utils/io.py,sha256=N90bRWZjtmUrnvlcwD_LTROJUs0OGnYDneGYF6jLnEs,6691
|
|
27
|
+
swcgeom/core/swc_utils/normalizer.py,sha256=LnPw00iiqWeacvXK0hf1_jvK3NkjvgOwrntSAHOaIDc,5576
|
|
28
|
+
swcgeom/core/swc_utils/subtree.py,sha256=kPB2_6DEX147mFNRy2viLqEOms8ypf6a7riLTu-qr_E,2530
|
|
29
|
+
swcgeom/images/__init__.py,sha256=gwBZzrsswJ2hyRQA72khFk2JPo1JfWko4-huuAYNCOU,705
|
|
30
|
+
swcgeom/images/augmentation.py,sha256=3ZWPRee3h1x1v_k2dDpAxCeUApvn2hu0TOPhTwuTe2g,4586
|
|
31
|
+
swcgeom/images/contrast.py,sha256=fLA8snaEJS-0dXkgitDmXepsMgpa4OE9MMGrU5YBz4M,2462
|
|
32
|
+
swcgeom/images/folder.py,sha256=YKJn5M090SKRVf-y5IG7sAmL6d8PsV2QeSquiuzFGHk,6847
|
|
33
|
+
swcgeom/images/io.py,sha256=p0Vm1VAQOlF-EbvOMFnf6xllWVsaJn-2NhFII7rejlI,20310
|
|
34
|
+
swcgeom/transforms/__init__.py,sha256=nE4Uyn5vpYyNiMltTiNHDRkyjYbW6B4ToyZOxUj0TU0,1370
|
|
35
|
+
swcgeom/transforms/base.py,sha256=v1EIpL5Kxg2Q1AfzZ8wSkocjSWHpD9cTeBk8dSmzDRc,4951
|
|
36
|
+
swcgeom/transforms/branch.py,sha256=gWR3lmd5b0PWYypF4WRRQ25O5DSlXok4wfm3Ycmxnbs,7560
|
|
37
|
+
swcgeom/transforms/branch_tree.py,sha256=Sc9gV-BD-KCY0kchID5zs1bIb-XwP0COLsynFPeHbaE,2882
|
|
38
|
+
swcgeom/transforms/geometry.py,sha256=8_v1ifR3taO-hL71fObLOv1jPXu3H1yaeerXkvoNn2k,8140
|
|
39
|
+
swcgeom/transforms/image_preprocess.py,sha256=bp3TIzK8sRetFdoExqfGhFkRSeZ-mv4GQzfxX2otu5c,4296
|
|
40
|
+
swcgeom/transforms/image_stack.py,sha256=SBtyLBWlBxlnt_q2uMXHgQicX5LeDwiKpmf1A-rJRUM,7353
|
|
41
|
+
swcgeom/transforms/images.py,sha256=uYIAwfQqzJwvG_yddeZ0fLXzQQbhF_OrpJ11iFQSPxQ,6264
|
|
42
|
+
swcgeom/transforms/mst.py,sha256=5XW_9R7mKI9HZmKZseTyQbizyaTv_sRybCj_4LmMxfM,6395
|
|
43
|
+
swcgeom/transforms/neurolucida_asc.py,sha256=YR-ycJAUflMFS14gBmdV1wtiSUrY3dixX0FiKd9DPds,14675
|
|
44
|
+
swcgeom/transforms/path.py,sha256=tqwSd6FDcL-xahs1u4r2GdJCdXvpL5BxpTTyQZbIZfs,1738
|
|
45
|
+
swcgeom/transforms/population.py,sha256=I9FqiW5IGlpN8DlED_8JnUx3gm9Y1GlNyEni5W5rNGU,1457
|
|
46
|
+
swcgeom/transforms/tree.py,sha256=TzLYuY9LxjLKFOG34AtlH8S6aO1IcCuRJ0vJYCF5Iso,8237
|
|
47
|
+
swcgeom/transforms/tree_assembler.py,sha256=a46N_XYpyPHoEOVdhyztcilA5e64_pqLtdF__oWF4Rg,5374
|
|
48
|
+
swcgeom/utils/__init__.py,sha256=sduLt0_W5KfoatIQ5Sj26DndwiCQhpPVkZhUVi7akFE,1215
|
|
49
|
+
swcgeom/utils/debug.py,sha256=ZOYLfj32YDjSU1tJrtThWF2SROwYhG2z7j4Fq0q4Dsw,1046
|
|
50
|
+
swcgeom/utils/download.py,sha256=8h1dLJu4Z09g6NgMI-78E1co1ebmKBQoz2TBebTZG9w,4145
|
|
51
|
+
swcgeom/utils/dsu.py,sha256=cci0YXGlOmL1wjqJKyp6la8SuvgBQrEcfuwjLtsGv6o,2267
|
|
52
|
+
swcgeom/utils/ellipse.py,sha256=kKDHTe4ZrVq88HISLyztkEedwR36ItwffB9yOLGCnKQ,4227
|
|
53
|
+
swcgeom/utils/file.py,sha256=Rfn0SDHk0BzHxUIqjFgCPcSTRLADcW3SWAMyPfBe2FI,3080
|
|
54
|
+
swcgeom/utils/neuromorpho.py,sha256=V_L_AU1Jhtg4CCLz_oYfj1mvvFX29DQNDz2BFB8Oetk,19294
|
|
55
|
+
swcgeom/utils/numpy_helper.py,sha256=XrHuG5ac45LhBJyvTm5QsB8CKl-v2dhb4cStcX_Ut0I,2183
|
|
56
|
+
swcgeom/utils/plotter_2d.py,sha256=ZVMQsiTjoHr5FKJfh_DTcsyXTJH4tM0_Zdg5lxnNzJ0,4359
|
|
57
|
+
swcgeom/utils/plotter_3d.py,sha256=lMxvjq51Aj7yBuiw2KOfWkPZwkPHMkaFuORxt2qHaTo,1405
|
|
58
|
+
swcgeom/utils/renderer.py,sha256=ILl9k1sxKK_s2CoKVfJhMKxQrYub1sJvbw4qAX0Ld20,4799
|
|
59
|
+
swcgeom/utils/sdf.py,sha256=wqetIH-7j3TKalIdkgIf-w4CarElvFMFSMJqCPv8IIE,10966
|
|
60
|
+
swcgeom/utils/solid_geometry.py,sha256=YoGDTqCs9lCS8YXrHyKhuA34zOUcPGaRZP_LvjIGSQ8,4578
|
|
61
|
+
swcgeom/utils/transforms.py,sha256=gTT4G6AvmCg2JFDx45OjUQaa4eoWQjP8_iLvk2rE70o,9576
|
|
62
|
+
swcgeom/utils/volumetric_object.py,sha256=fbTU_4rebc7r1dlYNnIeHfLg-vKdXP0ohrINVhe8RRg,15307
|
|
63
|
+
swcgeom-0.19.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
64
|
+
swcgeom-0.19.0.dist-info/METADATA,sha256=58gMTGMhk-QInpjCbn7HYHGdBHup0PBYEt8KiHsJ7YU,2323
|
|
65
|
+
swcgeom-0.19.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
66
|
+
swcgeom-0.19.0.dist-info/top_level.txt,sha256=hmLyUXWS61Gxl07haswFEKKefYPBVJYlUlol8ghNkjY,8
|
|
67
|
+
swcgeom-0.19.0.dist-info/RECORD,,
|
swcgeom/_version.py
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# file generated by setuptools_scm
|
|
2
|
-
# don't change, don't track in version control
|
|
3
|
-
TYPE_CHECKING = False
|
|
4
|
-
if TYPE_CHECKING:
|
|
5
|
-
from typing import Tuple, Union
|
|
6
|
-
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
|
-
else:
|
|
8
|
-
VERSION_TUPLE = object
|
|
9
|
-
|
|
10
|
-
version: str
|
|
11
|
-
__version__: str
|
|
12
|
-
__version_tuple__: VERSION_TUPLE
|
|
13
|
-
version_tuple: VERSION_TUPLE
|
|
14
|
-
|
|
15
|
-
__version__ = version = '0.18.1'
|
|
16
|
-
__version_tuple__ = version_tuple = (0, 18, 1)
|