@@ -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 ]} { precision [0 ]}  
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