swcgeom 0.18.3__py3-none-any.whl → 0.19.1__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 (62) hide show
  1. swcgeom/analysis/feature_extractor.py +22 -24
  2. swcgeom/analysis/features.py +18 -40
  3. swcgeom/analysis/lmeasure.py +227 -323
  4. swcgeom/analysis/sholl.py +17 -23
  5. swcgeom/analysis/trunk.py +23 -28
  6. swcgeom/analysis/visualization.py +37 -44
  7. swcgeom/analysis/visualization3d.py +16 -25
  8. swcgeom/analysis/volume.py +33 -47
  9. swcgeom/core/__init__.py +1 -6
  10. swcgeom/core/branch.py +10 -17
  11. swcgeom/core/branch_tree.py +3 -2
  12. swcgeom/core/compartment.py +1 -1
  13. swcgeom/core/node.py +3 -6
  14. swcgeom/core/path.py +11 -16
  15. swcgeom/core/population.py +32 -51
  16. swcgeom/core/swc.py +25 -16
  17. swcgeom/core/swc_utils/__init__.py +4 -6
  18. swcgeom/core/swc_utils/assembler.py +5 -12
  19. swcgeom/core/swc_utils/base.py +40 -31
  20. swcgeom/core/swc_utils/checker.py +3 -8
  21. swcgeom/core/swc_utils/io.py +32 -47
  22. swcgeom/core/swc_utils/normalizer.py +17 -23
  23. swcgeom/core/swc_utils/subtree.py +13 -20
  24. swcgeom/core/tree.py +61 -51
  25. swcgeom/core/tree_utils.py +36 -49
  26. swcgeom/core/tree_utils_impl.py +4 -6
  27. swcgeom/images/augmentation.py +23 -39
  28. swcgeom/images/contrast.py +22 -46
  29. swcgeom/images/folder.py +32 -34
  30. swcgeom/images/io.py +108 -126
  31. swcgeom/transforms/base.py +28 -19
  32. swcgeom/transforms/branch.py +31 -41
  33. swcgeom/transforms/branch_tree.py +3 -1
  34. swcgeom/transforms/geometry.py +13 -4
  35. swcgeom/transforms/image_preprocess.py +2 -0
  36. swcgeom/transforms/image_stack.py +40 -35
  37. swcgeom/transforms/images.py +31 -24
  38. swcgeom/transforms/mst.py +27 -40
  39. swcgeom/transforms/neurolucida_asc.py +13 -13
  40. swcgeom/transforms/path.py +4 -0
  41. swcgeom/transforms/population.py +4 -0
  42. swcgeom/transforms/tree.py +16 -11
  43. swcgeom/transforms/tree_assembler.py +37 -54
  44. swcgeom/utils/download.py +7 -14
  45. swcgeom/utils/dsu.py +12 -0
  46. swcgeom/utils/ellipse.py +26 -14
  47. swcgeom/utils/file.py +8 -13
  48. swcgeom/utils/neuromorpho.py +78 -92
  49. swcgeom/utils/numpy_helper.py +15 -12
  50. swcgeom/utils/plotter_2d.py +10 -16
  51. swcgeom/utils/plotter_3d.py +7 -9
  52. swcgeom/utils/renderer.py +16 -8
  53. swcgeom/utils/sdf.py +12 -23
  54. swcgeom/utils/solid_geometry.py +58 -2
  55. swcgeom/utils/transforms.py +164 -100
  56. swcgeom/utils/volumetric_object.py +29 -53
  57. {swcgeom-0.18.3.dist-info → swcgeom-0.19.1.dist-info}/METADATA +6 -5
  58. swcgeom-0.19.1.dist-info/RECORD +67 -0
  59. {swcgeom-0.18.3.dist-info → swcgeom-0.19.1.dist-info}/WHEEL +1 -1
  60. swcgeom-0.18.3.dist-info/RECORD +0 -67
  61. {swcgeom-0.18.3.dist-info → swcgeom-0.19.1.dist-info/licenses}/LICENSE +0 -0
  62. {swcgeom-0.18.3.dist-info → swcgeom-0.19.1.dist-info}/top_level.txt +0 -0
swcgeom/analysis/sholl.py CHANGED
@@ -16,7 +16,7 @@
16
16
  """Sholl analysis."""
