morph-spines-visualizer 0.2.6__tar.gz → 0.2.7__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 (32) hide show
  1. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/PKG-INFO +1 -1
  2. morph_spines_visualizer-0.2.6/examples/visualize_spiny_morphology.ipynb → morph_spines_visualizer-0.2.7/examples/visualize_morphology_synapses.ipynb +4 -3
  3. morph_spines_visualizer-0.2.7/examples/visualize_spines_heads_necks.ipynb +45 -0
  4. morph_spines_visualizer-0.2.7/examples/visualize_spiny_morphology.ipynb +49 -0
  5. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer/__init__.py +6 -3
  6. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer/core/k3d_visualization.py +139 -0
  7. morph_spines_visualizer-0.2.7/src/morph_spines_visualizer/utils/colors.py +23 -0
  8. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer.egg-info/PKG-INFO +1 -1
  9. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer.egg-info/SOURCES.txt +2 -0
  10. morph_spines_visualizer-0.2.6/examples/visualize_morphology_synapses.ipynb +0 -77
  11. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/.github/workflows/publish.yml +0 -0
  12. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/.gitignore +0 -0
  13. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/CHANGELOG.rst +0 -0
  14. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/LICENSE +0 -0
  15. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/README.md +0 -0
  16. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/data/864691134900032266.h5 +0 -0
  17. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/data/864691134900032266.obj +0 -0
  18. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/data/neuron.glb +0 -0
  19. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/data/neuron.obj +0 -0
  20. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/pyproject.toml +0 -0
  21. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/setup.cfg +0 -0
  22. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer/core/__init__.py +0 -0
  23. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer/core/data_loading.py +0 -0
  24. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer/core/geometry.py +0 -0
  25. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer/core/k3d_core.py +0 -0
  26. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer/core/spines.py +0 -0
  27. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer/utils/mesh_loading.py +0 -0
  28. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer/utils/supress.py +0 -0
  29. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer.egg-info/dependency_links.txt +0 -0
  30. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer.egg-info/requires.txt +0 -0
  31. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/src/morph_spines_visualizer.egg-info/top_level.txt +0 -0
  32. {morph_spines_visualizer-0.2.6 → morph_spines_visualizer-0.2.7}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: morph_spines_visualizer
3
- Version: 0.2.6
3
+ Version: 0.2.7
4
4
  Summary: Package to load and visualize morphologies with spines
5
5
  Author-email: Marwan Abdellah <marwan.abdellah@openbraininstitute.org>
6
6
  Maintainer-email: Marwan Abdellah <marwan.abdellah@openbraininstitute.org>
@@ -3,7 +3,7 @@
3
3
  {
4
4
  "cell_type": "code",
5
5
  "execution_count": null,
6
- "id": "90969a09",
6
+ "id": "b5f2224f",
7
7
  "metadata": {},
8
8
  "outputs": [],
9
9
  "source": [
@@ -14,7 +14,8 @@
14
14
  "mesh_path = \"../data/864691134900032266.obj\"\n",
15
15
  "morphology_path = \"../data/864691134900032266.h5\"\n",
16
16
  "\n",
17
- "morph_spines_visualizer.visualize_morphology_with_point_cloud(\n",
17
+ "# Visualize the data \n",
18
+ "morph_spines_visualizer.visualization_morphology_with_synapses(\n",
18
19
  " morphology_path=morphology_path, \n",
19
20
  " mesh_path=mesh_path\n",
20
21
  ")"
@@ -37,7 +38,7 @@
37
38
  "name": "python",
38
39
  "nbconvert_exporter": "python",
39
40
  "pygments_lexer": "ipython3",
40
- "version": "3.12.3"
41
+ "version": "3.12.12"
41
42
  }
42
43
  },
43
44
  "nbformat": 4,
