epicure.displaying

EpiCure display options

Handles the Display panel of EpiCure. Proposes some vizualisation options that could be convenient for some users. For example, handles the option to add a grid in the background for spatial guidance or to show the skeleton of the segmentation.

  1"""
  2    **EpiCure display options**
  3
  4    Handles the `Display` panel of EpiCure.
  5    Proposes some vizualisation options that could be convenient for some users.
  6    For example, handles the option to add a grid in the background for spatial guidance or to show the skeleton of the segmentation.
  7"""
  8
  9import numpy as np
 10from math import ceil
 11from qtpy.QtWidgets import QHBoxLayout, QVBoxLayout, QWidget, QComboBox
 12from qtpy.QtCore import Qt
 13from magicgui.widgets import TextEdit
 14import epicure.Utils as ut
 15import epicure.epiwidgets as wid
 16
 17
 18class Displaying(QWidget):
 19    """ Propose some visualization options """
 20
 21    def __init__(self, napari_viewer, epic):
 22        """ Create displaying widget instance """
 23        super().__init__()
 24        self.viewer = napari_viewer
 25        self.epicure = epic
 26        self.seglayer = self.viewer.layers["Segmentation"]
 27        self.gmode = 0  ## view only movie mode on/off
 28        self.dmode = 0  ## view with light segmentation on/off
 29        self.grid_color = [0.6, 0.7, 0.7, 0.7]  ## default grid color
 30        self.shapelayer_name = "ROIs"
 31
 32        layout = QVBoxLayout()
 33        
 34        ## Show a text window with some summary of the file
 35        show_summary = wid.add_button( "Show summary", self.show_summary_window, "Pops-up a summary of the movie and segmentation informations" )
 36        layout.addWidget(show_summary)
 37
 38        ## Draw and measure length of a line
 39        measure_line = wid.add_button( "Measure length", self.measure_line_length, "Draw a line and measure its length" )
 40        layout.addWidget(measure_line)
 41
 42        ## Option show segmentation skeleton
 43        self.show_skeleton = wid.add_check( "Show segmentation skeleton", False, self.show_skeleton_segmentation, "Add a layer with the segmentation skeleton (not automatically updated)" )
 44        layout.addWidget(self.show_skeleton)
 45        
 46        ## Option to show the movie and seg side by side
 47        show_sides = QHBoxLayout()
 48        self.show_side = wid.add_check( "Side by side view", False, self.show_side_side, "View the movie and the other layers side by side" )
 49        show_sides.addWidget( self.show_side )
 50        self.directions = QComboBox()
 51        self.directions.addItem( "Horizontal" )
 52        self.directions.addItem( "Vertical" )
 53        show_sides.addWidget( self.directions )
 54        self.directions.currentIndexChanged.connect( self.show_side_side )
 55        layout.addLayout( show_sides )
 56        
 57        ## Option show shifted segmentation
 58        self.show_shifted = wid.add_check( "Overlay previous segmentation", False, self.show_shifted_segmentation, "Overlay the (frame-1) segmentation on the current segmentation")
 59        layout.addWidget(self.show_shifted)
 60        
 61        ## Option show shifted movie (previous or next)
 62        show_prevmovie_line = QHBoxLayout()
 63        self.show_previous_movie = wid.add_check( "Overlay previous movie", False, self.show_shifted_previous_movie, "Overlay the (frame-1) of the movie on the current movie" )
 64        layout.addWidget(self.show_previous_movie)
 65        self.show_next_movie = wid.add_check( "Overlay next movie", False, self.show_shifted_next_movie, "Overlay (frame+1) of the movie on the current frame" )
 66        layout.addWidget(self.show_next_movie)
 67        
 68        ## Option create/show grid
 69        grid_line, self.show_grid_options, self.group_grid = wid.checkgroup_help( "Grid options", True, "Show/hide subpanel to control grid view", "Display#grid-options", self.epicure.display_colors, groupnb="group" )
 70        self.grid_parameters()
 71        layout.addWidget(self.show_grid_options)
 72        layout.addWidget(self.group_grid)
 73        
 74        self.save_contrast = wid.add_check("Save Movie current contrast", True, descr="When saving current settings, save also current contrast of the Movie layer" )
 75        save_pref = wid.add_button( "Set current settings as default", self.save_current_display, "Save the current settings so that EpiCure will open in the same state next time" )
 76        layout.addWidget(save_pref)
 77        
 78        self.add_display_overlay_message()
 79        self.key_bindings()        ## activate shortcuts for display options
 80        self.setLayout(layout)
 81        ut.set_active_layer( self.viewer, "Segmentation" )
 82    
 83    ### set current display as defaut
 84    def save_current_display( self ):
 85        """ Set current display parameters as defaut display """
 86        self.epicure.update_settings()
 87        self.epicure.pref.save()
 88
 89    def get_current_settings( self ):
 90        """ Returns current display settings """
 91        disp = {}
 92        disp["Layers"] = {}
 93        for layer in self.viewer.layers:
 94            disp["Layers"][layer.name] = layer.visible
 95        disp["Show Grid"] = self.show_grid_options.isChecked()
 96        disp["Grid nrows"] = self.nrows.text()
 97        disp["Grid ncols"] = self.ncols.text()
 98        disp["Grid width"] = self.gwidth.text()
 99        disp["Grid color"] = self.grid_color
