Skip to content

Commit 79c66fd

Browse files
committed
added utilities for labels + refactored crop + remove_from_viewer methods
+ lint
1 parent 954f6fb commit 79c66fd

File tree

11 files changed

+103
-74
lines changed

11 files changed

+103
-74
lines changed

.github/workflows/build_docs.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
build:
10+
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v1
15+
# Standard drop-in approach that should work for most people.
16+
- uses: ammaraskar/sphinx-action@master
17+
with:
18+
pre-build-command: "pip install -r dev.requirements.txt"
19+
docs-folder: "docs/"
20+
21+
- name: GitHub Pages action
22+
uses: peaceiris/[email protected]
23+
with:
24+
github_token: ${{ secrets.GITHUB_TOKEN }}
25+
publish_dir: ./docs/_build/html

src/napari_cellseg_annotator/model_framework.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -107,22 +107,6 @@ def __init__(self, viewer: "napari.viewer.Viewer"):
107107
self.btn_save_log.setVisible(False)
108108
#####################################################
109109

110-
def make_close_button(self):
111-
btn = ui.make_button("Close", self.close)
112-
return btn
113-
114-
def make_prev_button(self):
115-
btn = ui.make_button(
116-
"Previous", lambda: self.setCurrentIndex(self.currentIndex() - 1)
117-
)
118-
return btn
119-
120-
def make_next_button(self):
121-
btn = ui.make_button(
122-
"Next", lambda: self.setCurrentIndex(self.currentIndex() + 1)
123-
)
124-
return btn
125-
126110
def send_log(self, text):
127111
self.log.print_and_log(text)
128112

src/napari_cellseg_annotator/model_instance_seg.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,12 @@ def to_instance(image, is_file_path=True):
102102

103103
return result
104104

105+
105106
def to_semantic(image, is_file_path=True):
106107
if is_file_path:
107108
image = imread(image)
108109
image = image.compute()
109110

110111
image[image >= 1] = 1
111112
result = image.astype(np.uint16)
112-
return result
113+
return result

src/napari_cellseg_annotator/napari.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ contributions:
1212
title: Create Help
1313
python_name: napari_cellseg_annotator.plugins:Helper
1414

15-
- id: napari-cellseg-annotator.crop
16-
title: Crop utility
17-
python_name: napari_cellseg_annotator.plugins:Cropping
15+
- id: napari-cellseg-annotator.utils
16+
title: Create utilities
17+
python_name: napari_cellseg_annotator.plugins:Utilities
1818

1919
- id: napari-cellseg-annotator.infer
2020
title: Create Inferer
@@ -35,8 +35,8 @@ contributions:
3535
- command: napari-cellseg-annotator.train
3636
display_name: Training
3737

38-
- command: napari-cellseg-annotator.crop
39-
display_name: Crop utility
38+
- command: napari-cellseg-annotator.utils
39+
display_name: Utilities
4040

4141
- command: napari-cellseg-annotator.help
4242
display_name: Help/About...

src/napari_cellseg_annotator/plugin_base.py

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
class BasePluginSingleImage(QTabWidget):
1313
"""A basic plugin template for working with **single images**"""
1414

15-
def __init__(self, viewer: "napari.viewer.Viewer"):
15+
def __init__(self, viewer: "napari.viewer.Viewer", parent=None):
1616
"""Creates a Base plugin with several buttons pre-defined but not added to a layout :
1717
1818
* Open file prompt to select images directory
@@ -29,10 +29,13 @@ def __init__(self, viewer: "napari.viewer.Viewer"):
2929

3030
super().__init__()
3131

32-
# self.master = parent
32+
self.parent = parent
33+
"""Parent widget"""
3334
self._viewer = viewer
3435
"""napari.viewer.Viewer: viewer in which the widget is displayed"""
3536

37+
self.docked_widgets = []
38+
3639
self.image_path = ""
3740
"""str: path to image folder"""
3841

@@ -67,7 +70,7 @@ def __init__(self, viewer: "napari.viewer.Viewer"):
6770
QSizePolicy.Fixed, QSizePolicy.Fixed
6871
)
6972

70-
self.btn_close = ui.make_button("Close", self.close, self)
73+
self.btn_close = ui.make_button("Close", self.remove_from_viewer, self)
7174

7275
# self.lbl_ft = QLabel("Filetype :", self)
7376
# self.lbl_ft2 = QLabel("(Folders of .png or single .tif files)", self)
@@ -126,13 +129,23 @@ def update_default(self):
126129
def remove_from_viewer(self):
127130
"""Removes the widget from the napari window.
128131
Can be re-implemented in children classes if needed"""
132+
if len(self.docked_widgets) != 0:
133+
[
134+
self._viewer.window.remove_dock_widget(w)
135+
for w in self.docked_widgets
136+
if w is not None
137+
]
138+
139+
if self.parent is not None:
140+
self.parent.remove_from_viewer()
141+
return
129142
self._viewer.window.remove_dock_widget(self)
130143

131144

132145
class BasePluginFolder(QTabWidget):
133146
"""A basic plugin template for working with **folders of images**"""
134147

135-
def __init__(self, viewer: "napari.viewer.Viewer"):
148+
def __init__(self, viewer: "napari.viewer.Viewer", parent=None):
136149
"""Creates a plugin template with the following widgets defined but not added in a layout :
137150
138151
* A button to load a folder of images
@@ -143,7 +156,7 @@ def __init__(self, viewer: "napari.viewer.Viewer"):
143156
144157
* A dropdown menu to select the file extension to be loaded from the folders"""
145158
super().__init__()
146-
159+
self.parent = parent
147160
self._viewer = viewer
148161

149162
self.images_filepaths = [""]
@@ -188,6 +201,22 @@ def __init__(self, viewer: "napari.viewer.Viewer"):
188201
self.lbl_result_path.setReadOnly(True)
189202
#######################################################
190203

204+
def make_close_button(self):
205+
btn = ui.make_button("Close", self.remove_from_viewer)
206+
return btn
207+
208+
def make_prev_button(self):
209+
btn = ui.make_button(
210+
"Previous", lambda: self.setCurrentIndex(self.currentIndex() - 1)
211+
)
212+
return btn
213+
214+
def make_next_button(self):
215+
btn = ui.make_button(
216+
"Next", lambda: self.setCurrentIndex(self.currentIndex() + 1)
217+
)
218+
return btn
219+
191220
def load_dataset_paths(self):
192221
"""Loads all image paths (as str) in a given folder for which the extension matches the set filetype
193222
@@ -251,11 +280,15 @@ def remove_docked_widgets(self):
251280
[
252281
self._viewer.window.remove_dock_widget(w)
253282
for w in self.docked_widgets
283+
if w is not None
254284
]
255285
self.docked_widgets = []
256286
self.container_docked = False
257287