@@ -0,0 +1,45 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "id": "3d883861",
7
+ "metadata": {},
8
+ "outputs": [],
9
+ "source": [
10
+ "import morph_spines_visualizer\n",
11
+ "print(f\"Version: {morph_spines_visualizer.__version__}\")\n",
12
+ "\n",
13
+ "# Data paths \n",
14
+ "mesh_path = \"/ssd1/data/microns_v1718/testing/864691134886335738.obj\"\n",
15
+ "morphology_path = \"/ssd1/data/microns_v1718/testing/864691134886335738_skeletonization_9/864691134886335738.h5\"\n",
16
+ "\n",
17
+ "morph_spines_visualizer.visualize_spines_heads_and_necks(\n",
18
+ " morphology_path=morphology_path, \n",
19
+ " mesh_path=mesh_path\n",
20
+ ")"
21
+ ]
22
+ }
23
+ ],
24
+ "metadata": {
25
+ "kernelspec": {
26
+ "display_name": "Python 3",
27
+ "language": "python",
28
+ "name": "python3"
29
+ },
30
+ "language_info": {
31
+ "codemirror_mode": {
32
+ "name": "ipython",
33
+ "version": 3
34
+ },
35
+ "file_extension": ".py",
36
+ "mimetype": "text/x-python",
37
+ "name": "python",
38
+ "nbconvert_exporter": "python",
39
+ "pygments_lexer": "ipython3",
40
+ "version": "3.12.3"
41
+ }
42
+ },
43
+ "nbformat": 4,
44
+ "nbformat_minor": 5
45
+ }
@@ -0,0 +1,49 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "id": "90969a09",
7
+ "metadata": {},
8
+ "outputs": [],
9
+ "source": [
10
+ "import morph_spines_visualizer\n",
11
+ "print(f\"Version: {morph_spines_visualizer.__version__}\")\n",
12
+ "\n",
13
+ "# Data paths \n",
14
+ "mesh_path = \"../data/864691134900032266.obj\"\n",
15
+ "morphology_path = \"../data/864691134900032266.h5\"\n",
16
+ "\n",
17
+ "\n",
18
+ "mesh_path = \"/ssd1/data/microns_v1718/testing/864691134886335738.obj\"\n",
19
+ "morphology_path = \"/ssd1/data/microns_v1718/testing/864691134886335738_skeletonization_9/864691134886335738.h5\"\n",
20
+ "\n",
21
+ "morph_spines_visualizer.visualize_morphology_with_point_cloud(\n",
22
+ " morphology_path=morphology_path, \n",
23
+ " mesh_path=mesh_path\n",
24
+ ")"
25
+ ]
26
+ }
27
+ ],
28
+ "metadata": {
29
+ "kernelspec": {
30
+ "display_name": "Python 3",
31
+ "language": "python",
32
+ "name": "python3"
33
+ },
34
+ "language_info": {
35
+ "codemirror_mode": {
36
+ "name": "ipython",
37
+ "version": 3
38
+ },
39
+ "file_extension": ".py",
40
+ "mimetype": "text/x-python",
41
+ "name": "python",
42
+ "nbconvert_exporter": "python",
43
+ "pygments_lexer": "ipython3",
44
+ "version": "3.12.3"
45
+ }
46
+ },
47
+ "nbformat": 4,
48
+ "nbformat_minor": 5
49
+ }
@@ -1,5 +1,3 @@
1
- """morph_spines."""
2
-
3
1
  from importlib.metadata import version
4
2
 
5
3
  __version__ = version(__package__)