100        disp["Show side on"] = self.show_side.isChecked()
101        disp["Side direction"] = self.directions.currentText()
102        if "EpicGrid" in self.viewer.layers:
103            disp["Grid text"] = self.viewer.layers["EpicGrid"].text.visible
104            disp["Grid color"] = self.viewer.layers["EpicGrid"].edge_color[0]
105        return disp
106    
107    def apply_settings( self, settings ):
108        """ Set current display to prefered settings """
109        add_grid = False
110        show_text = False
111        ## read the settings and apply them
112        for setty, val in settings.items():
113            if setty == "Layers":
114                for layname, layvis in val.items():
115                    if layname in self.viewer.layers:
116                        self.viewer.layers[layname].visible = layvis
117                    else:
118                        if layname == "EpicGrid":
119                            add_grid = layvis 
120                continue
121            if setty == "Show Grid":
122                self.show_grid_options.setChecked( val )
123                continue
124            if setty == "Grid nrows":
125                self.nrows.setText( val )
126                continue
127            if setty == "Grid ncols":
128                self.ncols.setText( val )
129                continue
130            if setty == "Grid width":
131                self.gwidth.setText( val )
132                continue
133            if setty == "Grid text":
134                show_text = val
135                continue
136            if setty == "Grid color":
137                self.grid_color = val
138                continue
139            if setty == "Show side on":
140                self.show_side.setChecked( val )
141            if setty == "Side direction":
142                self.directions.setCurrentText( val )
143            
144        ## if grid should be added, do it at the end when all values are updated
145        if add_grid:
146            self.add_grid()
147            self.viewer.layers["EpicGrid"].text.visible = show_text
148
149
150
151    ######### overlay message
152    def add_display_overlay_message(self):
153        """ Shortcut list for display options """
154        disptext = "--- Display options --- \n"
155        sdisp = self.epicure.shortcuts["Display"]
156        disptext += ut.print_shortcuts( sdisp )
157        self.epicure.overtext["Display"] = disptext
158        sinfo = self.epicure.shortcuts["Info"]
159        self.epicure.overtext["info"] = "---- Info options --- \n"
160        self.epicure.overtext["info"] += ut.print_shortcuts( sinfo )
161
162
163
164    ################  Key binging for display options
165    def key_bindings(self):
166        sdisp = self.epicure.shortcuts["Display"]
167        sinfo = self.epicure.shortcuts["Info"]
168        
169        @self.seglayer.bind_key( sdisp["vis. segmentation"]["key"], overwrite=True )
170        def see_segmentlayer(seglayer):
171            seglayer.visible = not seglayer.visible
172        
173        @self.seglayer.bind_key( sdisp["vis. movie"]["key"], overwrite=True )
174        def see_movielayer(seglayer):
175            ut.inv_visibility(self.viewer, "Movie")
176        
177        @self.seglayer.bind_key( sdisp["vis. event"]["key"], overwrite=True )
178        def see_eventslayer(seglayer):
179            evlayer = self.viewer.layers["Events"]
180            evlayer.visible = not evlayer.visible
181        
182        @self.epicure.seglayer.bind_key( sinfo["measure length"]["key"], overwrite=True )
183        def measure_length(layer):
184            """ 
185            Draw a line and measure its length 
186            """
187            self.measure_line_length( layer )
188        
189        @self.seglayer.bind_key( sdisp["skeleton"]["key"], overwrite=True )
190        def show_skeleton(seglayer):
191            """ On/Off show skeleton """
192            if self.show_skeleton.isChecked():
193                self.show_skeleton.setChecked(False)
194            else:
195                self.show_skeleton.setChecked(True)
196        
197        @self.seglayer.bind_key( sdisp["show side"]["key"], overwrite=True )
198        def show_byside(seglayer):
199            self.show_side.setChecked( not self.show_side.isChecked() )
200            self.show_side_side()
201
202        @self.seglayer.bind_key( sdisp["increase"]["key"], overwrite=True )
203        def contour_increase(seglayer):
204            if seglayer is not None:
205                seglayer.contour = seglayer.contour + 1
206        
207        @self.seglayer.bind_key( sdisp["decrease"]["key"], overwrite=True )
208        def contour_decrease(seglayer):
209            if seglayer is not None:
210                if seglayer.contour > 0:
211                    seglayer.contour = seglayer.contour - 1
212        
213        @self.seglayer.bind_key( sdisp["only movie"]["key"], overwrite=True )
214        def see_onlymovielayer(seglayer):
215            """ if in "g" mode, show only movie, else put back to previous views """
216            if self.gmode == 0:
217                self.lay_view = []
218                for lay in self.viewer.layers:
219                    self.lay_view.append( (lay, lay.visible) )
220                    lay.visible = False
221                ut.inv_visibility(self.viewer, "Movie")
222                self.gmode = 1
223            else:
224                for lay, vis in self.lay_view:
225                    lay.visible = vis
226                self.gmode = 0
227
228        @self.seglayer.bind_key( sdisp["light view"]["key"], overwrite=True )
229        def segmentation_lightmode(seglayer):
230            """ if in "d" mode, show only movie and light segmentation, else put back to previous views """
231            if self.dmode == 0:
232                self.light_view = []
233                for lay in self.viewer.layers:
234                    self.light_view.append( (lay, lay.visible) )
235                    lay.visible = False
236                ut.inv_visibility(self.viewer, "Movie")
237                ut.inv_visibility(self.viewer, "Segmentation")
238                self.unlight_contour = self.seglayer.contour
239                self.unlight_opacity = self.seglayer.opacity
240                self.seglayer.contour = 1
241                self.seglayer.opacity = 0.2
242                self.dmode = 1
243            else:
244                for lay, vis in self.light_view:
245                    lay.visible = vis
246                self.seglayer.contour = self.unlight_contour
247                self.seglayer.opacity = self.unlight_opacity
248                self.dmode = 0
249        
250        @self.seglayer.bind_key( sdisp["grid"]["key"], overwrite=True )
251        def show_grid(seglayer):
252            """ show/hide the grid to have a repere in space """
253            self.show_grid()
254
255    ### Info options
256    def measure_line_length(self, layer=None):
257        """ 
258        Draw a line and measure its length 
259        """
260        self.old_mouse_drag, self.old_key_map = ut.clear_bindings( self.epicure.seglayer )
261        ut.show_info("Draw line to measure.")
262        if self.shapelayer_name not in self.viewer.layers:
263            self.create_shapelayer()
264        shape_lay = self.viewer.layers[self.shapelayer_name]
265        shape_lay.mode = "add_line"
266        shape_lay.visible = True
267        ut.set_active_layer( self.viewer, self.shapelayer_name)
268
269        @shape_lay.mouse_drag_callbacks.append
270        def click(layer, event):
271            if (event.type == "mouse_press") and (len(event.modifiers)==0) and (event.button==1):
272                ## dragg click to draw line
273                start_pos = event.position
274                yield
275                while event.type == 'mouse_move':
276                    #print( event.position)
277                    yield
278                end_pos = event.position
279                self.draw_line(shape_lay, start_pos, end_pos)
280                self.end_measure_mode()
281            else:
282                self.end_measure_mode()
283
284    def end_measure_mode(self):
285        """ Finish measuring mode """
286        if self.old_mouse_drag is not None:
287            if self.shapelayer_name in self.viewer.layers:
288                shape_lay = self.viewer.layers[self.shapelayer_name]
289                shape_lay.visible = False
290            ut.reactive_bindings( self.epicure.seglayer, self.old_mouse_drag, self.old_key_map )
291            ut.show_info("End measure")
292        ut.set_active_layer( self.viewer, "Segmentation" )
293    
294    def draw_line( self, shape_lay, start_position, end_position ):
295        """ Draw a line in the shape layer """
296        #shape_lay.data = np.array( [start_position, end_position] )
297        #shape_lay.features = { "length": np.linalg.norm(np.array(end_position[1:3]) - np.array(start_position[1:3])) }
298        length = np.linalg.norm(np.array(end_position[1:3]) - np.array(start_position[1:3])) 
299        ut.setOverlayText( self.viewer, "Length: "+str(round(length,1))+" µm" )
300        #shape_lay.text.string = "length"
301        #shape_lay.text.visible = True
302        shape_lay.data = shape_lay.data[:-1]  ## remove last line drawn
303        shape_lay.refresh()
304
305    
306    def show_summary_window(self):
307        """ Show a text window with some infos """
308        summwin = TextEdit()
309        summwin.name = "Epicure summary"
310        summwin.value = self.epicure.get_summary()
311        summwin.show()
312
313    ### Display options
314    def show_skeleton_segmentation(self):
315        """ Show/hide/update skeleton """
316        if "Skeleton" in self.viewer.layers:
317            ut.remove_layer(self.viewer, "Skeleton")
318        if self.show_skeleton.isChecked():
319            self.epicure.add_skeleton()
320            ut.set_active_layer( self.viewer, "Segmentation" )
321
322    def show_side_side( self ):
323        """ Show the layers side by side """
324        layout_grid = self.viewer.grid
325        if self.show_side.isChecked():
326            stride =  len( self.viewer.layers ) - 1
327            layout_grid.stride = stride
328            layout_grid.shape = (2,1)
329            if self.directions.currentText() == "Horizontal":
330                layout_grid.shape = (1,2)
331            layout_grid.enabled = True
332        else:
333            layout_grid.enabled = False
334
335
336    def show_shifted_segmentation(self):
337        """ Show/Hide temporally shifted segmentation on top of current one """
338        if ("PrevSegmentation" in self.viewer.layers):
339            if (not self.show_shifted.isChecked()):
340                ut.remove_layer(self.viewer, "PrevSegmentation")
341            else:
342                lay = self.viewer.layers["PrevSegmentation"]
343                lay.refresh()
344
345        if ("PrevSegmentation" not in self.viewer.layers) and (self.show_shifted.isChecked()):
346            if self.epicure.nframes > 1:
347                layer = self.viewer.add_labels( self.seglayer.data, name="PrevSegmentation", blending="additive", opacity=0.4 )
348                layer.contour = 2
349                layer.translate = [1, 0, 0]
350                self.seglayer.contour = 2
351                self.seglayer.opacity = 0.6
352            else:
353                ut.show_warning("Still image, cannot show previous frames")
354
355        ut.set_active_layer( self.viewer, "Segmentation" )
356    
357    def show_shifted_previous_movie(self):
358        """ Show/Hide temporally shifted movie previous frame on top of current one """
359        self.show_shifted_movie("PrevMovie", "red", 1)
360    
361    def show_shifted_next_movie(self):
362        """ Show/Hide temporally shifted movie next frame on top of current one """
363        self.show_shifted_movie("NextMovie", "green", -1)
364    
365    def show_shifted_movie(self, layname, color, translation):
366        """ Show/Hide temporally shifted movie on top of current one """
367        if (layname in self.viewer.layers):
368            if (not self.show_previous_movie.isChecked()):
369                ut.remove_layer(self.viewer, layname)
370            else:
371                lay = self.viewer.layers[layname]
372                lay.refresh()
373
374        if (layname not in self.viewer.layers) and (self.show_previous_movie.isChecked()):
375            if self.epicure.nframes > 1:
376                movlay = self.viewer.layers["Movie"]
377                arr = movlay.data
378                if translation == -1:
379                    arr = movlay.data[1:,]
380                layer = self.viewer.add_image( arr, name=layname, blending="additive", opacity=0.6, colormap=color )
381                if translation == 1:
382                    layer.translate = [translation, 0, 0]
383                layer.contrast_limits=self.epicure.quantiles()
384                layer.gamma=0.94
385            else:
386                ut.show_warning("Still image, cannot show previous frames")
387
388        ut.set_active_layer( self.viewer, "Segmentation" )
389
390    #### Show/load a grid to have a repere in space
391    def grid_parameters(self):
392        """ Interface to get grid parameters """
393        grid_layout = QVBoxLayout()
394        ## nrows
395        rows_line, self.nrows = wid.value_line( "Nb rows", "4", "Number of rows of the grid" )
396        grid_layout.addLayout(rows_line)
397        ## ncols
398        cols_line, self.ncols = wid.value_line( "Nb columns:", "4", "Number of columns in the grid" )
399        grid_layout.addLayout(cols_line)
400        ## grid edges width
401        width_line, self.gwidth = wid.value_line( "Grid width:", "3", "Width of the grid displayed lines/columns" )
402        grid_layout.addLayout(width_line)
403       ## go for grid
404        btn_add_grid = wid.add_button( "Add grid", self.add_grid, "Add a grid overlay to the main view" )
405        grid_layout.addWidget(btn_add_grid)
406        self.group_grid.setLayout(grid_layout)
407
408    def add_grid(self):
409        """ Create/Load a new grid and add it """
410        ut.remove_layer(self.viewer, "EpicGrid")
411        imshape = self.epicure.imgshape2D
412        if imshape is None:
413            ut.show_error("Load the image first")
414            return
415        nrows = int(self.nrows.text())
416        ncols = int(self.ncols.text())
417        wid = ceil(imshape[0]/nrows)
418        hei = ceil(imshape[1]/ncols)
419        rects = []
420        rects_names = []
421        gwidth = int(self.gwidth.text())
422        for x in range(nrows):
423            for y in range(ncols):
424                rect = np.array([[x*wid, y*hei], [(x+1)*wid, (y+1)*hei]])
425                rects.append(rect)
426                rects_names.append(chr(65+x)+"_"+str(y))
427        self.viewer.add_shapes(rects, name="EpicGrid", text=rects_names, face_color=[1,0,0,0], edge_color=self.grid_color, edge_width=gwidth, opacity=0.7, scale=self.viewer.layers["Segmentation"].scale[1:])
428        self.viewer.layers["EpicGrid"].text.visible = False
429        ut.set_active_layer( self.viewer, "Segmentation" )
430
431    def show_grid(self):
432        """ Interface to create/load a grid for repere """
433        if "EpicGrid" not in self.viewer.layers:
434            self.add_grid()
435        else:
436            gridlay = self.viewer.layers["EpicGrid"]
437            gridlay.visible = not gridlay.visible
438            gridlay.edge_color = self.grid_color
class Displaying(PyQt6.QtWidgets.QWidget):
 19class Displaying(QWidget):
 20    """ Propose some visualization options """
 21
 22    def __init__(self, napari_viewer, epic):
 23        """ Create displaying widget instance """
 24        super().__init__()
 25        self.viewer = napari_viewer
 26        self.epicure = epic
 27        self.seglayer = self.viewer.layers["Segmentation"]
 28        self.gmode = 0  ## view only movie mode on/off
 29        self.dmode = 0  ## view with light segmentation on/off
 30        self.grid_color = [0.6, 0.7, 0.7, 0.7]  ## default grid color
 31        self.shapelayer_name = "ROIs"
 32
 33        layout = QVBoxLayout()
 34        
 35        ## Show a text window with some summary of the file
 36        show_summary = wid.add_button( "Show summary", self.show_summary_window, "Pops-up a summary of the movie and segmentation informations" )
 37        layout.addWidget(show_summary)
 38
 39        ## Draw and measure length of a line
 40        measure_line = wid.add_button( "Measure length", self.measure_line_length, "Draw a line and measure its length" )
 41        layout.addWidget(measure_line)
 42
 43        ## Option show segmentation skeleton
 44        self.show_skeleton = wid.add_check( "Show segmentation skeleton", False, self.show_skeleton_segmentation, "Add a layer with the segmentation skeleton (not automatically updated)" )
 45        layout.addWidget(self.show_skeleton)
 46        
 47        ## Option to show the movie and seg side by side
 48        show_sides = QHBoxLayout()
 49        self.show_side = wid.add_check( "Side by side view", False, self.show_side_side, "View the movie and the other layers side by side" )
 50        show_sides.addWidget( self.show_side )
 51        self.directions = QComboBox()
 52        self.directions.addItem( "Horizontal" )
 53        self.directions.addItem( "Vertical" )
 54        show_sides.addWidget( self.directions )
 55        self.directions.currentIndexChanged.connect( self.show_side_side )
 56        layout.addLayout( show_sides )
 57        
 58        ## Option show shifted segmentation
 59        self.show_shifted = wid.add_check( "Overlay previous segmentation", False, self.show_shifted_segmentation, "Overlay the (frame-1) segmentation on the current segmentation")
 60        layout.addWidget(self.show_shifted)
 61        
 62        ## Option show shifted movie (previous or next)
 63        show_prevmovie_line = QHBoxLayout()
 64        self.show_previous_movie = wid.add_check( "Overlay previous movie", False, self.show_shifted_previous_movie, "Overlay the (frame-1) of the movie on the current movie" )
 65        layout.addWidget(self.show_previous_movie)
 66        self.show_next_movie = wid.add_check( "Overlay next movie", False, self.show_shifted_next_movie, "Overlay (frame+1) of the movie on the current frame" )
 67        layout.addWidget(self.show_next_movie)
 68        
 69        ## Option create/show grid
 70        grid_line, self.show_grid_options, self.group_grid = wid.checkgroup_help( "Grid options", True, "Show/hide subpanel to control grid view", "Display#grid-options", self.epicure.display_colors, groupnb="group" )
 71        self.grid_parameters()
 72        layout.addWidget(self.show_grid_options)
 73        layout.addWidget(self.group_grid)
 74        
 75        self.save_contrast = wid.add_check("Save Movie current contrast", True, descr="When saving current settings, save also current contrast of the Movie layer" )
 76        save_pref = wid.add_button( "Set current settings as default", self.save_current_display, "Save the current settings so that EpiCure will open in the same state next time" )
 77        layout.addWidget(save_pref)
 78        
 79        self.add_display_overlay_message()
 80        self.key_bindings()        ## activate shortcuts for display options
 81        self.setLayout(layout)
 82        ut.set_active_layer( self.viewer, "Segmentation" )
 83    
 84    ### set current display as defaut
 85    def save_current_display( self ):
 86        """ Set current display parameters as defaut display """
 87        self.epicure.update_settings()
 88        self.epicure.pref.save()
 89
 90    def get_current_settings( self ):
 91        """ Returns current display settings """
 92        disp = {}
 93        disp["Layers"] = {}
 94        for layer in self.viewer.layers:
 95            disp["Layers"][layer.name] = layer.visible
 96        disp["Show Grid"] = self.show_grid_options.isChecked()
 97        disp["Grid nrows"] = self.nrows.text()
 98        disp["Grid ncols"] = self.ncols.text()
 99        disp["Grid width"] = self.gwidth.text()
