@@ -223,6 +223,7 @@ def __init__(
223
223
self ._last_selected_label_layer = get_selected_or_valid_label_layer (
224
224
viewer = self ._viewer
225
225
)
226
+
226
227
# Initialize the classifier
227
228
if classifier :
228
229
self ._classifier = classifier
@@ -248,17 +249,10 @@ def __init__(
248
249
self ._viewer , get_class_selection (class_names = self .class_names )
249
250
)
250
251
251
- # Handle existing predictions layer
252
252
for layer in self ._viewer .layers :
253
253
if type (layer ) == napari .layers .Labels and layer .name == "Predictions" :
254
254
self ._viewer .layers .remove (layer )
255
- self ._prediction_layer = self ._viewer .add_labels (
256
- self ._last_selected_label_layer .data ,
257
- scale = self ._last_selected_label_layer .scale ,
258
- name = "Predictions" ,
259
- translate = self ._last_selected_label_layer .translate ,
260
- )
261
- self ._prediction_layer .contour = 2
255
+ self .add_prediction_layer ()
262
256
263
257
# Set the label selection to a valid label layer => Running into proxy bug
264
258
self ._viewer .layers .selection .active = self ._last_selected_label_layer
@@ -295,11 +289,6 @@ def __init__(
295
289
self ._export_button .clicked .connect (self .export_results )
296
290
self ._viewer .layers .selection .events .changed .connect (self .selection_changed )
297
291
self ._init_prediction_layer (self ._last_selected_label_layer )
298
- # Whenever the label layer is clicked, hide the prediction layer
299
- # (e.g. new annotations are made)
300
- # self._last_selected_label_layer.mouse_drag_callbacks.append(
301
- # self.hide_prediction_layer
302
- # )
303
292
304
293
def run (self ):
305
294
"""
@@ -349,6 +338,15 @@ def add_features_to_classifier(self):
349
338
dict_of_features [layer .name ] = layer .features
350
339
self ._classifier .add_dict_of_features (dict_of_features )
351
340
341
+ def add_prediction_layer (self ):
342
+ self ._prediction_layer = self ._viewer .add_labels (
343
+ self ._last_selected_label_layer .data ,
344
+ scale = self ._last_selected_label_layer .scale ,
345
+ name = "Predictions" ,
346
+ translate = self ._last_selected_label_layer .translate ,
347
+ )
348
+ self ._prediction_layer .contour = 2
349
+
352
350
def make_predictions (self ):
353
351
"""
354
352
Make predictions for all relevant label layers and add them to the
@@ -398,17 +396,72 @@ def selection_changed(self):
398
396
viewer = self ._viewer
399
397
):
400
398
self ._last_selected_label_layer = self ._viewer .layers .selection .active
401
- self ._init_prediction_layer (self ._viewer .layers .selection .active )
402
- # self._last_selected_label_layer.mouse_drag_callbacks.append(
403
- # self.hide_prediction_layer
404
- # )
399
+ self ._init_prediction_layer (
400
+ self ._viewer .layers .selection .active , ensure_layer_presence = False
401
+ )
405
402
self ._update_export_destination (self ._last_selected_label_layer )
406
403
407
- def _init_prediction_layer (self , label_layer : napari .layers .Labels ):
404
+ def reorder_layers (self ):
405
+ """Reorders layers if needed to ensure Annotation & Prediction layers
406
+ are above the currently selected label layer.
407
+ """
408
+ # Get the current order of layers
409
+ all_layers = list (self ._viewer .layers )
410
+
411
+ # Determine the indices of the layers if they exist
412
+ indices_to_move = []
413
+
414
+ # Find the index of "Prediction" layer if it exists
415
+ if "Predictions" in self ._viewer .layers :
416
+ indices_to_move .append (self ._viewer .layers .index ("Predictions" ))
417
+
418
+ # Find the index of "Annotation" layer if it exists
419
+ if "Annotations" in self ._viewer .layers :
420
+ indices_to_move .append (self ._viewer .layers .index ("Annotations" ))
421
+
422
+ # Find the index of the reference_label_layer
423
+ if self ._last_selected_label_layer .name in self ._viewer .layers :
424
+ indices_to_move .append (
425
+ self ._viewer .layers .index (self ._last_selected_label_layer .name )
426
+ )
427
+
428
+ # Calculate the new order of layer indices
429
+ remaining_indices = [
430
+ i for i in range (len (all_layers )) if i not in indices_to_move
431
+ ]
432
+ remaining_indices .reverse ()
433
+ new_order = indices_to_move + remaining_indices
434
+ new_order .reverse ()
435
+
436
+ # Reorder the layers using the move_multiple function
437
+ self ._viewer .layers .move_multiple (new_order )
438
+
439
+ def _init_prediction_layer (
440
+ self , label_layer : napari .layers .Labels , ensure_layer_presence : bool = True
441
+ ):
408
442
"""
409
443
Initialize the prediction layer and reset its data (to fit the input
410
- label_layer) and its colormap
444
+ label_layer) and its colormap.
445
+ ensure_layer_presence creates the Predictions layer if it doesn't exist
446
+ yet and triggers layer reordering.
411
447
"""
448
+ # Ensure that prediction layer exists
449
+ if (
450
+ "Predictions" not in [x .name for x in self ._viewer .layers ]
451
+ and ensure_layer_presence
452
+ ):
453
+ self .add_prediction_layer ()
454
+ if ensure_layer_presence :
455
+ # Ensure correct layer order: This sometimes fails with weird
456
+ # EmitLoopError & IndexError that should be ignored
457
+ try :
458
+ self .reorder_layers ()
459
+ except : # noqa
460
+ pass
461
+
462
+ # Ensure that prediction layer is above the current label layer
463
+ self ._last_selected_label_layer
464
+
412
465
# Check if the predict column already exists in the layer.features
413
466
if "prediction" not in label_layer .features :
414
467
unique_labels = np .unique (label_layer .data )[1 :]
@@ -448,12 +501,6 @@ def _init_prediction_layer(self, label_layer: napari.layers.Labels):
448
501
cmap = get_colormap (),
449
502
)
450
503
451
- # def hide_prediction_layer(self, labels_layer, event):
452
- # """
453
- # Hide the prediction layer
454
- # """
455
- # self._prediction_layer.visible = False
456
-
457
504
def get_relevant_label_layers (self ):
458
505
relevant_label_layers = []
459
506
required_columns = [self ._label_column , self ._roi_id_colum ]
@@ -613,12 +660,19 @@ def load(self):
613
660
with open (clf_path , "rb" ) as f : # pylint: disable=C0103
614
661
clf = pickle .load (f )
615
662
616
- self ._run_container = ClassifierRunContainer (
617
- self ._viewer ,
618
- clf ,
619
- classifier_save_path = clf_path ,
620
- auto_save = True ,
621
- )
663
+ try :
664
+ self ._run_container = ClassifierRunContainer (
665
+ self ._viewer ,
666
+ clf ,
667
+ classifier_save_path = clf_path ,
668
+ auto_save = True ,
669
+ )
670
+ except NotImplementedError :
671
+ napari_info (
672
+ "Create a label layer with a feature dataframe before loading "
673
+ "the classifier"
674
+ )
675
+ return
622
676
self .clear ()
623
677
self .append (self ._run_container )
624
678
0 commit comments