Skip to content

Commit 06747b8

Browse files
Added basic tests for each example script
1 parent 8bacced commit 06747b8

File tree

4 files changed

+312
-5
lines changed

4 files changed

+312
-5
lines changed

brainrender/actors/neurons.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,12 @@ def __init__(
7777
self.mesh.c(color).alpha(alpha)
7878

7979
def _from_morphapi_neuron(self, neuron: (MorphoNeuron)):
80+
# Temporarily set cache to false as meshes were being corrupted
81+
# on second load
8082
mesh = neuron.create_mesh(
8183
neurite_radius=self.neurite_radius,
8284
soma_radius=self.soma_radius,
85+
use_cache=False,
8386
)[1]
8487
return mesh
8588

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ dependencies = [
1010
"numpy",
1111
"pandas",
1212
"h5py<=3.9", # vedo requires hdf5 <=1.12.x but hdf5 is 1.14+ from h5py 3.10 onwards
13-
"vedo",
13+
"vedo>=2023.5.0",
1414
"k3d",
1515
"imio",
1616
"msgpack",
@@ -58,7 +58,8 @@ dev = [
5858
"pre-commit",
5959
"ruff",
6060
"setuptools_scm",
61-
"pyside2"
61+
"pyside2",
62+
"imio",
6263
]
6364
nb = ["jupyter", "k3d"]
6465
pyside2= ["PySide2"]

tests/files/volume.npy

622 KB
Binary file not shown.

tests/test_integration.py

Lines changed: 306 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
1+
from pathlib import Path
2+
3+
import imio
14
import numpy as np
5+
import pooch
26
import pytest
7+
from bg_space import AnatomicalSpace
8+
from vedo import Volume as VedoVolume
39

4-
from brainrender import Scene
5-
from brainrender.actors import Points
10+
from brainrender import Animation, Scene, VideoMaker
11+
from brainrender.actors import (
12+
Neuron,
13+
Points,
14+
PointsDensity,
15+
Volume,
16+
ruler,
17+
ruler_from_surface,
18+
)
19+
from brainrender.atlas_specific import GeneExpressionAPI
620

721

822
def get_n_points_in_region(region, N):
@@ -35,6 +49,7 @@ def check_bounds(bounds, parent_bounds):
3549
def scene():
3650
scene = Scene(inset=False)
3751
yield scene
52+
scene.close()
3853
del scene
3954

4055

@@ -95,6 +110,294 @@ def test_add_labels(scene):
95110
def test_add_mesh_from_file(scene, pytestconfig):
96111
root_path = pytestconfig.rootpath
97112
scene.add_brain_region("SCm", alpha=0.2)
98-
scene.add(
113+
file_mesh = scene.add(
99114
root_path / "tests" / "files" / "CC_134_1_ch1inj.obj", color="tomato"
100115
)
116+
117+
scene.render(interactive=False)
118+
119+
file_mesh_bounds = file_mesh.bounds()
120+
root_bounds = scene.root.bounds()
121+
122+
check_bounds(file_mesh_bounds, root_bounds)
123+
124+
125+
def test_animation(scene, pytestconfig):
126+
root_path = pytestconfig.rootpath
127+
128+
scene.add_brain_region("TH")
129+
anim = Animation(scene, "./examples", "vid3")
130+
131+
anim.add_keyframe(0, camera="top", zoom=1)
132+
anim.add_keyframe(1.5, camera="sagittal", zoom=0.95)
133+
anim.add_keyframe(3, camera="frontal", zoom=1)
134+
anim.add_keyframe(4, camera="frontal", zoom=1.2)
135+
136+
anim.make_video(duration=5, fps=15)
137+
138+
scene.render(interactive=False)
139+
scene.close()
140+
141+
vid_path = Path(root_path / "tests" / "examples" / "vid3.mp4")
142+
143+
assert vid_path.exists()
144+
vid_path.unlink()
145+
Path.rmdir(Path(root_path / "tests" / "examples"))
146+
147+
148+
def test_adding_multiple_brain_regions(scene):
149+
th = scene.add_brain_region("TH")
150+
brain_regions = scene.add_brain_region(
151+
"MOs", "CA1", alpha=0.2, color="green"
152+
)
153+
154+
scene.render(interactive=False)
155+
156+
assert len(scene.actors) == 4
157+
assert scene.actors[1].name == "TH"
158+
assert scene.actors[2].name == "MOs"
159+
assert scene.actors[3].name == "CA1"
160+
161+
root_bounds = scene.root.bounds()
162+
th_bounds = th.bounds()
163+
mos_bounds = brain_regions[0].bounds()
164+
ca1_bounds = brain_regions[1].bounds()
165+
166+
check_bounds(th_bounds, root_bounds)
167+
check_bounds(mos_bounds, root_bounds)
168+
check_bounds(ca1_bounds, root_bounds)
169+
170+
171+
def test_brainglobe_atlas():
172+
scene = Scene(atlas_name="mpin_zfish_1um", title="zebrafish")
173+
174+
scene.render(interactive=False)
175+
176+
assert len(scene.actors) == 2
177+
assert scene.actors[0].name == "root"
178+
assert scene.actors[1].name == "title"
179+
assert scene.atlas.atlas_name == "mpin_zfish_1um"
180+
181+
182+
def test_cell_density(scene):
183+
mos = scene.add_brain_region("MOs", alpha=0.0)
184+
coordinates = get_n_points_in_region(mos, 2000)
185+
186+
points = Points(coordinates, name="CELLS", colors="salmon")
187+
points_density = PointsDensity(coordinates)
188+
scene.add(points)
189+
scene.add(points_density)
190+
191+
scene.render(interactive=False)
192+
193+
assert scene.actors[1] == mos
194+
assert scene.actors[2] == points
195+
assert scene.actors[3] == points_density
196+
197+
root_bounds = scene.root.bounds()
198+
points_bounds = points.bounds()
199+
points_density_bounds = points_density.bounds()
200+
201+
check_bounds(points_bounds, root_bounds)
202+
check_bounds(points_density_bounds, root_bounds)
203+
204+
205+
def test_gene_expression(scene):
206+
gene = "Gpr161"
207+
geapi = GeneExpressionAPI()
208+
expids = geapi.get_gene_experiments(gene)
209+
data = geapi.get_gene_data(gene, expids[1])
210+
211+
gene_actor = geapi.griddata_to_volume(
212+
data, min_quantile=99, cmap="inferno"
213+
)
214+
ca1 = scene.add_brain_region("CA1", alpha=0.2, color="skyblue")
215+
act = scene.add(gene_actor)
216+
217+
scene.render(interactive=False)
218+
219+
# Expand bounds by 500 px
220+
ca1_bounds = ca1.bounds()
221+
expanded_bounds = [
222+
bound - 500 if i % 2 == 0 else bound + 500
223+
for i, bound in enumerate(ca1_bounds)
224+
]
225+
226+
gene_actor_bounds = act.bounds()
227+
228+
assert scene.actors[1] == ca1
229+
assert scene.actors[2] == act
230+
231+
check_bounds(gene_actor_bounds, expanded_bounds)
232+
233+
234+
def test_neurons(scene, pytestconfig):
235+
root_path = pytestconfig.rootpath
236+
237+
neuron = Neuron(root_path / "tests" / "files" / "neuron1.swc")
238+
scene.add(neuron)
239+
scene.render(interactive=False)
240+
241+
assert len(scene.actors) == 2
242+
assert scene.actors[1].name == "neuron1.swc"
243+
244+
neuron_bounds = scene.actors[1].bounds()
245+
# Based on pre-calculated bounds of this specific neuron
246+
expected_bounds = (2177, 7152, 2319, 5056, -9147, -1294)
247+
248+
check_bounds(neuron_bounds, expected_bounds)
249+
250+
251+
def test_ruler(scene):
252+
th, mos = scene.add_brain_region("TH", "MOs", alpha=0.3)
253+
p1 = th.center_of_mass()
254+
p2 = mos.center_of_mass()
255+
256+
rul1 = ruler(p1, p2, unit_scale=0.01, units="mm")
257+
rul2 = ruler_from_surface(p1, scene.root, unit_scale=0.01, units="mm")
258+
259+
scene.add(rul1, rul2)
260+
261+
scene.render(interactive=False)
262+
263+
assert len(scene.actors) == 5
264+
assert scene.actors[1] == th
265+
assert scene.actors[2] == mos
266+
assert scene.actors[3] == rul1
267+
assert scene.actors[4] == rul2
268+
269+
root_bounds = scene.root.bounds()
270+
th_bounds = th.bounds()
271+
mos_bounds = mos.bounds()
272+
rul1_bounds = rul1.bounds()
273+
rul2_bounds = rul2.bounds()
274+
275+
check_bounds(th_bounds, root_bounds)
276+
check_bounds(mos_bounds, root_bounds)
277+
check_bounds(rul1_bounds, root_bounds)
278+
check_bounds(rul2_bounds, root_bounds)
279+
280+
281+
def test_screenshot(scene, pytestconfig):
282+
root_path = pytestconfig.rootpath
283+
screenshot_folder = root_path / "tests"
284+
scene.screenshots_folder = screenshot_folder
285+
scene.add_brain_region("TH")
286+
287+
scene.render(interactive=False)
288+
scene.screenshot(name="test_screenshot", scale=2)
289+
screenshot_path = screenshot_folder / "test_screenshot.png"
290+
291+
assert screenshot_folder.exists()
292+
assert screenshot_path.exists()
293+
294+
screenshot_path.unlink()
295+
296+
297+
def test_slice(scene):
298+
th, mos, ca1 = scene.add_brain_region(
299+
"TH", "MOs", "CA1", alpha=0.2, color="green"
300+
)
301+
th_clone = th._mesh.clone()
302+
mos_clone = mos._mesh.clone()
303+
ca1_clone = ca1._mesh.clone()
304+
305+
scene.slice("frontal", actors=[mos])
306+
plane = scene.atlas.get_plane(pos=mos.center_of_mass(), norm=(1, 1, 2))
307+
scene.slice(plane, actors=[ca1])
308+
scene.render(interactive=False)
309+
310+
assert th_clone.bounds() == th.bounds()
311+
assert mos_clone.bounds() != mos.bounds()
312+
assert ca1_clone.bounds() != ca1.bounds()
313+
314+
315+
def test_user_volumetric_data():
316+
scene = Scene(atlas_name="mpin_zfish_1um")
317+
retrieved_paths = pooch.retrieve(
318+
url="https://api.mapzebrain.org/media/Lines/brn3cGFP/average_data/T_AVG_s356tTg.zip",
319+
known_hash="54b59146ba08b4d7eea64456bcd67741db4b5395235290044545263f61453a61",
320+
path=Path.home()
321+
/ ".brainglobe"
322+
/ "brainrender-example-data", # zip will be downloaded here
323+
progressbar=True,
324+
processor=pooch.Unzip(
325+
extract_dir=""
326+
# path to unzipped dir,
327+
# *relative* to the path set in 'path'
328+
),
329+
)
330+
331+
datafile = Path(retrieved_paths[1]) # [0] is zip file
332+
data = imio.load.load_any(datafile)
333+
source_space = AnatomicalSpace("ira")
334+
target_space = scene.atlas.space
335+
transformed_data = source_space.map_stack_to(target_space, data)
336+
337+
vol = VedoVolume(transformed_data).smooth_median()
338+
339+
mesh = vol.isosurface(value=20).decimate().clean()
340+
SHIFT = [30, 15, -20] # fine tune mesh position
341+
current_position = mesh.pos()
342+
new_position = [SHIFT[i] + current_position[i] for i in range(3)]
343+
mesh.pos(*new_position)
344+
345+
scene.add(mesh)
346+
scene.render(interactive=False)
347+
348+
assert len(scene.actors) == 2
349+
350+
root_bounds = scene.root.bounds()
351+
mesh_bounds = scene.actors[1].bounds()
352+
353+
# Have to expand root bounds by 20 px
354+
355+
expanded_bounds = [
356+
bound - 20 if i % 2 == 0 else bound + 20
357+
for i, bound in enumerate(root_bounds)
358+
]
359+
360+
check_bounds(mesh_bounds, expanded_bounds)
361+
362+
363+
def test_video(scene, pytestconfig):
364+
root_path = pytestconfig.rootpath
365+
video_directory = root_path / "tests" / "videos"
366+
367+
scene.add_brain_region("TH")
368+
vm = VideoMaker(scene, video_directory, "vid1")
369+
vm.make_video(elevation=2, duration=2, fps=15)
370+
video_path = video_directory / "vid1.mp4"
371+
372+
assert video_directory.exists()
373+
assert video_path.exists()
374+
375+
video_path.unlink()
376+
Path.rmdir(video_directory)
377+
378+
379+
def test_volumetric_data(scene, pytestconfig):
380+
root_path = pytestconfig.rootpath
381+
data = np.load(root_path / "tests" / "files" / "volume.npy")
382+
actor = Volume(
383+
data,
384+
voxel_size=200,
385+
as_surface=False,
386+
c="Reds",
387+
)
388+
scene.add(actor)
389+
scene.render(interactive=False)
390+
391+
assert len(scene.actors) == 2
392+
assert scene.actors[1] == actor
393+
394+
root_bounds = scene.root.bounds()
395+
actor_bounds = actor.bounds()
396+
397+
# Have to expand root bounds by 450 px
398+
expanded_bounds = [
399+
bound - 550 if i % 2 == 0 else bound + 550
400+
for i, bound in enumerate(root_bounds)
401+
]
402+
403+
check_bounds(actor_bounds, expanded_bounds)

0 commit comments

Comments
 (0)