swcgeom 0.15.0__tar.gz → 0.17.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 (115) hide show
  1. swcgeom-0.17.0/.github/workflows/build.yml +38 -0
  2. swcgeom-0.17.0/.github/workflows/github-publish.yml +35 -0
  3. {swcgeom-0.15.0 → swcgeom-0.17.0}/.github/workflows/pypi-publish.yml +12 -12
  4. {swcgeom-0.15.0 → swcgeom-0.17.0}/.github/workflows/test.yml +1 -1
  5. swcgeom-0.17.0/.vscode/settings.json +15 -0
  6. {swcgeom-0.15.0 → swcgeom-0.17.0}/CHANGELOG.md +69 -0
  7. {swcgeom-0.15.0/swcgeom.egg-info → swcgeom-0.17.0}/PKG-INFO +3 -3
  8. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/pytorch/branch_dataset.py +1 -1
  9. {swcgeom-0.15.0 → swcgeom-0.17.0}/pyproject.toml +2 -2
  10. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/_version.py +2 -2
  11. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/analysis/__init__.py +1 -3
  12. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/analysis/feature_extractor.py +3 -3
  13. swcgeom-0.15.0/swcgeom/analysis/node_features.py → swcgeom-0.17.0/swcgeom/analysis/features.py +105 -3
  14. swcgeom-0.17.0/swcgeom/analysis/lmeasure.py +821 -0
  15. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/analysis/sholl.py +31 -2
  16. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/__init__.py +4 -0
  17. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/branch.py +9 -4
  18. swcgeom-0.15.0/swcgeom/core/segment.py → swcgeom-0.17.0/swcgeom/core/compartment.py +14 -9
  19. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/node.py +0 -8
  20. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/path.py +21 -6
  21. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/population.py +47 -7
  22. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/swc_utils/assembler.py +12 -1
  23. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/swc_utils/base.py +12 -5
  24. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/swc_utils/checker.py +12 -2
  25. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/tree.py +34 -37
  26. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/tree_utils.py +4 -0
  27. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/images/augmentation.py +6 -1
  28. swcgeom-0.17.0/swcgeom/images/contrast.py +107 -0
  29. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/images/folder.py +71 -14
  30. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/images/io.py +74 -88
  31. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/transforms/__init__.py +2 -0
  32. swcgeom-0.17.0/swcgeom/transforms/image_preprocess.py +100 -0
  33. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/transforms/image_stack.py +1 -4
  34. swcgeom-0.17.0/swcgeom/transforms/images.py +203 -0
  35. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/transforms/mst.py +5 -5
  36. swcgeom-0.17.0/swcgeom/transforms/neurolucida_asc.py +495 -0
  37. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/transforms/tree.py +5 -1
  38. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/utils/__init__.py +1 -0
  39. swcgeom-0.17.0/swcgeom/utils/neuromorpho.py +594 -0
  40. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/utils/numpy_helper.py +14 -4
  41. swcgeom-0.17.0/swcgeom/utils/plotter_2d.py +130 -0
  42. swcgeom-0.17.0/swcgeom/utils/renderer.py +133 -0
  43. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/utils/sdf.py +5 -1
  44. {swcgeom-0.15.0 → swcgeom-0.17.0/swcgeom.egg-info}/PKG-INFO +3 -3
  45. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom.egg-info/SOURCES.txt +9 -4
  46. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom.egg-info/requires.txt +2 -2
  47. swcgeom-0.17.0/tests/transforms/test_neurolucida_asc.py +150 -0
  48. swcgeom-0.17.0/tests/utils/test_numpy_helper.py +46 -0
  49. swcgeom-0.15.0/.github/workflows/build.yml +0 -38
  50. swcgeom-0.15.0/.github/workflows/github-publish.yml +0 -35
  51. swcgeom-0.15.0/.vscode/settings.json +0 -20
  52. swcgeom-0.15.0/swcgeom/analysis/branch_features.py +0 -67
  53. swcgeom-0.15.0/swcgeom/analysis/path_features.py +0 -37
  54. swcgeom-0.15.0/swcgeom/transforms/images.py +0 -32
  55. swcgeom-0.15.0/swcgeom/utils/neuromorpho.py +0 -469
  56. swcgeom-0.15.0/swcgeom/utils/renderer.py +0 -244
  57. {swcgeom-0.15.0 → swcgeom-0.17.0}/.gitignore +0 -0
  58. {swcgeom-0.15.0 → swcgeom-0.17.0}/.pylintrc +0 -0
  59. {swcgeom-0.15.0 → swcgeom-0.17.0}/LICENSE +0 -0
  60. {swcgeom-0.15.0 → swcgeom-0.17.0}/README.md +0 -0
  61. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/Branch.ipynb +0 -0
  62. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/BranchTree.ipynb +0 -0
  63. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/CollectTips.ipynb +0 -0
  64. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/CutTree.ipynb +0 -0
  65. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/Features.ipynb +0 -0
  66. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/GeometryTransform.ipynb +0 -0
  67. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/ImageStack.ipynb +0 -0
  68. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/MST.ipynb +0 -0
  69. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/SpectralClustering.ipynb +0 -0
  70. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/Tree.ipynb +0 -0
  71. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/data/101711-10_4p5-of-16_initial.CNG.swc +0 -0
  72. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/data/101711-11_16-of-16_initial.CNG.swc +0 -0
  73. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/data/1059283677_15257_2226-X16029-Y23953.swc +0 -0
  74. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/data/toydata.swc +0 -0
  75. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/dgl/graph.py +0 -0
  76. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/pytorch/branch.py +0 -0
  77. {swcgeom-0.15.0 → swcgeom-0.17.0}/examples/pytorch/tree_folder_dataset.py +0 -0
  78. {swcgeom-0.15.0 → swcgeom-0.17.0}/git-conventional-commits.yaml +0 -0
  79. {swcgeom-0.15.0 → swcgeom-0.17.0}/setup.cfg +0 -0
  80. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/__init__.py +0 -0
  81. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/analysis/trunk.py +0 -0
  82. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/analysis/visualization.py +0 -0
  83. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/analysis/volume.py +0 -0
  84. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/branch_tree.py +0 -0
  85. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/swc.py +0 -0
  86. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/swc_utils/__init__.py +0 -0
  87. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/swc_utils/io.py +0 -0
  88. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/swc_utils/normalizer.py +0 -0
  89. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/swc_utils/subtree.py +0 -0
  90. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/core/tree_utils_impl.py +0 -0
  91. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/images/__init__.py +0 -0
  92. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/transforms/base.py +0 -0
  93. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/transforms/branch.py +0 -0
  94. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/transforms/geometry.py +0 -0
  95. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/transforms/path.py +0 -0
  96. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/transforms/population.py +0 -0
  97. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/transforms/tree_assembler.py +0 -0
  98. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/utils/debug.py +0 -0
  99. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/utils/download.py +0 -0
  100. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/utils/dsu.py +0 -0
  101. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/utils/ellipse.py +0 -0
  102. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/utils/file.py +0 -0
  103. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/utils/solid_geometry.py +0 -0
  104. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/utils/transforms.py +0 -0
  105. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom/utils/volumetric_object.py +0 -0
  106. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom.egg-info/dependency_links.txt +0 -0
  107. {swcgeom-0.15.0 → swcgeom-0.17.0}/swcgeom.egg-info/top_level.txt +0 -0
  108. {swcgeom-0.15.0 → swcgeom-0.17.0}/tests/__init__.py +0 -0
  109. {swcgeom-0.15.0 → swcgeom-0.17.0}/tests/analysis/test_volume.py +0 -0
  110. {swcgeom-0.15.0 → swcgeom-0.17.0}/tests/utils/__init__.py +0 -0
  111. {swcgeom-0.15.0 → swcgeom-0.17.0}/tests/utils/test_dsu.py +0 -0
  112. {swcgeom-0.15.0 → swcgeom-0.17.0}/tests/utils/test_sdf.py +0 -0
  113. {swcgeom-0.15.0 → swcgeom-0.17.0}/tests/utils/test_solid_geometry.py +0 -0
  114. {swcgeom-0.15.0 → swcgeom-0.17.0}/tests/utils/test_transforms.py +0 -0
  115. {swcgeom-0.15.0 → swcgeom-0.17.0}/tests/utils/test_volumetric_object.py +0 -0