100        disp["Grid color"] = self.grid_color
101        disp["Show side on"] = self.show_side.isChecked()
102        disp["Side direction"] = self.directions.currentText()
103        if "EpicGrid" in self.viewer.layers:
104            disp["Grid text"] = self.viewer.layers["EpicGrid"].text.visible
105            disp["Grid color"] = self.viewer.layers["EpicGrid"].edge_color[0]
106        return disp
107    
108    def apply_settings( self, settings ):
109        """ Set current display to prefered settings """
110        add_grid = False
111        show_text = False
112        ## read the settings and apply them
113        for setty, val in settings.items():
114            if setty == "Layers":
115                for layname, layvis in val.items():
116                    if layname in self.viewer.layers:
117                        self.viewer.layers[layname].visible = layvis
118                    else:
119                        if layname == "EpicGrid":
120                            add_grid = layvis 
121                continue
122            if setty == "Show Grid":
123                self.show_grid_options.setChecked( val )
124                continue
125            if setty == "Grid nrows":
126                self.nrows.setText( val )
127                continue
128            if setty == "Grid ncols":
129                self.ncols.setText( val )
130                continue
131            if setty == "Grid width":
132                self.gwidth.setText( val )
133                continue
134            if setty == "Grid text":
135                show_text = val
136                continue
137            if setty == "Grid color":
138                self.grid_color = val
139                continue
140            if setty == "Show side on":
141                self.show_side.setChecked( val )
142            if setty == "Side direction":
143                self.directions.setCurrentText( val )
144            
145        ## if grid should be added, do it at the end when all values are updated
146        if add_grid:
147            self.add_grid()
148            self.viewer.layers["EpicGrid"].text.visible = show_text
149
150
151
152    ######### overlay message
153    def add_display_overlay_message(self):
154        """ Shortcut list for display options """
155        disptext = "--- Display options --- \n"
156        sdisp = self.epicure.shortcuts["Display"]
157        disptext += ut.print_shortcuts( sdisp )
158        self.epicure.overtext["Display"] = disptext
159        sinfo = self.epicure.shortcuts["Info"]
160        self.epicure.overtext["info"] = "---- Info options --- \n"
161        self.epicure.overtext["info"] += ut.print_shortcuts( sinfo )
162
163
164
165    ################  Key binging for display options
166    def key_bindings(self):
167        sdisp = self.epicure.shortcuts["Display"]
168        sinfo = self.epicure.shortcuts["Info"]
169        
170        @self.seglayer.bind_key( sdisp["vis. segmentation"]["key"], overwrite=True )
171        def see_segmentlayer(seglayer):
172            seglayer.visible = not seglayer.visible
173        
174        @self.seglayer.bind_key( sdisp["vis. movie"]["key"], overwrite=True )
175        def see_movielayer(seglayer):
176            ut.inv_visibility(self.viewer, "Movie")
177        
178        @self.seglayer.bind_key( sdisp["vis. event"]["key"], overwrite=True )
179        def see_eventslayer(seglayer):
180            evlayer = self.viewer.layers["Events"]
181            evlayer.visible = not evlayer.visible
182        
183        @self.epicure.seglayer.bind_key( sinfo["measure length"]["key"], overwrite=True )
184        def measure_length(layer):
185            """ 
186            Draw a line and measure its length 
187            """
188            self.measure_line_length( layer )
189        
190        @self.seglayer.bind_key( sdisp["skeleton"]["key"], overwrite=True )
191        def show_skeleton(seglayer):
192            """ On/Off show skeleton """
193            if self.show_skeleton.isChecked():
194                self.show_skeleton.setChecked(False)
195            else:
196                self.show_skeleton.setChecked(True)
197        
198        @self.seglayer.bind_key( sdisp["show side"]["key"], overwrite=True )
199        def show_byside(seglayer):
200            self.show_side.setChecked( not self.show_side.isChecked() )
201            self.show_side_side()
202
203        @self.seglayer.bind_key( sdisp["increase"]["key"], overwrite=True )
204        def contour_increase(seglayer):
205            if seglayer is not None:
206                seglayer.contour = seglayer.contour + 1
207        
208        @self.seglayer.bind_key( sdisp["decrease"]["key"], overwrite=True )
209        def contour_decrease(seglayer):
210            if seglayer is not None:
211                if seglayer.contour > 0:
212                    seglayer.contour = seglayer.contour - 1
213        
214        @self.seglayer.bind_key( sdisp["only movie"]["key"], overwrite=True )
215        def see_onlymovielayer(seglayer):
216            """ if in "g" mode, show only movie, else put back to previous views """
217            if self.gmode == 0:
218                self.lay_view = []
219                for lay in self.viewer.layers:
220                    self.lay_view.append( (lay, lay.visible) )
221                    lay.visible = False
222                ut.inv_visibility(self.viewer, "Movie")
223                self.gmode = 1
224            else:
225                for lay, vis in self.lay_view:
226                    lay.visible = vis
227                self.gmode = 0
228
229        @self.seglayer.bind_key( sdisp["light view"]["key"], overwrite=True )
230        def segmentation_lightmode(seglayer):
231            """ if in "d" mode, show only movie and light segmentation, else put back to previous views """
232            if self.dmode == 0:
233                self.light_view = []
234                for lay in self.viewer.layers:
235                    self.light_view.append( (lay, lay.visible) )
236                    lay.visible = False
237                ut.inv_visibility(self.viewer, "Movie")
238                ut.inv_visibility(self.viewer, "Segmentation")
239                self.unlight_contour = self.seglayer.contour
240                self.unlight_opacity = self.seglayer.opacity
241                self.seglayer.contour = 1
242                self.seglayer.opacity = 0.2
243                self.dmode = 1
244            else:
245                for lay, vis in self.light_view:
246                    lay.visible = vis
247                self.seglayer.contour = self.unlight_contour
248                self.seglayer.opacity = self.unlight_opacity
249                self.dmode = 0
250        
251        @self.seglayer.bind_key( sdisp["grid"]["key"], overwrite=True )
252        def show_grid(seglayer):
253            """ show/hide the grid to have a repere in space """
254            self.show_grid()
255
256    ### Info options
257    def measure_line_length(self, layer=None):
258        """ 
259        Draw a line and measure its length 
260        """
261        self.old_mouse_drag, self.old_key_map = ut.clear_bindings( self.epicure.seglayer )
262        ut.show_info("Draw line to measure.")
263        if self.shapelayer_name not in self.viewer.layers:
264            self.create_shapelayer()
265        shape_lay = self.viewer.layers[self.shapelayer_name]
266        shape_lay.mode = "add_line"
267        shape_lay.visible = True
268        ut.set_active_layer( self.viewer, self.shapelayer_name)
269
270        @shape_lay.mouse_drag_callbacks.append
271        def click(layer, event):
272            if (event.type == "mouse_press") and (len(event.modifiers)==0) and (event.button==1):
273                ## dragg click to draw line
274                start_pos = event.position
275                yield
276                while event.type == 'mouse_move':
277                    #print( event.position)
278                    yield
279                end_pos = event.position
280                self.draw_line(shape_lay, start_pos, end_pos)
281                self.end_measure_mode()
282            else:
283                self.end_measure_mode()
284
285    def end_measure_mode(self):
286        """ Finish measuring mode """
287        if self.old_mouse_drag is not None:
288            if self.shapelayer_name in self.viewer.layers:
289                shape_lay = self.viewer.layers[self.shapelayer_name]
290                shape_lay.visible = False
291            ut.reactive_bindings( self.epicure.seglayer, self.old_mouse_drag, self.old_key_map )
292            ut.show_info("End measure")
293        ut.set_active_layer( self.viewer, "Segmentation" )
294    
295    def draw_line( self, shape_lay, start_position, end_position ):
296        """ Draw a line in the shape layer """
297        #shape_lay.data = np.array( [start_position, end_position] )
298        #shape_lay.features = { "length": np.linalg.norm(np.array(end_position[1:3]) - np.array(start_position[1:3])) }
299        length = np.linalg.norm(np.array(end_position[1:3]) - np.array(start_position[1:3])) 
300        ut.setOverlayText( self.viewer, "Length: "+str(round(length,1))+" µm" )
301        #shape_lay.text.string = "length"
302        #shape_lay.text.visible = True
303        shape_lay.data = shape_lay.data[:-1]  ## remove last line drawn
304        shape_lay.refresh()
305
306    
307    def show_summary_window(self):
308        """ Show a text window with some infos """
309        summwin = TextEdit()
310        summwin.name = "Epicure summary"
311        summwin.value = self.epicure.get_summary()
312        summwin.show()
313
314    ### Display options
315    def show_skeleton_segmentation(self):
316        """ Show/hide/update skeleton """
317        if "Skeleton" in self.viewer.layers:
318            ut.remove_layer(self.viewer, "Skeleton")
319        if self.show_skeleton.isChecked():
320            self.epicure.add_skeleton()
321            ut.set_active_layer( self.viewer, "Segmentation" )
322
323    def show_side_side( self ):
324        """ Show the layers side by side """
325        layout_grid = self.viewer.grid
326        if self.show_side.isChecked():
327            stride =  len( self.viewer.layers ) - 1
328            layout_grid.stride = stride
329            layout_grid.shape = (2,1)
330            if self.directions.currentText() == "Horizontal":
331                layout_grid.shape = (1,2)
332            layout_grid.enabled = True
333        else:
334            layout_grid.enabled = False
335
336
337    def show_shifted_segmentation(self):
338        """ Show/Hide temporally shifted segmentation on top of current one """
339        if ("PrevSegmentation" in self.viewer.layers):
340            if (not self.show_shifted.isChecked()):
341                ut.remove_layer(self.viewer, "PrevSegmentation")
342            else:
343                lay = self.viewer.layers["PrevSegmentation"]
344                lay.refresh()
345
346        if ("PrevSegmentation" not in self.viewer.layers) and (self.show_shifted.isChecked()):
347            if self.epicure.nframes > 1:
348                layer = self.viewer.add_labels( self.seglayer.data, name="PrevSegmentation", blending="additive", opacity=0.4 )
349                layer.contour = 2
350                layer.translate = [1, 0, 0]
351                self.seglayer.contour = 2
352                self.seglayer.opacity = 0.6
353            else:
354                ut.show_warning("Still image, cannot show previous frames")
355
356        ut.set_active_layer( self.viewer, "Segmentation" )
357    
358    def show_shifted_previous_movie(self):
359        """ Show/Hide temporally shifted movie previous frame on top of current one """
360        self.show_shifted_movie("PrevMovie", "red", 1)
361    
362    def show_shifted_next_movie(self):
363        """ Show/Hide temporally shifted movie next frame on top of current one """
364        self.show_shifted_movie("NextMovie", "green", -1)
365    
366    def show_shifted_movie(self, layname, color, translation):
367        """ Show/Hide temporally shifted movie on top of current one """
368        if (layname in self.viewer.layers):
369            if (not self.show_previous_movie.isChecked()):
370                ut.remove_layer(self.viewer, layname)
371            else:
372                lay = self.viewer.layers[layname]
373                lay.refresh()
374
375        if (layname not in self.viewer.layers) and (self.show_previous_movie.isChecked()):
376            if self.epicure.nframes > 1:
377                movlay = self.viewer.layers["Movie"]
378                arr = movlay.data
379                if translation == -1:
380                    arr = movlay.data[1:,]
381                layer = self.viewer.add_image( arr, name=layname, blending="additive", opacity=0.6, colormap=color )
382                if translation == 1:
383                    layer.translate = [translation, 0, 0]
384                layer.contrast_limits=self.epicure.quantiles()
385                layer.gamma=0.94
386            else:
387                ut.show_warning("Still image, cannot show previous frames")
388
389        ut.set_active_layer( self.viewer, "Segmentation" )
390
391    #### Show/load a grid to have a repere in space
392    def grid_parameters(self):
393        """ Interface to get grid parameters """
394        grid_layout = QVBoxLayout()
395        ## nrows
396        rows_line, self.nrows = wid.value_line( "Nb rows", "4", "Number of rows of the grid" )
397        grid_layout.addLayout(rows_line)
398        ## ncols
399        cols_line, self.ncols = wid.value_line( "Nb columns:", "4", "Number of columns in the grid" )
400        grid_layout.addLayout(cols_line)
401        ## grid edges width
402        width_line, self.gwidth = wid.value_line( "Grid width:", "3", "Width of the grid displayed lines/columns" )
403        grid_layout.addLayout(width_line)
404       ## go for grid
405        btn_add_grid = wid.add_button( "Add grid", self.add_grid, "Add a grid overlay to the main view" )
406        grid_layout.addWidget(btn_add_grid)
407        self.group_grid.setLayout(grid_layout)
408
409    def add_grid(self):
410        """ Create/Load a new grid and add it """
411        ut.remove_layer(self.viewer, "EpicGrid")
412        imshape = self.epicure.imgshape2D
413        if imshape is None:
414            ut.show_error("Load the image first")
415            return
416        nrows = int(self.nrows.text())
417        ncols = int(self.ncols.text())
418        wid = ceil(imshape[0]/nrows)
419        hei = ceil(imshape[1]/ncols)
420        rects = []
421        rects_names = []
422        gwidth = int(self.gwidth.text())
423        for x in range(nrows):
424            for y in range(ncols):
425                rect = np.array([[x*wid, y*hei], [(x+1)*wid, (y+1)*hei]])
426                rects.append(rect)
427                rects_names.append(chr(65+x)+"_"+str(y))
428        self.viewer.add_shapes(rects, name="EpicGrid", text=rects_names, face_color=[1,0,0,0], edge_color=self.grid_color, edge_width=gwidth, opacity=0.7, scale=self.viewer.layers["Segmentation"].scale[1:])
429        self.viewer.layers["EpicGrid"].text.visible = False
430        ut.set_active_layer( self.viewer, "Segmentation" )
431
432    def show_grid(self):
433        """ Interface to create/load a grid for repere """
434        if "EpicGrid" not in self.viewer.layers:
435            self.add_grid()
436        else:
437            gridlay = self.viewer.layers["EpicGrid"]
438            gridlay.visible = not gridlay.visible
439            gridlay.edge_color = self.grid_color

