@@ -69,6 +69,9 @@ def __init__(self, data, affine=None, axes=None, title=None):
6969        self ._title  =  title 
7070        self ._closed  =  False 
7171        self ._cross  =  True 
72+         self ._overlay  =  None 
73+         self ._threshold  =  None 
74+         self ._alpha  =  1 
7275
7376        data  =  np .asanyarray (data )
7477        if  data .ndim  <  3 :
@@ -286,6 +289,111 @@ def clim(self, clim):
286289        self ._clim  =  tuple (clim )
287290        self .draw ()
288291
292+     @property  
293+     def  overlay (self ):
294+         """The current overlay """ 
295+         return  self ._overlay 
296+ 
297+     @property  
298+     def  threshold (self ):
299+         """The current data display threshold  """ 
300+         return  self ._threshold 
301+ 
302+     @threshold .setter  
303+     def  threshold (self , threshold ):
304+         # mask data array 
305+         if  threshold  is  not None :
306+             self ._data  =  np .ma .masked_array (np .asarray (self ._data ),
307+                                             np .asarray (self ._data ) <=  threshold )
308+             self ._threshold  =  float (threshold )
309+         else :
310+             self ._data  =  np .asarray (self ._data )
311+             self ._threshold  =  threshold 
312+ 
313+         # update current volume data w/masked array and re-draw everything 
314+         if  self ._data .ndim  >  3 :
315+             self ._current_vol_data  =  self ._data [..., self ._data_idx [3 ]]
316+         else :
317+             self ._current_vol_data  =  self ._data 
318+         self ._set_position (None , None , None , notify = False )
319+ 
320+     @property  
321+     def  alpha (self ):
322+         """ The current alpha (transparency) value """ 
323+         return  self ._alpha 
324+ 
325+     @alpha .setter  
326+     def  alpha (self , alpha ):
327+         alpha  =  float (alpha )
328+         if  alpha  >  1  or  alpha  <  0 :
329+             raise  ValueError ('alpha must be between 0 and 1' )
330+         for  im  in  self ._ims :
331+             im .set_alpha (alpha )
332+         self ._alpha  =  alpha 
333+         self .draw ()
334+ 
335+     def  set_overlay (self , data , affine = None , threshold = None , cmap = 'viridis' ):
336+         if  affine  is  None :
337+             try :  # did we get an image? 
338+                 affine  =  data .affine 
339+                 data  =  data .dataobj 
340+             except  AttributeError :
341+                 pass 
342+ 
343+         # check that we have sufficient information to match the overlays 
344+         if  affine  is  None  and  data .shape [:3 ] !=  self ._data .shape [:3 ]:
345+             raise  ValueError ('Provided `data` do not match shape of ' 
346+                              'underlay and no `affine` matrix was ' 
347+                              'provided. Please provide an `affine` matrix ' 
348+                              'or resample first three dims of `data` to {}' 
349+                              .format (self ._data .shape [:3 ]))
350+ 
351+         # we need to resample the provided data to the already-plotted data 
352+         if  not  np .allclose (affine , self ._affine ):
353+             from  .processing  import  resample_from_to 
354+             from  .nifti1  import  Nifti1Image 
355+             target_shape  =  self ._data .shape [:3 ] +  data .shape [3 :]
356+             # we can't just use SpatialImage because we need an image type 
357+             # where the spatial axes are _always_ first 
358+             data  =  resample_from_to (Nifti1Image (data , affine ),
359+                                     (target_shape , self ._affine )).dataobj 
360+             affine  =  self ._affine 
361+ 
362+         if  self ._overlay  is  not None :
363+             # remove all images + cross hair lines 
364+             for  nn , im  in  enumerate (self ._overlay ._ims ):
365+                 im .remove ()
366+                 for  line  in  self ._overlay ._crosshairs [nn ].values ():
367+                     line .remove ()
368+             # remove the fourth axis, if it was created for the overlay 
369+             if  (self ._overlay .n_volumes  >  1  and  len (self ._overlay ._axes ) >  3 
370+                and  self .n_volumes  ==  1 ):
371+                 a  =  self ._axes .pop (- 1 )
372+                 a .remove ()
373+ 
374+         # create an axis if we have a 4D overlay (vs a 3D underlay) 
375+         axes  =  self ._axes 
376+         o_n_volumes  =  int (np .prod (data .shape [3 :]))
377+         if  o_n_volumes  >  self .n_volumes :
378+             axes  +=  [axes [0 ].figure .add_subplot (224 )]
379+         elif  o_n_volumes  <  self .n_volumes :
380+             axes  =  axes [:- 1 ]
381+ 
382+         # mask array for provided threshold 
383+         self ._overlay  =  self .__class__ (data , affine = affine , axes = axes )
384+         self ._overlay .threshold  =  threshold 
385+ 
386+         # set transparency and new cmap 
387+         self ._overlay .cmap  =  cmap 
388+         for  im  in  self ._overlay ._ims :
389+             im .set_alpha (0.7 )
390+ 
391+         # no double cross-hairs (they get confused when we have linked orthos) 
392+         for  cross  in  self ._overlay ._crosshairs :
393+             cross ['horiz' ].set_visible (False )
394+             cross ['vert' ].set_visible (False )
395+         self ._overlay ._draw ()
396+ 
289397    def  link_to (self , other ):
290398        """Link positional changes between two canvases 
291399
@@ -413,7 +521,7 @@ def _set_position(self, x, y, z, notify=True):
413521            idx  =  [slice (None )] *  len (self ._axes )
414522            for  ii  in  range (3 ):
415523                idx [self ._order [ii ]] =  self ._data_idx [ii ]
416-             vdata  =  self ._data [tuple (idx )].ravel ()
524+             vdata  =  np . asarray ( self ._data [tuple (idx )].ravel () )
417525            vdata  =  np .concatenate ((vdata , [vdata [- 1 ]]))
418526            self ._volume_ax_objs ['patch' ].set_x (self ._data_idx [3 ] -  0.5 )
419527            self ._volume_ax_objs ['step' ].set_ydata (vdata )
0 commit comments