Skip to content

Commit

Permalink
feat(vispy): allow saving meshdata for future usage
Browse files Browse the repository at this point in the history
Based on @Dhruvansu-Joshi 's PR:
#316

Fixes #278
  • Loading branch information
sanjayankur31 committed Aug 23, 2024
1 parent 5f42bf7 commit fe9b3ab
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 4 deletions.
9 changes: 9 additions & 0 deletions pyneuroml/plot/PlotMorphology.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ def process_args():
help="Name of the image file, for 2D plot",
)

parser.add_argument(
"-saveMeshTo",
type=str,
metavar="<Mesh file name (must end in '.obj' or '.gz')>",
default=None,
help="Name of the file to save 3D mesh data to",
)

parser.add_argument(
"-square",
action="store_true",
Expand Down Expand Up @@ -169,6 +177,7 @@ def plot_from_console(a: typing.Optional[typing.Any] = None, **kwargs: str):
plot_spec={"point_fraction": a.point_fraction},
upright=a.upright,
axes_pos=a.show_axes,
save_mesh_to=a.save_mesh_to,
)
else:
plot_2D(
Expand Down
46 changes: 42 additions & 4 deletions pyneuroml/plot/PlotMorphologyVispy.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
from vispy.color import get_color_dict, get_color_names
from vispy.geometry.generation import create_sphere
from vispy.geometry.meshdata import MeshData
from vispy.io.mesh import write_mesh
from vispy.scene.visuals import Mesh
from vispy.util.transforms import rotate
from vispy.visuals.filters import ShadingFilter
Expand Down Expand Up @@ -333,6 +334,7 @@ def plot_interactive_3D(
] = None,
highlight_spec: typing.Optional[typing.Dict[typing.Any, typing.Any]] = None,
upright: bool = False,
save_mesh_to: typing.Optional[str] = None,
):
"""Plot interactive plots in 3D using Vispy
Expand Down Expand Up @@ -438,6 +440,8 @@ def plot_interactive_3D(
"upwards" instead of "downwards" in most cases. Note that the original cell object
is unchanged, this is for visualization purposes only.
:type upright: bool
:param save_mesh_to: name of file to save mesh object to
:type save_mesh_to: str or None
:throws ValueError: if `plot_type` is not one of "detailed", "constant",
"schematic", or "point"
Expand Down Expand Up @@ -719,7 +723,9 @@ def plot_interactive_3D(
nogui=True,
meshdata=None,
upright=upright,
save_mesh_to=None,
)
assert new_meshdata is not None
mesh_data_with_offset = [(*x, pos) for x in new_meshdata]
meshdata.extend(mesh_data_with_offset)
elif (
Expand Down Expand Up @@ -757,6 +763,7 @@ def plot_interactive_3D(
meshdata=None,
highlight_spec=frozendict(cell_highlight_spec),
upright=upright,
save_mesh_to=None,
)
assert new_meshdata is not None
mesh_data_with_offset = [(*x, pos) for x in new_meshdata]
Expand All @@ -767,7 +774,9 @@ def plot_interactive_3D(
if not nogui:
if pbar is not None:
pbar.finish()
create_mesh(meshdata, plot_type, current_view, min_width)
create_mesh(
meshdata, plot_type, current_view, min_width, save_mesh_to=save_mesh_to
)
if pynml_in_jupyter:
display(current_canvas)
else:
Expand Down Expand Up @@ -797,6 +806,7 @@ def plot_3D_cell_morphology(
meshdata: typing.Optional[typing.List[typing.Any]] = None,
highlight_spec: typing.Optional[typing.Union[typing.Dict, frozendict]] = None,
upright: bool = False,
save_mesh_to: typing.Optional[str] = None,
) -> typing.Optional[typing.List[typing.Any]]:
"""Plot the detailed 3D morphology of a cell using vispy.
https://vispy.org/
Expand Down Expand Up @@ -896,6 +906,8 @@ def plot_3D_cell_morphology(
"upwards" instead of "downwards" in most cases. Note that the original cell object
is unchanged, this is for visualization purposes only.
:type upright: bool
:param save_mesh_to: name of file to save mesh object to
:type save_mesh_to: str or None
:returns: meshdata
:raises: ValueError if `cell` is None
Expand Down Expand Up @@ -1024,7 +1036,9 @@ def plot_3D_cell_morphology(
logger.debug(f"meshdata added: {meshdata[-1]}")

if not nogui:
create_mesh(meshdata, plot_type, current_view, min_width)
create_mesh(
meshdata, plot_type, current_view, min_width, save_mesh_to=save_mesh_to
)
if pynml_in_jupyter:
display(current_canvas)
else:
Expand Down Expand Up @@ -1054,6 +1068,7 @@ def plot_3D_schematic(
color: typing.Optional[str] = "Cell",
meshdata: typing.Optional[typing.List[typing.Any]] = None,
upright: bool = False,
save_mesh_to: typing.Optional[str] = None,
) -> typing.Optional[typing.List[typing.Any]]:
"""Plot a 3D schematic of the provided segment groups using vispy.
layer..
Expand Down Expand Up @@ -1129,6 +1144,8 @@ def plot_3D_schematic(
"upwards" instead of "downwards" in most cases. Note that the original cell object
is unchanged, this is for visualization purposes only.
:type upright: bool
:param save_mesh_to: name of file to save mesh object to
:type save_mesh_to: str or None
:returns: meshdata
"""
if title == "":
Expand Down Expand Up @@ -1242,7 +1259,9 @@ def plot_3D_schematic(
)

if not nogui:
create_mesh(meshdata, "Detailed", current_view, width)
create_mesh(
meshdata, "Detailed", current_view, width, save_mesh_to=save_mesh_to
)
if pynml_in_jupyter:
display(current_canvas)
else:
Expand Down Expand Up @@ -1359,7 +1378,7 @@ def create_cylindrical_mesh(
return MeshData(vertices=verts, faces=faces)


def create_mesh(meshdata, plot_type, current_view, min_width):
def create_mesh(meshdata, plot_type, current_view, min_width, save_mesh_to):
"""Internal function to create a mesh from the mesh data
See: https://vispy.org/api/vispy.scene.visuals.html#vispy.scene.visuals.Mesh
Expand All @@ -1372,6 +1391,8 @@ def create_mesh(meshdata, plot_type, current_view, min_width):
:type current_view: ViewBox
:param min_width: minimum width of tubes
:type min_width: float
:param save_mesh_to: name of file to save mesh object to
:type save_mesh_to: str or None
"""
mesh_start = time.time()
total_mesh_instances = len(meshdata)
Expand Down Expand Up @@ -1555,3 +1576,20 @@ def on_transform_change(event):
shading_filter.light_dir = transform.map(initial_light_dir)[:3]

attach_headlight(current_view)

if save_mesh_to is not None:
if not save_mesh_to.endswith((".obj", ".gz")):
logger.info(
f"Vispy requires mesh file to end in '.obj' or '.gz', appending '.obj' to {save_mesh_to}"
)
save_mesh_to += ".obj"

logger.info(f"Saving mesh to {save_mesh_to}")
write_mesh(
fname=save_mesh_to,
vertices=mesh.mesh_data.get_vertices(),
faces=mesh.mesh_data.get_faces(),
normals=None,
texcoords=None,
overwrite=False,
)

0 comments on commit fe9b3ab

Please sign in to comment.