Propose some visualization options

Displaying(napari_viewer, epic)
22    def __init__(self, napari_viewer, epic):
23        """ Create displaying widget instance """
24        super().__init__()
25        self.viewer = napari_viewer
26        self.epicure = epic
27        self.seglayer = self.viewer.layers["Segmentation"]
28        self.gmode = 0  ## view only movie mode on/off
29        self.dmode = 0  ## view with light segmentation on/off
30        self.grid_color = [0.6, 0.7, 0.7, 0.7]  ## default grid color
31        self.shapelayer_name = "ROIs"
32
33        layout = QVBoxLayout()
34        
35        ## Show a text window with some summary of the file
36        show_summary = wid.add_button( "Show summary", self.show_summary_window, "Pops-up a summary of the movie and segmentation informations" )
37        layout.addWidget(show_summary)
38
39        ## Draw and measure length of a line
40        measure_line = wid.add_button( "Measure length", self.measure_line_length, "Draw a line and measure its length" )
41        layout.addWidget(measure_line)
42
43        ## Option show segmentation skeleton
44        self.show_skeleton = wid.add_check( "Show segmentation skeleton", False, self.show_skeleton_segmentation, "Add a layer with the segmentation skeleton (not automatically updated)" )
45        layout.addWidget(self.show_skeleton)
46        
47        ## Option to show the movie and seg side by side
48        show_sides = QHBoxLayout()
49        self.show_side = wid.add_check( "Side by side view", False, self.show_side_side, "View the movie and the other layers side by side" )
50        show_sides.addWidget( self.show_side )
51        self.directions = QComboBox()
52        self.directions.addItem( "Horizontal" )
53        self.directions.addItem( "Vertical" )
54        show_sides.addWidget( self.directions )
55        self.directions.currentIndexChanged.connect( self.show_side_side )
56        layout.addLayout( show_sides )
57        
58        ## Option show shifted segmentation
59        self.show_shifted = wid.add_check( "Overlay previous segmentation", False, self.show_shifted_segmentation, "Overlay the (frame-1) segmentation on the current segmentation")
60        layout.addWidget(self.show_shifted)
61        
62        ## Option show shifted movie (previous or next)
63        show_prevmovie_line = QHBoxLayout()
64        self.show_previous_movie = wid.add_check( "Overlay previous movie", False, self.show_shifted_previous_movie, "Overlay the (frame-1) of the movie on the current movie" )
65        layout.addWidget(self.show_previous_movie)
66        self.show_next_movie = wid.add_check( "Overlay next movie", False, self.show_shifted_next_movie, "Overlay (frame+1) of the movie on the current frame" )
67        layout.addWidget(self.show_next_movie)
68        
69        ## Option create/show grid
70        grid_line, self.show_grid_options, self.group_grid = wid.checkgroup_help( "Grid options", True, "Show/hide subpanel to control grid view", "Display#grid-options", self.epicure.display_colors, groupnb="group" )
71        self.grid_parameters()
72        layout.addWidget(self.show_grid_options)
73        layout.addWidget(self.group_grid)
74        
75        self.save_contrast = wid.add_check("Save Movie current contrast", True, descr="When saving current settings, save also current contrast of the Movie layer" )
76        save_pref = wid.add_button( "Set current settings as default", self.save_current_display, "Save the current settings so that EpiCure will open in the same state next time" )
77        layout.addWidget(save_pref)
78        
79        self.add_display_overlay_message()
80        self.key_bindings()        ## activate shortcuts for display options
81        self.setLayout(layout)
82        ut.set_active_layer( self.viewer, "Segmentation" )

