swcgeom 0.11.1__tar.gz → 0.13.0__tar.gz

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 (106) hide show
  1. {swcgeom-0.11.1 → swcgeom-0.13.0}/.vscode/settings.json +6 -1
  2. {swcgeom-0.11.1 → swcgeom-0.13.0}/CHANGELOG.md +73 -0
  3. {swcgeom-0.11.1/swcgeom.egg-info → swcgeom-0.13.0}/PKG-INFO +24 -8
  4. {swcgeom-0.11.1 → swcgeom-0.13.0}/README.md +2 -4
  5. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/pytorch/tree_folder_dataset.py +2 -2
  6. swcgeom-0.13.0/pyproject.toml +43 -0
  7. swcgeom-0.13.0/swcgeom/__init__.py +6 -0
  8. swcgeom-0.13.0/swcgeom/_version.py +16 -0
  9. swcgeom-0.13.0/swcgeom/analysis/__init__.py +9 -0
  10. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/analysis/branch_features.py +1 -1
  11. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/analysis/feature_extractor.py +25 -12
  12. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/analysis/node_features.py +1 -1
  13. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/analysis/path_features.py +1 -1
  14. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/analysis/sholl.py +11 -7
  15. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/analysis/trunk.py +5 -5
  16. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/analysis/visualization.py +2 -2
  17. swcgeom-0.13.0/swcgeom/analysis/volume.py +80 -0
  18. swcgeom-0.13.0/swcgeom/core/__init__.py +11 -0
  19. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/branch.py +8 -4
  20. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/branch_tree.py +4 -5
  21. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/node.py +5 -3
  22. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/path.py +6 -3
  23. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/population.py +2 -2
  24. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/segment.py +8 -4
  25. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/swc.py +24 -3
  26. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/swc_utils/__init__.py +6 -6
  27. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/swc_utils/assembler.py +2 -2
  28. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/swc_utils/base.py +30 -1
  29. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/swc_utils/checker.py +30 -6
  30. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/swc_utils/io.py +31 -30
  31. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/swc_utils/normalizer.py +1 -1
  32. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/swc_utils/subtree.py +1 -1
  33. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/tree.py +38 -14
  34. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/core/tree_utils.py +47 -41
  35. swcgeom-0.13.0/swcgeom/core/tree_utils_impl.py +39 -0
  36. swcgeom-0.13.0/swcgeom/images/__init__.py +4 -0
  37. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/images/folder.py +2 -2
  38. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/images/io.py +48 -9
  39. swcgeom-0.13.0/swcgeom/transforms/__init__.py +12 -0
  40. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/transforms/branch.py +3 -3
  41. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/transforms/geometry.py +11 -4
  42. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/transforms/image_stack.py +3 -3
  43. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/transforms/images.py +1 -1
  44. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/transforms/mst.py +68 -13
  45. swcgeom-0.13.0/swcgeom/transforms/path.py +48 -0
  46. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/transforms/population.py +2 -2
  47. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/transforms/tree.py +18 -9
  48. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/transforms/tree_assembler.py +7 -4
  49. swcgeom-0.13.0/swcgeom/utils/__init__.py +12 -0
  50. swcgeom-0.13.0/swcgeom/utils/dsu.py +42 -0
  51. swcgeom-0.13.0/swcgeom/utils/file.py +91 -0
  52. swcgeom-0.13.0/swcgeom/utils/geometry_object.py +299 -0
  53. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/utils/neuromorpho.py +33 -11
  54. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/utils/renderer.py +5 -4
  55. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/utils/transforms.py +26 -1
  56. {swcgeom-0.11.1 → swcgeom-0.13.0/swcgeom.egg-info}/PKG-INFO +24 -8
  57. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom.egg-info/SOURCES.txt +13 -2
  58. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom.egg-info/requires.txt +3 -1
  59. swcgeom-0.13.0/tests/__init__.py +0 -0
  60. swcgeom-0.13.0/tests/utils/__init__.py +0 -0
  61. swcgeom-0.13.0/tests/utils/test_dsu.py +34 -0
  62. swcgeom-0.13.0/tests/utils/test_geometry_object.py +140 -0
  63. swcgeom-0.13.0/tests/utils/test_transforms.py +33 -0
  64. swcgeom-0.11.1/pyproject.toml +0 -43
  65. swcgeom-0.11.1/swcgeom/__init__.py +0 -6
  66. swcgeom-0.11.1/swcgeom/_version.py +0 -4
  67. swcgeom-0.11.1/swcgeom/analysis/__init__.py +0 -9
  68. swcgeom-0.11.1/swcgeom/core/__init__.py +0 -11
  69. swcgeom-0.11.1/swcgeom/images/__init__.py +0 -4
  70. swcgeom-0.11.1/swcgeom/transforms/__init__.py +0 -10
  71. swcgeom-0.11.1/swcgeom/utils/__init__.py +0 -9
  72. {swcgeom-0.11.1 → swcgeom-0.13.0}/.github/workflows/build.yml +0 -0
  73. {swcgeom-0.11.1 → swcgeom-0.13.0}/.github/workflows/github-publish.yml +0 -0
  74. {swcgeom-0.11.1 → swcgeom-0.13.0}/.github/workflows/pypi-publish.yml +0 -0
  75. {swcgeom-0.11.1 → swcgeom-0.13.0}/.github/workflows/test-pypi-publish.yml +0 -0
  76. {swcgeom-0.11.1 → swcgeom-0.13.0}/.gitignore +0 -0
  77. {swcgeom-0.11.1 → swcgeom-0.13.0}/.pylintrc +0 -0
  78. {swcgeom-0.11.1 → swcgeom-0.13.0}/LICENSE +0 -0
  79. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/Branch.ipynb +0 -0
  80. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/BranchTree.ipynb +0 -0
  81. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/CollectTips.ipynb +0 -0
  82. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/CutTree.ipynb +0 -0
  83. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/Features.ipynb +0 -0
  84. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/GeometryTransform.ipynb +0 -0
  85. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/ImageStack.ipynb +0 -0
  86. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/MST.ipynb +0 -0
  87. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/SpectralClustering.ipynb +0 -0
  88. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/Tree.ipynb +0 -0
  89. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/data/101711-10_4p5-of-16_initial.CNG.swc +0 -0
  90. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/data/101711-11_16-of-16_initial.CNG.swc +0 -0
  91. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/data/1059283677_15257_2226-X16029-Y23953.swc +0 -0
  92. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/data/toydata.swc +0 -0
  93. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/dgl/graph.py +0 -0
  94. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/pytorch/branch.py +0 -0
  95. {swcgeom-0.11.1 → swcgeom-0.13.0}/examples/pytorch/branch_dataset.py +0 -0
  96. {swcgeom-0.11.1 → swcgeom-0.13.0}/git-conventional-commits.yaml +0 -0
  97. {swcgeom-0.11.1 → swcgeom-0.13.0}/setup.cfg +0 -0
  98. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/images/augmentation.py +0 -0
  99. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/transforms/base.py +0 -0
  100. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/utils/debug.py +0 -0
  101. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/utils/download.py +0 -0
  102. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/utils/ellipse.py +0 -0
  103. /swcgeom-0.11.1/swcgeom/utils/numpy.py → /swcgeom-0.13.0/swcgeom/utils/numpy_helper.py +0 -0
  104. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom/utils/sdf.py +0 -0
  105. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom.egg-info/dependency_links.txt +0 -0
  106. {swcgeom-0.11.1 → swcgeom-0.13.0}/swcgeom.egg-info/top_level.txt +0 -0
