From 4877a6eb31f0aa6690fa25c8e845074be91a82c7 Mon Sep 17 00:00:00 2001 From: lej0hn Date: Wed, 3 Jul 2024 14:00:21 +0300 Subject: [PATCH 1/6] feat/Added return canvas statements for jupyter visualizations --- pyneuroml/plot/PlotMorphologyVispy.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pyneuroml/plot/PlotMorphologyVispy.py b/pyneuroml/plot/PlotMorphologyVispy.py index 84cddb19..560369ce 100644 --- a/pyneuroml/plot/PlotMorphologyVispy.py +++ b/pyneuroml/plot/PlotMorphologyVispy.py @@ -733,7 +733,7 @@ def plot_interactive_3D( logger.info( f"More meshes than threshold ({len(meshdata.keys())}/{precision[1]}), reducing precision to {precision[0]} and re-calculating." ) - plot_interactive_3D( + canvas = plot_interactive_3D( nml_file=plottable_nml_model, min_width=min_width, verbose=verbose, @@ -748,7 +748,7 @@ def plot_interactive_3D( upright=upright, ) # break the recursion, don't plot in the calling method - return + return canvas pbar_ctr += 1 @@ -757,6 +757,7 @@ def plot_interactive_3D( create_instanced_meshes(meshdata, plot_type, current_view, min_width) current_canvas.show() app.run() + return current_canvas def make_cell_upright( @@ -1075,6 +1076,7 @@ def plot_3D_cell_morphology( create_instanced_meshes(meshdata, plot_type, current_view, min_width) current_canvas.show() app.run() + return current_canvas return meshdata @@ -1395,6 +1397,7 @@ def plot_3D_schematic( if not nogui: create_instanced_meshes(meshdata, "Detailed", current_view, width) app.run() + return current_canvas def create_cylindrical_mesh( From 9f72ece1c8418dc6bc061bb79ca43238f940d109 Mon Sep 17 00:00:00 2001 From: lej0hn Date: Wed, 3 Jul 2024 16:23:43 +0300 Subject: [PATCH 2/6] Added jupyter-rfb package --- setup.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.cfg b/setup.cfg index b1b3006b..23ba82e0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -109,6 +109,9 @@ vispy = pyNeuroML[vispy-common] pyqt6 +jupyter = + jupyter-rfb + plotly = plotly From 7444db0efd2b2f07b57b344c44b2b16bfdd9c090 Mon Sep 17 00:00:00 2001 From: lej0hn Date: Wed, 3 Jul 2024 17:35:28 +0300 Subject: [PATCH 3/6] Added argument jupyter to run in notebooks --- pyneuroml/plot/PlotMorphologyVispy.py | 66 +++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/pyneuroml/plot/PlotMorphologyVispy.py b/pyneuroml/plot/PlotMorphologyVispy.py index 560369ce..adcf6094 100644 --- a/pyneuroml/plot/PlotMorphologyVispy.py +++ b/pyneuroml/plot/PlotMorphologyVispy.py @@ -318,6 +318,7 @@ def plot_interactive_3D( highlight_spec: typing.Optional[typing.Dict[typing.Any, typing.Any]] = None, precision: typing.Tuple[int, int] = (4, 200), upright: bool = False, + jupyter: bool = False, ): """Plot interactive plots in 3D using Vispy @@ -434,6 +435,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 jupyter: Set to True to run visualizations in jupyter notebooks. Default is False + :type jupyter: bool :throws ValueError: if `plot_type` is not one of "detailed", "constant", "schematic", or "point" @@ -451,6 +454,14 @@ def plot_interactive_3D( if verbose: logger.info(f"Visualising {nml_file}") + if not jupyter: + from IPython import get_ipython + + ipython = get_ipython() + # Check if the IPython instance is using the kernel environment + if ipython and "IPKernelApp" in ipython.config: + logging.warning("Kernel detected. Try setting jupyter=True") + # if it's a file, load it first if isinstance(nml_file, str): # load without optimization for older HDF5 API @@ -695,6 +706,7 @@ def plot_interactive_3D( meshdata=meshdata, mesh_precision=precision[0], upright=upright, + jupyter=jupyter, ) elif ( plot_type == "detailed" @@ -724,6 +736,7 @@ def plot_interactive_3D( mesh_precision=precision[0], highlight_spec=cell_highlight_spec, upright=upright, + jupyter=jupyter, ) # if too many meshes, reduce precision and retry, recursively @@ -746,18 +759,23 @@ def plot_interactive_3D( precision=precision, highlight_spec=highlight_spec, upright=upright, + jupyter=jupyter, ) # break the recursion, don't plot in the calling method - return canvas + return pbar_ctr += 1 if not nogui: pbar.finish() create_instanced_meshes(meshdata, plot_type, current_view, min_width) - current_canvas.show() - app.run() - return current_canvas + if jupyter: + from IPython.display import display + + display(current_canvas) + else: + current_canvas.show() + app.run() def make_cell_upright( @@ -839,6 +857,7 @@ def plot_3D_cell_morphology( mesh_precision: int = 2, highlight_spec: typing.Optional[typing.Dict[typing.Any, typing.Any]] = None, upright: bool = False, + jupyter: bool = False, ): """Plot the detailed 3D morphology of a cell using vispy. https://vispy.org/ @@ -939,6 +958,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 jupyter: Set to True to run visualizations in jupyter notebooks. Default is False + :type jupyter: bool :raises: ValueError if `cell` is None """ @@ -951,6 +972,14 @@ def plot_3D_cell_morphology( highlight_spec = {} logging.debug("highlight_spec is " + str(highlight_spec)) + if not jupyter: + from IPython import get_ipython + + ipython = get_ipython() + # Check if the IPython instance is using the kernel environment + if ipython and "IPKernelApp" in ipython.config: + logging.warning("Kernel detected. Try setting jupyter=True") + view_center = None if upright: cell = make_cell_upright(cell) @@ -1074,9 +1103,13 @@ def plot_3D_cell_morphology( if not nogui: create_instanced_meshes(meshdata, plot_type, current_view, min_width) - current_canvas.show() - app.run() - return current_canvas + if jupyter: + from IPython.display import display + + display(current_canvas) + else: + current_canvas.show() + app.run() return meshdata @@ -1224,6 +1257,7 @@ def plot_3D_schematic( meshdata: typing.Optional[typing.Dict[typing.Any, typing.Any]] = None, mesh_precision: int = 2, upright: bool = False, + jupyter: bool = False, ) -> None: """Plot a 3D schematic of the provided segment groups using vispy. layer.. @@ -1296,10 +1330,20 @@ 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 jupyter: Set to True to run visualizations in jupyter notebooks. Default is False + :type jupyter: bool """ if title == "": title = f"3D schematic of segment groups from {cell.id}" + if not jupyter: + from IPython import get_ipython + + ipython = get_ipython() + # Check if the IPython instance is using the kernel environment + if ipython and "IPKernelApp" in ipython.config: + logging.warning("Kernel detected. Try setting jupyter=True") + view_center = None if upright: cell = make_cell_upright(cell) @@ -1396,8 +1440,12 @@ def plot_3D_schematic( if not nogui: create_instanced_meshes(meshdata, "Detailed", current_view, width) - app.run() - return current_canvas + if jupyter: + from IPython.display import display + + display(current_canvas) + else: + app.run() def create_cylindrical_mesh( From af8ed816b426b43e0710b007415c961119043d4e Mon Sep 17 00:00:00 2001 From: lej0hn Date: Wed, 3 Jul 2024 17:37:43 +0300 Subject: [PATCH 4/6] Removed assignment to unused variable canvas --- pyneuroml/plot/PlotMorphologyVispy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyneuroml/plot/PlotMorphologyVispy.py b/pyneuroml/plot/PlotMorphologyVispy.py index adcf6094..489e1f8a 100644 --- a/pyneuroml/plot/PlotMorphologyVispy.py +++ b/pyneuroml/plot/PlotMorphologyVispy.py @@ -746,7 +746,7 @@ def plot_interactive_3D( logger.info( f"More meshes than threshold ({len(meshdata.keys())}/{precision[1]}), reducing precision to {precision[0]} and re-calculating." ) - canvas = plot_interactive_3D( + plot_interactive_3D( nml_file=plottable_nml_model, min_width=min_width, verbose=verbose, From 37deda456fdf31a2a0612e4ac91a6d89fd15e10a Mon Sep 17 00:00:00 2001 From: lej0hn Date: Wed, 10 Jul 2024 17:43:24 +0300 Subject: [PATCH 5/6] Made change to jupyter notebooks automatic, deleted jupyter argument --- pyneuroml/plot/PlotMorphologyVispy.py | 42 ++++++--------------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/pyneuroml/plot/PlotMorphologyVispy.py b/pyneuroml/plot/PlotMorphologyVispy.py index 489e1f8a..a9c0e544 100644 --- a/pyneuroml/plot/PlotMorphologyVispy.py +++ b/pyneuroml/plot/PlotMorphologyVispy.py @@ -318,7 +318,6 @@ def plot_interactive_3D( highlight_spec: typing.Optional[typing.Dict[typing.Any, typing.Any]] = None, precision: typing.Tuple[int, int] = (4, 200), upright: bool = False, - jupyter: bool = False, ): """Plot interactive plots in 3D using Vispy @@ -435,8 +434,6 @@ 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 jupyter: Set to True to run visualizations in jupyter notebooks. Default is False - :type jupyter: bool :throws ValueError: if `plot_type` is not one of "detailed", "constant", "schematic", or "point" @@ -454,13 +451,9 @@ def plot_interactive_3D( if verbose: logger.info(f"Visualising {nml_file}") - if not jupyter: - from IPython import get_ipython - - ipython = get_ipython() - # Check if the IPython instance is using the kernel environment - if ipython and "IPKernelApp" in ipython.config: - logging.warning("Kernel detected. Try setting jupyter=True") + jupyter = False + if app.Application.is_interactive(app): + jupyter = True # if it's a file, load it first if isinstance(nml_file, str): @@ -706,7 +699,6 @@ def plot_interactive_3D( meshdata=meshdata, mesh_precision=precision[0], upright=upright, - jupyter=jupyter, ) elif ( plot_type == "detailed" @@ -736,7 +728,6 @@ def plot_interactive_3D( mesh_precision=precision[0], highlight_spec=cell_highlight_spec, upright=upright, - jupyter=jupyter, ) # if too many meshes, reduce precision and retry, recursively @@ -759,7 +750,6 @@ def plot_interactive_3D( precision=precision, highlight_spec=highlight_spec, upright=upright, - jupyter=jupyter, ) # break the recursion, don't plot in the calling method return @@ -857,7 +847,6 @@ def plot_3D_cell_morphology( mesh_precision: int = 2, highlight_spec: typing.Optional[typing.Dict[typing.Any, typing.Any]] = None, upright: bool = False, - jupyter: bool = False, ): """Plot the detailed 3D morphology of a cell using vispy. https://vispy.org/ @@ -958,8 +947,6 @@ 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 jupyter: Set to True to run visualizations in jupyter notebooks. Default is False - :type jupyter: bool :raises: ValueError if `cell` is None """ @@ -972,13 +959,9 @@ def plot_3D_cell_morphology( highlight_spec = {} logging.debug("highlight_spec is " + str(highlight_spec)) - if not jupyter: - from IPython import get_ipython - - ipython = get_ipython() - # Check if the IPython instance is using the kernel environment - if ipython and "IPKernelApp" in ipython.config: - logging.warning("Kernel detected. Try setting jupyter=True") + jupyter = False + if app.Application.is_interactive(app): + jupyter = True view_center = None if upright: @@ -1257,7 +1240,6 @@ def plot_3D_schematic( meshdata: typing.Optional[typing.Dict[typing.Any, typing.Any]] = None, mesh_precision: int = 2, upright: bool = False, - jupyter: bool = False, ) -> None: """Plot a 3D schematic of the provided segment groups using vispy. layer.. @@ -1330,19 +1312,13 @@ 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 jupyter: Set to True to run visualizations in jupyter notebooks. Default is False - :type jupyter: bool """ if title == "": title = f"3D schematic of segment groups from {cell.id}" - if not jupyter: - from IPython import get_ipython - - ipython = get_ipython() - # Check if the IPython instance is using the kernel environment - if ipython and "IPKernelApp" in ipython.config: - logging.warning("Kernel detected. Try setting jupyter=True") + jupyter = False + if app.Application.is_interactive(app): + jupyter = True view_center = None if upright: From 9560f70df2b08213a39d0d71ab92b3b34d450bf1 Mon Sep 17 00:00:00 2001 From: lej0hn Date: Wed, 10 Jul 2024 18:37:26 +0300 Subject: [PATCH 6/6] chore:Made loggers debug and shortened progressbar --- pyneuroml/plot/PlotMorphologyVispy.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/pyneuroml/plot/PlotMorphologyVispy.py b/pyneuroml/plot/PlotMorphologyVispy.py index a9c0e544..2b94e832 100644 --- a/pyneuroml/plot/PlotMorphologyVispy.py +++ b/pyneuroml/plot/PlotMorphologyVispy.py @@ -477,22 +477,22 @@ def plot_interactive_3D( # if it isn't a NeuroMLDocument, create one if isinstance(nml_model, Cell): - logger.info("Got a cell") + logger.debug("Got a cell") plottable_nml_model = NeuroMLDocument(id="newdoc") plottable_nml_model.add(nml_model) - logger.info(f"plottable cell model is: {plottable_nml_model.cells[0]}") + logger.debug(f"plottable cell model is: {plottable_nml_model.cells[0]}") if title is None: title = f"{plottable_nml_model.cells[0].id}" # if it's only a cell, add it to an empty cell in a document elif isinstance(nml_model, Morphology): - logger.info("Received morph, adding to a dummy cell") + logger.debug("Received morph, adding to a dummy cell") plottable_nml_model = NeuroMLDocument(id="newdoc") nml_cell = plottable_nml_model.add( Cell, id=nml_model.id, morphology=nml_model, validate=False ) plottable_nml_model.add(nml_cell) - logger.info(f"plottable cell model is: {plottable_nml_model.cells[0]}") + logger.debug(f"plottable cell model is: {plottable_nml_model.cells[0]}") if title is None: title = f"{plottable_nml_model.cells[0].id}" elif isinstance(nml_model, NeuroMLDocument): @@ -524,10 +524,10 @@ def plot_interactive_3D( except AttributeError: total_segments += len(positions[pop_id]) - logger.info( + logger.debug( f"Visualising {total_segments} segments in {total_cells} cells in {len(pop_id_vs_cell)} populations" ) - logger.info( + logger.debug( f"Grouping into mesh instances by diameters at {precision[0]} decimal places" ) # not used later, clear up @@ -620,7 +620,7 @@ def plot_interactive_3D( pass meshdata = {} # type: typing.Dict[typing.Any, typing.Any] - logger.info("Processing cells") + logger.debug("Processing cells") pbar = progressbar.ProgressBar( max_value=total_cells, widgets=[progressbar.SimpleProgress(), progressbar.Bar(), progressbar.Timer()], @@ -734,7 +734,7 @@ def plot_interactive_3D( if (len(meshdata.keys()) > precision[1]) and (precision[0] > 0): precision = (precision[0] - 1, precision[1]) pbar.finish(dirty=True) - logger.info( + logger.debug( f"More meshes than threshold ({len(meshdata.keys())}/{precision[1]}), reducing precision to {precision[0]} and re-calculating." ) plot_interactive_3D( @@ -819,7 +819,7 @@ def make_cell_upright( if z_angle < 0: z_angle += numpy.pi - logger.info("Making cell upright for visualization") + logger.debug("Making cell upright for visualization") cell = translate_cell_to_coords(cell, inplace=inplace, dest=[0, 0, 0]) cell = rotate_cell( cell, 0, y_angle, z_angle, "yzx", relative_to_soma=False, inplace=inplace @@ -1117,7 +1117,7 @@ def create_instanced_meshes(meshdata, plot_type, current_view, min_width): total_mesh_instances = 0 for d, i in meshdata.items(): total_mesh_instances += len(i) - logger.info( + logger.debug( f"Visualising {len(meshdata.keys())} meshes with {total_mesh_instances} instances" ) @@ -1164,8 +1164,9 @@ def create_instanced_meshes(meshdata, plot_type, current_view, min_width): instance_positions = [] instance_transforms = [] instance_colors = [] - for im in i: - pbar.update(progress_ctr) + for num, im in enumerate(i): + if num % 2000 == 0: + pbar.update(progress_ctr) progress_ctr += 1 prox = im[0] dist = im[1]