Create displaying widget instance

viewer
epicure
seglayer
gmode
dmode
grid_color
shapelayer_name
show_skeleton
show_side
directions
show_shifted
show_previous_movie
show_next_movie
save_contrast
def save_current_display(self):
85    def save_current_display( self ):
86        """ Set current display parameters as defaut display """
87        self.epicure.update_settings()
88        self.epicure.pref.save()

Set current display parameters as defaut display

def get_current_settings(self):
 90    def get_current_settings( self ):
 91        """ Returns current display settings """
 92        disp = {}
 93        disp["Layers"] = {}
 94        for layer in self.viewer.layers:
 95            disp["Layers"][layer.name] = layer.visible
 96        disp["Show Grid"] = self.show_grid_options.isChecked()
 97        disp["Grid nrows"] = self.nrows.text()
 98        disp["Grid ncols"] = self.ncols.text()
 99        disp["Grid width"] = self.gwidth.text()
100        disp["Grid color"] = self.grid_color
101        disp["Show side on"] = self.show_side.isChecked()
102        disp["Side direction"] = self.directions.currentText()
103        if "EpicGrid" in self.viewer.layers:
104            disp["Grid text"] = self.viewer.layers["EpicGrid"].text.visible
105            disp["Grid color"] = self.viewer.layers["EpicGrid"].edge_color[0]
106        return disp