258288
def remove_from_viewer(self):
259289
"""Close the widget and the docked widgets, if any"""
260290
self.remove_docked_widgets()
291+
if self.parent is not None:
292+
self.parent.remove_from_viewer()
293+
return
261294
self._viewer.window.remove_dock_widget(self)

src/napari_cellseg_annotator/plugin_convert.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44

55
import napari_cellseg_annotator.interface as ui
66
from napari_cellseg_annotator import utils
7-
from napari_cellseg_annotator.model_instance_seg import to_semantic, to_instance
7+
from napari_cellseg_annotator.model_instance_seg import (
8+
to_semantic,
9+
to_instance,
10+
)
811
from napari_cellseg_annotator.plugin_base import BasePluginFolder
912

1013

1114
class ConvertUtils(BasePluginFolder):
1215
"""Utility widget that allows to convert labels from instance to semantic and the reverse."""
1316

14-
def __init__(self, viewer: "napari.viewer.Viewer"):
17+
def __init__(self, viewer: "napari.viewer.Viewer", parent):
1518
"""Builds a ConvertUtils widget with the following buttons:
1619
1720
* A button to convert a folder of labels to semantic labels
@@ -23,7 +26,7 @@ def __init__(self, viewer: "napari.viewer.Viewer"):
2326
* A button to convert a currently selected layer to instance labels
2427
"""
2528

26-
super().__init__(viewer)
29+
super().__init__(viewer, parent)
2730

2831
self._viewer = viewer
2932

@@ -119,11 +122,13 @@ def build(self):
119122
layer_group_w.setLayout(layer_group_l)
120123
layout.addWidget(layer_group_w)
121124

122-
ui.make_scrollable(layout, self, min_wh=[110, 100], base_wh=[110, 150])
125+
ui.add_blank(layout=layout, widget=self)
126+
layout.addWidget(self.make_close_button())
123127

128+
ui.make_scrollable(layout, self, min_wh=[120, 100], base_wh=[120, 150])
124129

125130
def folder_to_semantic(self):
126-
131+
"""Converts folder of labels to semantic labels"""
127132
for file in self.labels_filepaths:
128133

129134
image = to_semantic(file)

src/napari_cellseg_annotator/plugin_crop.py

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
class Cropping(BasePluginSingleImage):
2323
"""A utility plugin for cropping 3D volumes."""
2424

25-
def __init__(self, viewer: "napari.viewer.Viewer"):
25+
def __init__(self, viewer: "napari.viewer.Viewer", parent):
2626
"""Creates a Cropping plugin with several buttons :
2727
2828
* Open file prompt to select volumes directory
@@ -38,7 +38,7 @@ def __init__(self, viewer: "napari.viewer.Viewer"):
3838
* A button to close the widget
3939
"""
4040

41-
super().__init__(viewer)
41+
super().__init__(viewer, parent)
4242

4343
self.btn_start = ui.make_button("Start", self.start, self)
4444

@@ -48,10 +48,6 @@ def __init__(self, viewer: "napari.viewer.Viewer"):
4848
self.lbl_label.setVisible(False)
4949
self.btn_label.setVisible(False)
5050

