@@ -251,12 +251,17 @@ def plot_interactive_3D(
251251 plot_spec : typing .Optional [
252252 typing .Dict [str , typing .Union [str , typing .List [int ], float ]]
253253 ] = None ,
254+ highlight_spec : typing .Optional [typing .Dict [typing .Any , typing .Any ]] = None ,
254255 precision : typing .Tuple [int , int ] = (4 , 200 ),
255256):
256257 """Plot interactive plots in 3D using Vispy
257258
258259 https://vispy.org
259260
261+ .. versionadded:: 1.1.12
262+ The hightlight_spec parameter
263+
264+
260265 :param nml_file: path to NeuroML cell file or
261266 :py:class:`neuroml.NeuroMLDocument` or :py:class:`neuroml.Cell` object
262267 :type nml_file: str or neuroml.NeuroMLDocument or neuroml.Cell
@@ -298,6 +303,34 @@ def plot_interactive_3D(
298303 The last three lists override the point_fraction setting. If a cell id
299304 is not included in the spec here, it will follow the plot_type provided
300305 before.
306+ :type plot_spec: dict
307+ :param highlight_spec: dictionary that allows passing some
308+ specifications to allow highlighting of particular elements. Only used
309+ when plotting multi-compartmental cells for marking segments on them
310+ ("plot_type" is either "constant" or "detailed")
311+
312+ Each key in the dictionary will be of the cell id and the values will
313+ be more dictionaries, with the segment id as key and the following keys
314+ in it:
315+
316+ - marker_color: color of the marker
317+ - marker_size: [diameter 1, diameter 2] (in case of sphere, the first value
318+ is used)
319+
320+ E.g.:
321+
322+ .. code-block:: python
323+
324+ {
325+ "cell id1": {
326+ "seg id1": {
327+ "marker_color": "blue",
328+ "marker_size": [0.1, 0.1]
329+ }
330+ }
331+ }
332+
333+ :type highlight_spec: dict
301334 :param precision: tuple containing two values: (number of decimal places,
302335 maximum number of meshes). The first is used to group segments into
303336 meshes to create instances. More precision means fewer segments will be
@@ -315,6 +348,9 @@ def plot_interactive_3D(
315348 "plot_type must be one of 'detailed', 'constant', 'schematic', 'point'"
316349 )
317350
351+ if highlight_spec is None :
352+ highlight_spec = {}
353+
318354 if verbose :
319355 logger .info (f"Visualising { nml_file } " )
320356
@@ -525,6 +561,7 @@ def plot_interactive_3D(
525561 logger .debug (f"meshdata added: { key } : { meshdata [key ]} " )
526562
527563 elif plot_type == "schematic" or cell .id in schematic_cells :
564+ logger .debug (f"Cell for 3d schematic is: { cell .id } " )
528565 plot_3D_schematic (
529566 offset = pos ,
530567 cell = cell ,
@@ -544,6 +581,12 @@ def plot_interactive_3D(
544581 or cell .id in constant_cells
545582 ):
546583 logger .debug (f"Cell for 3d is: { cell .id } " )
584+ cell_highlight_spec = {}
585+ try :
586+ cell_highlight_spec = highlight_spec [cell .id ]
587+ except KeyError :
588+ pass
589+
547590 plot_3D_cell_morphology (
548591 offset = pos ,
549592 cell = cell ,
@@ -556,6 +599,7 @@ def plot_interactive_3D(
556599 nogui = True ,
557600 meshdata = meshdata ,
558601 mesh_precision = precision [0 ],
602+ highlight_spec = cell_highlight_spec ,
559603 )
560604
561605 # if too many meshes, reduce precision and retry, recursively
@@ -566,15 +610,16 @@ def plot_interactive_3D(
566610 f"More meshes than threshold ({ len (meshdata .keys ())} /{ precision [1 ]} ), reducing precision to { precision [0 ]} and re-calculating."
567611 )
568612 plot_interactive_3D (
569- nml_model ,
570- min_width ,
571- verbose ,
572- plot_type ,
573- title ,
574- theme ,
575- nogui ,
576- plot_spec ,
577- precision ,
613+ nml_file = nml_model ,
614+ min_width = min_width ,
615+ verbose = verbose ,
616+ plot_type = plot_type ,
617+ title = title ,
618+ theme = theme ,
619+ nogui = nogui ,
620+ plot_spec = plot_spec ,
621+ precision = precision ,
622+ highlight_spec = highlight_spec ,
578623 )
579624 # break the recursion, don't plot in the calling method
580625 return
@@ -603,12 +648,16 @@ def plot_3D_cell_morphology(
603648 theme : str = "light" ,
604649 meshdata : typing .Optional [typing .Dict [typing .Any , typing .Any ]] = None ,
605650 mesh_precision : int = 2 ,
651+ highlight_spec : typing .Optional [typing .Dict [typing .Any , typing .Any ]] = None ,
606652):
607653 """Plot the detailed 3D morphology of a cell using vispy.
608654 https://vispy.org/
609655
610656 .. versionadded:: 1.0.0
611657
658+ .. versionadded:: 1.1.12
659+ The hightlight_spec parameter
660+
612661 .. seealso::
613662
614663 :py:func:`plot_2D`
@@ -671,6 +720,17 @@ def plot_3D_cell_morphology(
671720 instances: more precision means more detail (meshes), means less
672721 performance
673722 :type mesh_precision: int
723+ :param highlight_spec: dictionary that allows passing some
724+ specifications to allow highlighting of particular elements. Mostly
725+ only helpful for marking segments on multi-compartmental cells. In the
726+ main dictionary are more dictionaries, one for each segment id which
727+ will be the key:
728+
729+ - marker_color: color of the marker
730+ - marker_size: [diameter 1, diameter 2] (in case of sphere, the first value
731+ is used)
732+
733+ :type highlight_spec: dict
674734 :raises: ValueError if `cell` is None
675735
676736 """
@@ -679,6 +739,10 @@ def plot_3D_cell_morphology(
679739 "No cell provided. If you would like to plot a network of point neurons, consider using `plot_2D_point_cells` instead"
680740 )
681741
742+ if highlight_spec is None :
743+ highlight_spec = {}
744+ logging .debug ("highlight_spec is " + str (highlight_spec ))
745+
682746 try :
683747 soma_segs = cell .get_all_segments_in_group ("soma_group" )
684748 except Exception :
@@ -726,6 +790,25 @@ def plot_3D_cell_morphology(
726790 # round up to precision
727791 r1 = round (p .diameter / 2 , mesh_precision )
728792 r2 = round (d .diameter / 2 , mesh_precision )
793+
794+ segment_spec = {
795+ "marker_size" : None ,
796+ "marker_color" : None ,
797+ }
798+ try :
799+ segment_spec .update (highlight_spec [str (seg .id )])
800+ # if there's no spec for this segment
801+ except KeyError :
802+ logger .debug ("No segment highlight spec found for segment" + str (seg .id ))
803+
804+ logger .debug ("segment_spec for " + str (seg .id ) + " is" + str (segment_spec ))
805+
806+ if segment_spec ["marker_size" ] is not None :
807+ if type (segment_spec ["marker_size" ]) is not list :
808+ raise RuntimeError ("The marker size must be a list" )
809+ r1 = round (float (segment_spec ["marker_size" ][0 ]) / 2 , mesh_precision )
810+ r2 = round (float (segment_spec ["marker_size" ][1 ]) / 2 , mesh_precision )
811+
729812 key = (
730813 f"{ r1 :.{mesh_precision }f} " ,
731814 f"{ r2 :.{mesh_precision }f} " ,
@@ -756,6 +839,9 @@ def plot_3D_cell_morphology(
756839 else :
757840 seg_color = color
758841
842+ if segment_spec ["marker_color" ] is not None :
843+ seg_color = segment_spec ["marker_color" ]
844+
759845 try :
760846 meshdata [key ].append ((p , d , seg_color , offset ))
761847 except KeyError :
0 commit comments