Returns current display settings

def apply_settings(self, settings):
108    def apply_settings( self, settings ):
109        """ Set current display to prefered settings """
110        add_grid = False
111        show_text = False
112        ## read the settings and apply them
113        for setty, val in settings.items():
114            if setty == "Layers":
115                for layname, layvis in val.items():
116                    if layname in self.viewer.layers:
117                        self.viewer.layers[layname].visible = layvis
118                    else:
119                        if layname == "EpicGrid":
120                            add_grid = layvis 
121                continue
122            if setty == "Show Grid":
123                self.show_grid_options.setChecked( val )
124                continue
125            if setty == "Grid nrows":
126                self.nrows.setText( val )
127                continue
128            if setty == "Grid ncols":
129                self.ncols.setText( val )
130                continue
131            if setty == "Grid width":
132                self.gwidth.setText( val )
133                continue
134            if setty == "Grid text":
135                show_text = val
136                continue
137            if setty == "Grid color":
138                self.grid_color = val
139                continue
140            if setty == "Show side on":
141                self.show_side.setChecked( val )
142            if setty == "Side direction":
143                self.directions.setCurrentText( val )
144            
145        ## if grid should be added, do it at the end when all values are updated
146        if add_grid:
147            self.add_grid()
148            self.viewer.layers["EpicGrid"].text.visible = show_text

