celldetective 1.3.9.post5__py3-none-any.whl → 1.4.0__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.
- celldetective/__init__.py +0 -3
- celldetective/_version.py +1 -1
- celldetective/events.py +2 -4
- celldetective/extra_properties.py +132 -0
- celldetective/gui/InitWindow.py +33 -45
- celldetective/gui/__init__.py +1 -0
- celldetective/gui/about.py +19 -15
- celldetective/gui/analyze_block.py +34 -19
- celldetective/gui/base_components.py +23 -0
- celldetective/gui/btrack_options.py +26 -34
- celldetective/gui/classifier_widget.py +68 -81
- celldetective/gui/configure_new_exp.py +113 -17
- celldetective/gui/control_panel.py +68 -141
- celldetective/gui/generic_signal_plot.py +9 -12
- celldetective/gui/gui_utils.py +49 -21
- celldetective/gui/json_readers.py +5 -4
- celldetective/gui/layouts.py +246 -22
- celldetective/gui/measurement_options.py +32 -17
- celldetective/gui/neighborhood_options.py +10 -13
- celldetective/gui/plot_measurements.py +21 -17
- celldetective/gui/plot_signals_ui.py +125 -72
- celldetective/gui/process_block.py +180 -123
- celldetective/gui/processes/compute_neighborhood.py +594 -0
- celldetective/gui/processes/measure_cells.py +5 -0
- celldetective/gui/processes/segment_cells.py +27 -6
- celldetective/gui/processes/track_cells.py +6 -0
- celldetective/gui/retrain_segmentation_model_options.py +12 -20
- celldetective/gui/retrain_signal_model_options.py +57 -56
- celldetective/gui/seg_model_loader.py +21 -62
- celldetective/gui/signal_annotator.py +129 -70
- celldetective/gui/signal_annotator2.py +431 -635
- celldetective/gui/signal_annotator_options.py +8 -11
- celldetective/gui/survival_ui.py +49 -95
- celldetective/gui/tableUI.py +28 -25
- celldetective/gui/thresholds_gui.py +617 -1221
- celldetective/gui/viewers.py +106 -39
- celldetective/gui/workers.py +9 -3
- celldetective/io.py +57 -20
- celldetective/measure.py +63 -27
- celldetective/neighborhood.py +342 -268
- celldetective/preprocessing.py +25 -17
- celldetective/relative_measurements.py +50 -29
- celldetective/scripts/analyze_signals.py +4 -1
- celldetective/scripts/measure_relative.py +4 -1
- celldetective/scripts/segment_cells.py +0 -6
- celldetective/scripts/track_cells.py +3 -1
- celldetective/scripts/train_segmentation_model.py +7 -4
- celldetective/signals.py +29 -14
- celldetective/tracking.py +7 -2
- celldetective/utils.py +36 -8
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/METADATA +24 -16
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/RECORD +57 -55
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/WHEEL +1 -1
- tests/test_qt.py +21 -21
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info/licenses}/LICENSE +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/top_level.txt +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import QRadioButton, QButtonGroup,
|
|
1
|
+
from PyQt5.QtWidgets import QRadioButton, QButtonGroup, QApplication, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QTextEdit, QLineEdit, QVBoxLayout, QLabel, QHBoxLayout, QPushButton
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
3
|
from PyQt5.QtGui import QDoubleValidator
|
|
4
4
|
|
|
5
5
|
from celldetective.gui.gui_utils import center_window, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, help_generic
|
|
6
|
-
from superqt import QLabeledDoubleSlider,QLabeledSlider
|
|
6
|
+
from superqt import QLabeledDoubleSlider, QLabeledSlider
|
|
7
7
|
from superqt.fonticon import icon
|
|
8
8
|
from fonticon_mdi6 import MDI6
|
|
9
9
|
from celldetective.utils import extract_experiment_channels, get_software_location
|
|
@@ -16,9 +16,10 @@ import os
|
|
|
16
16
|
import matplotlib.pyplot as plt
|
|
17
17
|
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
|
18
18
|
from glob import glob
|
|
19
|
-
from celldetective.gui import
|
|
19
|
+
from celldetective.gui import CelldetectiveWidget, CelldetectiveMainWindow
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
class ConfigTracking(CelldetectiveMainWindow):
|
|
22
23
|
|
|
23
24
|
"""
|
|
24
25
|
UI to set tracking parameters for bTrack.
|
|
@@ -34,15 +35,10 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
34
35
|
self.exp_dir = self.parent_window.exp_dir
|
|
35
36
|
self.floatValidator = QDoubleValidator()
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
self.track_instructions_write_path = self.parent_window.exp_dir + os.sep.join(["configs","tracking_instructions_targets.json"])
|
|
40
|
-
elif self.mode=="effectors":
|
|
41
|
-
self.config_name = os.sep.join(["configs","btrack_config_effectors.json"])
|
|
42
|
-
self.track_instructions_write_path = self.parent_window.exp_dir + os.sep.join(["configs", "tracking_instructions_effectors.json"])
|
|
38
|
+
self.config_name = os.sep.join(["configs", f"btrack_config_{self.mode}.json"])
|
|
39
|
+
self.track_instructions_write_path = self.parent_window.exp_dir + os.sep.join(["configs", f"tracking_instructions_{self.mode}.json"])
|
|
43
40
|
self.soft_path = get_software_location()
|
|
44
41
|
|
|
45
|
-
exp_config = self.exp_dir +"config.ini"
|
|
46
42
|
self.config_path = self.exp_dir + self.config_name
|
|
47
43
|
self.channel_names, self.channels = extract_experiment_channels(self.exp_dir)
|
|
48
44
|
self.channel_names = np.array(self.channel_names)
|
|
@@ -66,10 +62,10 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
66
62
|
|
|
67
63
|
# Create button widget and layout
|
|
68
64
|
self.scroll_area = QScrollArea(self)
|
|
69
|
-
self.button_widget =
|
|
65
|
+
self.button_widget = CelldetectiveWidget()
|
|
70
66
|
main_layout = QVBoxLayout()
|
|
71
67
|
self.button_widget.setLayout(main_layout)
|
|
72
|
-
main_layout.setContentsMargins(30,30,30,30)
|
|
68
|
+
main_layout.setContentsMargins(30, 30, 30, 30)
|
|
73
69
|
|
|
74
70
|
# First collapsable Frame CONFIG
|
|
75
71
|
|
|
@@ -86,7 +82,7 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
86
82
|
self.populate_config_frame()
|
|
87
83
|
|
|
88
84
|
tracker_hbox = QHBoxLayout()
|
|
89
|
-
tracker_hbox.setContentsMargins(15,15,15,15)
|
|
85
|
+
tracker_hbox.setContentsMargins(15, 15, 15, 15)
|
|
90
86
|
tracker_hbox.addWidget(self.btrack_option, 50, alignment=Qt.AlignCenter)
|
|
91
87
|
tracker_hbox.addWidget(self.trackpy_option, 50, alignment=Qt.AlignCenter)
|
|
92
88
|
main_layout.addLayout(tracker_hbox)
|
|
@@ -149,7 +145,6 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
149
145
|
#self.scroll_area.setMinimumHeight(self.minimum_height)
|
|
150
146
|
#self.adjustSize()
|
|
151
147
|
|
|
152
|
-
|
|
153
148
|
def populate_post_proc_frame(self):
|
|
154
149
|
|
|
155
150
|
"""
|
|
@@ -172,13 +167,13 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
172
167
|
title_hbox = QHBoxLayout()
|
|
173
168
|
|
|
174
169
|
self.collapse_post_proc_btn = QPushButton()
|
|
175
|
-
self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_down,color="black"))
|
|
170
|
+
self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_down, color="black"))
|
|
176
171
|
self.collapse_post_proc_btn.setIconSize(QSize(20, 20))
|
|
177
172
|
self.collapse_post_proc_btn.setStyleSheet(self.button_select_all)
|
|
178
173
|
#grid.addWidget(self.collapse_post_proc_btn, 0, 0, 1, 4, alignment=Qt.AlignRight)
|
|
179
174
|
|
|
180
175
|
self.help_post_btn = QPushButton()
|
|
181
|
-
self.help_post_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
|
|
176
|
+
self.help_post_btn.setIcon(icon(MDI6.help_circle, color=self.help_color))
|
|
182
177
|
self.help_post_btn.setIconSize(QSize(20, 20))
|
|
183
178
|
self.help_post_btn.clicked.connect(self.help_post)
|
|
184
179
|
self.help_post_btn.setStyleSheet(self.button_select_all)
|
|
@@ -188,7 +183,7 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
188
183
|
title_hbox.addWidget(QLabel(), 85, alignment=Qt.AlignCenter)
|
|
189
184
|
title_hbox.addWidget(self.help_post_btn, 5)
|
|
190
185
|
title_hbox.addWidget(self.collapse_post_proc_btn, 5)
|
|
191
|
-
grid.addLayout(title_hbox, 0,0,1,4)
|
|
186
|
+
grid.addLayout(title_hbox, 0, 0, 1, 4)
|
|
192
187
|
|
|
193
188
|
self.generate_post_proc_panel_contents()
|
|
194
189
|
grid.addWidget(self.ContentsPostProc, 1, 0, 1, 4, alignment=Qt.AlignTop)
|
|
@@ -205,13 +200,13 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
205
200
|
is_open = np.array([features_open, config_open, post_open])
|
|
206
201
|
|
|
207
202
|
if self.ContentsPostProc.isHidden():
|
|
208
|
-
self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_down,color="black"))
|
|
203
|
+
self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_down, color="black"))
|
|
209
204
|
self.collapse_post_proc_btn.setIconSize(QSize(20, 20))
|
|
210
205
|
if len(is_open[is_open])==0:
|
|
211
206
|
self.scroll_area.setMinimumHeight(int(self.minimum_height))
|
|
212
207
|
self.adjustSize()
|
|
213
208
|
else:
|
|
214
|
-
self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_up,color="black"))
|
|
209
|
+
self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_up, color="black"))
|
|
215
210
|
self.collapse_post_proc_btn.setIconSize(QSize(20, 20))
|
|
216
211
|
self.scroll_area.setMinimumHeight(min(int(930), int(0.9*self.screen_height)))
|
|
217
212
|
|
|
@@ -222,7 +217,7 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
222
217
|
Helper for track post-processing strategy.
|
|
223
218
|
"""
|
|
224
219
|
|
|
225
|
-
dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','track-postprocessing.json'])
|
|
220
|
+
dict_path = os.sep.join([get_software_location(), 'celldetective', 'gui', 'help', 'track-postprocessing.json'])
|
|
226
221
|
|
|
227
222
|
with open(dict_path) as f:
|
|
228
223
|
d = json.load(f)
|
|
@@ -246,7 +241,7 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
246
241
|
Helper for track post-processing strategy.
|
|
247
242
|
"""
|
|
248
243
|
|
|
249
|
-
dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','feature-btrack.json'])
|
|
244
|
+
dict_path = os.sep.join([get_software_location(), 'celldetective', 'gui', 'help', 'feature-btrack.json'])
|
|
250
245
|
|
|
251
246
|
with open(dict_path) as f:
|
|
252
247
|
d = json.load(f)
|
|
@@ -300,7 +295,7 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
300
295
|
title_hbox.addWidget(QLabel(), 85, alignment=Qt.AlignCenter)
|
|
301
296
|
title_hbox.addWidget(self.help_feature_btn, 5)
|
|
302
297
|
title_hbox.addWidget(self.collapse_features_btn, 5)
|
|
303
|
-
grid.addLayout(title_hbox, 0,0,1,4)
|
|
298
|
+
grid.addLayout(title_hbox, 0, 0, 1, 4)
|
|
304
299
|
|
|
305
300
|
self.generate_feature_panel_contents()
|
|
306
301
|
grid.addWidget(self.ContentsFeatures, 1, 0, 1, 4, alignment=Qt.AlignTop)
|
|
@@ -321,13 +316,13 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
321
316
|
is_open = np.array([features_open, config_open, post_open])
|
|
322
317
|
|
|
323
318
|
if self.ContentsFeatures.isHidden():
|
|
324
|
-
self.collapse_features_btn.setIcon(icon(MDI6.chevron_down,color="black"))
|
|
319
|
+
self.collapse_features_btn.setIcon(icon(MDI6.chevron_down, color="black"))
|
|
325
320
|
self.collapse_features_btn.setIconSize(QSize(20, 20))
|
|
326
321
|
if len(is_open[is_open])==0:
|
|
327
322
|
self.scroll_area.setMinimumHeight(int(self.minimum_height))
|
|
328
323
|
self.adjustSize()
|
|
329
324
|
else:
|
|
330
|
-
self.collapse_features_btn.setIcon(icon(MDI6.chevron_up,color="black"))
|
|
325
|
+
self.collapse_features_btn.setIcon(icon(MDI6.chevron_up, color="black"))
|
|
331
326
|
self.collapse_features_btn.setIconSize(QSize(20, 20))
|
|
332
327
|
self.scroll_area.setMinimumHeight(min(int(930), int(0.9*self.screen_height)))
|
|
333
328
|
|
|
@@ -351,7 +346,7 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
351
346
|
self.min_tracklength_slider.setSingleStep(1)
|
|
352
347
|
self.min_tracklength_slider.setTickInterval(1)
|
|
353
348
|
self.min_tracklength_slider.setSingleStep(1)
|
|
354
|
-
self.min_tracklength_slider.setOrientation(
|
|
349
|
+
self.min_tracklength_slider.setOrientation(Qt.Horizontal)
|
|
355
350
|
self.min_tracklength_slider.setRange(0,self.parent_window.parent_window.len_movie)
|
|
356
351
|
self.min_tracklength_slider.setValue(0)
|
|
357
352
|
tracklength_layout.addWidget(QLabel('Min. tracklength: '),40)
|
|
@@ -391,7 +386,6 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
391
386
|
|
|
392
387
|
layout.addLayout(clean_traj_sublayout)
|
|
393
388
|
|
|
394
|
-
|
|
395
389
|
def generate_feature_panel_contents(self):
|
|
396
390
|
|
|
397
391
|
self.ContentsFeatures = QFrame()
|
|
@@ -456,10 +450,9 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
456
450
|
|
|
457
451
|
# Slider to set vmin & vmax
|
|
458
452
|
self.haralick_scale_slider = QLabeledDoubleSlider()
|
|
459
|
-
self.haralick_scale_slider.setSingleStep(0.05)
|
|
460
453
|
self.haralick_scale_slider.setTickInterval(0.05)
|
|
461
454
|
self.haralick_scale_slider.setSingleStep(1)
|
|
462
|
-
self.haralick_scale_slider.setOrientation(
|
|
455
|
+
self.haralick_scale_slider.setOrientation(Qt.Horizontal)
|
|
463
456
|
self.haralick_scale_slider.setRange(0,1)
|
|
464
457
|
self.haralick_scale_slider.setValue(0.5)
|
|
465
458
|
self.haralick_scale_lbl = QLabel('Scale: ')
|
|
@@ -671,7 +664,7 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
671
664
|
self.memory_slider.setSingleStep(1)
|
|
672
665
|
self.memory_slider.setTickInterval(1)
|
|
673
666
|
self.memory_slider.setSingleStep(1)
|
|
674
|
-
self.memory_slider.setOrientation(
|
|
667
|
+
self.memory_slider.setOrientation(Qt.Horizontal)
|
|
675
668
|
self.memory_slider.setRange(0,self.parent_window.parent_window.len_movie)
|
|
676
669
|
self.memory_slider.setValue(0)
|
|
677
670
|
memory_layout.addWidget(self.memory_lbl, 30)
|
|
@@ -745,7 +738,7 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
745
738
|
copyfile(self.filename, self.config_path)
|
|
746
739
|
self.load_cell_config()
|
|
747
740
|
except Exception as e:
|
|
748
|
-
print(e
|
|
741
|
+
print(e)
|
|
749
742
|
return None
|
|
750
743
|
|
|
751
744
|
def reset_btrack_config(self):
|
|
@@ -994,7 +987,7 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
994
987
|
if 'search_range' in tracking_instructions:
|
|
995
988
|
search_range = tracking_instructions['search_range']
|
|
996
989
|
if search_range is not None:
|
|
997
|
-
self.search_range_le.setText(str(search_range).replace('.',','))
|
|
990
|
+
self.search_range_le.setText(str(search_range).replace('.', ','))
|
|
998
991
|
if 'memory' in tracking_instructions:
|
|
999
992
|
memory = tracking_instructions['memory']
|
|
1000
993
|
if memory is not None:
|
|
@@ -1072,7 +1065,7 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
1072
1065
|
Load the first frame of the first movie found in the experiment folder as a sample.
|
|
1073
1066
|
"""
|
|
1074
1067
|
|
|
1075
|
-
movies = glob(self.parent_window.parent_window.exp_dir + os.sep.join(["*","*","movie",self.parent_window.parent_window.movie_prefix+"*.tif"]))
|
|
1068
|
+
movies = glob(self.parent_window.parent_window.exp_dir + os.sep.join(["*", "*", "movie", self.parent_window.parent_window.movie_prefix+"*.tif"]))
|
|
1076
1069
|
if len(movies)==0:
|
|
1077
1070
|
msgBox = QMessageBox()
|
|
1078
1071
|
msgBox.setIcon(QMessageBox.Warning)
|
|
@@ -1088,7 +1081,6 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
1088
1081
|
n_channels = len(self.channels)
|
|
1089
1082
|
self.test_frame = load_frames(np.arange(n_channels), stack0, scale=None, normalize_input=False)
|
|
1090
1083
|
|
|
1091
|
-
|
|
1092
1084
|
def control_haralick_digitalization(self):
|
|
1093
1085
|
|
|
1094
1086
|
"""
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import
|
|
1
|
+
from PyQt5.QtWidgets import QLineEdit, QMessageBox, QHBoxLayout, QVBoxLayout, QPushButton, QLabel, \
|
|
2
2
|
QCheckBox, QRadioButton, QButtonGroup, QComboBox
|
|
3
3
|
from PyQt5.QtCore import Qt, QSize
|
|
4
|
-
from superqt import QLabeledSlider,QLabeledDoubleSlider, QSearchableComboBox
|
|
4
|
+
from superqt import QLabeledSlider, QLabeledDoubleSlider, QSearchableComboBox
|
|
5
5
|
from superqt.fonticon import icon
|
|
6
6
|
from fonticon_mdi6 import MDI6
|
|
7
7
|
|
|
@@ -11,11 +11,11 @@ import matplotlib.pyplot as plt
|
|
|
11
11
|
import json
|
|
12
12
|
|
|
13
13
|
from celldetective.gui.gui_utils import FigureCanvas, center_window, color_from_status, help_generic
|
|
14
|
-
from celldetective.gui import
|
|
14
|
+
from celldetective.gui.base_components import CelldetectiveWidget
|
|
15
15
|
from celldetective.utils import get_software_location
|
|
16
16
|
from celldetective.measure import classify_cells_from_query, interpret_track_classification
|
|
17
17
|
|
|
18
|
-
class ClassifierWidget(
|
|
18
|
+
class ClassifierWidget(CelldetectiveWidget):
|
|
19
19
|
|
|
20
20
|
def __init__(self, parent_window):
|
|
21
21
|
|
|
@@ -33,7 +33,7 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
33
33
|
|
|
34
34
|
is_number = np.vectorize(lambda x: np.issubdtype(x, np.number))
|
|
35
35
|
is_number_test = is_number(self.df.dtypes)
|
|
36
|
-
self.cols = [col for t,col in zip(is_number_test,self.df.columns) if t]
|
|
36
|
+
self.cols = [col for t, col in zip(is_number_test, self.df.columns) if t]
|
|
37
37
|
|
|
38
38
|
self.class_name = 'custom'
|
|
39
39
|
self.name_le = QLineEdit(self.class_name)
|
|
@@ -44,7 +44,7 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
layout = QVBoxLayout(self)
|
|
47
|
-
layout.setContentsMargins(30,30,30,30)
|
|
47
|
+
layout.setContentsMargins(30, 30, 30, 30)
|
|
48
48
|
|
|
49
49
|
name_layout = QHBoxLayout()
|
|
50
50
|
name_layout.addWidget(QLabel('class name: '), 33)
|
|
@@ -55,7 +55,7 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
55
55
|
fig_btn_hbox.addWidget(QLabel(''), 95)
|
|
56
56
|
self.project_times_btn = QPushButton('')
|
|
57
57
|
self.project_times_btn.setStyleSheet(self.parent_window.parent_window.parent_window.button_select_all)
|
|
58
|
-
self.project_times_btn.setIcon(icon(MDI6.math_integral,color="black"))
|
|
58
|
+
self.project_times_btn.setIcon(icon(MDI6.math_integral, color="black"))
|
|
59
59
|
self.project_times_btn.setToolTip("Project measurements at all times.")
|
|
60
60
|
self.project_times_btn.setIconSize(QSize(20, 20))
|
|
61
61
|
self.project_times = False
|
|
@@ -70,8 +70,8 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
70
70
|
# slider
|
|
71
71
|
self.frame_slider = QLabeledSlider()
|
|
72
72
|
self.frame_slider.setSingleStep(1)
|
|
73
|
-
self.frame_slider.setOrientation(
|
|
74
|
-
self.frame_slider.setRange(0,int(self.df.FRAME.max()) - 1)
|
|
73
|
+
self.frame_slider.setOrientation(Qt.Horizontal)
|
|
74
|
+
self.frame_slider.setRange(0, int(self.df.FRAME.max()) - 1)
|
|
75
75
|
self.frame_slider.setValue(0)
|
|
76
76
|
self.currentFrame = 0
|
|
77
77
|
|
|
@@ -84,8 +84,8 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
84
84
|
# transparency slider
|
|
85
85
|
self.alpha_slider = QLabeledDoubleSlider()
|
|
86
86
|
self.alpha_slider.setSingleStep(0.001)
|
|
87
|
-
self.alpha_slider.setOrientation(
|
|
88
|
-
self.alpha_slider.setRange(0,1)
|
|
87
|
+
self.alpha_slider.setOrientation(Qt.Horizontal)
|
|
88
|
+
self.alpha_slider.setRange(0, 1)
|
|
89
89
|
self.alpha_slider.setValue(1.0)
|
|
90
90
|
self.alpha_slider.setDecimals(3)
|
|
91
91
|
|
|
@@ -95,8 +95,8 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
95
95
|
layout.addLayout(slider_alpha_hbox)
|
|
96
96
|
|
|
97
97
|
|
|
98
|
-
self.features_cb = [QSearchableComboBox() for
|
|
99
|
-
self.log_btns = [QPushButton() for
|
|
98
|
+
self.features_cb = [QSearchableComboBox() for _ in range(2)]
|
|
99
|
+
self.log_btns = [QPushButton() for _ in range(2)]
|
|
100
100
|
|
|
101
101
|
for i in range(2):
|
|
102
102
|
hbox_feat = QHBoxLayout()
|
|
@@ -106,7 +106,7 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
106
106
|
layout.addLayout(hbox_feat)
|
|
107
107
|
|
|
108
108
|
self.features_cb[i].clear()
|
|
109
|
-
self.features_cb[i].addItems(sorted(list(self.cols),key=str.lower))
|
|
109
|
+
self.features_cb[i].addItems(sorted(list(self.cols), key=str.lower))
|
|
110
110
|
self.features_cb[i].currentTextChanged.connect(self.update_props_scatter)
|
|
111
111
|
self.features_cb[i].setCurrentIndex(i)
|
|
112
112
|
|
|
@@ -134,15 +134,15 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
134
134
|
self.time_corr.setEnabled(False)
|
|
135
135
|
|
|
136
136
|
time_prop_hbox = QHBoxLayout()
|
|
137
|
-
time_prop_hbox.addWidget(self.time_corr,alignment=Qt.AlignCenter)
|
|
137
|
+
time_prop_hbox.addWidget(self.time_corr, alignment=Qt.AlignCenter)
|
|
138
138
|
|
|
139
139
|
self.help_propagate_btn = QPushButton()
|
|
140
|
-
self.help_propagate_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
|
|
140
|
+
self.help_propagate_btn.setIcon(icon(MDI6.help_circle, color=self.help_color))
|
|
141
141
|
self.help_propagate_btn.setIconSize(QSize(20, 20))
|
|
142
142
|
self.help_propagate_btn.clicked.connect(self.help_propagate)
|
|
143
143
|
self.help_propagate_btn.setStyleSheet(self.button_select_all)
|
|
144
144
|
self.help_propagate_btn.setToolTip("Help.")
|
|
145
|
-
time_prop_hbox.addWidget(self.help_propagate_btn,5,alignment=Qt.AlignRight)
|
|
145
|
+
time_prop_hbox.addWidget(self.help_propagate_btn, 5, alignment=Qt.AlignRight)
|
|
146
146
|
|
|
147
147
|
layout.addLayout(time_prop_hbox)
|
|
148
148
|
|
|
@@ -154,23 +154,23 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
154
154
|
|
|
155
155
|
time_corr_layout = QHBoxLayout()
|
|
156
156
|
time_corr_layout.addWidget(self.unique_state_btn, 33, alignment=Qt.AlignCenter)
|
|
157
|
-
time_corr_layout.addWidget(self.irreversible_event_btn, 33,alignment=Qt.AlignCenter)
|
|
158
|
-
time_corr_layout.addWidget(self.transient_event_btn, 33,alignment=Qt.AlignCenter)
|
|
157
|
+
time_corr_layout.addWidget(self.irreversible_event_btn, 33, alignment=Qt.AlignCenter)
|
|
158
|
+
time_corr_layout.addWidget(self.transient_event_btn, 33, alignment=Qt.AlignCenter)
|
|
159
159
|
layout.addLayout(time_corr_layout)
|
|
160
160
|
|
|
161
161
|
self.prereq_event_check = QCheckBox('prerequisite event:')
|
|
162
162
|
self.prereq_event_check.toggled.connect(self.activate_prereq_cb)
|
|
163
163
|
self.prereq_event_cb = QComboBox()
|
|
164
|
-
event_cols = ['--'] + [c.replace('t_','') for c in self.cols if c.startswith('t_')]
|
|
164
|
+
event_cols = ['--'] + [c.replace('t_', '') for c in self.cols if c.startswith('t_')]
|
|
165
165
|
self.prereq_event_cb.addItems(event_cols)
|
|
166
166
|
self.prereq_event_check.setEnabled(False)
|
|
167
167
|
self.prereq_event_cb.setEnabled(False)
|
|
168
168
|
|
|
169
169
|
self.r2_slider = QLabeledDoubleSlider()
|
|
170
170
|
self.r2_slider.setValue(0.75)
|
|
171
|
-
self.r2_slider.setRange(0,1)
|
|
171
|
+
self.r2_slider.setRange(0, 1)
|
|
172
172
|
self.r2_slider.setSingleStep(0.01)
|
|
173
|
-
self.r2_slider.setOrientation(
|
|
173
|
+
self.r2_slider.setOrientation(Qt.Horizontal)
|
|
174
174
|
self.r2_label = QLabel('R2 tolerance:')
|
|
175
175
|
self.r2_label.setToolTip('Minimum R2 between the fit sigmoid and the binary response to the filters to accept the event.')
|
|
176
176
|
|
|
@@ -196,7 +196,7 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
196
196
|
wg.setEnabled(False)
|
|
197
197
|
|
|
198
198
|
prereq_layout = QHBoxLayout()
|
|
199
|
-
prereq_layout.setContentsMargins(30,0,0,0)
|
|
199
|
+
prereq_layout.setContentsMargins(30, 0, 0, 0)
|
|
200
200
|
prereq_layout.addWidget(self.prereq_event_check, 20)
|
|
201
201
|
prereq_layout.addWidget(self.prereq_event_cb, 80)
|
|
202
202
|
layout.addLayout(prereq_layout)
|
|
@@ -212,7 +212,6 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
212
212
|
self.frame_slider.valueChanged.connect(self.set_frame)
|
|
213
213
|
self.alpha_slider.valueChanged.connect(self.set_transparency)
|
|
214
214
|
|
|
215
|
-
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
216
215
|
|
|
217
216
|
def activate_prereq_cb(self):
|
|
218
217
|
if self.prereq_event_check.isChecked():
|
|
@@ -270,11 +269,10 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
270
269
|
Define properties scatter.
|
|
271
270
|
"""
|
|
272
271
|
|
|
273
|
-
self.fig_props, self.ax_props = plt.subplots(figsize=(4,4),tight_layout=True)
|
|
272
|
+
self.fig_props, self.ax_props = plt.subplots(figsize=(4, 4), tight_layout=True)
|
|
274
273
|
self.propscanvas = FigureCanvas(self.fig_props, interactive=True)
|
|
275
274
|
self.fig_props.set_facecolor('none')
|
|
276
|
-
self.
|
|
277
|
-
self.scat_props = self.ax_props.scatter([],[], color="k", alpha=self.currentAlpha)
|
|
275
|
+
self.scat_props = self.ax_props.scatter([], [], color="k", alpha=self.currentAlpha)
|
|
278
276
|
self.propscanvas.canvas.draw_idle()
|
|
279
277
|
self.propscanvas.canvas.setMinimumHeight(self.screen_height//5)
|
|
280
278
|
|
|
@@ -295,25 +293,24 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
295
293
|
self.log_btns[0].setEnabled(True)
|
|
296
294
|
|
|
297
295
|
if np.any(self.df[self.features_cb[1].currentText()].to_numpy() <= 0.):
|
|
298
|
-
if self.ax_props.get_xscale()=='log':
|
|
296
|
+
if self.ax_props.get_xscale() == 'log':
|
|
299
297
|
self.log_btns[1].click()
|
|
300
298
|
self.log_btns[1].setEnabled(False)
|
|
301
299
|
else:
|
|
302
300
|
self.log_btns[1].setEnabled(True)
|
|
303
301
|
except Exception as e:
|
|
304
|
-
|
|
305
|
-
pass
|
|
302
|
+
print(e)
|
|
306
303
|
|
|
307
304
|
class_name = self.class_name
|
|
308
305
|
|
|
309
306
|
try:
|
|
310
307
|
|
|
311
308
|
if not self.project_times:
|
|
312
|
-
self.scat_props.set_offsets(self.df.loc[self.df['FRAME']==self.currentFrame,[self.features_cb[1].currentText(),self.features_cb[0].currentText()]].to_numpy())
|
|
313
|
-
colors = [color_from_status(c) for c in self.df.loc[self.df['FRAME']==self.currentFrame,class_name].to_numpy()]
|
|
309
|
+
self.scat_props.set_offsets(self.df.loc[self.df['FRAME'] == self.currentFrame, [self.features_cb[1].currentText(), self.features_cb[0].currentText()]].to_numpy())
|
|
310
|
+
colors = [color_from_status(c) for c in self.df.loc[self.df['FRAME'] == self.currentFrame, class_name].to_numpy()]
|
|
314
311
|
self.scat_props.set_facecolor(colors)
|
|
315
312
|
else:
|
|
316
|
-
self.scat_props.set_offsets(self.df[[self.features_cb[1].currentText(),self.features_cb[0].currentText()]].to_numpy())
|
|
313
|
+
self.scat_props.set_offsets(self.df[[self.features_cb[1].currentText(), self.features_cb[0].currentText()]].to_numpy())
|
|
317
314
|
colors = [color_from_status(c) for c in self.df[class_name].to_numpy()]
|
|
318
315
|
self.scat_props.set_facecolor(colors)
|
|
319
316
|
|
|
@@ -333,18 +330,18 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
333
330
|
|
|
334
331
|
x_padding = (max_x - min_x) * 0.05
|
|
335
332
|
y_padding = (max_y - min_y) * 0.05
|
|
336
|
-
if x_padding==0:
|
|
333
|
+
if x_padding == 0:
|
|
337
334
|
x_padding = 0.05
|
|
338
|
-
if y_padding==0:
|
|
335
|
+
if y_padding == 0:
|
|
339
336
|
y_padding = 0.05
|
|
340
337
|
|
|
341
|
-
if min_x==min_x and max_x==max_x:
|
|
342
|
-
if self.ax_props.get_xscale()=='linear':
|
|
338
|
+
if min_x == min_x and max_x == max_x:
|
|
339
|
+
if self.ax_props.get_xscale() == 'linear':
|
|
343
340
|
self.ax_props.set_xlim(min_x - x_padding, max_x + x_padding)
|
|
344
341
|
else:
|
|
345
342
|
self.ax_props.set_xlim(min_x, max_x)
|
|
346
|
-
if min_y==min_y and max_y==max_y:
|
|
347
|
-
if self.ax_props.get_yscale()=='linear':
|
|
343
|
+
if min_y == min_y and max_y == max_y:
|
|
344
|
+
if self.ax_props.get_yscale() == 'linear':
|
|
348
345
|
self.ax_props.set_ylim(min_y - y_padding, max_y + y_padding)
|
|
349
346
|
else:
|
|
350
347
|
self.ax_props.set_ylim(min_y, max_y)
|
|
@@ -379,7 +376,7 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
379
376
|
if self.df is None:
|
|
380
377
|
msgBox = QMessageBox()
|
|
381
378
|
msgBox.setIcon(QMessageBox.Warning)
|
|
382
|
-
msgBox.setText(f"The query could not be understood. No filtering was applied.
|
|
379
|
+
msgBox.setText(f"The query could not be understood. No filtering was applied.")
|
|
383
380
|
msgBox.setWindowTitle("Warning")
|
|
384
381
|
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
385
382
|
returnValue = msgBox.exec()
|
|
@@ -390,22 +387,18 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
390
387
|
self.update_props_scatter(feature_changed=False)
|
|
391
388
|
|
|
392
389
|
def set_frame(self, value):
|
|
393
|
-
xlim=self.ax_props.get_xlim()
|
|
394
|
-
ylim=self.ax_props.get_ylim()
|
|
390
|
+
xlim = self.ax_props.get_xlim()
|
|
391
|
+
ylim = self.ax_props.get_ylim()
|
|
395
392
|
self.currentFrame = value
|
|
396
393
|
self.update_props_scatter(feature_changed=False)
|
|
397
394
|
self.ax_props.set_xlim(xlim)
|
|
398
395
|
self.ax_props.set_ylim(ylim)
|
|
399
396
|
|
|
400
|
-
|
|
401
397
|
def set_transparency(self, value):
|
|
402
|
-
xlim=self.ax_props.get_xlim()
|
|
403
|
-
ylim=self.ax_props.get_ylim()
|
|
398
|
+
xlim = self.ax_props.get_xlim()
|
|
399
|
+
ylim = self.ax_props.get_ylim()
|
|
404
400
|
self.currentAlpha = value
|
|
405
|
-
|
|
406
|
-
#fc[:, 3] = value
|
|
407
|
-
#self.scat_props.set_facecolors(fc)
|
|
408
|
-
#self.propscanvas.canvas.draw_idle()
|
|
401
|
+
|
|
409
402
|
self.update_props_scatter(feature_changed=False)
|
|
410
403
|
self.ax_props.set_xlim(xlim)
|
|
411
404
|
self.ax_props.set_ylim(ylim)
|
|
@@ -413,12 +406,12 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
413
406
|
def switch_projection(self):
|
|
414
407
|
if self.project_times:
|
|
415
408
|
self.project_times = False
|
|
416
|
-
self.project_times_btn.setIcon(icon(MDI6.math_integral,color="black"))
|
|
409
|
+
self.project_times_btn.setIcon(icon(MDI6.math_integral, color="black"))
|
|
417
410
|
self.project_times_btn.setIconSize(QSize(20, 20))
|
|
418
411
|
self.frame_slider.setEnabled(True)
|
|
419
412
|
else:
|
|
420
413
|
self.project_times = True
|
|
421
|
-
self.project_times_btn.setIcon(icon(MDI6.math_integral_box,color="black"))
|
|
414
|
+
self.project_times_btn.setIcon(icon(MDI6.math_integral_box, color="black"))
|
|
422
415
|
self.project_times_btn.setIconSize(QSize(20, 20))
|
|
423
416
|
self.frame_slider.setEnabled(False)
|
|
424
417
|
self.update_props_scatter(feature_changed=False)
|
|
@@ -432,12 +425,13 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
432
425
|
|
|
433
426
|
if self.time_corr.isChecked():
|
|
434
427
|
self.class_name_user = 'class_'+self.name_le.text()
|
|
435
|
-
print(f'User defined class name: {self.class_name_user}
|
|
428
|
+
print(f'User defined class name: {self.class_name_user}...')
|
|
436
429
|
if self.class_name_user in self.df.columns:
|
|
437
430
|
|
|
438
431
|
msgBox = QMessageBox()
|
|
439
432
|
msgBox.setIcon(QMessageBox.Information)
|
|
440
|
-
msgBox.setText(f"The class column {self.class_name_user} already exists in the table.\nProceeding will
|
|
433
|
+
msgBox.setText(f"The class column {self.class_name_user} already exists in the table.\nProceeding will "
|
|
434
|
+
f"reclassify. Do you want to continue?")
|
|
441
435
|
msgBox.setWindowTitle("Warning")
|
|
442
436
|
msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
|
|
443
437
|
returnValue = msgBox.exec()
|
|
@@ -447,7 +441,6 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
447
441
|
return None
|
|
448
442
|
|
|
449
443
|
name_map = {self.class_name: self.class_name_user}
|
|
450
|
-
print(f"{name_map=}")
|
|
451
444
|
self.df = self.df.drop(list(set(name_map.values()) & set(self.df.columns)), axis=1).rename(columns=name_map)
|
|
452
445
|
self.df.reset_index(inplace=True, drop=True)
|
|
453
446
|
|
|
@@ -455,7 +448,7 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
455
448
|
if self.prereq_event_check.isChecked() and "t_"+self.prereq_event_cb.currentText() in self.cols:
|
|
456
449
|
pre_event = self.prereq_event_cb.currentText()
|
|
457
450
|
|
|
458
|
-
self.df = interpret_track_classification(self.df, self.class_name_user, irreversible_event=self.irreversible_event_btn.isChecked(), unique_state=self.unique_state_btn.isChecked(), transient_event=self.transient_event_btn.isChecked(),r2_threshold=self.r2_slider.value(), pre_event=pre_event)
|
|
451
|
+
self.df = interpret_track_classification(self.df, self.class_name_user, irreversible_event=self.irreversible_event_btn.isChecked(), unique_state=self.unique_state_btn.isChecked(), transient_event=self.transient_event_btn.isChecked(), r2_threshold=self.r2_slider.value(), pre_event=pre_event)
|
|
459
452
|
|
|
460
453
|
else:
|
|
461
454
|
self.group_name_user = 'group_' + self.name_le.text()
|
|
@@ -465,7 +458,8 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
465
458
|
msgBox = QMessageBox()
|
|
466
459
|
msgBox.setIcon(QMessageBox.Information)
|
|
467
460
|
msgBox.setText(
|
|
468
|
-
f"The group column {self.group_name_user} already exists in the table.\nProceeding will
|
|
461
|
+
f"The group column {self.group_name_user} already exists in the table.\nProceeding will "
|
|
462
|
+
f"reclassify. Do you want to continue?")
|
|
469
463
|
msgBox.setWindowTitle("Warning")
|
|
470
464
|
msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
|
|
471
465
|
returnValue = msgBox.exec()
|
|
@@ -477,18 +471,18 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
477
471
|
name_map = {self.class_name: self.group_name_user}
|
|
478
472
|
self.df = self.df.drop(list(set(name_map.values()) & set(self.df.columns)), axis=1).rename(columns=name_map)
|
|
479
473
|
print(self.df.columns)
|
|
480
|
-
#self.df[self.group_name_user] = self.df[self.group_name_user].replace({0: 1, 1: 0})
|
|
474
|
+
# self.df[self.group_name_user] = self.df[self.group_name_user].replace({0: 1, 1: 0})
|
|
481
475
|
self.df.reset_index(inplace=True, drop=True)
|
|
482
476
|
|
|
483
477
|
if 'custom' in list(self.df.columns):
|
|
484
|
-
self.df = self.df.drop(['custom'],axis=1)
|
|
478
|
+
self.df = self.df.drop(['custom'], axis=1)
|
|
485
479
|
|
|
486
|
-
self.fig_props.set_size_inches(4,3)
|
|
480
|
+
self.fig_props.set_size_inches(4, 3)
|
|
487
481
|
self.fig_props.suptitle(self.property_query_le.text(), fontsize=10)
|
|
488
482
|
self.fig_props.tight_layout()
|
|
489
|
-
for pos,pos_group in self.df.groupby('position'):
|
|
490
|
-
self.fig_props.savefig(pos+os.sep.join(['output',f'{self.class_name}.png']), bbox_inches='tight', dpi=300)
|
|
491
|
-
pos_group.to_csv(pos+os.sep.join(['output', 'tables', f'trajectories_{self.mode}.csv']), index=False)
|
|
483
|
+
for pos, pos_group in self.df.groupby('position'):
|
|
484
|
+
self.fig_props.savefig(str(pos)+os.sep.join(['output', f'{self.class_name}.png']), bbox_inches='tight', dpi=300)
|
|
485
|
+
pos_group.to_csv(str(pos)+os.sep.join(['output', 'tables', f'trajectories_{self.mode}.csv']), index=False)
|
|
492
486
|
|
|
493
487
|
self.parent_window.parent_window.update_position_options()
|
|
494
488
|
self.close()
|
|
@@ -500,7 +494,7 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
500
494
|
Helper for segmentation strategy between threshold-based and Deep learning.
|
|
501
495
|
"""
|
|
502
496
|
|
|
503
|
-
dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','propagate-classification.json'])
|
|
497
|
+
dict_path = os.sep.join([get_software_location(), 'celldetective', 'gui', 'help', 'propagate-classification.json'])
|
|
504
498
|
|
|
505
499
|
with open(dict_path) as f:
|
|
506
500
|
d = json.load(f)
|
|
@@ -524,53 +518,46 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
524
518
|
Switch threshold histogram to log scale. Auto adjust.
|
|
525
519
|
"""
|
|
526
520
|
|
|
527
|
-
if i==1:
|
|
521
|
+
if i == 1:
|
|
528
522
|
try:
|
|
529
523
|
feat_x = self.features_cb[1].currentText()
|
|
530
524
|
min_x = self.df.dropna(subset=feat_x)[feat_x].min()
|
|
531
525
|
max_x = self.df.dropna(subset=feat_x)[feat_x].max()
|
|
532
526
|
x_padding = (max_x - min_x) * 0.05
|
|
533
|
-
if x_padding==0:
|
|
527
|
+
if x_padding == 0:
|
|
534
528
|
x_padding = 0.05
|
|
535
529
|
|
|
536
|
-
if self.ax_props.get_xscale()=='linear':
|
|
530
|
+
if self.ax_props.get_xscale() == 'linear':
|
|
537
531
|
self.ax_props.set_xlim(min_x, max_x)
|
|
538
532
|
self.ax_props.set_xscale('log')
|
|
539
|
-
self.log_btns[i].setIcon(icon(MDI6.math_log,color="#1565c0"))
|
|
533
|
+
self.log_btns[i].setIcon(icon(MDI6.math_log, color="#1565c0"))
|
|
540
534
|
else:
|
|
541
535
|
self.ax_props.set_xscale('linear')
|
|
542
536
|
self.ax_props.set_xlim(min_x - x_padding, max_x + x_padding)
|
|
543
|
-
self.log_btns[i].setIcon(icon(MDI6.math_log,color="black"))
|
|
537
|
+
self.log_btns[i].setIcon(icon(MDI6.math_log, color="black"))
|
|
544
538
|
except Exception as e:
|
|
545
539
|
print(e)
|
|
546
|
-
elif i==0:
|
|
540
|
+
elif i == 0:
|
|
547
541
|
try:
|
|
548
542
|
feat_y = self.features_cb[0].currentText()
|
|
549
543
|
min_y = self.df.dropna(subset=feat_y)[feat_y].min()
|
|
550
544
|
max_y = self.df.dropna(subset=feat_y)[feat_y].max()
|
|
551
545
|
y_padding = (max_y - min_y) * 0.05
|
|
552
|
-
if y_padding==0:
|
|
546
|
+
if y_padding == 0:
|
|
553
547
|
y_padding = 0.05
|
|
554
548
|
|
|
555
|
-
if self.ax_props.get_yscale()=='linear':
|
|
549
|
+
if self.ax_props.get_yscale() == 'linear':
|
|
556
550
|
self.ax_props.set_ylim(min_y, max_y)
|
|
557
551
|
self.ax_props.set_yscale('log')
|
|
558
|
-
self.log_btns[i].setIcon(icon(MDI6.math_log,color="#1565c0"))
|
|
552
|
+
self.log_btns[i].setIcon(icon(MDI6.math_log, color="#1565c0"))
|
|
559
553
|
else:
|
|
560
554
|
self.ax_props.set_yscale('linear')
|
|
561
555
|
self.ax_props.set_ylim(min_y - y_padding, max_y + y_padding)
|
|
562
|
-
self.log_btns[i].setIcon(icon(MDI6.math_log,color="black"))
|
|
556
|
+
self.log_btns[i].setIcon(icon(MDI6.math_log, color="black"))
|
|
563
557
|
except Exception as e:
|
|
564
558
|
print(e)
|
|
565
559
|
|
|
566
560
|
self.ax_props.autoscale()
|
|
567
561
|
self.propscanvas.canvas.draw_idle()
|
|
568
562
|
|
|
569
|
-
print('Done.')
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
563
|
+
print('Done.')
|