@@ -0,0 +1,38 @@
1
+ name: Build Python Package
2
+
3
+ on:
4
+ workflow_call:
5
+
6
+ jobs:
7
+ build:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v3
11
+
12
+ - name: Set up Python
13
+ uses: actions/setup-python@v3
14
+ with:
15
+ python-version: "3.10"
16
+
17
+ - name: Get history and tags for SCM versioning to work
18
+ run: |
19
+ git fetch --prune --unshallow
20
+ git fetch --depth=1 origin +refs/tags/*:refs/tags/*
21
+ git describe --tags
22
+ git describe --tags $(git rev-list --tags --max-count=1)
23
+
24
+ - name: Install dependencies
25
+ run: |
26
+ python -m pip install --upgrade pip
27
+ pip install build
28
+
29
+ - name: Build package
30
+ run: python -m build
31
+
32
+ - name: Archive production artifacts
33
+ uses: actions/upload-artifact@v3
34
+ with:
35
+ name: release
36
+ path: |
37
+ dist/
38
+ swcgeom.egg-info/
@@ -0,0 +1,35 @@
1
+ name: Release to GitHub
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - v*
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ build:
13
+ uses: ./.github/workflows/build.yml
14
+
15
+ publish:
16
+ runs-on: ubuntu-latest
17
+ needs: build
18
+ steps:
19
+ - name: Get version
20
+ id: get_version
21
+ run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
22
+
23
+ - name: Download release
24
+ uses: actions/download-artifact@v3
25
+ with:
26
+ name: release
27
+
28
+ - name: Pack release
29
+ run: tar czf swcgeom-${{ steps.get_version.outputs.VERSION }}.tgz dist/
30
+
31
+ - name: Create release
32
+ uses: softprops/action-gh-release@v1
33
+ with:
34
+ token: ${{ secrets.GH_TOKEN }}
35
+ files: swcgeom-${{ steps.get_version.outputs.VERSION }}.tgz
@@ -6,26 +6,26 @@ name: Release to PyPI
6
6
  on:
7
7
  push:
8
8
  tags:
9
- - v*
9
+ - v*
10
10
 
11
11
  permissions:
12
12
  contents: read
13
13
 
14
14
  jobs:
15
- build:
15
+ build:
16
16
  uses: ./.github/workflows/build.yml
17
17
 
18
- release:
18
+ publish:
19
19
  runs-on: ubuntu-latest
20
20
  needs: build
21
21
  steps:
22
- - name: Download release
23
- uses: actions/download-artifact@v3
24
- with:
25
- name: release
22
+ - name: Download release
23
+ uses: actions/download-artifact@v3
24
+ with:
25
+ name: release
26
26
 
27
- - name: Publish package
28
- uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
29
- with:
30
- user: __token__
31
- password: ${{ secrets.PYPI_API_TOKEN }}
27
+ - name: Publish package
28
+ uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
29
+ with:
30
+ user: __token__
31
+ password: ${{ secrets.PYPI_API_TOKEN }}
@@ -3,7 +3,7 @@ name: Run tests
3
3
  on: [push]
4
4
 
5
5
  jobs:
6
- build:
6
+ test:
7
7
  runs-on: ubuntu-latest
8
8
  strategy:
9
9
  matrix:
@@ -0,0 +1,15 @@
1
+ {
2
+ "[python]": {
3
+ "editor.defaultFormatter": "ms-python.black-formatter"
4
+ },
5
+ "python.analysis.typeCheckingMode": "basic",
6
+ "python.testing.pytestArgs": [
7
+ "tests"
8
+ ],
9
+ "python.testing.unittestEnabled": false,
10
+ "python.testing.pytestEnabled": true,
11
+ "isort.args": [
12
+ "--profile",
13
+ "black"
14
+ ],
15
+ }
@@ -1,5 +1,74 @@
1
1
  # Changelog
2
2
 
3
+ ## **0.17.0**&emsp;<sub><sup>2024-04-04 ([59257cb...2072139](https://github.com/yzx9/swcgeom/compare/59257cbfb6264afd3ca31fcba002f692bbb69ed0...20721393086e5a890b097b3ae32aaa1e4ad6b898?diff=split))</sup></sub>
4
+
5
+ ### Features
6
+
7
+ ##### &ensp;`images`
8
+
9
+ - handle raw file in terafly ([67ecd63](https://github.com/yzx9/swcgeom/commit/67ecd63bf4124d49b00e779c2702a7b939ef710b))
10
+ - add image stack dtype support ([7313ead](https://github.com/yzx9/swcgeom/commit/7313ead09ec61970f221b9e0c3691d31c269b591))
11
+
12
+ ##### &ensp;`transforms`
13
+
14
+ - add new image transformation classes ([7b5d805](https://github.com/yzx9/swcgeom/commit/7b5d805a1aa0deac3f9d7576a9aecab36b59774b))
15
+ - add image flip and notes ([5f2a4d1](https://github.com/yzx9/swcgeom/commit/5f2a4d1a9c2b5fb68e8221c7b024a411b247ab6d))
16
+
17
+
18
+ ### BREAKING CHANGES
19
+ - `images` remove deprecated \`swap\_xy\` and \`filp\_xy\` flag ([2072139](https://github.com/yzx9/swcgeom/commit/20721393086e5a890b097b3ae32aaa1e4ad6b898))
20
+ <br>
21
+
22
+
23
+ ## **0.16.0**&emsp;<sub><sup>2024-03-16 ([bf2bf95...7029483](https://github.com/yzx9/swcgeom/compare/bf2bf95ee9fbfb7eba871db7303292f1dfcc7b8f...70294836643e51ca43d039887bbd71de3a9b561b?diff=split))</sup></sub>
24
+
25
+ ### Features
26
+
27
+ ##### &ensp;`analysis`
28
+
29
+ - add l\-measure support \(close \#13\) ([15ddc33](https://github.com/yzx9/swcgeom/commit/15ddc333c4cdce42fe99fb2383fa0768bc2e35b2))
30
+
31
+ ##### &ensp;`core`
32
+
33
+ - \`Tree\` accpet values with custom names ([722f84f](https://github.com/yzx9/swcgeom/commit/722f84fdd71133d07e74b5f90171b3671a4fe4c9))
34
+ - add \`Population\.map\` parallel processing support ([a1ee5bb](https://github.com/yzx9/swcgeom/commit/a1ee5bb6344ad5ab7b6572962f3b84caedf1351f))
35
+
36
+ ##### &ensp;`images`
37
+
38
+ - add image contrast functions ([85b881e](https://github.com/yzx9/swcgeom/commit/85b881e91e878daf6fb3aa2862b5cd62eaa3488b))
39
+ - stat image stack folder ([ffc5e3a](https://github.com/yzx9/swcgeom/commit/ffc5e3a649a4d8203c2530b6351a7b509b262cf3))
40
+
41
+ ##### &ensp;`transforms`
42
+
43
+ - add basic neuronlucida asc format support \(close \#12\) ([619a275](https://github.com/yzx9/swcgeom/commit/619a275aaa5a311c66e1a2438e6251ee4b9bd703))
44
+ - add \`SGuoImPreProcess\` ([dab7481](https://github.com/yzx9/swcgeom/commit/dab74818e5ea82d27450758f868bdc633b8992bf))
45
+ - add image stack related transforms ([7029483](https://github.com/yzx9/swcgeom/commit/70294836643e51ca43d039887bbd71de3a9b561b))
46
+
47
+ ##### &ensp;`utils`
48
+
49
+ - \`Tree\` support array like inputs ([1f228d0](https://github.com/yzx9/swcgeom/commit/1f228d055b99c8545ba51da5af2bca8d7b760f3f))
50
+ - download source swc and log from neuromorpho ([d4fbfb6](https://github.com/yzx9/swcgeom/commit/d4fbfb6f0b89990bf63b481333d6c3c3cb16705c))
51
+
52
+ ### Bug Fixes
53
+
54
+ ##### &ensp;`utils`
55
+
56
+ - expecting a figure from the axes ([bf2bf95](https://github.com/yzx9/swcgeom/commit/bf2bf95ee9fbfb7eba871db7303292f1dfcc7b8f))
57
+
58
+ ### Performance Improvements
59
+
60
+ ##### &ensp;`core`
61
+
62
+ - use NamedTuple for SWCNames and SWCTypes ([300bfea](https://github.com/yzx9/swcgeom/commit/300bfeac92b90e09f262a850ecc226257c2af2e5))
63
+
64
+
65
+ ### BREAKING CHANGES
66
+
67
+ - `core` \`Tree\` accpet values with custom names ([722f84f](https://github.com/yzx9/swcgeom/commit/722f84fdd71133d07e74b5f90171b3671a4fe4c9))
68
+ - `core` remove deprecated \`Tree\.Node\.get\_branch\` and \`Node\.child\_ids\` method ([1de86af](https://github.com/yzx9/swcgeom/commit/1de86afc21451be4c6bde5084688170d901eb625))
69
+
70
+ <br>
71
+
3
72
  ## **0.15.0**&emsp;<sub><sup>2024-01-28 ([d300b41...8c9e0ab](https://github.com/yzx9/swcgeom/compare/d300b41689ee892fe5a23dad57f92e1054c0f9e9...8c9e0ab45c447d3d8121b0cc4178be5f65d18a56?diff=split))</sup></sub>
4
73
 
5
74
  ### Features
@@ -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
@@ -8,7 +8,7 @@ import torch
8
8
  import torch.utils.data
9
9
  from tree_folder_dataset import TreeFolderDataset
10
10
 
11
- from swcgeom import Branch
11
+ from swcgeom.core import Branch
12
12
  from swcgeom.transforms import Identity, Transform
13
13
  from swcgeom.utils import numpy_err
14
14
 
@@ -22,6 +22,7 @@ dependencies = [
22
22
  "seaborn>=0.12.0",
23
23
  "tifffile>=2022.8.12",
24
24
  "typing_extensions>=4.4.0",
25
+ "tqdm>=4.46.1",
25
26
  "v3d-py-helper>=0.1.0",
26
27
  ]
27
28
 
@@ -31,8 +32,7 @@ all = [
31
32
  "certifi>=2023.5.7",
32
33
  "chardet>=5.2.0",
33
34
  "lmdb>=1.4.1",
34
- "pycurl>=7.0.0",
35
- "tqdm>=4.46.1",
35
+ "requests>=2.0.0",
36
36
  "urllib3>=1.26.0",
37
37
  ]
38
38
 
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.15.0'
16
- __version_tuple__ = version_tuple = (0, 15, 0)
15
+ __version__ = version = '0.17.0'
16
+ __version_tuple__ = version_tuple = (0, 17, 0)
@@ -1,9 +1,7 @@
1
1
  """Analysis for neuron trees."""
2
2
 
3
- from swcgeom.analysis.branch_features import *
4
3
  from swcgeom.analysis.feature_extractor import *
5
- from swcgeom.analysis.node_features import *
6
- from swcgeom.analysis.path_features import *
4
+ from swcgeom.analysis.features import *
7
5
  from swcgeom.analysis.sholl import *
8
6
  from swcgeom.analysis.trunk import *
9
7
  from swcgeom.analysis.visualization import *
@@ -17,13 +17,13 @@ import numpy.typing as npt
17
17
  import seaborn as sns
18
18
  from matplotlib.axes import Axes
19
19
 
20
- from swcgeom.analysis.branch_features import BranchFeatures
21
- from swcgeom.analysis.node_features import (
20
+ from swcgeom.analysis.features import (
22
21
  BifurcationFeatures,
22
+ BranchFeatures,
23
23
  NodeFeatures,
24
+ PathFeatures,
24
25
  TipFeatures,
25
26
  )
26
- from swcgeom.analysis.path_features import PathFeatures
27
27
  from swcgeom.analysis.sholl import Sholl
28
28
  from swcgeom.analysis.volume import get_volume
29
29
  from swcgeom.core import Population, Populations, Tree
@@ -1,15 +1,26 @@
1
- """Depth distribution of tree."""
1
+ """Feature anlysis of tree."""
2
2
 
3
3
  from abc import ABC, abstractmethod
4
4
  from functools import cached_property
5
+ from typing import List, TypeVar
5
6
 
6
7
  import numpy as np
7
8
  import numpy.typing as npt
8
9
  from typing_extensions import Self
9
10
 
10
- from swcgeom.core import BranchTree, Tree
11
+ from swcgeom.core import Branch, BranchTree, Tree
11
12
 
12
- __all__ = ["NodeFeatures", "BifurcationFeatures", "TipFeatures"]
13
+ __all__ = [
14
+ "NodeFeatures",
15
+ "BifurcationFeatures",
16
+ "TipFeatures",
17
+ "PathFeatures",
18
+ "BranchFeatures",
19
+ ]
20
+
21
+ T = TypeVar("T", bound=Branch)
22
+
23
+ # Node Level
13
24
 
14
25
 
15
26
  class NodeFeatures:
@@ -31,6 +42,7 @@ class NodeFeatures:
31
42
  -------
32
43
  count : array of shape (1,)
33
44
  """
45
+
34
46
  return np.array([self.tree.number_of_nodes()], dtype=np.float32)
35
47
 
36
48
  def get_radial_distance(self) -> npt.NDArray[np.float32]:
@@ -41,6 +53,7 @@ class NodeFeatures:
41
53
  radial_distance : npt.NDArray[np.float32]
42
54
  Array of shape (N,).
43
55
  """
56
+
44
57
  xyz = self.tree.xyz() - self.tree.soma().xyz()
45
58
  radial_distance = np.linalg.norm(xyz, axis=1)
46
59
  return radial_distance
@@ -58,6 +71,7 @@ class NodeFeatures:
58
71
  order : npt.NDArray[np.int32]
59
72
  Array of shape (N,), which k is the number of branchs.
60
73
  """
74
+
61
75
  order = np.zeros_like(self._branch_tree.id(), dtype=np.int32)
62
76
 
63
77
  def assign_depth(n: Tree.Node, pre_depth: int | None) -> int:
@@ -88,6 +102,7 @@ class _SubsetNodesFeatures(ABC):
88
102
  count : npt.NDArray[np.float32]
89
103
  Array of shape (1,).
90
104
  """
105
+
91
106
  return np.array([np.count_nonzero(self.nodes)], dtype=np.float32)
92
107
 
93
108
  def get_radial_distance(self) -> npt.NDArray[np.float32]:
@@ -98,6 +113,7 @@ class _SubsetNodesFeatures(ABC):
98
113
  radial_distance : npt.NDArray[np.float32]
99
114
  Array of shape (N,).
100
115
  """
116
+
101
117
  return self._features.get_radial_distance()[self.nodes]
102
118
 
103
119
  @classmethod
@@ -119,3 +135,89 @@ class TipFeatures(_SubsetNodesFeatures):
119
135
  @cached_property
120
136
  def nodes(self) -> npt.NDArray[np.bool_]:
121
137
  return np.array([n.is_tip() for n in self._features.tree])
138
+
139
+
140
+ # Path Level
141
+
142
+
143
+ class PathFeatures:
144
+ """Path analysis of tree."""
145
+
146
+ tree: Tree
147
+
148
+ def __init__(self, tree: Tree) -> None:
149
+ self.tree = tree
150
+
151
+ def get_count(self) -> int:
152
+ return len(self._paths)
153
+
154
+ def get_length(self) -> npt.NDArray[np.float32]:
155
+ """Get length of paths."""
156
+
157
+ length = [path.length() for path in self._paths]
158
+ return np.array(length, dtype=np.float32)
159
+
160
+ def get_tortuosity(self) -> npt.NDArray[np.float32]:
161
+ """Get tortuosity of path."""
162
+
163
+ return np.array([path.tortuosity() for path in self._paths], dtype=np.float32)
164
+
165
+ @cached_property
166
+ def _paths(self) -> List[Tree.Path]:
167
+ return self.tree.get_paths()
168
+
169
+
170
+ class BranchFeatures:
171
+ """Analysis bransh of tree."""
172
+
173
+ tree: Tree
174
+
175
+ def __init__(self, tree: Tree) -> None:
176
+ self.tree = tree
177
+
178
+ def get_count(self) -> int:
179
+ return len(self._branches)
180
+
181
+ def get_length(self) -> npt.NDArray[np.float32]:
182
+ """Get length of branches."""
183
+
184
+ length = [br.length() for br in self._branches]
185
+ return np.array(length, dtype=np.float32)
186
+
187
+ def get_tortuosity(self) -> npt.NDArray[np.float32]:
188
+ """Get tortuosity of path."""
189
+
190
+ return np.array([br.tortuosity() for br in self._branches], dtype=np.float32)
191
+
192
+ def get_angle(self, eps: float = 1e-7) -> npt.NDArray[np.float32]:
193
+ """Get agnle between branches.
194
+
195
+ Returns
196
+ -------
197
+ angle : npt.NDArray[np.float32]
198
+ An array of shape (N, N), which N is length of branches.
199
+ """
200
+
201
+ return self.calc_angle(self._branches, eps=eps)
202
+
203
+ @staticmethod
204
+ def calc_angle(branches: List[T], eps: float = 1e-7) -> npt.NDArray[np.float32]:
205
+ """Calc agnle between branches.
206
+
207
+ Returns
208
+ -------
209
+ angle : npt.NDArray[np.float32]
210
+ An array of shape (N, N), which N is length of branches.
211
+ """
212
+
213
+ vector = np.array([br[-1].xyz() - br[0].xyz() for br in branches])
214
+ vector_dot = np.matmul(vector, vector.T)
215
+ vector_norm = np.linalg.norm(vector, ord=2, axis=1, keepdims=True)
216
+ vector_norm_dot = np.matmul(vector_norm, vector_norm.T) + eps
217
+ arccos = np.clip(vector_dot / vector_norm_dot, -1, 1)
218
+ angle = np.arccos(arccos)
219
+ return angle
220
+
221
+ @cached_property
222
+ def _branches(self) -> List[Tree.Branch]:
223
+ return self.tree.get_branches()