Set current display to prefered settings

def add_display_overlay_message(self):
153    def add_display_overlay_message(self):
154        """ Shortcut list for display options """
155        disptext = "--- Display options --- \n"
156        sdisp = self.epicure.shortcuts["Display"]
157        disptext += ut.print_shortcuts( sdisp )
158        self.epicure.overtext["Display"] = disptext
159        sinfo = self.epicure.shortcuts["Info"]
160        self.epicure.overtext["info"] = "---- Info options --- \n"
161        self.epicure.overtext["info"] += ut.print_shortcuts( sinfo )

Shortcut list for display options

def key_bindings(self):
166    def key_bindings(self):
167        sdisp = self.epicure.shortcuts["Display"]
168        sinfo = self.epicure.shortcuts["Info"]
169        
170        @self.seglayer.bind_key( sdisp["vis. segmentation"]["key"], overwrite=True )
171        def see_segmentlayer(seglayer):
172            seglayer.visible = not seglayer.visible
173        
174        @self.seglayer.bind_key( sdisp["vis. movie"]["key"], overwrite=True )
175        def see_movielayer(seglayer):
176            ut.inv_visibility(self.viewer, "Movie")
177        
178        @self.seglayer.bind_key( sdisp["vis. event"]["key"], overwrite=True )
179        def see_eventslayer(seglayer):
180            evlayer = self.viewer.layers["Events"]
181            evlayer.visible = not evlayer.visible
182        
183        @self.epicure.seglayer.bind_key( sinfo["measure length"]["key"], overwrite=True )
184        def measure_length(layer):
185            """ 
186            Draw a line and measure its length 
187            """
188            self.measure_line_length( layer )
189        
190        @self.seglayer.bind_key( sdisp["skeleton"]["key"], overwrite=True )
191        def show_skeleton(seglayer):
192            """ On/Off show skeleton """
193            if self.show_skeleton.isChecked():
194                self.show_skeleton.setChecked(False)
195            else:
196                self.show_skeleton.setChecked(True)
197        
198        @self.seglayer.bind_key( sdisp["show side"]["key"], overwrite=True )
199        def show_byside(seglayer):
200            self.show_side.setChecked( not self.show_side.isChecked() )
201            self.show_side_side()
202
203        @self.seglayer.bind_key( sdisp["increase"]["key"], overwrite=True )
204        def contour_increase(seglayer):
205            if seglayer is not None:
206                seglayer.contour = seglayer.contour + 1
207        
208        @self.seglayer.bind_key( sdisp["decrease"]["key"], overwrite=True )
209        def contour_decrease(seglayer):
210            if seglayer is not None:
211                if seglayer.contour > 0:
212                    seglayer.contour = seglayer.contour - 1
213        
214        @self.seglayer.bind_key( sdisp["only movie"]["key"], overwrite=True )
215        def see_onlymovielayer(seglayer):
216            """ if in "g" mode, show only movie, else put back to previous views """
217            if self.gmode == 0:
218                self.lay_view = []
219                for lay in self.viewer.layers:
220                    self.lay_view.append( (lay, lay.visible) )
221                    lay.visible = False
222                ut.inv_visibility(self.viewer, "Movie")
223                self.gmode = 1
224            else:
225                for lay, vis in self.lay_view:
226                    lay.visible = vis
227                self.gmode = 0
228
229        @self.seglayer.bind_key( sdisp["light view"]["key"], overwrite=True )
230        def segmentation_lightmode(seglayer):
231            """ if in "d" mode, show only movie and light segmentation, else put back to previous views """
232            if self.dmode == 0:
233                self.light_view = []
234                for lay in self.viewer.layers:
235                    self.light_view.append( (lay, lay.visible) )
236                    lay.visible = False
237                ut.inv_visibility(self.viewer, "Movie")
238                ut.inv_visibility(self.viewer, "Segmentation")
239                self.unlight_contour = self.seglayer.contour
240                self.unlight_opacity = self.seglayer.opacity
241                self.seglayer.contour = 1
242                self.seglayer.opacity = 0.2
243                self.dmode = 1
244            else:
245                for lay, vis in self.light_view:
246                    lay.visible = vis
247                self.seglayer.contour = self.unlight_contour
248                self.seglayer.opacity = self.unlight_opacity
249                self.dmode = 0
250        
251        @self.seglayer.bind_key( sdisp["grid"]["key"], overwrite=True )
252        def show_grid(seglayer):
253            """ show/hide the grid to have a repere in space """
254            self.show_grid()
def measure_line_length(self, layer=None):
257    def measure_line_length(self, layer=None):
258        """ 
259        Draw a line and measure its length 
260        """
261        self.old_mouse_drag, self.old_key_map = ut.clear_bindings( self.epicure.seglayer )
262        ut.show_info("Draw line to measure.")
263        if self.shapelayer_name not in self.viewer.layers:
264            self.create_shapelayer()
265        shape_lay = self.viewer.layers[self.shapelayer_name]
266        shape_lay.mode = "add_line"
267        shape_lay.visible = True
268        ut.set_active_layer( self.viewer, self.shapelayer_name)
269
270        @shape_lay.mouse_drag_callbacks.append
271        def click(layer, event):
272            if (event.type == "mouse_press") and (len(event.modifiers)==0) and (event.button==1):
273                ## dragg click to draw line
274                start_pos = event.position
275                yield
276                while event.type == 'mouse_move':
277                    #print( event.position)
278                    yield
279                end_pos = event.position
280                self.draw_line(shape_lay, start_pos, end_pos)
281                self.end_measure_mode()
282            else:
283                self.end_measure_mode()

Draw a line and measure its length

def end_measure_mode(self):
285    def end_measure_mode(self):
286        """ Finish measuring mode """
287        if self.old_mouse_drag is not None:
288            if self.shapelayer_name in self.viewer.layers:
289                shape_lay = self.viewer.layers[self.shapelayer_name]
290                shape_lay.visible = False
291            ut.reactive_bindings( self.epicure.seglayer, self.old_mouse_drag, self.old_key_map )
292            ut.show_info("End measure")
293        ut.set_active_layer( self.viewer, "Segmentation" )

Finish measuring mode

