morphoview 0.1.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Subhasis Ray
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,209 @@
1
+ Metadata-Version: 2.4
2
+ Name: morphoview
3
+ Version: 0.1.0
4
+ Summary: Read, analyze and visualize neuronal morphologies in SWC format.
5
+ Author: Subhasis Ray
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/subhacom/morphoview
8
+ Keywords: neuroscience,morphology,SWC,visualization,neuron
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Scientific/Engineering :: Visualization
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: numpy>=1.20
18
+ Requires-Dist: networkx>=3.0
19
+ Provides-Extra: mpl
20
+ Requires-Dist: matplotlib>=3.4; extra == "mpl"
21
+ Provides-Extra: vtk
22
+ Requires-Dist: vtk>=9.0; extra == "vtk"
23
+ Provides-Extra: vispy
24
+ Requires-Dist: vispy>=0.11; extra == "vispy"
25
+ Provides-Extra: all
26
+ Requires-Dist: matplotlib>=3.4; extra == "all"
27
+ Requires-Dist: vtk>=9.0; extra == "all"
28
+ Requires-Dist: vispy>=0.11; extra == "all"
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0; extra == "dev"
31
+ Requires-Dist: matplotlib>=3.4; extra == "dev"
32
+ Requires-Dist: vtk>=9.0; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # morphoview
36
+
37
+ Read, analyze and visualize neuronal morphologies stored in
38
+ [SWC](http://www.neuronland.org/NLMorphologyConverter/MorphologyFormats/SWC/Spec.html)
39
+ format.
40
+
41
+ `morphoview` loads an SWC trace into a `networkx` graph, computes
42
+ morphology statistics (branch points, leaves, path lengths, total
43
+ neurite length), and renders the cell in 2-D or 3-D using any of three
44
+ pluggable backends:
45
+
46
+ | Backend | Strengths | Extra dependency |
47
+ |--------------|----------------------------------------------|------------------|
48
+ | `mpl` | Portable, figure-quality 2-D/3-D line plots | `matplotlib` |
49
+ | `vtk` | Tapered tubes, interactive, PNG/movie export | `vtk` |
50
+ | `vispy` | GPU-accelerated interactive tube view | `vispy` |
51
+
52
+ The core I/O and analysis need only `numpy` and `networkx`; each
53
+ rendering backend is optional and imported lazily.
54
+
55
+ This is a refactored, Python-3-native successor to the `morphutils`
56
+ scripts (`neurograph.py`, `displaycell.py`, `morph3d*.py`, `cellmovie.py`).
57
+
58
+ ## Installation
59
+
60
+ ```bash
61
+ pip install -e . # core only (numpy + networkx)
62
+ pip install -e ".[mpl]" # + matplotlib backend
63
+ pip install -e ".[vtk]" # + VTK backend
64
+ pip install -e ".[all]" # everything
65
+ ```
66
+
67
+ ## Command line
68
+
69
+ ```bash
70
+ # Print morphology statistics
71
+ morphoview info examples/sample.swc
72
+
73
+ # Interactive 3-D display (VTK, tapered tubes, coloured by structure)
74
+ morphoview display examples/sample.swc
75
+
76
+ # Matplotlib 2-D projection onto the XY plane
77
+ morphoview display examples/sample.swc -b mpl --proj xy -c 4cp
78
+
79
+ # Several cells at once, positioned independently
80
+ morphoview display cellA.swc cellB.swc -t "0 0 0" -t "200 0 0" -r "z 90"
81
+
82
+ # Save a snapshot without opening a window (headless)
83
+ morphoview display examples/sample.swc --save cell.png --offscreen
84
+
85
+ # Render a rotating movie sweeping 360 degrees about Y
86
+ morphoview movie -i examples/sample.swc -o cell.avi -y 360
87
+ ```
88
+
89
+ Useful `display` options:
90
+
91
+ - `-b/--backend {vtk,mpl,vispy}` — pick the renderer (default `vtk`).
92
+ - `-l/--lines W` — draw fixed-width lines of width `W` instead of tubes.
93
+ - `-c/--colormap NAME` — structure colour palette (see below).
94
+ - `-t/--translate "X Y Z"`, `-r/--rotate "x 90 y 45"`, `-m/--mirror x` —
95
+ per-file rigid transforms (repeat the flag once per input file).
96
+ - `--branches`, `--leaves`, `-s/--struct-id ID...` — label nodes.
97
+ - `-a/--scalebar`, `-F/--fullscreen`, `--save FILE.png`, `--offscreen`.
98
+
99
+ ## Python API
100
+
101
+ ```python
102
+ import morphoview as nv
103
+
104
+ graph = nv.swc_to_graph("examples/sample.swc")
105
+ print(nv.summary(graph))
106
+ # {'nodes': 19, 'edges': 18, 'branch_points': 3, 'branches': 8,
107
+ # 'leaves': 5, 'total_length': 57.76...}
108
+
109
+ # Per-structure node lists (soma / axon / dendrites / custom regions)
110
+ by_type = nv.structure_node_map(graph)
111
+
112
+ # Path length from the soma to every node
113
+ distances = nv.soma_distance(graph)
114
+
115
+ # Render with matplotlib
116
+ from morphoview.backends import mpl
117
+ ax = mpl.plot_3d(graph, color=nv.get_colormap("3cd2"))
118
+ mpl.show()
119
+
120
+ # Render with VTK (tapered tubes)
121
+ from morphoview.backends import vtk
122
+ vtk.show(graph, colormap=nv.get_colormap("3cd2"), axes=True)
123
+ ```
124
+
125
+ ### Transformations
126
+
127
+ ```python
128
+ from morphoview import transform as tf
129
+
130
+ tf.rotate(graph, thetaz=90) # degrees, about the origin
131
+ tf.translate(graph, 100, 0, 0) # micrometres
132
+ tf.mirror(graph, "x") # reflect across the YZ plane
133
+
134
+ combined = nv.combine(graph_a, graph_b) # merge, renumbering node ids
135
+ ```
136
+
137
+ ## Structure ids and colour palettes
138
+
139
+ SWC tags each point with a structure id. The standard ids are
140
+ `1=soma`, `2=axon`, `3=basal dendrite`, `4=apical dendrite`; ids `>= 5`
141
+ are custom (`morphoview` also names the GGN regions `5=LCA`, `6=MCA`,
142
+ `7=LH`, `8=alphaL`).
143
+
144
+ Palettes are keyed by short names combining a class count and a scheme,
145
+ mostly from [colorbrewer2.org](https://colorbrewer2.org) and the
146
+ [SRON](https://personal.sron.nl/~pault/) colour-blind-safe sets:
147
+ `3cd2` (default), `3cs2`, `3cp`, `4cp`, `5cd2`, `5cs3`, `7q`, `7cp`,
148
+ `7ca`, `7cd2`, `9q`, `10cp`, `10cs3`, `15cb`. Structure ids beyond a
149
+ palette's length wrap around so every morphology still renders.
150
+
151
+ ## Project layout
152
+
153
+ ```
154
+ src/morphoview/
155
+ swc.py SWC file I/O (numpy structured arrays)
156
+ graph.py networkx graph construction + morphology analysis
157
+ colors.py structure-id names and colour palettes
158
+ transform.py rigid transforms (translate/rotate/mirror)
159
+ cli.py the `morphoview` command-line entry point
160
+ backends/
161
+ mpl.py matplotlib 2-D/3-D
162
+ vtk.py VTK tubes/lines, labels, PNG export
163
+ vispy.py vispy tube view
164
+ movie.py VTK rotating-movie export
165
+ tests/ pytest suite (core + matplotlib backend)
166
+ examples/sample.swc small synthetic neuron for demos/tests
167
+ ```
168
+
169
+ ## Development
170
+
171
+ ```bash
172
+ pip install -e ".[dev]"
173
+ pytest
174
+ ```
175
+
176
+ ## Releasing to PyPI
177
+
178
+ Publishing is automated by
179
+ [`.github/workflows/publish.yml`](.github/workflows/publish.yml). It builds
180
+ the sdist and wheel on every push/PR as a smoke test, and uploads them to
181
+ PyPI when a GitHub Release is published, using
182
+ [Trusted Publishing](https://docs.pypi.org/trusted-publishers/) (OIDC) — so
183
+ there are no API tokens to store as secrets.
184
+
185
+ One-time setup on PyPI: at
186
+ <https://pypi.org/manage/account/publishing/> add a *pending publisher* for
187
+ this project with
188
+
189
+ - PyPI project name: `morphoview`
190
+ - Owner: `subhacom`
191
+ - Repository: `morphoview`
192
+ - Workflow: `publish.yml`
193
+ - Environment: `pypi`
194
+
195
+ To cut a release:
196
+
197
+ 1. Bump `version` in `pyproject.toml` (and commit).
198
+ 2. Create a GitHub Release with a tag matching that version, e.g. `v0.1.0`
199
+ (the leading `v` is optional). The workflow verifies the tag matches
200
+ `pyproject.toml` and fails fast on a mismatch.
201
+ 3. Publishing runs automatically once the release is published.
202
+
203
+ ## History
204
+ It was refactored and updated by Claude Opus 4.8 from the morphology utilities developed for the GGN model published in Ray S, Aldworth ZN, Stopfer MA. Feedback inhibition and its control in an insect olfactory circuit. Scott K, editor. eLife. 2020 Mar 12;9:e53281. doi:10.7554/eLife.53281.
205
+
206
+
207
+ ## License
208
+
209
+ MIT
@@ -0,0 +1,175 @@
1
+ # morphoview
2
+
3
+ Read, analyze and visualize neuronal morphologies stored in
4
+ [SWC](http://www.neuronland.org/NLMorphologyConverter/MorphologyFormats/SWC/Spec.html)
5
+ format.
6
+
7
+ `morphoview` loads an SWC trace into a `networkx` graph, computes
8
+ morphology statistics (branch points, leaves, path lengths, total
9
+ neurite length), and renders the cell in 2-D or 3-D using any of three
10
+ pluggable backends:
11
+
12
+ | Backend | Strengths | Extra dependency |
13
+ |--------------|----------------------------------------------|------------------|
14
+ | `mpl` | Portable, figure-quality 2-D/3-D line plots | `matplotlib` |
15
+ | `vtk` | Tapered tubes, interactive, PNG/movie export | `vtk` |
16
+ | `vispy` | GPU-accelerated interactive tube view | `vispy` |
17
+
18
+ The core I/O and analysis need only `numpy` and `networkx`; each
19
+ rendering backend is optional and imported lazily.
20
+
21
+ This is a refactored, Python-3-native successor to the `morphutils`
22
+ scripts (`neurograph.py`, `displaycell.py`, `morph3d*.py`, `cellmovie.py`).
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ pip install -e . # core only (numpy + networkx)
28
+ pip install -e ".[mpl]" # + matplotlib backend
29
+ pip install -e ".[vtk]" # + VTK backend
30
+ pip install -e ".[all]" # everything
31
+ ```
32
+
33
+ ## Command line
34
+
35
+ ```bash
36
+ # Print morphology statistics
37
+ morphoview info examples/sample.swc
38
+
39
+ # Interactive 3-D display (VTK, tapered tubes, coloured by structure)
40
+ morphoview display examples/sample.swc
41
+
42
+ # Matplotlib 2-D projection onto the XY plane
43
+ morphoview display examples/sample.swc -b mpl --proj xy -c 4cp
44
+
45
+ # Several cells at once, positioned independently
46
+ morphoview display cellA.swc cellB.swc -t "0 0 0" -t "200 0 0" -r "z 90"
47
+
48
+ # Save a snapshot without opening a window (headless)
49
+ morphoview display examples/sample.swc --save cell.png --offscreen
50
+
51
+ # Render a rotating movie sweeping 360 degrees about Y
52
+ morphoview movie -i examples/sample.swc -o cell.avi -y 360
53
+ ```
54
+
55
+ Useful `display` options:
56
+
57
+ - `-b/--backend {vtk,mpl,vispy}` — pick the renderer (default `vtk`).
58
+ - `-l/--lines W` — draw fixed-width lines of width `W` instead of tubes.
59
+ - `-c/--colormap NAME` — structure colour palette (see below).
60
+ - `-t/--translate "X Y Z"`, `-r/--rotate "x 90 y 45"`, `-m/--mirror x` —
61
+ per-file rigid transforms (repeat the flag once per input file).
62
+ - `--branches`, `--leaves`, `-s/--struct-id ID...` — label nodes.
63
+ - `-a/--scalebar`, `-F/--fullscreen`, `--save FILE.png`, `--offscreen`.
64
+
65
+ ## Python API
66
+
67
+ ```python
68
+ import morphoview as nv
69
+
70
+ graph = nv.swc_to_graph("examples/sample.swc")
71
+ print(nv.summary(graph))
72
+ # {'nodes': 19, 'edges': 18, 'branch_points': 3, 'branches': 8,
73
+ # 'leaves': 5, 'total_length': 57.76...}
74
+
75
+ # Per-structure node lists (soma / axon / dendrites / custom regions)
76
+ by_type = nv.structure_node_map(graph)
77
+
78
+ # Path length from the soma to every node
79
+ distances = nv.soma_distance(graph)
80
+
81
+ # Render with matplotlib
82
+ from morphoview.backends import mpl
83
+ ax = mpl.plot_3d(graph, color=nv.get_colormap("3cd2"))
84
+ mpl.show()
85
+
86
+ # Render with VTK (tapered tubes)
87
+ from morphoview.backends import vtk
88
+ vtk.show(graph, colormap=nv.get_colormap("3cd2"), axes=True)
89
+ ```
90
+
91
+ ### Transformations
92
+
93
+ ```python
94
+ from morphoview import transform as tf
95
+
96
+ tf.rotate(graph, thetaz=90) # degrees, about the origin
97
+ tf.translate(graph, 100, 0, 0) # micrometres
98
+ tf.mirror(graph, "x") # reflect across the YZ plane
99
+
100
+ combined = nv.combine(graph_a, graph_b) # merge, renumbering node ids
101
+ ```
102
+
103
+ ## Structure ids and colour palettes
104
+
105
+ SWC tags each point with a structure id. The standard ids are
106
+ `1=soma`, `2=axon`, `3=basal dendrite`, `4=apical dendrite`; ids `>= 5`
107
+ are custom (`morphoview` also names the GGN regions `5=LCA`, `6=MCA`,
108
+ `7=LH`, `8=alphaL`).
109
+
110
+ Palettes are keyed by short names combining a class count and a scheme,
111
+ mostly from [colorbrewer2.org](https://colorbrewer2.org) and the
112
+ [SRON](https://personal.sron.nl/~pault/) colour-blind-safe sets:
113
+ `3cd2` (default), `3cs2`, `3cp`, `4cp`, `5cd2`, `5cs3`, `7q`, `7cp`,
114
+ `7ca`, `7cd2`, `9q`, `10cp`, `10cs3`, `15cb`. Structure ids beyond a
115
+ palette's length wrap around so every morphology still renders.
116
+
117
+ ## Project layout
118
+
119
+ ```
120
+ src/morphoview/
121
+ swc.py SWC file I/O (numpy structured arrays)
122
+ graph.py networkx graph construction + morphology analysis
123
+ colors.py structure-id names and colour palettes
124
+ transform.py rigid transforms (translate/rotate/mirror)
125
+ cli.py the `morphoview` command-line entry point
126
+ backends/
127
+ mpl.py matplotlib 2-D/3-D
128
+ vtk.py VTK tubes/lines, labels, PNG export
129
+ vispy.py vispy tube view
130
+ movie.py VTK rotating-movie export
131
+ tests/ pytest suite (core + matplotlib backend)
132
+ examples/sample.swc small synthetic neuron for demos/tests
133
+ ```
134
+
135
+ ## Development
136
+
137
+ ```bash
138
+ pip install -e ".[dev]"
139
+ pytest
140
+ ```
141
+
142
+ ## Releasing to PyPI
143
+
144
+ Publishing is automated by
145
+ [`.github/workflows/publish.yml`](.github/workflows/publish.yml). It builds
146
+ the sdist and wheel on every push/PR as a smoke test, and uploads them to
147
+ PyPI when a GitHub Release is published, using
148
+ [Trusted Publishing](https://docs.pypi.org/trusted-publishers/) (OIDC) — so
149
+ there are no API tokens to store as secrets.
150
+
151
+ One-time setup on PyPI: at
152
+ <https://pypi.org/manage/account/publishing/> add a *pending publisher* for
153
+ this project with
154
+
155
+ - PyPI project name: `morphoview`
156
+ - Owner: `subhacom`
157
+ - Repository: `morphoview`
158
+ - Workflow: `publish.yml`
159
+ - Environment: `pypi`
160
+
161
+ To cut a release:
162
+
163
+ 1. Bump `version` in `pyproject.toml` (and commit).
164
+ 2. Create a GitHub Release with a tag matching that version, e.g. `v0.1.0`
165
+ (the leading `v` is optional). The workflow verifies the tag matches
166
+ `pyproject.toml` and fails fast on a mismatch.
167
+ 3. Publishing runs automatically once the release is published.
168
+
169
+ ## History
170
+ It was refactored and updated by Claude Opus 4.8 from the morphology utilities developed for the GGN model published in Ray S, Aldworth ZN, Stopfer MA. Feedback inhibition and its control in an insect olfactory circuit. Scott K, editor. eLife. 2020 Mar 12;9:e53281. doi:10.7554/eLife.53281.
171
+
172
+
173
+ ## License
174
+
175
+ MIT
@@ -0,0 +1,48 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "morphoview"
7
+ version = "0.1.0"
8
+ description = "Read, analyze and visualize neuronal morphologies in SWC format."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Subhasis Ray" },
14
+ ]
15
+ keywords = ["neuroscience", "morphology", "SWC", "visualization", "neuron"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Science/Research",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Topic :: Scientific/Engineering :: Visualization",
22
+ ]
23
+ dependencies = [
24
+ "numpy>=1.20",
25
+ "networkx>=3.0",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ mpl = ["matplotlib>=3.4"]
30
+ vtk = ["vtk>=9.0"]
31
+ vispy = ["vispy>=0.11"]
32
+ all = ["matplotlib>=3.4", "vtk>=9.0", "vispy>=0.11"]
33
+ dev = ["pytest>=7.0", "matplotlib>=3.4", "vtk>=9.0"]
34
+
35
+ [project.scripts]
36
+ morphoview = "morphoview.cli:main"
37
+
38
+ [project.urls]
39
+ Homepage = "https://github.com/subhacom/morphoview"
40
+
41
+ [tool.setuptools.packages.find]
42
+ where = ["src"]
43
+
44
+ [tool.setuptools.package-data]
45
+ morphoview = ["py.typed"]
46
+
47
+ [tool.pytest.ini_options]
48
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,93 @@
1
+ """morphoview -- read, analyze and visualize neuronal morphologies.
2
+
3
+ Quick start::
4
+
5
+ import morphoview as nv
6
+
7
+ graph = nv.swc_to_graph("cell.swc")
8
+ print(nv.summary(graph))
9
+
10
+ # Matplotlib (portable, always available if matplotlib is installed)
11
+ from morphoview.backends import mpl
12
+ mpl.plot_3d(graph, color=nv.get_colormap("3cd2"))
13
+ mpl.show()
14
+
15
+ # VTK (tapered tubes, interactive)
16
+ from morphoview.backends import vtk
17
+ vtk.show(graph, colormap=nv.get_colormap("3cd2"), axes=True)
18
+
19
+ The rendering backends (matplotlib, VTK, vispy) are optional and imported
20
+ lazily, so the core I/O and analysis work with just numpy + networkx.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ from . import colors, graph, swc, transform
26
+ from .colors import (
27
+ COLORMAPS,
28
+ DEFAULT_COLORMAP,
29
+ STRUCTURE_IDS,
30
+ STRUCTURE_NAMES,
31
+ color_for_structure,
32
+ get_colormap,
33
+ normalize,
34
+ structure_name,
35
+ )
36
+ from .graph import (
37
+ branch_points,
38
+ combine,
39
+ graph_to_swc,
40
+ leaf_nodes,
41
+ n_branches,
42
+ n_leaves,
43
+ soma_distance,
44
+ soma_pathlen,
45
+ structure_node_map,
46
+ summary,
47
+ swc_to_graph,
48
+ total_length,
49
+ )
50
+ from .swc import SWC_DTYPE, load_swc, save_swc
51
+ from .transform import apply_transform, mirror, rotate, translate
52
+
53
+ __version__ = "0.1.0"
54
+
55
+ __all__ = [
56
+ "__version__",
57
+ # submodules
58
+ "colors",
59
+ "graph",
60
+ "swc",
61
+ "transform",
62
+ # colors
63
+ "COLORMAPS",
64
+ "DEFAULT_COLORMAP",
65
+ "STRUCTURE_IDS",
66
+ "STRUCTURE_NAMES",
67
+ "color_for_structure",
68
+ "get_colormap",
69
+ "normalize",
70
+ "structure_name",
71
+ # swc I/O
72
+ "SWC_DTYPE",
73
+ "load_swc",
74
+ "save_swc",
75
+ # graph
76
+ "swc_to_graph",
77
+ "graph_to_swc",
78
+ "combine",
79
+ "branch_points",
80
+ "n_branches",
81
+ "leaf_nodes",
82
+ "n_leaves",
83
+ "total_length",
84
+ "soma_distance",
85
+ "soma_pathlen",
86
+ "structure_node_map",
87
+ "summary",
88
+ # transforms
89
+ "apply_transform",
90
+ "translate",
91
+ "rotate",
92
+ "mirror",
93
+ ]
@@ -0,0 +1,9 @@
1
+ """Rendering backends for neuronal morphologies.
2
+
3
+ Each backend is imported lazily so that the heavy, optional dependencies
4
+ (matplotlib, VTK, vispy) are only required if you actually use them.
5
+ Import the one you need directly, e.g.::
6
+
7
+ from morphoview.backends import mpl
8
+ from morphoview.backends import vtk
9
+ """
@@ -0,0 +1,101 @@
1
+ """Render a rotating movie of a morphology with VTK.
2
+
3
+ Rotates the neuron about one or more axes and writes each frame, producing
4
+ an animation. Requires the ``vtk`` package.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Dict, Optional, Tuple
10
+
11
+ import networkx as nx
12
+
13
+ from .. import colors, transform
14
+ from . import vtk as vtk_backend
15
+
16
+ vtk = vtk_backend.vtk
17
+
18
+
19
+ def _bounding_center(graph: nx.DiGraph) -> Tuple[float, float, float]:
20
+ xs = [graph.nodes[n]["x"] for n in graph]
21
+ ys = [graph.nodes[n]["y"] for n in graph]
22
+ zs = [graph.nodes[n]["z"] for n in graph]
23
+ return (
24
+ (min(xs) + max(xs)) * 0.5,
25
+ (min(ys) + max(ys)) * 0.5,
26
+ (min(zs) + max(zs)) * 0.5,
27
+ )
28
+
29
+
30
+ def dump_movie(
31
+ filename: str,
32
+ graph: nx.DiGraph,
33
+ colormap: Optional[Dict[int, colors.RGB]] = None,
34
+ background: Tuple[float, float, float] = (0, 0, 0),
35
+ lines: float = 0.0,
36
+ xrot: float = 0.0,
37
+ yrot: float = 0.0,
38
+ zrot: float = 0.0,
39
+ xangle: float = 0.0,
40
+ yangle: float = 0.0,
41
+ zangle: float = 0.0,
42
+ frames_per_degree: int = 10,
43
+ framerate: int = 25,
44
+ size: Tuple[int, int] = (800, 600),
45
+ ) -> None:
46
+ """Write a rotating animation of ``graph`` to ``filename`` (AVI).
47
+
48
+ ``xrot/yrot/zrot`` orient the neuron before recording; ``xangle`` etc.
49
+ are the total sweep in degrees about each axis during the movie.
50
+ """
51
+ if colormap is None:
52
+ colormap = colors.get_colormap(colors.DEFAULT_COLORMAP)
53
+
54
+ # Centre the morphology at the origin, then apply the initial orientation.
55
+ cx, cy, cz = _bounding_center(graph)
56
+ transform.apply_transform(
57
+ graph,
58
+ transform.rotation_translation_matrix(-cx, -cy, -cz, xrot, yrot, zrot),
59
+ )
60
+
61
+ renderer = vtk_backend.make_renderer(
62
+ graph, colormap=colormap, background=background, lines=lines
63
+ )
64
+ actor = renderer.GetActors().GetLastActor()
65
+ cx, cy, cz = _bounding_center(graph)
66
+ actor.SetOrigin(cx, cy, cz)
67
+
68
+ window = vtk.vtkRenderWindow()
69
+ window.SetSize(*size)
70
+ window.AddRenderer(renderer)
71
+ interactor = vtk.vtkRenderWindowInteractor()
72
+ interactor.SetRenderWindow(window)
73
+ window.Render()
74
+ interactor.Initialize()
75
+
76
+ def _step(angle):
77
+ return (0.0 if angle == 0 else 1.0 / frames_per_degree,
78
+ int(angle * frames_per_degree))
79
+
80
+ dx, xframes = _step(xangle)
81
+ dy, yframes = _step(yangle)
82
+ dz, zframes = _step(zangle)
83
+ frames = max(xframes, yframes, zframes)
84
+
85
+ w2if = vtk.vtkWindowToImageFilter()
86
+ w2if.SetInput(window)
87
+ w2if.ReadFrontBufferOff()
88
+ w2if.Update()
89
+ writer = vtk.vtkAVIWriter()
90
+ writer.SetRate(framerate)
91
+ writer.SetInputConnection(w2if.GetOutputPort())
92
+ writer.SetFileName(filename)
93
+ writer.Start()
94
+ for _ in range(frames):
95
+ actor.RotateX(dx)
96
+ actor.RotateY(dy)
97
+ actor.RotateZ(dz)
98
+ window.Render()
99
+ w2if.Modified() # crucial: force the filter to grab the new frame
100
+ writer.Write()
101
+ writer.End()