17
17
 
18
18
  import warnings
19
- from typing import Literal, Optional
19
+ from typing import Literal
20
20
 
21
21
  import numpy as np
22
22
  import numpy.typing as npt
@@ -39,13 +39,12 @@ YLABLE = "Count of Intersections"
39
39
  class Sholl:
40
40
  """Sholl analysis.
41
41
 
42
- Implementation of original Sholl analysis as described in [1]_. The
43
- Sholl analysis is a method to quantify the spatial distribution of
44
- neuronal processes. It is based on the number of intersections of
45
- concentric circles with the neuronal processes.
42
+ Implementation of original Sholl analysis as described in [1]_. The Sholl analysis
43
+ is a method to quantify the spatial distribution of neuronal processes. It is
44
+ based on the number of intersections of concentric circles with the neuronal
45
+ processes.
46
46
 
47
- References
48
- ----------
47
+ References:
49
48
  .. [1] Dendritic organization in the neurons of the visual and
50
49
  motor cortices of the cat J. Anat., 87 (1953), pp. 387-406
51
50
  """
@@ -57,11 +56,7 @@ class Sholl:
57
56
  # compat
58
57
  step: float | None = None
59
58
 
60
- def __init__(
61
- self,
62
- tree: Tree | str,
63
- step: Optional[float] = None,
64
- ) -> None:
59
+ def __init__(self, tree: Tree | str, step: float | None = None) -> None:
65
60
  tree = Tree.from_swc(tree) if isinstance(tree, str) else tree
66
61
  try:
67
62
  self.tree = TranslateOrigin.transform(tree) # shift
@@ -109,18 +104,14 @@ class Sholl:
109
104
  ) -> tuple[Figure, Axes]:
110
105
  """Plot Sholl analysis.
111
106
 
112
- Parameters
113
- ----------
114
- steps : int or list[float], default to 20
115
- Steps of raius of circle. If steps is int, then it will be
116
- evenly divided into n radii.
117
- kind : "bar" | "linechart" | "circles", default `circles`
118
- fig : ~matplotlib.figure.Figure
119
- ax : ~matplotlib.axes.Axes
120
- **kwargs :
121
- Forwarding to plot method.
107
+ Args:
108
+ steps: Steps of raius of circle.
109
+ If steps is int, then it will be evenly divided into n radii.
110
+ kind: Kind of plot.
111
+ fig: The figure to plot on.
112
+ ax: The axes to plot on.
113
+ **kwargs: Forwarding to plot method.
122
114
  """
123
-
124
115
  if plot_type is not None:
125
116
  warnings.warn(
126
117
  "`plot_type` has been renamed to `kind` since v0.5.0, "
@@ -136,9 +127,11 @@ class Sholl:
136
127
  case "bar":
137
128
  sns.barplot(x=xs, y=ys, ax=ax, **kwargs)
138
129
  ax.set_ylabel(YLABLE)
130
+
139
131
  case "linechart":
140
132
  sns.lineplot(x=xs, y=ys, ax=ax, **kwargs)
141
133
  ax.set_ylabel(YLABLE)
134
+
142
135
  case "circles":
143
136
  kwargs.setdefault("y_min", 0)
144
137
  drawtree = kwargs.pop("drawtree", True)
@@ -155,6 +148,7 @@ class Sholl:
155
148
  fig.colorbar(patches, ax=ax, label=YLABLE)
156
149
  elif isinstance(colorbar, (Axes, np.ndarray, list)):
157
150
  fig.colorbar(patches, ax=colorbar, label=YLABLE)
151
+
158
152
  case _:
159
153
  raise ValueError(f"unsupported kind: {kind}")
160
154
 
swcgeom/analysis/trunk.py CHANGED
@@ -19,7 +19,7 @@
19
19
 
20
20
  from collections.abc import Iterable
21
21
  from itertools import chain
22
- from typing import Any, Literal, Optional, cast
22
+ from typing import Any, Literal, cast
23
23
 
24
24
  import numpy as np
25
25
  import numpy.typing as npt
@@ -42,8 +42,8 @@ def draw_trunk(
42
42
  t: Tree,
43
43
  florets: Iterable[int | Iterable[int]],
44
44
  *,
45
- fig: Optional[Figure] = None,
46
- ax: Optional[Axes] = None,
45
+ fig: Figure | None = None,
46
+ ax: Axes | None = None,
47
47
  bound: Bounds | tuple[Bounds, dict[str, Any]] | None = "ellipse",
48
48
  point: bool | dict[str, Any] = True,
49
49
  projection: Projection = "2d",
@@ -52,29 +52,24 @@ def draw_trunk(
52
52
  ) -> tuple[Figure, Axes]:
53
53
  """Draw trunk tree.
54
54
 
55
- Parameters
56
- ----------
57
- t : Tree
58
- florets : List of (int | list of int)
59
- The florets that needs to be removed, each floret can be a
60
- subtree or multiple subtrees (e.g., dendrites are a bunch of
61
- subtrees), each number is the id of a tree node.
62
- fig : ~matplotlib.figure.Figure, optional
63
- ax : ~matplotlib.axes.Axes, optional
64
- bound : Bounds | (Bounds, dict[str, Any]) | None, default 'ellipse'
65
- Kind of bound, support 'aabb', 'ellipse'. If bound is None, no
66
- bound will be drawn. If bound is a tuple, the second item will
67
- used as kwargs and forward to draw function.
68
- point : bool | dict[str, Any], default True
69
- Draw point at the start of a subtree. If point is False, no
70
- point will be drawn. If point is a dict, this will used a
71
- kwargs and forward to draw function.
72
- cmap : Any, default 'viridis'
73
- Colormap, any value supported by ~matplotlib.cm.Colormap. We
74
- will use the ratio of the length of the subtree to the total
75
- length of the tree to determine the color.
76
- **kwargs : dict[str, Any]
77
- Forward to ~swcgeom.analysis.draw.
55
+ Args:
56
+ t: Tree
57
+ florets: The florets that needs to be removed.
58
+ Each floret can be a subtree or multiple subtrees (e.g., dendrites are a
59
+ bunch of subtrees), each number is the id of a tree node.
60
+ fig: Figure to plot on.
61
+ ax: Axes to plot on.
62
+ bound: Kind of bound, support 'aabb', 'ellipse'.
63
+ If bound is None, no bound will be drawn. If bound is a tuple, the second
64
+ item will used as kwargs and forward to draw function.
65
+ point: Draw point at the start of a subtree.
66
+ If point is False, no point will be drawn. If point is a dict, this will
67
+ used a kwargs and forward to draw function.
68
+ cmap: Colormap.
69
+ Any value supported by ~matplotlib.cm.Colormap. We will use the ratio of
70
+ the length of the subtree to the total length of the tree to determine the
71
+ color.
72
+ **kwargs: Forward to ~swcgeom.analysis.draw.
78
73
  """
79
74
  # pylint: disable=too-many-locals
80
75
  trunk, tss = split_florets(t, florets)
@@ -138,7 +133,7 @@ def create_bound_2d(ts: Iterable[Tree], bound: Bounds, **kwargs) -> Patch:
138
133
  return create_aabb_2d(xy, **kwargs)
139
134
  if bound == "ellipse":
140
135
  return create_ellipse_2d(xy, **kwargs)
141
- raise ValueError(f"unsupport bound `{bound}` in 2d projection")
136
+ raise ValueError(f"unsupported bound `{bound}` in 2d projection")
142
137
 
143
138
 
144
139
  def create_aabb_2d(xy: npt.NDArray, fill: bool = False, **kwargs) -> Rectangle:
@@ -177,7 +172,7 @@ def draw_point(ts: Iterable[Tree], ax: Axes, projection: Projection, **kwargs) -
177
172
 
178
173
 
179
174
  def create_point_2d(
180
- ts: Iterable[Tree], radius: Optional[float] = None, **kwargs
175
+ ts: Iterable[Tree], radius: float | None = None, **kwargs
181
176
  ) -> Circle:
182
177
  if radius is None:
183
178
  xyz = np.concatenate([t.xyz() for t in ts]) # TODO: cache
@@ -1,4 +1,5 @@
1
1
  # Copyright 2022-2025 Zexin Yuan
2
+
2
3
  #
3
4
  # Licensed under the Apache License, Version 2.0 (the "License");
4
5
  # you may not use this file except in compliance with the License.
@@ -17,7 +18,7 @@
17
18
 
18
19
  import os
19
20
  import weakref
20
- from typing import Any, Literal, Optional
21
+ from typing import Any, Literal
21
22
 
22
23
  import numpy as np
23
24
  from matplotlib.axes import Axes
@@ -50,52 +51,45 @@ ax_weak_memo = weakref.WeakKeyDictionary[Axes, dict[str, Any]]({})
50
51
  def draw(
51
52
  swc: SWCLike | str,
52
53
  *,
53
- fig: Optional[Figure] = None,
54
- ax: Optional[Axes] = None,
54
+ fig: Figure | None = None,
55
+ ax: Axes | None = None,
55
56
  show: bool | None = None,
56
57
  camera: CameraOptions = "xy",
57
- color: Optional[dict[int, str] | str] = None,
58
+ color: dict[int, str] | str | None = None,
58
59
  label: str | bool = True,
59
60
  direction_indicator: Positions | Literal[False] = "rb",
60
- unit: Optional[str] = None,
61
+ unit: str | None = None,
61
62
  **kwargs,
62
63
  ) -> tuple[Figure, Axes]:
63
64
  r"""Draw neuron tree.
64
65
 
65
- Parameters
66
- ----------
67
- swc : SWCLike | str
68
- If it is str, then it is treated as the path of swc file.
69
- fig : ~matplotlib.axes.Figure, optional
70
- ax : ~matplotlib.axes.Axes, optional
71
- show : bool | None, default `None`
72
- Wheather to call `plt.show()`. If not specified, it will depend
73
- on if ax is passed in, it will not be called, otherwise it will
74
- be called by default.
75
- camera : CameraOptions | CameraPreset, default "xy"
76
- Camera options (position, look-at, up). One, two, or three
77
- vectors are supported, if only one vector, then threat it as
78
- look-at, so camera is ((0, 0, 0), look-at, (0, 1, 0)); if two
79
- vector, then then threat it as (look-at, up), so camera is
80
- ((0, 0, 0), look-at, up). An easy way is to use the presets
81
- "xy", "yz" and "zx".
82
- color : dict[int, str] | "vaa3d" | str, optional
83
- Color map. If is dict, segments will be colored by the type of
84
- parent node.If is string, the value will be use for any type.
85
- label : str | bool, default True
86
- Label of legend, disable if False.
87
- direction_indicator : str or (float, float), default 'rb'
88
- Draw a xyz direction indicator, can be place on 'lt', 'lb',
89
- 'rt', 'rb', or custom position.
90
- unit : str, optional
91
- Add unit text, e.g.: r"$\mu m$".
92
- **kwargs : dict[str, Unknown]
93
- Forwarded to `~matplotlib.collections.LineCollection`.
94
-
95
- Returns
96
- -------
97
- fig : ~matplotlib.axes.Figure
98
- ax : ~matplotlib.axes.Axes
66
+ Args:
67
+ swc: The swc tree to draw.
68
+ If it is str, then it is treated as the path of swc file.
69
+ fig: The figure to plot on.
70
+ ax: The axes to plot on.
71
+ show: Weather to call `plt.show()`.
72
+ If not specified, it will depend on if ax is passed in, it will not be
73
+ called, otherwise it will be called by default.
74
+ camera: Camera options (position, look-at, up).
75
+ One, two, or three vectors are supported, if only one vector, then threat
76
+ it as look-at, so camera is ((0, 0, 0), look-at, (0, 1, 0)); if two vector,
77
+ then then threat it as (look-at, up), so camera is ((0, 0, 0), look-at, up).
78
+ An easy way is to use the presets "xy", "yz" and "zx".
79
+ color: Color map.
80
+ If is dict, segments will be colored by the type of parent node.If is
81
+ string, the value will be use for any type.
82
+ label: Label of legend, disable if False.
83
+ direction_indicator: Draw a xyz direction indicator.
84
+ Can be place on 'lt', 'lb', 'rt', 'rb', or custom position.
85
+ unit: str, optional
86
+ Add unit text, e.g.: r"$\mu m$".
87
+ **kwargs: dict[str, Unknown]
88
+ Forwarded to `~matplotlib.collections.LineCollection`.
89
+
90
+ Returns:
91
+ fig: The figure to plot on.
92
+ ax: The axes to plot on.
99
93
  """
100
94
  # pylint: disable=too-many-locals
101
95
  swc = Tree.from_swc(swc) if isinstance(swc, str) else swc
@@ -141,7 +135,9 @@ def get_ax_swc(ax: Axes) -> list[SWCLike]:
141
135
 
142
136
 
143
137
  def get_ax_color(
144
- ax: Axes, swc: SWCLike, color: Optional[dict[int, str] | str] = None
138
+ ax: Axes,
139
+ swc: SWCLike,
140
+ color: dict[int, str] | str | None = None, # TODO: improve typing
145
141
  ) -> str | list[str]:
146
142
  if color == "vaa3d":
147
143
  color = palette.vaa3d
@@ -176,10 +172,7 @@ def set_ax_legend(ax: Axes, *args, **kwargs) -> Legend | None:
176
172
 
177
173
 
178
174
  def _set_ax_memo(
179
- ax: Axes,
180
- swc: SWCLike,
181
- label: Optional[str | bool] = None,
182
- handle: Optional[Any] = None,
175
+ ax: Axes, swc: SWCLike, label: str | bool | None = None, handle: Any | None = None
183
176
  ):
184
177
  ax_weak_memo.setdefault(ax, {})
185
178
  ax_weak_memo[ax].setdefault("swc", [])
@@ -15,13 +15,9 @@
15
15
 
16
16
  """Painter utils.
17
17
 
18
- Notes
19
- -----
20
- This is a experimental function, it may be changed in the future.
18
+ NOTE: This is a experimental function, it may be changed in the future.
21
19
  """
22
20
 
23
- from typing import Optional
24
-
25
21
  import numpy as np
26
22
  from matplotlib.axes import Axes
27
23
  from matplotlib.figure import Figure
@@ -45,37 +41,32 @@ def draw3d(
45
41
  *,
46
42
  ax: Axes,
47
43
  show: bool | None = None,
48
- color: Optional[dict[int, str] | str] = None,
44
+ color: dict[int, str] | str | None = None, # TODO: improve typing
49
45
  label: str | bool = True,
50
46
  **kwargs,
51
47
  ) -> tuple[Figure, Axes]:
52
48
  r"""Draw neuron tree.
53
49
 
54
- Parameters
55
- ----------
56
- swc : SWCLike | str
57
- If it is str, then it is treated as the path of swc file.
58
- fig : ~matplotlib.axes.Figure, optional
59
- ax : ~matplotlib.axes.Axes, optional
60
- show : bool | None, default `None`
61
- Wheather to call `plt.show()`. If not specified, it will depend
62
- on if ax is passed in, it will not be called, otherwise it will
63
- be called by default.
64
- color : dict[int, str] | "vaa3d" | str, optional
65
- Color map. If is dict, segments will be colored by the type of
66
- parent node.If is string, the value will be use for any type.
67
- label : str | bool, default True
68
- Label of legend, disable if False.
69
- **kwargs : dict[str, Unknown]
70
- Forwarded to `~mpl_toolkits.mplot3d.art3d.Line3DCollection`.
50
+ Args:
51
+ swc: The swc tree to draw.
52
+ If it is str, then it is treated as the path of swc file.
53
+ fig: The figure to plot on.
54
+ ax: The axes to plot on.
55
+ show: Weather to call `plt.show()`.
56
+ If not specified, it will depend on if ax is passed in, it will not be
57
+ called, otherwise it will be called by default.
58
+ color: Color map.
59
+ If is dict, segments will be colored by the type of parent node.If is
60
+ string, the value will be use for any type.
61
+ label: Label of legend, disable if False.
62
+ **kwargs: Forwarded to `~mpl_toolkits.mplot3d.art3d.Line3DCollection`.
71
63
  """
72
-
73
64
  assert isinstance(ax, Axes3D), "only support 3D axes."
74
65
 
75
66
  swc = Tree.from_swc(swc) if isinstance(swc, str) else swc
76
67
 
77
68
  show = (show is True) or (show is None and ax is None)
78
- my_color = get_ax_color(ax, swc, color) # type: ignore
69
+ my_color = get_ax_color(ax, swc, color)
79
70
 
80
71
  xyz = swc.xyz()
81
72
  starts, ends = swc.id()[1:], swc.pid()[1:]
@@ -37,45 +37,34 @@ def get_volume(
37
37
  ) -> float:
38
38
  """Get the volume of the tree.
39
39
 
40
- Parameters
41
- ----------
42
- tree : Tree
43
- Neuronal tree.
44
- method : {"frustum_cone"}, optional
45
- Method for volume calculation.
46
- accuracy : int or {"low", "middle", "high"}, optional
47
- Accuracy level for volume calculation. The higher the accuracy,
48
- the more accurate the volume calculation, but the slower the
49
- calculation. The accuracy level can be specified either as an
50
- integer or as a string.
51
-
52
- The string values correspond to the following accuracy levels:
53
-
54
- - "low": 3
55
- - "middle": 5
56
- - "high": 8
57
-
58
- Returns
59
- -------
60
- volume : float
61
- Volume of the tree.
62
-
63
- Notes
64
- -----
65
- The SWC format is a method for representing neurons, which includes
66
- both the radius of individual points and their interconnectivity.
67
- Consequently, there are multiple distinct approaches to
68
- representation within this framework.
69
-
70
- Currently, we support a standard approach to volume calculation.
71
- This method involves treating each node as a sphere and
72
- representing the connections between them as truncated cone-like
73
- structures, or frustums, with varying radii at their top and bottom
74
- surfaces.
40
+ Args:
41
+ tree: Neuronal tree.
42
+ method: Method for volume calculation.
43
+ accuracy: Accuracy level for volume calculation. The higher the accuracy,
44
+ the more accurate the volume calculation, but the slower the
45
+ calculation. The accuracy level can be specified either as an
46
+ integer or as a string.
47
+
48
+ The string values correspond to the following accuracy levels:
49
+
50
+ - "low": 3
51
+ - "middle": 5
52
+ - "high": 8
53
+
54
+ Returns:
55
+ volume: Volume of the tree.
56
+
57
+ NOTE: The SWC format is a method for representing neurons, which includes both the
58
+ radius of individual points and their interconnectivity. Consequently, there are
59
+ multiple distinct approaches to representation within this framework.
60
+
61
+ Currently, we support a standard approach to volume calculation. This method
62
+ involves treating each node as a sphere and representing the connections between
63
+ them as truncated cone-like structures, or frustums, with varying radii at their
64
+ top and bottom surfaces.
75
65
 
76
66
  We welcome additional representation methods through pull requests.
77
67
  """
78
-
79
68
  if isinstance(accuracy, str):
80
69
  accuracy = ACCURACY_LEVELS[accuracy]
81
70
 
@@ -91,18 +80,15 @@ def get_volume(
91
80
  def _get_volume_frustum_cone(tree: Tree, *, accuracy: int) -> float:
92
81
  """Get the volume of the tree using the frustum cone method.
93
82
 
94
- Parameters
95
- ----------
96
- tree : Tree
97
- Neuronal tree.
98
- accuracy : int
99
- 1 : Sphere only
100
- 2 : Sphere and Frustum Cone
101
- 3 : Sphere, Frustum Cone, and intersection in single-branch
102
- 5 : Above and Sphere-Frustum Cone intersection in multi-branch
103
- 10 : Fully calculated by Monte Carlo method
83
+ Args:
84
+ tree: Neuronal tree.
85
+ accuracy: Accuracy level.
86
+ 1 : Sphere only
87
+ 2 : Sphere and Frustum Cone
88
+ 3 : Sphere, Frustum Cone, and intersection in single-branch
89
+ 5 : Above and Sphere-Frustum Cone intersection in multi-branch
90
+ 10 : Fully calculated by Monte Carlo method
104
91
  """
105
-
106
92
  if accuracy == 10:
107
93
  return _get_volume_frustum_cone_mc_only(tree)
108
94
 
swcgeom/core/__init__.py CHANGED
@@ -20,12 +20,7 @@ from swcgeom.core.branch import * # noqa: F403
20
20
  from swcgeom.core.branch_tree import * # noqa: F403
21
21
 
22
22
  # Segment and Segments don't expose
23
- from swcgeom.core.compartment import (
24
- Compartment as Compartment,
25
- )
26
- from swcgeom.core.compartment import (
27
- Compartments as Compartments,
28
- )
23
+ from swcgeom.core.compartment import Compartment, Compartments # noqa: F401
29
24
  from swcgeom.core.node import * # noqa: F403
30
25
  from swcgeom.core.path import * # noqa: F403
31
26
  from swcgeom.core.population import * # noqa: F403
swcgeom/core/branch.py CHANGED
@@ -31,10 +31,8 @@ __all__ = ["Branch"]
31
31
  class Branch(Path, Generic[SWCTypeVar]):
32
32
  r"""Neural branch.
33
33
 
34
- Notes
35
- -----
36
- Only a part of data of branch nodes is valid, such as `x`, `y`, `z` and
37
- `r`, but the `id` and `pid` is usually invalid.
34
+ NOTE: Only a part of data of branch nodes is valid, such as `x`, `y`, `z` and `r`,
35
+ but the `id` and `pid` is usually invalid.
38
36
  """
39
37
 
40
38
  attach: SWCTypeVar
@@ -76,12 +74,10 @@ class Branch(Path, Generic[SWCTypeVar]):
76
74
  def from_xyzr(cls, xyzr: npt.NDArray[np.float32]) -> "Branch[DictSWC]":
77
75
  r"""Create a branch from ~numpy.ndarray.
78
76
 
79
- Parameters
80
- ----------
81
- xyzr : npt.NDArray[np.float32]
82
- Collection of nodes. If shape (n, 4), both `x`, `y`, `z`, `r` of
83
- nodes is enabled. If shape (n, 3), only `x`, `y`, `z` is enabled
84
- and `r` will fill by 1.
77
+ Args:
78
+ xyzr: Collection of nodes.
79
+ If shape (n, 4), both `x`, `y`, `z`, `r` of nodes is enabled. If shape
80
+ (n, 3), only `x`, `y`, `z` is enabled and `r` will fill by 1.
85
81
  """
86
82
  assert xyzr.ndim == 2 and xyzr.shape[1] in (
87
83
  3,
@@ -111,14 +107,11 @@ class Branch(Path, Generic[SWCTypeVar]):
111
107
  ) -> list["Branch[DictSWC]"]:
112
108
  r"""Create list of branch form ~numpy.ndarray.
113
109
 
114
- Parameters
115
- ----------
116
- xyzr : npt.NDArray[np.float32]
117
- Batch of collection of nodes. If shape (bs, n, 4), both `x`, `y`,
118
- `z`, `r` of nodes is enabled. If shape (bs, n, 3), only `x`, `y`,
119
- `z` is enabled and `r` will fill by 1.
110
+ Args:
111
+ xyzr: Batch of collection of nodes.
112
+ If shape (bs, n, 4), both `x`, `y`, `z`, `r` of nodes is enabled. If
113
+ shape (bs, n, 3), only `x`, `y`, `z` is enabled and `r` will fill by 1.
120
114
  """
121
-
122
115
  assert xyzr_batch.ndim == 3
123
116
  assert xyzr_batch.shape[1] >= 3
124
117
 
@@ -19,6 +19,7 @@ import itertools
19
19
 
20
20
  import numpy as np
21
21
  import pandas as pd
22
+ from typing_extensions import Self
22
23
 
23
24
  from swcgeom.core.branch import Branch
24
25
  from swcgeom.core.swc_utils import to_sub_topology
@@ -44,7 +45,7 @@ class BranchTree(Tree):
44
45
  return self.branches[idx]
45
46
 
46
47
  @classmethod
47
- def from_tree(cls, tree: Tree) -> "BranchTree":
48
+ def from_tree(cls, tree: Tree) -> Self:
48
49
  """Generating a branch tree from tree."""
49
50
 
50
51
  branches = tree.get_branches()
@@ -69,6 +70,6 @@ class BranchTree(Tree):
69
70
  return branch_tree
70
71
 
71
72
  @classmethod
72
- def from_data_frame(cls, df: pd.DataFrame, *args, **kwargs) -> "BranchTree":
73
+ def from_data_frame(cls, df: pd.DataFrame, *args, **kwargs) -> Self:
73
74
  tree = super().from_data_frame(df, *args, **kwargs)
74
75
  return cls.from_tree(tree)
@@ -60,7 +60,7 @@ T = TypeVar("T", bound=Compartment)
60
60
 
61
61
 
62
62
  class Compartments(list[T]):
63
- r"""Comparments contains a set of comparment."""
63
+ r"""Comparments contains a set of compartment."""
64
64
 
65
65
  names: SWCNames
66
66
 
swcgeom/core/node.py CHANGED
@@ -119,11 +119,9 @@ class Node(Generic[SWCTypeVar]):
119
119
  def is_bifurcation(self) -> bool:
120
120
  """Is furcation node.
121
121
 
122
- Notes
123
- -----
124
- Deprecated due to the wrong spelling of furcation. For now, it
125
- is just an alias of `is_furcation` and raise a warning. It will
126
- be change to raise an error in the future.
122
+ NOTE: Deprecated due to the wrong spelling of furcation. For now, it is just an
123
+ alias of `is_furcation` and raise a warning. It will be change to raise an
124
+ error in the future.
127
125
  """
128
126
  return self.is_furcation()
129
127
 
@@ -132,7 +130,6 @@ class Node(Generic[SWCTypeVar]):
132
130
 
133
131
  def detach(self) -> "Node[DictSWC]":
134
132
  """Detach from current attached object."""
135
- # pylint: disable=consider-using-dict-items
136
133
  attact = DictSWC(
137
134
  **{k: np.array([self[k]]) for k in self.keys()},
138
135
  source=self.attach.source,
swcgeom/core/path.py CHANGED
@@ -56,15 +56,12 @@ class Path(SWCLike, Generic[SWCTypeVar]):
56
56
  def __repr__(self) -> str:
57
57
  return f"Neuron path with {len(self)} nodes."
58
58
 
59
- # fmt:off
60
59
  @overload
61
60
  def __getitem__(self, key: int) -> Node: ...
62
61
  @overload
63
62
  def __getitem__(self, key: slice) -> list[Node]: ...
64
63
  @overload
65
64
  def __getitem__(self, key: str) -> npt.NDArray: ...
66
- # fmt:on
67
-
68
65
  def __getitem__(self, key):
69
66
  if isinstance(key, slice):
70
67
  return [self.node(i) for i in range(*key.indices(len(self)))]
@@ -118,22 +115,22 @@ class Path(SWCLike, Generic[SWCTypeVar]):
118
115
  def id(self) -> npt.NDArray[np.int32]: # pylint: disable=invalid-name
119
116
  """Get the ids of shape (n_sample,).
120
117
 
121
- Returns a consecutively incremented id.
118
+ Returns:
119
+ a consecutively incremented id.
122
120
 
123
- See Also
124
- --------
125
- self.origin_id
121
+ See Also:
122
+ self.origin_id
126
123
  """
127
124
  return np.arange(len(self.origin_id()), dtype=np.int32)
128
125
 
129
126
  def pid(self) -> npt.NDArray[np.int32]:
130
127
  """Get the ids of shape (n_sample,).
131
128
 
132
- Returns a consecutively incremented pid.
129
+ Returns:
130
+ a consecutively incremented pid.
133
131
 
134
- See Also
135
- --------
136
- self.origin_pid
132
+ See Also:
133
+ self.origin_pid
137
134
  """
138
135
  return np.arange(-1, len(self.origin_id()) - 1, dtype=np.int32)
139
136
 
@@ -153,17 +150,15 @@ class Path(SWCLike, Generic[SWCTypeVar]):
153
150
  def straight_line_distance(self) -> float:
154
151
  """Straight-line distance of path.
155
152
 
156
- The end-to-end straight-line distance between start point and
157
- end point.
153
+ The end-to-end straight-line distance between start point and end point.
158
154
  """
159
155
  return np.linalg.norm(self.node(-1).xyz() - self.node(0).xyz()).item()
160
156
 
161
157
  def tortuosity(self) -> float:
162
158
  """Tortuosity of path.
163
159
 
164
- The straight-line distance between two consecutive branch
165
- points divided by the length of the neuronal path between
166
- those points.
160
+ The straight-line distance between two consecutive branch points divided by the
161
+ length of the neuronal path between those points.
167
162
  """
168
163
  if (length := self.length()) == 0:
169
164
  return 1