def draw_line(self, shape_lay, start_position, end_position):
295    def draw_line( self, shape_lay, start_position, end_position ):
296        """ Draw a line in the shape layer """
297        #shape_lay.data = np.array( [start_position, end_position] )
298        #shape_lay.features = { "length": np.linalg.norm(np.array(end_position[1:3]) - np.array(start_position[1:3])) }
299        length = np.linalg.norm(np.array(end_position[1:3]) - np.array(start_position[1:3])) 
300        ut.setOverlayText( self.viewer, "Length: "+str(round(length,1))+" µm" )
301        #shape_lay.text.string = "length"
302        #shape_lay.text.visible = True
303        shape_lay.data = shape_lay.data[:-1]  ## remove last line drawn
304        shape_lay.refresh()

Draw a line in the shape layer

def show_summary_window(self):
307    def show_summary_window(self):
308        """ Show a text window with some infos """
309        summwin = TextEdit()
310        summwin.name = "Epicure summary"
311        summwin.value = self.epicure.get_summary()
312        summwin.show()

Show a text window with some infos

def show_skeleton_segmentation(self):
315    def show_skeleton_segmentation(self):
316        """ Show/hide/update skeleton """
317        if "Skeleton" in self.viewer.layers:
318            ut.remove_layer(self.viewer, "Skeleton")
319        if self.show_skeleton.isChecked():
320            self.epicure.add_skeleton()
321            ut.set_active_layer( self.viewer, "Segmentation" )

Show/hide/update skeleton

def show_side_side(self):
323    def show_side_side( self ):
324        """ Show the layers side by side """
325        layout_grid = self.viewer.grid
326        if self.show_side.isChecked():
327            stride =  len( self.viewer.layers ) - 1
328            layout_grid.stride = stride
329            layout_grid.shape = (2,1)
330            if self.directions.currentText() == "Horizontal":
331                layout_grid.shape = (1,2)
332            layout_grid.enabled = True
333        else:
334            layout_grid.enabled = False

Show the layers side by side

def show_shifted_segmentation(self):
337    def show_shifted_segmentation(self):
338        """ Show/Hide temporally shifted segmentation on top of current one """
339        if ("PrevSegmentation" in self.viewer.layers):
340            if (not self.show_shifted.isChecked()):
341                ut.remove_layer(self.viewer, "PrevSegmentation")
342            else:
343                lay = self.viewer.layers["PrevSegmentation"]
344                lay.refresh()
345
346        if ("PrevSegmentation" not in self.viewer.layers) and (self.show_shifted.isChecked()):
347            if self.epicure.nframes > 1:
348                layer = self.viewer.add_labels( self.seglayer.data, name="PrevSegmentation", blending="additive", opacity=0.4 )
349                layer.contour = 2
350                layer.translate = [1, 0, 0]
351                self.seglayer.contour = 2
352                self.seglayer.opacity = 0.6
353            else:
354                ut.show_warning("Still image, cannot show previous frames")
355
356        ut.set_active_layer( self.viewer, "Segmentation" )

Show/Hide temporally shifted segmentation on top of current one

def show_shifted_previous_movie(self):
358    def show_shifted_previous_movie(self):
359        """ Show/Hide temporally shifted movie previous frame on top of current one """
360        self.show_shifted_movie("PrevMovie", "red", 1)

Show/Hide temporally shifted movie previous frame on top of current one

def show_shifted_next_movie(self):
362    def show_shifted_next_movie(self):
363        """ Show/Hide temporally shifted movie next frame on top of current one """
364        self.show_shifted_movie("NextMovie", "green", -1)

Show/Hide temporally shifted movie next frame on top of current one

def show_shifted_movie(self, layname, color, translation):
366    def show_shifted_movie(self, layname, color, translation):
367        """ Show/Hide temporally shifted movie on top of current one """
368        if (layname in self.viewer.layers):
369            if (not self.show_previous_movie.isChecked()):
370                ut.remove_layer(self.viewer, layname)
371            else:
372                lay = self.viewer.layers[layname]
373                lay.refresh()
374
375        if (layname not in self.viewer.layers) and (self.show_previous_movie.isChecked()):
376            if self.epicure.nframes > 1:
377                movlay = self.viewer.layers["Movie"]
378                arr = movlay.data
379                if translation == -1:
380                    arr = movlay.data[1:,]
381                layer = self.viewer.add_image( arr, name=layname, blending="additive", opacity=0.6, colormap=color )
382                if translation == 1:
383                    layer.translate = [translation, 0, 0]
384                layer.contrast_limits=self.epicure.quantiles()
385                layer.gamma=0.94
386            else:
387                ut.show_warning("Still image, cannot show previous frames")
388
389        ut.set_active_layer( self.viewer, "Segmentation" )

Show/Hide temporally shifted movie on top of current one

def grid_parameters(self):
392    def grid_parameters(self):
393        """ Interface to get grid parameters """
394        grid_layout = QVBoxLayout()
395        ## nrows
396        rows_line, self.nrows = wid.value_line( "Nb rows", "4", "Number of rows of the grid" )
397        grid_layout.addLayout(rows_line)
398        ## ncols
399        cols_line, self.ncols = wid.value_line( "Nb columns:", "4", "Number of columns in the grid" )
400        grid_layout.addLayout(cols_line)
401        ## grid edges width
402        width_line, self.gwidth = wid.value_line( "Grid width:", "3", "Width of the grid displayed lines/columns" )
403        grid_layout.addLayout(width_line)
404       ## go for grid
405        btn_add_grid = wid.add_button( "Add grid", self.add_grid, "Add a grid overlay to the main view" )
406        grid_layout.addWidget(btn_add_grid)
407        self.group_grid.setLayout(grid_layout)

Interface to get grid parameters

def add_grid(self):
409    def add_grid(self):
410        """ Create/Load a new grid and add it """
411        ut.remove_layer(self.viewer, "EpicGrid")
412        imshape = self.epicure.imgshape2D
413        if imshape is None:
414            ut.show_error("Load the image first")
415            return
416        nrows = int(self.nrows.text())
417        ncols = int(self.ncols.text())
418        wid = ceil(imshape[0]/nrows)
419        hei = ceil(imshape[1]/ncols)
420        rects = []
421        rects_names = []
422        gwidth = int(self.gwidth.text())
423        for x in range(nrows):
424            for y in range(ncols):
425                rect = np.array([[x*wid, y*hei], [(x+1)*wid, (y+1)*hei]])
426                rects.append(rect)
427                rects_names.append(chr(65+x)+"_"+str(y))
428        self.viewer.add_shapes(rects, name="EpicGrid", text=rects_names, face_color=[1,0,0,0], edge_color=self.grid_color, edge_width=gwidth, opacity=0.7, scale=self.viewer.layers["Segmentation"].scale[1:])
429        self.viewer.layers["EpicGrid"].text.visible = False
430        ut.set_active_layer( self.viewer, "Segmentation" )

Create/Load a new grid and add it

def show_grid(self):
432    def show_grid(self):
433        """ Interface to create/load a grid for repere """
434        if "EpicGrid" not in self.viewer.layers:
435            self.add_grid()
436        else:
437            gridlay = self.viewer.layers["EpicGrid"]
438            gridlay.visible = not gridlay.visible
439            gridlay.edge_color = self.grid_color

Interface to create/load a grid for repere