@@ -24,10 +22,15 @@ from morph_spines_visualizer.core.spines import (
24
22
 
25
23
  from morph_spines_visualizer.core.k3d_visualization import (
26
24
  visualize_morphology_with_point_cloud,
27
- visualization_morphology_with_synapses
25
+ visualization_morphology_with_synapses,
26
+ visualize_spines_heads_and_necks
28
27
  )
29
28
 
30
29
  from morph_spines_visualizer.utils.mesh_loading import (
31
30
  load_mesh_vertices_and_faces,
32
31
  load_mesh_vertices
32
+ )
33
+
34
+ from morph_spines_visualizer.utils.colors import (
35
+ rgb_to_hex
33
36
  )
@@ -2,6 +2,7 @@ import k3d
2
2
  import numpy as np
3
3
  from morph_spines_visualizer.core import k3d_core, data_loading, geometry
4
4
  from morph_spines_visualizer.core import spines as spines_lib
5
+ from morph_spines_visualizer.utils.colors import rgb_to_hex
5
6
  import ipywidgets as widgets
6
7
  from IPython.display import display
7
8
 
@@ -390,3 +391,141 @@ def visualization_morphology_with_synapses(
390
391
  # Display everything
391
392
  display(container)
392
393
 
394
+ def visualize_spines_heads_and_necks(
395
+ mesh_path: str,
396
+ morphology_path: str,
397
+ grid_visible: bool = False,
398
+ axes_helper: bool = False,
399
+ head_color: tuple = (1.0, 0.4, 0.4),
400
+ neck_color: tuple = (0.4, 0.8, 0.4),
401
+ neuron_color: tuple = (0.5, 0.5, 1.0),
402
+ neuron_point_size: float = 0.025,
403
+ background_color: int = 0xffffff):
404
+ """
405
+ Visualize a spiny neuron morphology with spine heads and necks shown in distinct colors.
406
+
407
+ Spine heads are rendered in one color and necks in another, allowing visual
408
+ distinction of spine sub-compartments per section.
409
+
410
+ Args:
411
+ mesh_path (str): Path to the mesh file.
412
+ morphology_path (str): Path to the morphology file.
413
+ grid_visible (bool, optional): Show grid. Defaults to False.
414
+ axes_helper (bool, optional): Show axes helper. Defaults to False.
415
+ head_color (tuple, optional): RGB color for spine heads. Defaults to (1.0, 0.4, 0.4).
416
+ neck_color (tuple, optional): RGB color for spine necks. Defaults to (0.4, 0.8, 0.4).
417
+ neuron_color (tuple, optional): RGB color for neuron mesh. Defaults to (0.5, 0.5, 1.0).
418
+ neuron_point_size (float, optional): Point size for neuron mesh. Defaults to 0.025.
419
+ background_color (int, optional): Background color (hex). Defaults to 0xffffff.
420
+ """
421
+
422
+ # Convert RGB tuples to hex
423
+ head_color_hex = rgb_to_hex(*head_color)
424
+ neck_color_hex = rgb_to_hex(*neck_color)
425
+ neuron_color_hex = rgb_to_hex(*neuron_color)
426
+
427
+ # Load data
428
+ morphology = data_loading.load_spiny_morphology(morphology_path)
429
+ mesh_vertices = data_loading.load_mesh_vertices_pyvista(mesh_path, scale_factor=1e-3)
430
+
431
+ # Create K3D plot
432
+ plot = k3d.plot(
433
+ grid_visible=grid_visible, axes_helper=axes_helper, background_color=background_color)
434
+
435
+ # Draw the neuron mesh as point cloud
436
+ plot += k3d.points(
437
+ mesh_vertices,
438
+ point_size=neuron_point_size,
439
+ color=neuron_color_hex,
440
+ opacity=0.5,
441
+ shader='flat',
442
+ )
443
+
444
+ # State: track spine mesh objects for clean removal
445
+ spine_objs = []
446
+
447
+ def display_spine(spine_id):
448
+ """Display a spine (head/neck) and focus the camera on it."""
449
+ nonlocal spine_objs, plot
450
+
451
+ # Remove previous spine meshes
452
+ for obj in spine_objs:
453
+ try:
454
+ plot -= obj
455
+ except Exception:
456
+ pass
457
+ spine_objs.clear()
458
+
459
+ neck = morphology.spines.spine_mesh(spine_id, include_head=False)
460
+ head = morphology.spines.spine_mesh(spine_id, include_neck=False)
461
+
462
+ if len(neck.faces) > 0:
463
+ obj = k3d.mesh(
464
+ neck.vertices.astype(np.float32),
465
+ neck.faces.astype(np.uint32),
466
+ color=neck_color_hex,
467
+ flat_shading=True,
468
+ )
469
+ plot += obj
470
+ spine_objs.append(obj)
471
+
472
+ if len(head.faces) > 0:
473
+ obj = k3d.mesh(
474
+ head.vertices.astype(np.float32),
475
+ head.faces.astype(np.uint32),
476
+ color=head_color_hex,
477
+ flat_shading=True,
478
+ )
479
+ plot += obj
480
+ spine_objs.append(obj)
481
+
482
+ # Focus camera on the spine
483
+ full = morphology.spines.spine_mesh(spine_id)
484
+ center = full.centroid.astype(np.float32)
485
+ radius = float(np.linalg.norm(full.vertices - center, axis=1).max())
486
+ camera_pos = center + np.array([0, 0, 4.0 * radius], dtype=np.float32)
487
+ plot.camera_auto_fit = False
488
+ plot.camera = camera_pos.tolist() + center.tolist() + [0, 1, 0]
489
+
490
+ # Build list of valid spine indices (those with non-empty meshes)
491
+ valid_spines = []
492
+ for i in range(morphology.spines.spine_count):
493
+ try:
494
+ mesh = morphology.spines.spine_mesh(i)
495
+ if mesh is not None and len(mesh.faces) > 0:
496
+ valid_spines.append(i)
497
+ except Exception:
498
+ pass
499
+ print(f'Valid spines: {len(valid_spines)} / {morphology.spines.spine_count}')
500
+
501
+ if not valid_spines:
502
+ print("No valid spines found.")
503
+ display(plot)
504
+ return
505
+
506
+ # Dropdown for spine selection
507
+ dropdown = widgets.Dropdown(
508
+ options=valid_spines,
509
+ value=valid_spines[0],
510
+ description='Spine #:',
511
+ style={'description_width': 'initial'},
512
+ layout=widgets.Layout(width='200px'),
513
+ )
514
+
515
+ def on_change(change):
516
+ if change.get('name') == 'value':
517
+ display_spine(change['new'])
518
+
519
+ dropdown.observe(on_change, names='value')
520
+
521
+ # Camera reset button
522
+ reset_btn = widgets.Button(description='Reset Camera', button_style='primary')
523
+ reset_btn.on_click(lambda _: (plot.camera_reset(), setattr(plot, 'camera_auto_fit', True)))
524
+
525
+ # Layout and display
526
+ controls = widgets.HBox([dropdown, reset_btn])
527
+ display(widgets.VBox([plot, controls]))
528
+
529
+ # Trigger initial spine display
530
+ display_spine(valid_spines[0])
531
+
@@ -0,0 +1,23 @@
1
+ def rgb_to_hex(r, g, b) -> int:
2
+ """Convert RGB color values to a hex color integer.
3
+
4
+ Automatically detects whether inputs are in 0.0-1.0 or 0-255 range.
5
+ Float values > 1.0 are treated as 0-255 range.
6
+
7
+ Args:
8
+ r: Red channel.
9
+ g: Green channel.
10
+ b: Blue channel.
11
+
12
+ Returns:
13
+ Hex color as an integer (e.g., 0xFF8000).
14
+ """
15
+ channels = [r, g, b]
16
+ if all(isinstance(c, float) and c <= 1.0 for c in channels):
17
+ r, g, b = (int(round(c * 255)) for c in channels)
18
+ else:
19
+ r, g, b = (int(round(c)) for c in channels)
20
+ r = max(0, min(255, r))
21
+ g = max(0, min(255, g))
22
+ b = max(0, min(255, b))
23
+ return (r << 16) | (g << 8) | b
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: morph_spines_visualizer
3
- Version: 0.2.6
3
+ Version: 0.2.7
4
4
  Summary: Package to load and visualize morphologies with spines
5
5
  Author-email: Marwan Abdellah <marwan.abdellah@openbraininstitute.org>
6
6
  Maintainer-email: Marwan Abdellah <marwan.abdellah@openbraininstitute.org>
@@ -10,6 +10,7 @@ data/864691134900032266.obj
10
10
  data/neuron.glb
11
11
  data/neuron.obj
12
12
  examples/visualize_morphology_synapses.ipynb
13
+ examples/visualize_spines_heads_necks.ipynb
13
14
  examples/visualize_spiny_morphology.ipynb
14
15
  src/morph_spines_visualizer/__init__.py
15
16
  src/morph_spines_visualizer.egg-info/PKG-INFO
@@ -23,5 +24,6 @@ src/morph_spines_visualizer/core/geometry.py
23
24
  src/morph_spines_visualizer/core/k3d_core.py
24
25
  src/morph_spines_visualizer/core/k3d_visualization.py
25
26
  src/morph_spines_visualizer/core/spines.py
27
+ src/morph_spines_visualizer/utils/colors.py
26
28
  src/morph_spines_visualizer/utils/mesh_loading.py
27
29
  src/morph_spines_visualizer/utils/supress.py
@@ -1,77 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 1,
6
- "id": "b5f2224f",
7
- "metadata": {},
8
- "outputs": [
9
- {
10
- "name": "stdout",
11
- "output_type": "stream",
12
- "text": [
13
- "Version: 0.1.dev6\n"
14
- ]
15
- },
16
- {
17
- "name": "stderr",
18
- "output_type": "stream",
19
- "text": [
20
- "\n",
21
- "\u001b[1;33mHDF5 GROUP:0:warning\u001b[0m\n",
22
- "Warning: no soma found in file\n"
23
- ]
24
- },
25
- {
26
- "data": {
27
- "application/vnd.jupyter.widget-view+json": {
28
- "model_id": "e1552001ff094862b02905926070676c",
29
- "version_major": 2,
30
- "version_minor": 0
31
- },
32
- "text/plain": [
33
- "VBox(children=(Plot(antialias=3, axes=['x', 'y', 'z'], axes_helper_colors=[16711680, 65280, 255], background_c…"
34
- ]
35
- },
36
- "metadata": {},
37
- "output_type": "display_data"
38
- }
39
- ],
40
- "source": [
41
- "import morph_spines_visualizer\n",
42
- "print(f\"Version: {morph_spines_visualizer.__version__}\")\n",
43
- "\n",
44
- "# Data paths \n",
45
- "mesh_path = \"../data/864691134900032266.obj\"\n",
46
- "morphology_path = \"../data/864691134900032266.h5\"\n",
47
- "\n",
48
- "# Visualize the data \n",
49
- "morph_spines_visualizer.visualization_morphology_with_synapses(\n",
50
- " morphology_path=morphology_path, \n",
51
- " mesh_path=mesh_path\n",
52
- ")"
53
- ]
54
- }
55
- ],
56
- "metadata": {
57
- "kernelspec": {
58
- "display_name": "Python 3",
59
- "language": "python",
60
- "name": "python3"
61
- },
62
- "language_info": {
63
- "codemirror_mode": {
64
- "name": "ipython",
65
- "version": 3
66
- },
67
- "file_extension": ".py",
68
- "mimetype": "text/x-python",
69
- "name": "python",
70
- "nbconvert_exporter": "python",
71
- "pygments_lexer": "ipython3",
72
- "version": "3.12.12"
73
- }
74
- },
75
- "nbformat": 4,
76
- "nbformat_minor": 5
77
- }