brainrender 2.1.19__tar.gz → 2.2.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.
Files changed (46) hide show
  1. {brainrender-2.1.19 → brainrender-2.2.0}/PKG-INFO +18 -12
  2. {brainrender-2.1.19 → brainrender-2.2.0}/README.md +13 -9
  3. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/_io.py +24 -1
  4. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/_jupyter.py +8 -4
  5. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/_video.py +1 -1
  6. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/actor.py +154 -79
  7. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/atlas.py +95 -37
  8. brainrender-2.2.0/brainrender/atlas_specific/allen_brain_atlas/streamlines.py +232 -0
  9. brainrender-2.2.0/brainrender/camera.py +169 -0
  10. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/cameras.py +6 -0
  11. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/render.py +120 -55
  12. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/scene.py +180 -100
  13. brainrender-2.2.0/brainrender/video.py +628 -0
  14. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender.egg-info/PKG-INFO +18 -12
  15. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender.egg-info/SOURCES.txt +2 -0
  16. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender.egg-info/requires.txt +4 -2
  17. brainrender-2.2.0/brainrender.egg-info/scm_file_list.json +112 -0
  18. brainrender-2.2.0/brainrender.egg-info/scm_version.json +8 -0
  19. {brainrender-2.1.19 → brainrender-2.2.0}/pyproject.toml +4 -2
  20. brainrender-2.1.19/brainrender/atlas_specific/allen_brain_atlas/streamlines.py +0 -111
  21. brainrender-2.1.19/brainrender/camera.py +0 -110
  22. brainrender-2.1.19/brainrender/video.py +0 -437
  23. {brainrender-2.1.19 → brainrender-2.2.0}/.github/workflows/test_and_deploy.yml +0 -0
  24. {brainrender-2.1.19 → brainrender-2.2.0}/.gitignore +0 -0
  25. {brainrender-2.1.19 → brainrender-2.2.0}/CITATION.cff +0 -0
  26. {brainrender-2.1.19 → brainrender-2.2.0}/LICENSE +0 -0
  27. {brainrender-2.1.19 → brainrender-2.2.0}/MANIFEST.in +0 -0
  28. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/__init__.py +0 -0
  29. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/_colors.py +0 -0
  30. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/_utils.py +0 -0
  31. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/actors/__init__.py +0 -0
  32. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/actors/cylinder.py +0 -0
  33. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/actors/line.py +0 -0
  34. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/actors/neurons.py +0 -0
  35. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/actors/points.py +0 -0
  36. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/actors/ruler.py +0 -0
  37. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/actors/streamlines.py +0 -0
  38. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/actors/volume.py +0 -0
  39. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/atlas_specific/__init__.py +0 -0
  40. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/atlas_specific/allen_brain_atlas/gene_expression/__init__.py +0 -0
  41. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/atlas_specific/allen_brain_atlas/gene_expression/api.py +0 -0
  42. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/atlas_specific/allen_brain_atlas/gene_expression/ge_utils.py +0 -0
  43. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender/settings.py +0 -0
  44. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender.egg-info/dependency_links.txt +0 -0
  45. {brainrender-2.1.19 → brainrender-2.2.0}/brainrender.egg-info/top_level.txt +0 -0
  46. {brainrender-2.1.19 → brainrender-2.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: brainrender
3
- Version: 2.1.19
3
+ Version: 2.2.0
4
4
  Summary: Visualisation and exploration of brain atlases and other anatomical data
5
5
  Author-email: "Federico Claudi, Adam Tyson, Luigi Petrucco" <hello@brainglobe.info>
6
6
  License: BSD-3-Clause
@@ -23,12 +23,14 @@ Requires-Python: >=3.11
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
25
  Requires-Dist: brainglobe-atlasapi>=2.0.1
26
+ Requires-Dist: cloud-volume>=3.11.0
26
27
  Requires-Dist: brainglobe-space>=1.0.0
27
28
  Requires-Dist: brainglobe-utils>=0.5.0
28
- Requires-Dist: h5py<3.16.0
29
+ Requires-Dist: h5py
29
30
  Requires-Dist: k3d
30
31
  Requires-Dist: loguru
31
- Requires-Dist: morphapi>=0.2.1
32
+ Requires-Dist: meshio
33
+ Requires-Dist: morphapi>=0.3.3
32
34
  Requires-Dist: msgpack
33
35
  Requires-Dist: myterial
34
36
  Requires-Dist: numpy
@@ -55,18 +57,22 @@ Requires-Dist: jupyter; extra == "nb"
55
57
  Requires-Dist: k3d; extra == "nb"
56
58
  Dynamic: license-file
57
59
 
58
- # brainrender
59
-
60
- *A user-friendly python library to create high-quality, 3D neuro-anatomical renderings combining data from publicly available brain atlases with user-generated experimental data.*
61
-
62
- [![Python Version](https://img.shields.io/pypi/pyversions/brainrender.svg)](https://pypi.org/project/brainrender)
63
- [![PyPI](https://img.shields.io/pypi/v/brainrender.svg)](https://pypi.org/project/brainrender)
60
+ [![Docs](https://img.shields.io/badge/Docs-brainrender-blue)](https://brainglobe.info/documentation/brainrender/index.html)
61
+ [![Get in Touch](https://img.shields.io/badge/Get%20in%20Touch-BrainGlobe-blue)](https://brainglobe.info/contact.html)
62
+ [![DOI](https://img.shields.io/badge/DOI-10.7554%2FeLife.65751-green)](https://doi.org/10.7554/eLife.65751)
63
+ [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
64
64
  [![tests](https://github.com/brainglobe/brainrender/workflows/tests/badge.svg)](https://github.com/brainglobe/brainrender/actions)
65
65
  [![codecov](https://codecov.io/gh/brainglobe/brainrender/graph/badge.svg)](https://codecov.io/gh/brainglobe/brainrender)
66
+ [![Python Version](https://img.shields.io/pypi/pyversions/brainrender.svg)](https://pypi.org/project/brainrender)
67
+ [![PyPI](https://img.shields.io/pypi/v/brainrender.svg)](https://pypi.org/project/brainrender)
66
68
  [![Downloads](https://static.pepy.tech/badge/brainrender)](https://pepy.tech/project/brainrender)
67
- [![image.sc forum](https://img.shields.io/badge/dynamic/json.svg?label=forum&url=https%3A%2F%2Fforum.image.sc%2Ftags%2Fbrainglobe.json&query=%24.topic_list.tags.0.topic_count&colorB=brightgreen&suffix=%20topics&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAABPklEQVR42m3SyyqFURTA8Y2BER0TDyExZ+aSPIKUlPIITFzKeQWXwhBlQrmFgUzMMFLKZeguBu5y+//17dP3nc5vuPdee6299gohUYYaDGOyyACq4JmQVoFujOMR77hNfOAGM+hBOQqB9TjHD36xhAa04RCuuXeKOvwHVWIKL9jCK2bRiV284QgL8MwEjAneeo9VNOEaBhzALGtoRy02cIcWhE34jj5YxgW+E5Z4iTPkMYpPLCNY3hdOYEfNbKYdmNngZ1jyEzw7h7AIb3fRTQ95OAZ6yQpGYHMMtOTgouktYwxuXsHgWLLl+4x++Kx1FJrjLTagA77bTPvYgw1rRqY56e+w7GNYsqX6JfPwi7aR+Y5SA+BXtKIRfkfJAYgj14tpOF6+I46c4/cAM3UhM3JxyKsxiOIhH0IO6SH/A1Kb1WBeUjbkAAAAAElFTkSuQmCC)](https://forum.image.sc/tag/brainglobe)
68
- [![Bluesky](https://img.shields.io/badge/Bluesky-0285FF?logo=bluesky&logoColor=fff)](https://bsky.app/profile/brainglobe.info)
69
- [![Mastodon](https://img.shields.io/badge/Mastodon-6364FF?logo=mastodon&logoColor=fff)](https://mastodon.online/@brainglobe)
69
+ [![Code style: Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/format.json)](https://github.com/astral-sh/ruff)
70
+ [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-green?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
71
+ [![Contributions Welcome](https://img.shields.io/badge/Contributions-Welcome-green.svg)](https://brainglobe.info/community/developers/index.html)
72
+
73
+ # brainrender
74
+
75
+ *A user-friendly python library to create high-quality, 3D neuro-anatomical renderings combining data from publicly available brain atlases with user-generated experimental data.*
70
76
 
71
77
  &nbsp;
72
78
  &nbsp;
@@ -1,15 +1,19 @@
1
- # brainrender
2
-
3
- *A user-friendly python library to create high-quality, 3D neuro-anatomical renderings combining data from publicly available brain atlases with user-generated experimental data.*
4
-
5
- [![Python Version](https://img.shields.io/pypi/pyversions/brainrender.svg)](https://pypi.org/project/brainrender)
6
- [![PyPI](https://img.shields.io/pypi/v/brainrender.svg)](https://pypi.org/project/brainrender)
1
+ [![Docs](https://img.shields.io/badge/Docs-brainrender-blue)](https://brainglobe.info/documentation/brainrender/index.html)
2
+ [![Get in Touch](https://img.shields.io/badge/Get%20in%20Touch-BrainGlobe-blue)](https://brainglobe.info/contact.html)
3
+ [![DOI](https://img.shields.io/badge/DOI-10.7554%2FeLife.65751-green)](https://doi.org/10.7554/eLife.65751)
4
+ [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
7
5
  [![tests](https://github.com/brainglobe/brainrender/workflows/tests/badge.svg)](https://github.com/brainglobe/brainrender/actions)
8
6
  [![codecov](https://codecov.io/gh/brainglobe/brainrender/graph/badge.svg)](https://codecov.io/gh/brainglobe/brainrender)
7
+ [![Python Version](https://img.shields.io/pypi/pyversions/brainrender.svg)](https://pypi.org/project/brainrender)
8
+ [![PyPI](https://img.shields.io/pypi/v/brainrender.svg)](https://pypi.org/project/brainrender)
9
9
  [![Downloads](https://static.pepy.tech/badge/brainrender)](https://pepy.tech/project/brainrender)
10
- [![image.sc forum](https://img.shields.io/badge/dynamic/json.svg?label=forum&url=https%3A%2F%2Fforum.image.sc%2Ftags%2Fbrainglobe.json&query=%24.topic_list.tags.0.topic_count&colorB=brightgreen&suffix=%20topics&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAABPklEQVR42m3SyyqFURTA8Y2BER0TDyExZ+aSPIKUlPIITFzKeQWXwhBlQrmFgUzMMFLKZeguBu5y+//17dP3nc5vuPdee6299gohUYYaDGOyyACq4JmQVoFujOMR77hNfOAGM+hBOQqB9TjHD36xhAa04RCuuXeKOvwHVWIKL9jCK2bRiV284QgL8MwEjAneeo9VNOEaBhzALGtoRy02cIcWhE34jj5YxgW+E5Z4iTPkMYpPLCNY3hdOYEfNbKYdmNngZ1jyEzw7h7AIb3fRTQ95OAZ6yQpGYHMMtOTgouktYwxuXsHgWLLl+4x++Kx1FJrjLTagA77bTPvYgw1rRqY56e+w7GNYsqX6JfPwi7aR+Y5SA+BXtKIRfkfJAYgj14tpOF6+I46c4/cAM3UhM3JxyKsxiOIhH0IO6SH/A1Kb1WBeUjbkAAAAAElFTkSuQmCC)](https://forum.image.sc/tag/brainglobe)
11
- [![Bluesky](https://img.shields.io/badge/Bluesky-0285FF?logo=bluesky&logoColor=fff)](https://bsky.app/profile/brainglobe.info)
12
- [![Mastodon](https://img.shields.io/badge/Mastodon-6364FF?logo=mastodon&logoColor=fff)](https://mastodon.online/@brainglobe)
10
+ [![Code style: Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/format.json)](https://github.com/astral-sh/ruff)
11
+ [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-green?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
12
+ [![Contributions Welcome](https://img.shields.io/badge/Contributions-Welcome-green.svg)](https://brainglobe.info/community/developers/index.html)
13
+
14
+ # brainrender
15
+
16
+ *A user-friendly python library to create high-quality, 3D neuro-anatomical renderings combining data from publicly available brain atlases with user-generated experimental data.*
13
17
 
14
18
  &nbsp;
15
19
  &nbsp;
@@ -1,7 +1,7 @@
1
1
  from pathlib import Path
2
2
 
3
3
  import requests
4
- from vedo import load
4
+ from vedo import Mesh, load
5
5
 
6
6
 
7
7
  def connected_to_internet(url="http://www.google.com/", timeout=5):
@@ -85,3 +85,26 @@ def load_mesh_from_file(filepath, color=None, alpha=None):
85
85
  actor = load(str(filepath))
86
86
  actor.c(color).alpha(alpha)
87
87
  return actor
88
+
89
+
90
+ def convert_meshio_to_vedo(meshio_mesh, color=None, alpha=None):
91
+ """
92
+ Convert a meshio mesh to a vedo mesh.
93
+
94
+ Parameters
95
+ ----------
96
+ meshio_mesh : meshio.Mesh
97
+ The meshio mesh to convert.
98
+ color : str, optional
99
+ The color to apply to the mesh. Default is None.
100
+ alpha : float, optional
101
+ The transparency to apply to the mesh. Default is None.
102
+
103
+ Returns
104
+ -------
105
+ vedo.Mesh
106
+ The converted vedo mesh.
107
+ """
108
+ actor = Mesh([meshio_mesh.points, meshio_mesh.cells_dict["triangle"]])
109
+ actor.c(color).alpha(alpha)
110
+ return actor
@@ -43,9 +43,13 @@ class not_on_jupyter: # pragma: no cover
43
43
  return self.func(obj, *args, **kwargs)
44
44
  else:
45
45
  print(
46
- f"[{orange_dark}]Cannot run function [bold {salmon}]{self.func.__name__}[/ bold {salmon}] in a jupyter notebook",
47
- f"[{orange_dark}]Try setting the correct backend before creating your scene:\n",
48
- Syntax("from vedo import embedWindow", lexer="python"),
49
- Syntax("embedWindow(None)", lexer="python"),
46
+ f"[{orange_dark}]Cannot run function [bold {salmon}]{self.func.__name__}[/bold {salmon}] in a jupyter notebook.",
47
+ f"[{orange_dark}]To use brainrender in a Jupyter notebook, set the vedo backend to 'k3d' before creating your scene:\n",
48
+ Syntax("import vedo", lexer="python"),
49
+ Syntax(
50
+ "vedo.settings.default_backend = 'k3d'", lexer="python"
51
+ ),
52
+ f"\n[{orange_dark}]Note: some features are not available in the k3d backend.",
53
+ f"[{orange_dark}]To use all features, run brainrender in a standard Python script or interactive terminal instead.",
50
54
  )
51
55
  return None
@@ -30,7 +30,7 @@ class Video(VtkVideo):
30
30
  if self.size:
31
31
  fmt += f" -s {self.size}"
32
32
 
33
- command = f"ffmpeg -hide_banner -loglevel panic -y -r {fps} -start_number 0 -i {fld} {fmt} {name}"
33
+ command = f'ffmpeg -hide_banner -loglevel panic -y -r {fps} -start_number 0 -i "{fld}" {fmt} "{name}"'
34
34
  out = os.system(command)
35
35
  self.tmp_dir.cleanup()
36
36
  return out, command
@@ -1,5 +1,9 @@
1
+ """Actor class and label utilities for brainrender scenes."""
2
+
3
+ from __future__ import annotations
4
+
1
5
  from io import StringIO
2
- from typing import Optional
6
+ from typing import Any, Self
3
7
 
4
8
  import numpy as np
5
9
  import numpy.typing as npt
@@ -7,8 +11,8 @@ import pyinspect as pi
7
11
  from brainglobe_atlasapi import BrainGlobeAtlas
8
12
  from brainglobe_space import AnatomicalSpace
9
13
  from myterial import amber, orange, salmon
10
- from rich.console import Console
11
- from vedo import Sphere, Text3D
14
+ from rich.console import Console, ConsoleOptions, RenderResult
15
+ from vedo import Mesh, Sphere, Text3D
12
16
 
13
17
  from brainrender._utils import listify
14
18
 
@@ -17,27 +21,44 @@ label_mtx = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
17
21
 
18
22
 
19
23
  def make_actor_label(
20
- atlas,
21
- actors,
22
- labels,
23
- size=300,
24
- color=None,
25
- radius=100,
26
- xoffset=0,
27
- yoffset=-500,
28
- zoffset=0,
29
- ):
24
+ atlas: BrainGlobeAtlas,
25
+ actors: Actor | list[Actor],
26
+ labels: str | list[str],
27
+ size: int = 300,
28
+ color: str | list[float] | None = None,
29
+ radius: int | None = 100,
30
+ xoffset: int = 0,
31
+ yoffset: int = -500,
32
+ zoffset: int = 0,
33
+ ) -> list[Text3D | Sphere]:
30
34
  """
31
- Adds a 2D text anchored to a point on the actor's mesh
32
- to label what the actor is
33
-
34
- :param kwargs: keyword arguments can be passed to determine
35
- text appearance and location:
36
- - size: int, text size. Default 300
37
- - color: str, text color. A list of colors can be passed
38
- if None a gray color is used. Default None.
39
- - xoffset, yoffset, zoffset: integers that shift the label position
40
- - radius: radius of sphere used to denote label anchor. Set to 0 or None to hide.
35
+ Create 3D text labels anchored to actor meshes.
36
+
37
+ Parameters
38
+ ----------
39
+ atlas
40
+ Atlas used for hemisphere queries and point mirroring.
41
+ actors
42
+ Actors to label.
43
+ labels
44
+ Label string(s) for each actor.
45
+ size
46
+ Text size. Default 300.
47
+ color
48
+ Label colour. Defaults to dark grey if None.
49
+ radius
50
+ Radius of the anchor sphere. Set to None to hide. Default 100.
51
+ xoffset
52
+ Positional offset along x. Default 0.
53
+ yoffset
54
+ Positional offset along y. Default -500.
55
+ zoffset
56
+ Positional offset along z. Default 0.
57
+
58
+ Returns
59
+ -------
60
+ list
61
+ Flat list of vedo Text3D and Sphere objects.
41
62
  """
42
63
  offset = [-yoffset, -zoffset, xoffset]
43
64
  default_offset = np.array([0, -200, 100])
@@ -79,40 +100,50 @@ def make_actor_label(
79
100
 
80
101
 
81
102
  class Actor:
82
- _needs_label = False # needs to make a label
83
- _needs_silhouette = False # needs to make a silhouette
84
- _is_transformed = False # has been transformed to correct axes orientation
85
- _is_added = False # has the actor been added to the scene already
103
+ """
104
+ Represents any object displayed in a brainrender scene.
105
+
106
+ Wraps a vedo Mesh with a name and class type, and provides helpers
107
+ for creating silhouettes and 3D labels. Unknown attribute lookups
108
+ are delegated to the underlying mesh.
109
+
110
+ Parameters
111
+ ----------
112
+ mesh
113
+ The 3D mesh for this actor.
114
+ name
115
+ Actor name. Default ``"Actor"``.
116
+ br_class
117
+ Brainrender class type. Default ``"None"``.
118
+ is_text
119
+ Whether this actor is a 2D text annotation. Default False.
120
+ color
121
+ Colour to apply to the mesh on construction.
122
+ alpha
123
+ Transparency to apply to the mesh on construction.
124
+ """
125
+
126
+ _needs_label: bool = False # needs to make a label
127
+ _needs_silhouette: bool = False # needs to make a silhouette
128
+ _is_transformed: bool = (
129
+ False # has been transformed to correct axes orientation
130
+ )
131
+ _is_added: bool = False # has the actor been added to the scene already
86
132
 
87
- labels = []
88
- silhouette = None
133
+ labels: list[Actor] = []
134
+ silhouette: Actor | None = None
89
135
 
90
136
  def __init__(
91
137
  self,
92
- mesh,
93
- name=None,
94
- br_class=None,
95
- is_text=False,
96
- color=None,
97
- alpha=None,
98
- ):
99
- """
100
- Actor class representing anything shown in a brainrender scene.
101
- Methods in brainrender.actors are used to creates actors specific
102
- for different data types.
103
-
104
- An actor has a mesh, a name and a brainrender class type.
105
- It also has methods to create a silhouette or a label.
106
-
107
- :param mesh: instance of vedo.Mesh
108
- :param name: str, actor name
109
- :param br_class: str, name of brainrender actors class
110
- :param is_text: bool, is it a 2d text or annotation?
111
- :param color: str, name or hex code of color to assign to actor's mesh
112
- :param alpha: float, transparency to assign to actor's mesh
113
- """
138
+ mesh: Mesh,
139
+ name: str | None = None,
140
+ br_class: str | None = None,
141
+ is_text: bool = False,
142
+ color: str | None = None,
143
+ alpha: float | None = None,
144
+ ) -> None:
114
145
  self.mesh = mesh
115
- self.name = name or "Actor"
146
+ self.name = name or Actor
116
147
  self.br_class = br_class or "None"
117
148
  self.is_text = is_text
118
149
 
@@ -121,10 +152,14 @@ class Actor:
121
152
  if alpha:
122
153
  self.mesh.alpha(alpha)
123
154
 
124
- def __getattr__(self, attr):
155
+ def __getattr__(self, attr: str) -> Any:
125
156
  """
126
- If an unknown attribute is called, try `self.mesh.attr`
127
- to get the mesh's attribute
157
+ Delegate unknown attribute lookups to the underlying mesh.
158
+
159
+ Raises
160
+ ------
161
+ AttributeError
162
+ If the attribute is not found on any mesh object.
128
163
  """
129
164
  if "mesh" not in self.__dict__.keys():
130
165
  raise AttributeError(
@@ -148,10 +183,10 @@ class Actor:
148
183
  f"Actor does not have attribute {attr}"
149
184
  ) # pragma: no cover
150
185
 
151
- def __repr__(self): # pragma: no cover
186
+ def __repr__(self) -> str: # pragma: no cover
152
187
  return f"brainrender.Actor: {self.name}-{self.br_class}"
153
188
 
154
- def __str__(self):
189
+ def __str__(self) -> str:
155
190
  buf = StringIO()
156
191
  _console = Console(file=buf, force_jupyter=False)
157
192
  _console.print(self)
@@ -159,23 +194,50 @@ class Actor:
159
194
  return buf.getvalue()
160
195
 
161
196
  @property
162
- def center(self):
197
+ def center(self) -> npt.NDArray[np.float64]:
163
198
  """
164
- Returns the coordinates of the mesh's center
199
+ Return the mesh's centre of mass coordinates.
200
+
201
+ Returns
202
+ -------
203
+ numpy.ndarray
204
+ Array of shape (3,) with (x, y, z) coordinates.
165
205
  """
166
206
  return self.mesh.center_of_mass()
167
207
 
168
208
  @classmethod
169
- def make_actor(cls, mesh, name, br_class):
209
+ def make_actor(cls, mesh: Mesh, name: str, br_class: str) -> Self:
170
210
  """
171
- Make an actor from a given mesh
211
+ Construct an Actor from an existing mesh.
212
+
213
+ Parameters
214
+ ----------
215
+ mesh
216
+ Mesh to wrap.
217
+ name
218
+ Actor name.
219
+ br_class
220
+ Brainrender class type.
221
+
222
+ Returns
223
+ -------
224
+ Actor
172
225
  """
173
226
  return cls(mesh, name=name, br_class=br_class)
174
227
 
175
- def make_label(self, atlas):
228
+ def make_label(self, atlas: BrainGlobeAtlas) -> list[Actor]:
176
229
  """
177
- Create a new Actor with a sphere and a text
178
- labelling this actor
230
+ Create 3D label actors anchored to this actor's mesh.
231
+
232
+ Parameters
233
+ ----------
234
+ atlas
235
+ Atlas used for hemisphere queries and mirroring.
236
+
237
+ Returns
238
+ -------
239
+ list of Actor
240
+ Label actors (text and optional sphere markers).
179
241
  """
180
242
  labels = make_actor_label(
181
243
  atlas, self, self._label_str, **self._label_kwargs
@@ -188,9 +250,14 @@ class Actor:
188
250
  self.labels = lbls
189
251
  return lbls
190
252
 
191
- def make_silhouette(self):
253
+ def make_silhouette(self) -> Actor:
192
254
  """
193
- Create a new silhouette actor outlining this actor
255
+ Create a silhouette actor outlining this actor's mesh.
256
+
257
+ Returns
258
+ -------
259
+ Actor
260
+ Silhouette actor with brainrender class ``"silhouette"``.
194
261
  """
195
262
  lw = self._silhouette_kwargs["lw"]
196
263
  color = self._silhouette_kwargs["color"]
@@ -208,19 +275,25 @@ class Actor:
208
275
  def mirror(
209
276
  self,
210
277
  axis: str,
211
- origin: Optional[npt.NDArray] = None,
212
- atlas: Optional[BrainGlobeAtlas] = None,
213
- ):
278
+ origin: npt.NDArray | None = None,
279
+ atlas: BrainGlobeAtlas | None = None,
280
+ ) -> None:
214
281
  """
215
- Mirror the actor's mesh around the specified axis, using the
216
- parent_center as the center of the mirroring operation. The axes can
217
- be specified using an abbreviation, e.g. 'x' for the x-axis, or anatomical
218
- convention e.g. 'sagittal'. If an atlas is provided, then the anatomical
219
- space of the atlas is used, otherwise `asr` is assumed.
220
-
221
- :param axis: str, axis around which to mirror the mesh
222
- :param origin: np.ndarray, center of the mirroring operation
223
- :param atlas: BrainGlobeAtlas, atlas object to use for anatomical space
282
+ Mirror the actor's mesh across the given axis.
283
+
284
+ Accepts Cartesian axes (``'x'``, ``'y'``, ``'z'``) or anatomical
285
+ plane names (``'sagittal'``, ``'vertical'``, ``'frontal'``).
286
+ If an anatomical name is used without an atlas, ``'asr'`` space
287
+ is assumed. The mesh is updated in place.
288
+
289
+ Parameters
290
+ ----------
291
+ axis
292
+ Axis or anatomical plane to mirror across.
293
+ origin
294
+ Centre of the mirroring operation. Default None.
295
+ atlas
296
+ Atlas used to resolve anatomical axis names. Default None.
224
297
  """
225
298
  if axis in ["sagittal", "vertical", "frontal"]:
226
299
  anatomical_space = atlas.space if atlas else AnatomicalSpace("asr")
@@ -230,7 +303,9 @@ class Actor:
230
303
 
231
304
  self.mesh = self.mesh.mirror(axis, origin)
232
305
 
233
- def __rich_console__(self, *args):
306
+ def __rich_console__(
307
+ self, console: Console, options: ConsoleOptions
308
+ ) -> RenderResult:
234
309
  """
235
310
  Print some useful characteristics to console.
236
311
  """
@@ -1,24 +1,36 @@
1
+ """Atlas subclass adding region and plane Actor support for scenes."""
2
+
3
+ from typing import Any
4
+
1
5
  import numpy as np
6
+ import numpy.typing as npt
2
7
  from brainglobe_atlasapi.bg_atlas import BrainGlobeAtlas
3
8
  from loguru import logger
4
9
  from vedo import Plane
5
10
 
6
11
  from brainrender import settings
7
- from brainrender._io import load_mesh_from_file
12
+ from brainrender._io import convert_meshio_to_vedo
8
13
  from brainrender._utils import return_list_smart
9
14
  from brainrender.actor import Actor
10
15
 
11
16
 
12
17
  class Atlas(BrainGlobeAtlas):
13
- def __init__(self, atlas_name=None, check_latest=True):
14
- """
15
- Brainrender's Atlas class subclasses BrainGlobeAtlas
16
- to add methods to get regions meshes as Actors
17
- and to get a plane at a given point and normal.
18
-
19
- :param atlas_name: str, atlas name from brainglobe's atlas API atlases
20
- :param check_latest: bool, if True checks that the atlas is the latest version
21
- """
18
+ """
19
+ Subclass of BrainGlobeAtlas with helpers for rendering.
20
+
21
+ Parameters
22
+ ----------
23
+ atlas_name
24
+ Falls back to ``settings.DEFAULT_ATLAS`` if None.
25
+ check_latest
26
+ Check for the latest atlas version. Default True.
27
+ """
28
+
29
+ def __init__(
30
+ self,
31
+ atlas_name: str | None = None,
32
+ check_latest: bool = True,
33
+ ) -> None:
22
34
  atlas_name = atlas_name or settings.DEFAULT_ATLAS
23
35
  self.atlas_name = atlas_name
24
36
  logger.debug(f"Generating ATLAS: {atlas_name}")
@@ -30,9 +42,9 @@ class Atlas(BrainGlobeAtlas):
30
42
  super().__init__(atlas_name=atlas_name, check_latest=check_latest)
31
43
 
32
44
  @property
33
- def zoom(self):
45
+ def zoom(self) -> float:
34
46
  """
35
- Returns the best camera zoom given the atlas resolution
47
+ Return a reasonable camera zoom given the atlas resolution.
36
48
  """
37
49
  res = np.max(self.metadata["resolution"])
38
50
 
@@ -44,20 +56,44 @@ class Atlas(BrainGlobeAtlas):
44
56
  else:
45
57
  return 40 / res
46
58
 
47
- def _get_region_color(self, region):
59
+ def _get_region_color(self, region: str | int) -> list[float]:
48
60
  """
49
- Gets the rgb color of a region in the atlas
61
+ Get the rgb color of a region in the atlas.
62
+
63
+ Parameters
64
+ ----------
65
+ region
66
+ Region acronym or ID.
67
+
68
+ Returns
69
+ -------
70
+ list of float
50
71
  """
51
72
  return [
52
73
  x / 255 for x in self._get_from_structure(region, "rgb_triplet")
53
74
  ]
54
75
 
55
- def get_region(self, *regions, alpha=1, color=None):
76
+ def get_region(
77
+ self,
78
+ *regions: str | int,
79
+ alpha: float = 1,
80
+ color: str | list[float] | None = None,
81
+ ) -> Actor | list[Actor] | None:
56
82
  """
57
- Get brain regions meshes as Actors
58
- :param regions: str with names of brain regions in the atlas
59
- :param alpha: float
60
- :param color: str
83
+ Get brain regions meshes as Actors.
84
+
85
+ Parameters
86
+ ----------
87
+ *regions
88
+ Region acronyms or IDs.
89
+ alpha
90
+ Mesh transparency. Default 1.
91
+ color
92
+ Uses atlas RGB colour if None.
93
+
94
+ Returns
95
+ -------
96
+ Actor or list of Actor or None
61
97
  """
62
98
  if not regions:
63
99
  return None
@@ -75,12 +111,14 @@ class Atlas(BrainGlobeAtlas):
75
111
  continue
76
112
 
77
113
  # Get mesh
78
- obj_file = str(self.meshfile_from_structure(region))
79
114
  try:
80
- mesh = load_mesh_from_file(obj_file, color=color, alpha=alpha)
115
+ meshio_mesh = self.mesh_from_structure(region)
116
+ mesh = convert_meshio_to_vedo(
117
+ meshio_mesh, color=color, alpha=alpha
118
+ )
81
119
  except FileNotFoundError:
82
120
  print(
83
- f"The region {region} is in the onthology but does not have a corresponding volume in the atlas being used: {self.atlas_name}. Skipping"
121
+ f"The region {region} is in the ontology but does not have a corresponding volume in the atlas being used: {self.atlas_name}. Skipping"
84
122
  )
85
123
  continue
86
124
 
@@ -99,25 +137,45 @@ class Atlas(BrainGlobeAtlas):
99
137
 
100
138
  def get_plane(
101
139
  self,
102
- pos=None,
103
- norm=None,
104
- plane=None,
105
- sx=None,
106
- sy=None,
107
- color="lightgray",
108
- alpha=0.25,
109
- **kwargs,
110
- ):
140
+ pos: npt.ArrayLike | None = None,
141
+ norm: npt.ArrayLike | None = None,
142
+ plane: str | None = None,
143
+ sx: float | None = None,
144
+ sy: float | None = None,
145
+ color: str = "lightgray",
146
+ alpha: float = 0.25,
147
+ **kwargs: Any,
148
+ ) -> Actor:
111
149
  """
112
150
  Returns a plane going through a point at pos, oriented
113
- orthogonally to the vector norm and of width and height
151
+ orthogonally to the ``norm`` vector and of width and height
114
152
  sx, sy.
115
153
 
116
- :param pos: 3-tuple or list with x,y,z, coords of point the plane goes through
117
- :param norm: 3-tuple with plane's normal vector (optional)
118
- :param sx, sy: int, width and height of the plane
119
- :param plane: "sagittal", "horizontal", or "frontal"
120
- :param color, alpha: plane color and transparency
154
+ Parameters
155
+ ----------
156
+ pos
157
+ (x, y, z) the plane passes through. Defaults to root centre of mass.
158
+ norm
159
+ Normal vector. Derived from *plane* if not given.
160
+ plane
161
+ ``"sagittal"``, ``"horizontal"``, or ``"frontal"``.
162
+ sx
163
+ Width. Inferred from root bounds if None.
164
+ sy
165
+ Height. Inferred from root bounds if None.
166
+ color
167
+ Default ``"lightgray"``.
168
+ alpha
169
+ Default 0.25.
170
+
171
+ Returns
172
+ -------
173
+ Actor
174
+
175
+ Raises
176
+ ------
177
+ ValueError
178
+ If *plane* has no matching normal in the atlas space.
121
179
  """
122
180
  axes_pairs = dict(sagittal=(0, 1), horizontal=(2, 0), frontal=(2, 1))
123
181