@@ -11,5 +11,10 @@
11
11
  ],
12
12
  "[python]": {
13
13
  "editor.defaultFormatter": "ms-python.black-formatter"
14
- }
14
+ },
15
+ "python.testing.pytestArgs": [
16
+ "tests"
17
+ ],
18
+ "python.testing.unittestEnabled": false,
19
+ "python.testing.pytestEnabled": true
15
20
  }
@@ -1,5 +1,78 @@
1
1
  # Changelog
2
2
 
3
+ ## **0.13.0**&emsp;<sub><sup>2023-12-14 ([e2add59...06239bd](https://github.com/yzx9/swcgeom/compare/e2add59652bfc02d802f6770ea2c5fbc3fd7d729...06239bd129e6fab329ec80326352b48049fb504e?diff=split))</sup></sub>
4
+
5
+ ### Features
6
+
7
+ ##### `analysis`
8
+ * import sholl plot ([b03b45c](https://github.com/yzx9/swcgeom/commit/b03b45c4f20f2ed57263b1c2398316533b45b837))
9
+ * calc volume of tree \(close \#9\) ([a5004da](https://github.com/yzx9/swcgeom/commit/a5004dab71e71e68fd4a512757c9310f557878cf))
10
+
11
+ ##### `core`
12
+ * check if it has a cyclic \(\#1\) ([e2add59](https://github.com/yzx9/swcgeom/commit/e2add59652bfc02d802f6770ea2c5fbc3fd7d729))
13
+
14
+ ##### `utils`
15
+ * transform batch of vec3 to vec4 ([d2d660c](https://github.com/yzx9/swcgeom/commit/d2d660ca53b9886a81b02193ea77f76da4620ffa))
16
+
17
+ ### Bug Fixes
18
+
19
+ ##### `utils`
20
+ * should support \`StringIO\` ([de439db](https://github.com/yzx9/swcgeom/commit/de439dba00ce7407d4ae18c9427eab1e5af4d95e))
21
+
22
+ ### Performance Improvements
23
+ * improve dsu ([8b414c3](https://github.com/yzx9/swcgeom/commit/8b414c37f4fc3f4ded9c8b19eb8ee0ad52dedd53))
24
+
25
+ <br>
26
+
27
+
28
+ ## **0.12.0**&emsp;<sub><sup>2023-10-12 ([d9ba943...0824e9b](https://github.com/yzx9/swcgeom/compare/d9ba9433735c69edf979013632278e5f498a6fe0...0824e9b4110f820cd11c469ca6e319c1b2f14145?diff=split))</sup></sub>
29
+
30
+ ### Features
31
+
32
+ ##### `core`
33
+
34
+ * support read from io ([8fe9df8](https://github.com/yzx9/swcgeom/commit/8fe9df8459e8cef3cd6bde4ff3546e1a83871eda))
35
+ * get neurites and dendrites ([a9acfde](https://github.com/yzx9/swcgeom/commit/a9acfde5ab77bac22d36e7c461089f5159e6330a))
36
+ * add swc types ([7439288](https://github.com/yzx9/swcgeom/commit/7439288d199d558cd170600b07d1ab51a8489bc4))
37
+ * add type check in \`Tree\.Node\.is\_soma\` ([35b53d6](https://github.com/yzx9/swcgeom/commit/35b53d68c30e444b0b8ae57519f8196c5dbdcb4d))
38
+
39
+ ##### `images`
40
+
41
+ * support \`v3dpbd\` and \`v3draw\` \(close \#6\) ([ca8267d](https://github.com/yzx9/swcgeom/commit/ca8267d694f62abc59b9c8174efc91512a9ccec9))
42
+
43
+ ##### `transforms`
44
+
45
+ * sort mst tree by default ([7878f3f](https://github.com/yzx9/swcgeom/commit/7878f3fdb9beeebd31ecfa7649611fdd03e34eff))
46
+ * add path transforms ([aaa1b1e](https://github.com/yzx9/swcgeom/commit/aaa1b1e3c718017ae18a52d91918b29c02f302b3))
47
+
48
+ ##### `utils`
49
+
50
+ * change to utf\-8 encode ([45e971e](https://github.com/yzx9/swcgeom/commit/45e971eef9cc88abb8e1fca5f26b99e46fcb5aaf))
51
+
52
+ ### Bug Fixes
53
+
54
+ ##### `core`
55
+
56
+ * avoid duplicate cols comments ([f99eaf3](https://github.com/yzx9/swcgeom/commit/f99eaf3946846522d7eac1769f6a9a4fd20e8bf0))
57
+ * inherit source ([702efab](https://github.com/yzx9/swcgeom/commit/702efabb5db9a27e8eaed9d1feb45f24e6b4e808))
58
+ * remove original point when cat tree ([065125e](https://github.com/yzx9/swcgeom/commit/065125e7ccf0d3f6ef9ff9c7689a0e7aeb6be349))
59
+
60
+ ##### `images`
61
+
62
+ * shape should be vec4i ([0824e9b](https://github.com/yzx9/swcgeom/commit/0824e9b4110f820cd11c469ca6e319c1b2f14145))
63
+
64
+ ##### `transforms`
65
+
66
+ * add missing exports ([93bf8e6](https://github.com/yzx9/swcgeom/commit/93bf8e6076d8d7a3898a1ff88cbe05d855d1173c))
67
+
68
+ ### Performance Improvements
69
+
70
+ ##### `transforms`
71
+
72
+ * disable \`detach\` operation ([204d44c](https://github.com/yzx9/swcgeom/commit/204d44cbab563309d85f9c6f64793e5eda028547))
73
+
74
+ <br>
75
+
3
76
  ## **0.11.1**&emsp;<sub><sup>2023-08-12 ([36fa413...36fa413](https://github.com/yzx9/swcgeom/compare/36fa4135f2001694b8caea74e82c5ffa1118e90d...36fa4135f2001694b8caea74e82c5ffa1118e90d?diff=split))</sup></sub>
4
77
 
5
78
  *no relevant changes*
@@ -1,31 +1,47 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: swcgeom
3
- Version: 0.11.1
4
- Summary: A neuron geometry library for swc format
3
+ Version: 0.13.0
4
+ Summary: Neuron geometry library for swc format
5
5
  Author-email: yzx9 <yuan.zx@outlook.com>
6
6
  License: CC4.0 BY-NC-SA
7
7
  Project-URL: repository, https://github.com/yzx9/swcgeom
8
- Keywords: neuron,swc,geom
8
+ Keywords: neuronscience,neuron,neuroanatomy,neuron-morphology
9
9
  Requires-Python: >=3.10
10
10
  Description-Content-Type: text/markdown
11
- Provides-Extra: all
12
11
  License-File: LICENSE
12
+ Requires-Dist: imagecodecs>=2023.3.16
13
+ Requires-Dist: matplotlib>=3.5.2
14
+ Requires-Dist: numpy>=1.22.3
15
+ Requires-Dist: pandas>=1.4.2
16
+ Requires-Dist: pynrrd>=1.0.0
17
+ Requires-Dist: scipy>=1.9.1
18
+ Requires-Dist: seaborn>=0.12.0
19
+ Requires-Dist: sympy>=1.12
20
+ Requires-Dist: tifffile>=2022.8.12
21
+ Requires-Dist: typing_extensions>=4.4.0
22
+ Requires-Dist: v3d-py-helper-0.1.0
23
+ Provides-Extra: all
24
+ Requires-Dist: beautifulsoup4>=4.11.1; extra == "all"
25
+ Requires-Dist: certifi>=2023.5.7; extra == "all"
26
+ Requires-Dist: chardet>=5.2.0; extra == "all"
27
+ 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"
30
+ Requires-Dist: urllib3>=1.26.0; extra == "all"
13
31
 
14
- # SWC GEOM
32
+ # SWCGEOM
15
33
 
16
34
  <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a><br />
17
35
 
18
36
  [![Release to GitHub](https://github.com/yzx9/swcgeom/actions/workflows/github-publish.yml/badge.svg)](https://github.com/yzx9/swcgeom/releases)
19
-
20
37
  [![Release to PyPI](https://github.com/yzx9/swcgeom/actions/workflows/pypi-publish.yml/badge.svg)](https://pypi.org/project/swcgeom/)
21
-
22
38
  [![Release to Test PyPI](https://github.com/yzx9/swcgeom/actions/workflows/test-pypi-publish.yml/badge.svg)](https://test.pypi.org/project/swcgeom/)
23
39
 
24
40
  A neuron geometry library for swc format.
25
41
 
26
42
  ## Usage
27
43
 
28
- See documents for details.
44
+ See examples for details.
29
45
 
30
46
  ## Development
31
47
 
@@ -1,18 +1,16 @@
1
- # SWC GEOM
1
+ # SWCGEOM
2
2
 
3
3
  <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a><br />
4
4
 
5
5
  [![Release to GitHub](https://github.com/yzx9/swcgeom/actions/workflows/github-publish.yml/badge.svg)](https://github.com/yzx9/swcgeom/releases)
6
-
7
6
  [![Release to PyPI](https://github.com/yzx9/swcgeom/actions/workflows/pypi-publish.yml/badge.svg)](https://pypi.org/project/swcgeom/)
8
-
9
7
  [![Release to Test PyPI](https://github.com/yzx9/swcgeom/actions/workflows/test-pypi-publish.yml/badge.svg)](https://test.pypi.org/project/swcgeom/)
10
8
 
11
9
  A neuron geometry library for swc format.
12
10
 
13
11
  ## Usage
14
12
 
15
- See documents for details.
13
+ See examples for details.
16
14
 
17
15
  ## Development
18
16
 
@@ -4,8 +4,8 @@ from typing import Generic, TypeVar, cast
4
4
 
5
5
  import torch.utils.data
6
6
 
7
- from ...core import Population, Tree
8
- from ...transforms import Identity, Transform
7
+ from swcgeom import Population, Tree
8
+ from swcgeom.transforms import Identity, Transform
9
9
 
10
10
  __all__ = ["TreeFolderDataset"]
11
11
 
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "setuptools_scm[toml]>=6.2"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "swcgeom"
7
+ dynamic = ["version"]
8
+ description = "Neuron geometry library for swc format"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ authors = [{ name = "yzx9", email = "yuan.zx@outlook.com" }]
12
+ keywords = ["neuronscience", "neuron", "neuroanatomy", "neuron-morphology"]
13
+ license = { text = "CC4.0 BY-NC-SA" }
14
+ dependencies = [
15
+ "imagecodecs>=2023.3.16",
16
+ "matplotlib>=3.5.2",
17
+ "numpy>=1.22.3",
18
+ "pandas>=1.4.2",
19
+ "pynrrd>=1.0.0",
20
+ "scipy>=1.9.1",
21
+ "seaborn>=0.12.0",
22
+ "sympy>=1.12",
23
+ "tifffile>=2022.8.12",
24
+ "typing_extensions>=4.4.0",
25
+ "v3d-py-helper-0.1.0",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ all = [
30
+ "beautifulsoup4>=4.11.1",
31
+ "certifi>=2023.5.7",
32
+ "chardet>=5.2.0",
33
+ "lmdb>=1.4.1",
34
+ "pycurl>=7.0.0",
35
+ "tqdm>=4.46.1",
36
+ "urllib3>=1.26.0",
37
+ ]
38
+
39
+ [project.urls]
40
+ repository = "https://github.com/yzx9/swcgeom"
41
+
42
+ [tool.setuptools_scm]
43
+ write_to = "swcgeom/_version.py"
@@ -0,0 +1,6 @@
1
+ """A neuron geometry library for swc format."""
2
+
3
+ from swcgeom import analysis, core, images, transforms
4
+ from swcgeom._version import __version__, __version_tuple__
5
+ from swcgeom.analysis import draw
6
+ from swcgeom.core import BranchTree, Population, Populations, Tree
@@ -0,0 +1,16 @@
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.13.0'
16
+ __version_tuple__ = version_tuple = (0, 13, 0)
@@ -0,0 +1,9 @@
1
+ """Analysis for neuron trees."""
2
+
3
+ from swcgeom.analysis.branch_features import *
4
+ from swcgeom.analysis.feature_extractor import *
5
+ from swcgeom.analysis.node_features import *
6
+ from swcgeom.analysis.path_features import *
7
+ from swcgeom.analysis.sholl import *
8
+ from swcgeom.analysis.trunk import *
9
+ from swcgeom.analysis.visualization import *
@@ -6,7 +6,7 @@ from typing import List, TypeVar
6
6
  import numpy as np
7
7
  import numpy.typing as npt
8
8
 
9
- from ..core import Branch, Tree
9
+ from swcgeom.core import Branch, Tree
10
10
 
11
11
  __all__ = ["BranchFeatures"]
12
12
 
@@ -17,17 +17,23 @@ import numpy.typing as npt
17
17
  import seaborn as sns
18
18
  from matplotlib.axes import Axes
19
19
 
20
- from ..core import Population, Populations, Tree
21
- from ..utils import padding1d
22
- from .branch_features import BranchFeatures
23
- from .node_features import BifurcationFeatures, NodeFeatures, TipFeatures
24
- from .path_features import PathFeatures
25
- from .sholl import Sholl
20
+ from swcgeom.analysis.branch_features import BranchFeatures
21
+ from swcgeom.analysis.node_features import (
22
+ BifurcationFeatures,
23
+ NodeFeatures,
24
+ TipFeatures,
25
+ )
26
+ from swcgeom.analysis.path_features import PathFeatures
27
+ from swcgeom.analysis.sholl import Sholl
28
+ from swcgeom.analysis.volume import get_volume
29
+ from swcgeom.core import Population, Populations, Tree
30
+ from swcgeom.utils import padding1d
26
31
 
27
32
  __all__ = ["Feature", "extract_feature"]
28
33
 
29
34
  Feature = Literal[
30
35
  "length",
36
+ "volume",
31
37
  "sholl",
32
38
  # node
33
39
  "node_count",
@@ -50,7 +56,7 @@ Feature = Literal[
50
56
  NDArrayf32 = npt.NDArray[np.float32]
51
57
  FeatAndKwargs = Feature | Tuple[Feature, Dict[str, Any]]
52
58
 
53
- Feature1D = set(["length", "node_count", "bifurcation_count", "tip_count"])
59
+ Feature1D = set(["length", "volume", "node_count", "bifurcation_count", "tip_count"])
54
60
 
55
61
 
56
62
  class Features:
@@ -101,6 +107,9 @@ class Features:
101
107
  def get_length(self, **kwargs) -> NDArrayf32:
102
108
  return np.array([self.tree.length(**kwargs)], dtype=np.float32)
103
109
 
110
+ def get_volume(self, **kwargs) -> NDArrayf32:
111
+ return np.array([get_volume(self.tree, **kwargs)], dtype=np.float32)
112
+
104
113
  def get_sholl(self, **kwargs) -> NDArrayf32:
105
114
  return self.sholl.get(**kwargs).astype(np.float32)
106
115
 
@@ -284,9 +293,11 @@ class PopulationFeatureExtractor(FeatureExtractor):
284
293
  v = np.stack([padding1d(len_max, v, dtype=np.float32) for v in vals])
285
294
  return v
286
295
 
287
- def _get_sholl_impl(self, **kwargs) -> Tuple[NDArrayf32, NDArrayf32]:
296
+ def _get_sholl_impl(
297
+ self, steps: int = 20, **kwargs
298
+ ) -> Tuple[NDArrayf32, NDArrayf32]:
288
299
  rmax = max(t.sholl.rmax for t in self._features)
289
- rs = Sholl.get_rs(rmax=rmax, steps=20)
300
+ rs = Sholl.get_rs(rmax=rmax, steps=steps)
290
301
  vals = self._get_impl("sholl", steps=rs, **kwargs)
291
302
  return vals, rs
292
303
 
@@ -356,10 +367,12 @@ class PopulationsFeatureExtractor(FeatureExtractor):
356
367
 
357
368
  return out
358
369
 
359
- def _get_sholl_impl(self, **kwargs) -> Tuple[NDArrayf32, NDArrayf32]:
370
+ def _get_sholl_impl(
371
+ self, steps: int = 20, **kwargs
372
+ ) -> Tuple[NDArrayf32, NDArrayf32]:
360
373
  rmaxs = chain.from_iterable((t.sholl.rmax for t in p) for p in self._features)
361
374
  rmax = max(rmaxs)
362
- rs = Sholl.get_rs(rmax=rmax, steps=20)
375
+ rs = Sholl.get_rs(rmax=rmax, steps=steps)
363
376
  vals = self._get_impl("sholl", steps=rs, **kwargs)
364
377
  return vals, rs
365
378
 
@@ -404,7 +417,7 @@ class PopulationsFeatureExtractor(FeatureExtractor):
404
417
  return ax
405
418
 
406
419
 
407
- def extract_feature(obj: Tree | Population) -> FeatureExtractor:
420
+ def extract_feature(obj: Tree | Population | Populations) -> FeatureExtractor:
408
421
  if isinstance(obj, Tree):
409
422
  return TreeFeatureExtractor(obj)
410
423
 
@@ -7,7 +7,7 @@ import numpy as np
7
7
  import numpy.typing as npt
8
8
  from typing_extensions import Self
9
9
 
10
- from ..core import BranchTree, Tree
10
+ from swcgeom.core import BranchTree, Tree
11
11
 
12
12
  __all__ = ["NodeFeatures", "BifurcationFeatures", "TipFeatures"]
13
13
 
@@ -7,7 +7,7 @@ from typing import List
7
7
  import numpy as np
8
8
  import numpy.typing as npt
9
9
 
10
- from ..core import Tree
10
+ from swcgeom.core import Tree
11
11
 
12
12
  __all__ = ["PathFeatures"]
13
13
 
@@ -9,10 +9,10 @@ import seaborn as sns
9
9
  from matplotlib.axes import Axes
10
10
  from matplotlib.figure import Figure
11
11
 
12
- from ..core import Tree
13
- from ..transforms import TranslateOrigin
14
- from ..utils import draw_circles, get_fig_ax
15
- from .visualization import draw
12
+ from swcgeom.analysis.visualization import draw
13
+ from swcgeom.core import Tree
14
+ from swcgeom.transforms import TranslateOrigin
15
+ from swcgeom.utils import draw_circles, get_fig_ax
16
16
 
17
17
  __all__ = ["Sholl"]
18
18
 
@@ -42,9 +42,12 @@ class Sholl:
42
42
  step: Optional[float] = None,
43
43
  ) -> None:
44
44
  tree = Tree.from_swc(tree) if isinstance(tree, str) else tree
45
- self.tree = TranslateOrigin.transform(tree) # shift
46
- self.rs = np.linalg.norm(self.tree.get_segments().xyz(), axis=2)
47
- self.rmax = self.rs.max()
45
+ try:
46
+ self.tree = TranslateOrigin.transform(tree) # shift
47
+ self.rs = np.linalg.norm(self.tree.get_segments().xyz(), axis=2)
48
+ self.rmax = self.rs.max()
49
+ except Exception as e:
50
+ raise ValueError(f"invalid tree: {tree.source or ''}") from e
48
51
 
49
52
  if step is not None:
50
53
  warnings.warn(
@@ -96,6 +99,7 @@ class Sholl:
96
99
  **kwargs :
97
100
  Forwarding to plot method.
98
101
  """
102
+
99
103
  if plot_type is not None:
100
104
  warnings.warn(
101
105
  "`plot_type` has been renamed to `kind` since v0.5.0, "
@@ -12,9 +12,9 @@ from matplotlib.axes import Axes
12
12
  from matplotlib.figure import Figure
13
13
  from matplotlib.patches import Circle, Ellipse, Patch, Rectangle
14
14
 
15
- from ..core import Tree, get_subtree, to_subtree
16
- from ..utils import get_fig_ax, mvee
17
- from .visualization import draw
15
+ from swcgeom.analysis.visualization import draw
16
+ from swcgeom.core import Tree, get_subtree, to_subtree
17
+ from swcgeom.utils import get_fig_ax, mvee
18
18
 
19
19
  __all__ = ["draw_trunk"]
20
20
 
@@ -178,5 +178,5 @@ def create_point_2d(
178
178
  # Helpers
179
179
 
180
180
 
181
- def get_dendrites(tree: Tree) -> Iterable[int]: # TODO: move to `Tree`
182
- return [n.id for n in tree.soma().children() if n.type in [3, 4]]
181
+ def get_dendrites(tree: Tree) -> Iterable[int]:
182
+ return (t.node(0).id for t in tree.get_dendrites())
@@ -9,8 +9,8 @@ from matplotlib.axes import Axes
9
9
  from matplotlib.figure import Figure
10
10
  from matplotlib.legend import Legend
11
11
 
12
- from ..core import SWCLike, Tree
13
- from ..utils import (
12
+ from swcgeom.core import SWCLike, Tree
13
+ from swcgeom.utils import (
14
14
  CameraOptions,
15
15
  SimpleCamera,
16
16
  draw_direction_indicator,
@@ -0,0 +1,80 @@
1
+ """Analysis of volume of a SWC tree."""
2
+
3
+ from typing import List
4
+
5
+ from swcgeom.core import Tree
6
+ from swcgeom.utils import GeomFrustumCone, GeomSphere
7
+
8
+ __all__ = ["get_volume"]
9
+
10
+
11
+ def get_volume(tree: Tree):
12
+ """Get the volume of the tree.
13
+
14
+ Parameters
15
+ ----------
16
+ tree : Tree
17
+ SWC tree.
18
+
19
+ Returns
20
+ -------
21
+ volume : float
22
+ Volume of the tree.
23
+
24
+ Notes
25
+ -----
26
+ The SWC format is a method for representing neurons, which includes
27
+ both the radius of individual points and their interconnectivity.
28
+ Consequently, there are multiple distinct approaches to
29
+ representation within this framework.
30
+
31
+ Currently, we support a standard approach to volume calculation.
32
+ This method involves treating each node as a sphere and
33
+ representing the connections between them as truncated cone-like
34
+ structures, or frustums, with varying radii at their top and bottom
35
+ surfaces.
36
+
37
+ More representation methods will be supported in the future.
38
+ """
39
+ volume = 0.0
40
+
41
+ def leave(node: Tree.Node, children: List[GeomSphere]) -> GeomSphere:
42
+ sphere = GeomSphere(node.xyz(), node.r)
43
+ frustum_cones = [
44
+ GeomFrustumCone(node.xyz(), node.r, c.center, c.radius) for c in children
45
+ ]
46
+
47
+ v = sphere.get_volume()
48
+ v += sum(fc.get_volume() for fc in frustum_cones)
49
+ v -= sum(sphere.get_intersect_volume(fc) for fc in frustum_cones)
50
+ v -= sum(s.get_intersect_volume(fc) for s, fc in zip(children, frustum_cones))
51
+
52
+ # TODO
53
+ # remove volume of intersection between frustum cones
54
+ # v -= sum(
55
+ # fc1.get_intersect_volume(fc2)
56
+ # for fc1 in frustum_cones
57
+ # for fc2 in frustum_cones
58
+ # if fc1 != fc2
59
+ # )
60
+
61
+ nonlocal volume
62
+ volume += v
63
+ return sphere
64
+
65
+ tree.traverse(leave=leave)
66
+ return volume
67
+
68
+
69
+ if __name__ == "__main__":
70
+ from io import StringIO
71
+
72
+ swc = """
73
+ 1 1 0 0 0 1 -1
74
+ 2 1 2 0 0 1 1
75
+ 3 1 4 0 0 1 2
76
+ """
77
+
78
+ tree = Tree.from_swc(StringIO(swc))
79
+ volume = get_volume(tree)
80
+ print(volume)
@@ -0,0 +1,11 @@
1
+ """Neuron trees."""
2
+
3
+ from swcgeom.core import swc_utils
4
+ from swcgeom.core.branch import *
5
+ from swcgeom.core.branch_tree import *
6
+ from swcgeom.core.node import *
7
+ from swcgeom.core.path import *
8
+ from swcgeom.core.population import *
9
+ from swcgeom.core.swc import *
10
+ from swcgeom.core.tree import *
11
+ from swcgeom.core.tree_utils import *
@@ -5,9 +5,9 @@ from typing import Generic, Iterable, List
5
5
  import numpy as np
6
6
  import numpy.typing as npt
7
7
 
8
- from .path import Path
9
- from .segment import Segment, Segments
10
- from .swc import DictSWC, SWCTypeVar
8
+ from swcgeom.core.path import Path
9
+ from swcgeom.core.segment import Segment, Segments
10
+ from swcgeom.core.swc import DictSWC, SWCTypeVar
11
11
 
12
12
  __all__ = ["Branch"]
13
13
 
@@ -42,7 +42,11 @@ class Branch(Path, Generic[SWCTypeVar]):
42
42
  def detach(self) -> "Branch[DictSWC]":
43
43
  """Detach from current attached object."""
44
44
  # pylint: disable=consider-using-dict-items
45
- attact = DictSWC(**{k: self[k] for k in self.keys()}, names=self.names)
45
+ attact = DictSWC(
46
+ **{k: self[k] for k in self.keys()},
47
+ source=self.attach.source,
48
+ names=self.names,
49
+ )
46
50
  attact.ndata[self.names.id] = self.id()
47
51
  attact.ndata[self.names.pid] = self.pid()
48
52
  return Branch(attact, self.id())
@@ -7,9 +7,9 @@ import numpy as np
7
7
  import pandas as pd
8
8
  from typing_extensions import Self
9
9
 
10
- from .branch import Branch
11
- from .swc_utils import to_sub_topology
12
- from .tree import Tree
10
+ from swcgeom.core.branch import Branch
11
+ from swcgeom.core.swc_utils import to_sub_topology
12
+ from swcgeom.core.tree import Tree
13
13
 
14
14
  __all__ = ["BranchTree"]
15
15
 
@@ -45,8 +45,7 @@ class BranchTree(Tree):
45
45
  ndata = {k: tree.get_ndata(k)[id_map].copy() for k in tree.keys()}
46
46
  ndata.update(id=new_id, pid=new_pid)
47
47
 
48
- branch_tree = cls(n_nodes, **ndata, names=tree.names)
49
- branch_tree.source = tree.source # TODO
48
+ branch_tree = cls(n_nodes, **ndata, source=tree.source, names=tree.names)
50
49
 
51
50
  branch_tree.branches = {}
52
51
  for br in branches:
@@ -6,8 +6,8 @@ from typing import Any, Generic, Iterable
6
6
  import numpy as np
7
7
  import numpy.typing as npt
8
8
 
9
- from .swc import DictSWC, SWCTypeVar
10
- from .swc_utils import SWCNames
9
+ from swcgeom.core.swc import DictSWC, SWCTypeVar
10
+ from swcgeom.core.swc_utils import SWCNames
11
11
 
12
12
  __all__ = ["Node"]
13
13
 
@@ -113,7 +113,9 @@ class Node(Generic[SWCTypeVar]):
113
113
  """Detach from current attached object."""
114
114
  # pylint: disable=consider-using-dict-items
115
115
  attact = DictSWC(
116
- **{k: np.array([self[k]]) for k in self.keys()}, names=self.names
116
+ **{k: np.array([self[k]]) for k in self.keys()},
117
+ source=self.attach.source,
118
+ names=self.names,
117
119
  )
118
120
  attact.ndata[self.names.id] = np.array([0])
119
121
  attact.ndata[self.names.pid] = np.array([-1])
@@ -5,8 +5,8 @@ from typing import Generic, Iterable, Iterator, List, overload
5
5
  import numpy as np
6
6
  import numpy.typing as npt
7
7
 
8
- from .node import Node
9
- from .swc import DictSWC, SWCLike, SWCTypeVar
8
+ from swcgeom.core.node import Node
9
+ from swcgeom.core.swc import DictSWC, SWCLike, SWCTypeVar
10
10
 
11
11
  __all__ = ["Path"]
12
12
 
@@ -28,6 +28,7 @@ class Path(SWCLike, Generic[SWCTypeVar]):
28
28
  self.attach = attach
29
29
  self.names = attach.names
30
30
  self.idx = np.array(idx, dtype=np.int32)
31
+ self.source = self.attach.source
31
32
 
32
33
  def __iter__(self) -> Iterator[Node]:
33
34
  return (self.get_node(i) for i in range(len(self)))
@@ -79,7 +80,9 @@ class Path(SWCLike, Generic[SWCTypeVar]):
79
80
  """Detach from current attached object."""
80
81
  # pylint: disable-next=consider-using-dict-items
81
82
  attact = DictSWC(
82
- **{k: self.get_ndata(k) for k in self.keys()}, names=self.names
83
+ **{k: self.get_ndata(k) for k in self.keys()},
84
+ source=self.source,
85
+ names=self.names,
83
86
  )
84
87
  attact.ndata[self.names.id] = self.id()
85
88
  attact.ndata[self.names.pid] = self.pid()
@@ -19,8 +19,8 @@ import numpy as np
19
19
  import numpy.typing as npt
20
20
  from typing_extensions import Self
21
21
 
22
- from .swc import eswc_cols
23
- from .tree import Tree
22
+ from swcgeom.core.swc import eswc_cols
23
+ from swcgeom.core.tree import Tree
24
24
 
25
25
  __all__ = ["LazyLoadingTrees", "ChainTrees", "Population", "Populations"]
26
26