napari-tapenade-processing 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- napari_tapenade_processing/__init__.py +7 -0
- napari_tapenade_processing/_custom_widgets.py +99 -0
- napari_tapenade_processing/_macro_recorder.py +99 -0
- napari_tapenade_processing/_widget.py +1775 -0
- napari_tapenade_processing/napari.yaml +15 -0
- napari_tapenade_processing-0.0.1.dist-info/LICENSE +22 -0
- napari_tapenade_processing-0.0.1.dist-info/METADATA +151 -0
- napari_tapenade_processing-0.0.1.dist-info/RECORD +11 -0
- napari_tapenade_processing-0.0.1.dist-info/WHEEL +5 -0
- napari_tapenade_processing-0.0.1.dist-info/entry_points.txt +2 -0
- napari_tapenade_processing-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from qtpy.QtCore import Qt
|
|
2
|
+
from qtpy.QtWidgets import (
|
|
3
|
+
QHBoxLayout,
|
|
4
|
+
QLabel,
|
|
5
|
+
QPushButton,
|
|
6
|
+
QScrollArea,
|
|
7
|
+
QSizePolicy,
|
|
8
|
+
QStackedWidget,
|
|
9
|
+
QVBoxLayout,
|
|
10
|
+
QWidget,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MultiLineTabWidget(QWidget):
|
|
15
|
+
def __init__(self):
|
|
16
|
+
super().__init__()
|
|
17
|
+
self.initUI()
|
|
18
|
+
|
|
19
|
+
def initUI(self):
|
|
20
|
+
self.layout = QVBoxLayout()
|
|
21
|
+
self.tabBarLayout = QVBoxLayout()
|
|
22
|
+
|
|
23
|
+
self.scrollArea = QScrollArea()
|
|
24
|
+
self.scrollArea.setWidgetResizable(True)
|
|
25
|
+
self.tabContainer = QWidget()
|
|
26
|
+
self.tabContainer.setLayout(self.tabBarLayout)
|
|
27
|
+
self.scrollArea.setWidget(self.tabContainer)
|
|
28
|
+
|
|
29
|
+
self.layout.addWidget(self.scrollArea)
|
|
30
|
+
|
|
31
|
+
self.stackedWidget = QStackedWidget()
|
|
32
|
+
self.layout.addWidget(self.stackedWidget)
|
|
33
|
+
|
|
34
|
+
self.setLayout(self.layout)
|
|
35
|
+
|
|
36
|
+
self.tabs = []
|
|
37
|
+
|
|
38
|
+
def addTab(self, widget, title):
|
|
39
|
+
tabButton = QPushButton(title)
|
|
40
|
+
tabButton.setCheckable(True)
|
|
41
|
+
tabButton.clicked.connect(lambda: self.onTabClicked(tabButton))
|
|
42
|
+
|
|
43
|
+
tabRowLayout = None
|
|
44
|
+
if len(self.tabs) % 3 == 0:
|
|
45
|
+
tabRowLayout = QHBoxLayout()
|
|
46
|
+
self.tabBarLayout.addLayout(tabRowLayout)
|
|
47
|
+
else:
|
|
48
|
+
tabRowLayout = self.tabBarLayout.itemAt(
|
|
49
|
+
self.tabBarLayout.count() - 1
|
|
50
|
+
).layout()
|
|
51
|
+
|
|
52
|
+
tabRowLayout.addWidget(tabButton)
|
|
53
|
+
self.tabs.append(tabButton)
|
|
54
|
+
|
|
55
|
+
self.stackedWidget.addWidget(widget)
|
|
56
|
+
|
|
57
|
+
def onTabClicked(self, tabButton):
|
|
58
|
+
for i, btn in enumerate(self.tabs):
|
|
59
|
+
if btn == tabButton:
|
|
60
|
+
self.stackedWidget.setCurrentIndex(i)
|
|
61
|
+
btn.setChecked(True)
|
|
62
|
+
else:
|
|
63
|
+
btn.setChecked(False)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class RichTextPushButton(QPushButton):
|
|
67
|
+
def __init__(self, parent=None, text=None):
|
|
68
|
+
if parent is not None:
|
|
69
|
+
super().__init__(parent)
|
|
70
|
+
else:
|
|
71
|
+
super().__init__()
|
|
72
|
+
self.__lbl = QLabel(self)
|
|
73
|
+
if text is not None:
|
|
74
|
+
self.__lbl.setText(text)
|
|
75
|
+
self.__lyt = QHBoxLayout()
|
|
76
|
+
self.__lyt.setContentsMargins(0, 0, 0, 0)
|
|
77
|
+
self.__lyt.setSpacing(0)
|
|
78
|
+
self.setLayout(self.__lyt)
|
|
79
|
+
self.__lbl.setAttribute(Qt.WA_TranslucentBackground)
|
|
80
|
+
self.__lbl.setAttribute(Qt.WA_TransparentForMouseEvents)
|
|
81
|
+
self.__lbl.setSizePolicy(
|
|
82
|
+
QSizePolicy.Expanding,
|
|
83
|
+
QSizePolicy.Expanding,
|
|
84
|
+
)
|
|
85
|
+
self.__lbl.setTextFormat(Qt.RichText)
|
|
86
|
+
self.__lyt.addWidget(self.__lbl)
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
def setText(self, text):
|
|
90
|
+
self.__lbl.setText(text)
|
|
91
|
+
self.updateGeometry()
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
def sizeHint(self):
|
|
95
|
+
s = QPushButton.sizeHint(self)
|
|
96
|
+
w = self.__lbl.sizeHint()
|
|
97
|
+
s.setWidth(w.width())
|
|
98
|
+
s.setHeight(w.height())
|
|
99
|
+
return s
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
from collections import OrderedDict
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MacroRecorder:
|
|
8
|
+
def __init__(self, adjective_dict):
|
|
9
|
+
self._is_recording_parameters = False
|
|
10
|
+
self._record_parameters_list = []
|
|
11
|
+
|
|
12
|
+
# key: napari name, value: standardized name
|
|
13
|
+
self._record_data_dict = {
|
|
14
|
+
"mask": {},
|
|
15
|
+
"image": {},
|
|
16
|
+
"labels": {},
|
|
17
|
+
"tracks": {},
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
self._adjective_dict = adjective_dict
|
|
21
|
+
|
|
22
|
+
def _reset_recording(self):
|
|
23
|
+
for k in self._record_data_dict.keys():
|
|
24
|
+
self._record_data_dict[k] = {}
|
|
25
|
+
self._record_parameters_list = []
|
|
26
|
+
|
|
27
|
+
def dump_recorded_parameters(self, path: str):
|
|
28
|
+
date = (
|
|
29
|
+
str(datetime.now())
|
|
30
|
+
.split(".")[:-1][0]
|
|
31
|
+
.replace(" ", "_")
|
|
32
|
+
.replace(":", "-")
|
|
33
|
+
)
|
|
34
|
+
filename = f"recorded_parameters_{date}.json"
|
|
35
|
+
|
|
36
|
+
with open(os.path.join(path, filename), "w") as f:
|
|
37
|
+
json.dump(self._record_parameters_list, f)
|
|
38
|
+
|
|
39
|
+
self._reset_recording()
|
|
40
|
+
|
|
41
|
+
def record(
|
|
42
|
+
self,
|
|
43
|
+
function_name: str,
|
|
44
|
+
layers_names_in: dict,
|
|
45
|
+
layers_names_out: dict,
|
|
46
|
+
func_params: dict,
|
|
47
|
+
overwrite: bool,
|
|
48
|
+
):
|
|
49
|
+
"""
|
|
50
|
+
layer_names are dicts that map layer_type (e.g 'mask', 'image'...) to
|
|
51
|
+
the names of the layers in the viewer
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
dict_in = dict()
|
|
55
|
+
dict_out = OrderedDict()
|
|
56
|
+
|
|
57
|
+
for layer_type in ["mask", "image", "labels", "tracks"]:
|
|
58
|
+
# building dict_in
|
|
59
|
+
layer_in = None
|
|
60
|
+
if layer_type in layers_names_in:
|
|
61
|
+
layer_name_in = layers_names_in[layer_type]
|
|
62
|
+
|
|
63
|
+
if layer_name_in is not None:
|
|
64
|
+
layer_in = self._record_data_dict[layer_type].get(
|
|
65
|
+
layer_name_in, layer_type
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
dict_in[layer_type] = layer_in
|
|
69
|
+
# building dict_out
|
|
70
|
+
if layer_type in layers_names_out:
|
|
71
|
+
layer_name_out = layers_names_out[layer_type]
|
|
72
|
+
|
|
73
|
+
if layer_name_out is not None:
|
|
74
|
+
if overwrite and layer_in is not None:
|
|
75
|
+
layer_out = layer_in
|
|
76
|
+
elif layer_in is not None:
|
|
77
|
+
adjective = self._adjective_dict[function_name]
|
|
78
|
+
layer_out = f"{layer_in}_{adjective}"
|
|
79
|
+
self._record_data_dict[layer_type][
|
|
80
|
+
layer_name_out
|
|
81
|
+
] = layer_out
|
|
82
|
+
else:
|
|
83
|
+
layer_out = layer_type
|
|
84
|
+
self._record_data_dict[layer_type][
|
|
85
|
+
layer_name_out
|
|
86
|
+
] = layer_out
|
|
87
|
+
else:
|
|
88
|
+
layer_out = None
|
|
89
|
+
|
|
90
|
+
dict_out[layer_type] = layer_out
|
|
91
|
+
|
|
92
|
+
params = {
|
|
93
|
+
"function": function_name,
|
|
94
|
+
"in": dict_in,
|
|
95
|
+
"out": dict_out,
|
|
96
|
+
"func_params": func_params,
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
self._record_parameters_list.append(params)
|