51-
self.docked_widgets = (
52-
[]
53-
) # container of docked widgets for removal on close
54-
5551
self.box_widgets = ui.make_n_spinboxes(3, 1, 1000, DEFAULT_CROP_SIZE)
5652
self.box_lbl = [
5753
QLabel("Size in " + axis + " of cropped volume :")
@@ -87,7 +83,7 @@ def toggle_label_path(self):
8783
def build(self):
8884
"""Build buttons in a layout and add them to the napari Viewer"""
8985

90-
tab, layout = ui.make_container_widget(0, 0, 1, 11)
86+
w, layout = ui.make_container_widget(0, 0, 1, 11)
9187

9288
data_group_w, data_group_l = ui.make_group("Data")
9389
data_group_l.addWidget(
@@ -128,15 +124,7 @@ def build(self):
128124
layout.addWidget(self.btn_start, alignment=ui.LEFT_AL)
129125
layout.addWidget(self.btn_close, alignment=ui.LEFT_AL)
130126

131-
ui.make_scrollable(layout, tab, min_wh=[180, 100])
132-
133-
self.addTab(tab, "Crop")
134-
135-
from napari_cellseg_annotator.plugin_convert import ConvertUtils
136-
137-
convert = ConvertUtils(self._viewer)
138-
self.addTab(convert, "Convert")
139-
self.setMaximumSize(230, 800)
127+
ui.make_scrollable(layout, self, min_wh=[180, 100])
140128

141129
def quicksave(self):
142130
"""Quicksaves the cropped volume in the folder from which they originate, with their original file extension.
@@ -265,16 +253,6 @@ def save_widget():
265253

266254
self.add_crop_sliders()
267255

268-
def remove_from_viewer(self):
269-
"""Can be re-implemented in children classes"""
270-
if len(self.docked_widgets) != 0:
271-
[
272-
self._viewer.window.remove_dock_widget(w)
273-
for w in self.docked_widgets
274-
]
275-
276-
self._viewer.window.remove_dock_widget(self)
277-
278256
def add_crop_sliders(
279257
self,
280258
): # TODO fix OOB behaviour (check if <0 or >max_size ?)

src/napari_cellseg_annotator/plugin_helper.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,14 @@
66

77
# local
88
from napari_cellseg_annotator import interface as ui
9-
from napari_cellseg_annotator import utils
109

1110

1211
class Helper(QWidget):
1312
# widget testing
1413
def __init__(self, viewer: "napari.viewer.Viewer"):
1514
super().__init__()
1615
# self.master = parent
17-
self.help_url = (
18-
"https://github.com/C-Achard/cellseg-annotator-test/tree/main"
19-
)
16+
self.help_url = "https://c-achard.github.io/cellseg-annotator-test/" # "https://github.com/C-Achard/cellseg-annotator-test/tree/main"
2017

2118
self.about_url = "https://wysscenter.ch/advances/3d-computer-vision-for-brain-analysis"
2219
self._viewer = viewer
@@ -26,14 +23,14 @@ def __init__(self, viewer: "napari.viewer.Viewer"):
2623
self.btn2 = ui.make_button(
2724
"About...", lambda: ui.open_url(self.about_url)
2825
)
29-
self.btnc = ui.make_button("Close", self.close)
26+
self.btnc = ui.make_button("Close", self.remove_from_viewer)
3027

3128
###################
3229
###################
3330
###################
3431
###################
3532
# TODO test remove later
36-
self.test = utils.ENABLE_TEST_MODE()
33+
self.test = False # utils.ENABLE_TEST_MODE()
3734

3835
if self.test:
3936
self.dock = None

src/napari_cellseg_annotator/plugin_metrics.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33

44
class MetricsUtils(BasePluginFolder):
5-
def __init__(self, viewer: "napari.viewer.Viewer"):
5+
def __init__(self, viewer: "napari.viewer.Viewer", parent):
66

7-
super().__init__(viewer)
7+
super().__init__(viewer, parent)
88

99
self._viewer = viewer
1010

src/napari_cellseg_annotator/plugin_utilities.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,24 @@
1111
class Utilities(QTabWidget):
1212
def __init__(self, viewer: "napari.viewer.Viewer"):
1313

14-
super().__init__(viewer)
14+
super().__init__()
1515

1616
self._viewer = viewer
1717

18-
self.cropping_tab = Cropping(viewer)
19-
self.metrics_tab = MetricsUtils(viewer)
20-
self.convert_tab = ConvertUtils(viewer)
18+
self.cropping_tab = Cropping(viewer, parent=self)
19+
self.metrics_tab = MetricsUtils(viewer, parent=self)
20+
self.convert_tab = ConvertUtils(viewer, parent=self)
2121

2222
self.build()
2323

2424
def build(self):
2525

26-
self.addTab(self.cropping_tab, "Crop")
27-
self.addTab(self.metrics_tab, "Metrics")
2826
self.addTab(self.convert_tab, "Convert")
27+
# self.addTab(self.metrics_tab, "Metrics")
28+
self.addTab(self.cropping_tab, "Crop")
29+
30+
self.setBaseSize(220, 150)
31+
self.setMinimumSize(220, 100)
32+
33+
def remove_from_viewer(self):
34+
self._viewer.window.remove_dock_widget(self)

0 commit comments

Comments
 (0)