celldetective 1.2.0__py3-none-any.whl → 1.2.2__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.
Files changed (54) hide show
  1. celldetective/__main__.py +12 -5
  2. celldetective/events.py +28 -2
  3. celldetective/gui/about.py +0 -1
  4. celldetective/gui/analyze_block.py +3 -18
  5. celldetective/gui/btrack_options.py +126 -21
  6. celldetective/gui/classifier_widget.py +68 -107
  7. celldetective/gui/configure_new_exp.py +37 -4
  8. celldetective/gui/control_panel.py +14 -30
  9. celldetective/gui/generic_signal_plot.py +793 -0
  10. celldetective/gui/gui_utils.py +401 -226
  11. celldetective/gui/json_readers.py +0 -2
  12. celldetective/gui/layouts.py +269 -25
  13. celldetective/gui/measurement_options.py +14 -23
  14. celldetective/gui/neighborhood_options.py +6 -16
  15. celldetective/gui/plot_measurements.py +10 -23
  16. celldetective/gui/plot_signals_ui.py +53 -687
  17. celldetective/gui/process_block.py +320 -186
  18. celldetective/gui/retrain_segmentation_model_options.py +30 -47
  19. celldetective/gui/retrain_signal_model_options.py +5 -14
  20. celldetective/gui/seg_model_loader.py +129 -113
  21. celldetective/gui/signal_annotator.py +93 -103
  22. celldetective/gui/signal_annotator2.py +9 -13
  23. celldetective/gui/styles.py +32 -0
  24. celldetective/gui/survival_ui.py +49 -712
  25. celldetective/gui/tableUI.py +4 -39
  26. celldetective/gui/thresholds_gui.py +38 -11
  27. celldetective/gui/viewers.py +6 -7
  28. celldetective/io.py +62 -84
  29. celldetective/measure.py +374 -15
  30. celldetective/models/segmentation_effectors/ricm-bimodal/config_input.json +130 -0
  31. celldetective/models/segmentation_effectors/ricm-bimodal/ricm-bimodal +0 -0
  32. celldetective/models/segmentation_effectors/ricm-bimodal/training_instructions.json +37 -0
  33. celldetective/neighborhood.py +3 -7
  34. celldetective/preprocessing.py +2 -4
  35. celldetective/relative_measurements.py +0 -3
  36. celldetective/scripts/analyze_signals.py +0 -1
  37. celldetective/scripts/measure_cells.py +1 -3
  38. celldetective/scripts/measure_relative.py +1 -2
  39. celldetective/scripts/segment_cells.py +16 -12
  40. celldetective/scripts/segment_cells_thresholds.py +17 -10
  41. celldetective/scripts/track_cells.py +18 -18
  42. celldetective/scripts/train_segmentation_model.py +1 -2
  43. celldetective/scripts/train_signal_model.py +0 -3
  44. celldetective/segmentation.py +1 -1
  45. celldetective/signals.py +20 -8
  46. celldetective/tracking.py +2 -1
  47. celldetective/utils.py +126 -18
  48. {celldetective-1.2.0.dist-info → celldetective-1.2.2.dist-info}/METADATA +19 -12
  49. celldetective-1.2.2.dist-info/RECORD +92 -0
  50. {celldetective-1.2.0.dist-info → celldetective-1.2.2.dist-info}/WHEEL +1 -1
  51. celldetective-1.2.0.dist-info/RECORD +0 -88
  52. {celldetective-1.2.0.dist-info → celldetective-1.2.2.dist-info}/LICENSE +0 -0
  53. {celldetective-1.2.0.dist-info → celldetective-1.2.2.dist-info}/entry_points.txt +0 -0
  54. {celldetective-1.2.0.dist-info → celldetective-1.2.2.dist-info}/top_level.txt +0 -0
@@ -1,23 +1,20 @@
1
1
  from PyQt5.QtWidgets import QMainWindow, QComboBox, QLabel, QRadioButton, QLineEdit, QFileDialog, QApplication, \
2
- QPushButton, QWidget, QVBoxLayout, QHBoxLayout, QMessageBox, QAction, QShortcut, QLineEdit, QSlider, QCheckBox
2
+ QPushButton, QWidget, QVBoxLayout, QHBoxLayout, QMessageBox, QShortcut, QLineEdit, QSlider, QCheckBox
3
3
  from PyQt5.QtCore import Qt, QSize
4
4
  from PyQt5.QtGui import QKeySequence, QIntValidator
5
- from matplotlib.widgets import Slider
6
- from tifffile import imread
7
5
 
8
- from celldetective.gui.gui_utils import center_window, QHSeperationLine, FilterChoice, color_from_state
9
- from superqt import QLabeledDoubleSlider, QLabeledDoubleRangeSlider, QLabeledSlider, QSearchableComboBox
6
+ from celldetective.gui.gui_utils import center_window, color_from_state
7
+ from superqt import QLabeledDoubleSlider, QLabeledDoubleRangeSlider, QSearchableComboBox
10
8
  from celldetective.utils import extract_experiment_channels, get_software_location, _get_img_num_per_channel
11
- from celldetective.io import auto_load_number_of_frames, load_frames, locate_stack, locate_labels, relabel_segmentation, \
9
+ from celldetective.io import auto_load_number_of_frames, load_frames, \
12
10
  load_napari_data
13
- from celldetective.gui.gui_utils import FigureCanvas, color_from_status, color_from_class
11
+ from celldetective.gui.gui_utils import FigureCanvas, color_from_status, color_from_class, ExportPlotBtn
14
12
  import json
15
13
  import numpy as np
16
14
  from superqt.fonticon import icon
17
15
  from fonticon_mdi6 import MDI6
18
16
  import os
19
17
  from glob import glob
20
- from natsort import natsorted
21
18
  import matplotlib.pyplot as plt
22
19
  from matplotlib.ticker import MultipleLocator
23
20
  from tqdm import tqdm
@@ -38,6 +35,8 @@ class SignalAnnotator(QMainWindow, Styles):
38
35
  def __init__(self, parent_window=None):
39
36
 
40
37
  super().__init__()
38
+ center_window(self)
39
+
41
40
  self.parent_window = parent_window
42
41
  self.setWindowTitle("Signal annotator")
43
42
  self.mode = self.parent_window.mode
@@ -49,14 +48,15 @@ class SignalAnnotator(QMainWindow, Styles):
49
48
  self.recently_modified = False
50
49
  self.selection = []
51
50
  if self.mode == "targets":
52
- self.instructions_path = self.exp_dir + "configs/signal_annotator_config_targets.json"
53
- self.trajectories_path = self.pos + 'output/tables/trajectories_targets.csv'
51
+ self.instructions_path = self.exp_dir + os.sep.join(['configs', 'signal_annotator_config_targets.json'])
52
+ self.trajectories_path = self.pos + os.sep.join(['output','tables','trajectories_targets.csv'])
54
53
  elif self.mode == "effectors":
55
- self.instructions_path = self.exp_dir + "configs/signal_annotator_config_effectors.json"
56
- self.trajectories_path = self.pos + 'output/tables/trajectories_effectors.csv'
54
+ self.instructions_path = self.exp_dir + os.sep.join(['configs', 'signal_annotator_config_effectors.json'])
55
+ self.trajectories_path = self.pos + os.sep.join(['output','tables','trajectories_effectors.csv'])
57
56
 
58
57
  self.screen_height = self.parent_window.parent_window.parent_window.screen_height
59
58
  self.screen_width = self.parent_window.parent_window.parent_window.screen_width
59
+ #self.setMinimumHeight(int(0.8*self.screen_height))
60
60
  self.value_magnitude = 1
61
61
 
62
62
  # default params
@@ -64,8 +64,6 @@ class SignalAnnotator(QMainWindow, Styles):
64
64
  self.time_name = 't0'
65
65
  self.status_name = 'status'
66
66
 
67
- center_window(self)
68
-
69
67
  self.locate_stack()
70
68
  self.load_annotator_config()
71
69
  self.locate_tracks()
@@ -78,11 +76,6 @@ class SignalAnnotator(QMainWindow, Styles):
78
76
 
79
77
  self.populate_widget()
80
78
 
81
- #self.setMinimumWidth(int(0.8 * self.screen_width))
82
- # self.setMaximumHeight(int(0.8*self.screen_height))
83
- #self.setMinimumHeight(int(0.8 * self.screen_height))
84
- # self.setMaximumHeight(int(0.8*self.screen_height))
85
-
86
79
  self.setAttribute(Qt.WA_DeleteOnClose)
87
80
 
88
81
  def populate_widget(self):
@@ -98,12 +91,13 @@ class SignalAnnotator(QMainWindow, Styles):
98
91
 
99
92
  main_layout.setContentsMargins(30, 30, 30, 30)
100
93
  self.left_panel = QVBoxLayout()
101
- self.left_panel.setContentsMargins(30, 30, 30, 30)
102
- self.left_panel.setSpacing(10)
94
+ self.left_panel.setContentsMargins(30, 5, 30, 5)
95
+ self.left_panel.setSpacing(3)
103
96
 
104
97
  self.right_panel = QVBoxLayout()
105
98
 
106
99
  class_hbox = QHBoxLayout()
100
+ class_hbox.setContentsMargins(0,0,0,0)
107
101
  class_hbox.addWidget(QLabel('event: '), 25)
108
102
  self.class_choice_cb = QComboBox()
109
103
 
@@ -140,14 +134,14 @@ class SignalAnnotator(QMainWindow, Styles):
140
134
  self.del_class_btn.clicked.connect(self.del_event_class)
141
135
  class_hbox.addWidget(self.del_class_btn, 5)
142
136
 
143
- self.left_panel.addLayout(class_hbox)
137
+ self.left_panel.addLayout(class_hbox,5)
144
138
 
145
139
  self.cell_info = QLabel('')
146
- self.left_panel.addWidget(self.cell_info)
140
+ self.left_panel.addWidget(self.cell_info,10)
147
141
 
148
142
  # Annotation buttons
149
143
  options_hbox = QHBoxLayout()
150
- options_hbox.setContentsMargins(150, 30, 50, 0)
144
+ options_hbox.setContentsMargins(0, 0, 0, 0)
151
145
  self.event_btn = QRadioButton('event')
152
146
  self.event_btn.setStyleSheet(self.button_style_sheet_2)
153
147
  self.event_btn.toggled.connect(self.enable_time_of_interest)
@@ -160,25 +154,28 @@ class SignalAnnotator(QMainWindow, Styles):
160
154
  self.else_btn.setStyleSheet(self.button_style_sheet_2)
161
155
  self.else_btn.toggled.connect(self.enable_time_of_interest)
162
156
 
163
- self.suppr_btn = QRadioButton('mark for\nsuppression')
157
+ self.suppr_btn = QRadioButton('remove')
158
+ self.suppr_btn.setToolTip('Mark for deletion. Upon saving, the cell\nwill be removed from the tables.')
164
159
  self.suppr_btn.setStyleSheet(self.button_style_sheet_2)
165
160
  self.suppr_btn.toggled.connect(self.enable_time_of_interest)
166
161
 
167
- options_hbox.addWidget(self.event_btn, 25)
168
- options_hbox.addWidget(self.no_event_btn, 25)
169
- options_hbox.addWidget(self.else_btn, 25)
170
- options_hbox.addWidget(self.suppr_btn, 25)
171
- self.left_panel.addLayout(options_hbox)
162
+ options_hbox.addWidget(self.event_btn, 25, alignment=Qt.AlignCenter)
163
+ options_hbox.addWidget(self.no_event_btn, 25, alignment=Qt.AlignCenter)
164
+ options_hbox.addWidget(self.else_btn, 25, alignment=Qt.AlignCenter)
165
+ options_hbox.addWidget(self.suppr_btn, 25, alignment=Qt.AlignCenter)
166
+ self.left_panel.addLayout(options_hbox,5)
172
167
 
173
168
  time_option_hbox = QHBoxLayout()
174
- time_option_hbox.setContentsMargins(100, 30, 100, 30)
169
+ time_option_hbox.setContentsMargins(0, 5, 100, 10)
175
170
  self.time_of_interest_label = QLabel('time of interest: ')
176
- time_option_hbox.addWidget(self.time_of_interest_label, 30)
171
+ time_option_hbox.addWidget(self.time_of_interest_label, 10)
177
172
  self.time_of_interest_le = QLineEdit()
178
- time_option_hbox.addWidget(self.time_of_interest_le, 70)
179
- self.left_panel.addLayout(time_option_hbox)
173
+ time_option_hbox.addWidget(self.time_of_interest_le, 15)
174
+ time_option_hbox.addWidget(QLabel(''), 75)
175
+ self.left_panel.addLayout(time_option_hbox,5)
180
176
 
181
177
  main_action_hbox = QHBoxLayout()
178
+ main_action_hbox.setContentsMargins(0,0,0,0)
182
179
  self.correct_btn = QPushButton('correct')
183
180
  self.correct_btn.setIcon(icon(MDI6.redo_variant, color="white"))
184
181
  self.correct_btn.setIconSize(QSize(20, 20))
@@ -193,7 +190,7 @@ class SignalAnnotator(QMainWindow, Styles):
193
190
  self.cancel_btn.setEnabled(False)
194
191
  self.cancel_btn.clicked.connect(self.cancel_selection)
195
192
  main_action_hbox.addWidget(self.cancel_btn)
196
- self.left_panel.addLayout(main_action_hbox)
193
+ self.left_panel.addLayout(main_action_hbox,5)
197
194
 
198
195
  self.annotation_btns_to_hide = [self.event_btn, self.no_event_btn,
199
196
  self.else_btn, self.time_of_interest_label,
@@ -210,7 +207,8 @@ class SignalAnnotator(QMainWindow, Styles):
210
207
  self.no_event_shortcut.setEnabled(False)
211
208
 
212
209
  # Cell signals
213
- self.left_panel.addWidget(self.cell_fcanvas)
210
+
211
+ self.left_panel.addWidget(self.cell_fcanvas, 45)
214
212
 
215
213
  plot_buttons_hbox = QHBoxLayout()
216
214
  plot_buttons_hbox.setContentsMargins(0, 0, 0, 0)
@@ -232,10 +230,13 @@ class SignalAnnotator(QMainWindow, Styles):
232
230
  self.log_btn.clicked.connect(self.switch_to_log)
233
231
  plot_buttons_hbox.addWidget(self.log_btn, 5)
234
232
 
235
- self.left_panel.addLayout(plot_buttons_hbox)
233
+ self.export_plot_btn = ExportPlotBtn(self.cell_fig, export_dir = self.exp_dir)
234
+ plot_buttons_hbox.addWidget(self.export_plot_btn, 5)
235
+
236
+ self.left_panel.addLayout(plot_buttons_hbox,5)
236
237
 
237
238
  signal_choice_vbox = QVBoxLayout()
238
- signal_choice_vbox.setContentsMargins(30, 0, 30, 50)
239
+ signal_choice_vbox.setContentsMargins(30, 0, 30, 0)
239
240
  for i in range(len(self.signal_choice_cb)):
240
241
  hlayout = QHBoxLayout()
241
242
  hlayout.addWidget(self.signal_choice_label[i], 20)
@@ -247,9 +248,10 @@ class SignalAnnotator(QMainWindow, Styles):
247
248
  # self.log_btns[i].setStyleSheet(self.parent.parent.parent.button_select_all)
248
249
  # self.log_btns[i].clicked.connect(lambda ch, i=i: self.switch_to_log(i))
249
250
 
250
- self.left_panel.addLayout(signal_choice_vbox)
251
+ self.left_panel.addLayout(signal_choice_vbox,15)
251
252
 
252
253
  btn_hbox = QHBoxLayout()
254
+ btn_hbox.setContentsMargins(0,10,0,0)
253
255
  self.save_btn = QPushButton('Save')
254
256
  self.save_btn.setStyleSheet(self.button_style_sheet)
255
257
  self.save_btn.clicked.connect(self.save_trajectories)
@@ -261,7 +263,7 @@ class SignalAnnotator(QMainWindow, Styles):
261
263
  self.export_btn.setIcon(icon(MDI6.export, color="black"))
262
264
  self.export_btn.setIconSize(QSize(25, 25))
263
265
  btn_hbox.addWidget(self.export_btn, 10)
264
- self.left_panel.addLayout(btn_hbox)
266
+ self.left_panel.addLayout(btn_hbox,5)
265
267
 
266
268
  # Animation
267
269
  animation_buttons_box = QHBoxLayout()
@@ -315,9 +317,6 @@ class SignalAnnotator(QMainWindow, Styles):
315
317
  self.contrast_slider.setSingleStep(0.001)
316
318
  self.contrast_slider.setTickInterval(0.001)
317
319
  self.contrast_slider.setOrientation(1)
318
- print(self.stack.shape, np.unique(self.stack))
319
- print('range: ',
320
- [np.nanpercentile(self.stack, 0.001), np.nanpercentile(self.stack, 99.999)])
321
320
  self.contrast_slider.setRange(
322
321
  *[np.nanpercentile(self.stack, 0.001), np.nanpercentile(self.stack, 99.999)])
323
322
  self.contrast_slider.setValue(
@@ -477,14 +476,12 @@ class SignalAnnotator(QMainWindow, Styles):
477
476
  self.time_name = self.expected_time
478
477
  self.status_name = self.expected_status
479
478
 
480
- print('selection and expected names: ', self.class_name, self.expected_time, self.expected_status)
481
479
  cols = list(self.df_tracks.columns)
482
480
 
483
481
  if self.time_name in cols and self.class_name in cols and not self.status_name in cols:
484
482
  # only create the status column if it does not exist to not erase static classification results
485
483
  self.make_status_column()
486
484
  elif self.time_name in cols and self.class_name in cols and self.df_tracks[self.status_name].isnull().all():
487
- print('this is the case!', )
488
485
  self.make_status_column()
489
486
  elif self.time_name in cols and self.class_name in cols:
490
487
  # all good, do nothing
@@ -643,7 +640,7 @@ class SignalAnnotator(QMainWindow, Styles):
643
640
 
644
641
  """
645
642
 
646
- movies = glob(self.pos + f"movie/{self.parent_window.parent_window.movie_prefix}*.tif")
643
+ movies = glob(self.pos + os.sep.join(["movie", f"{self.parent_window.parent_window.movie_prefix}*.tif"]))
647
644
 
648
645
  if len(movies) == 0:
649
646
  msgBox = QMessageBox()
@@ -782,8 +779,8 @@ class SignalAnnotator(QMainWindow, Styles):
782
779
  # self.loc_t, self.loc_idx = np.where(self.tracks==self.track_of_interest)
783
780
 
784
781
  def make_status_column(self):
785
- print(self.class_name, self.time_name, self.status_name)
786
- print('remaking the status column')
782
+
783
+ print(f'Generating status information for class `{self.class_name}` and time `{self.time_name}`...')
787
784
  for tid, group in self.df_tracks.groupby('TRACK_ID'):
788
785
 
789
786
  indices = group.index
@@ -811,7 +808,7 @@ class SignalAnnotator(QMainWindow, Styles):
811
808
  # self.log_btns = [QPushButton() for i in range(self.n_signals)]
812
809
 
813
810
  signals = list(self.df_tracks.columns)
814
- print(signals)
811
+
815
812
  to_remove = ['TRACK_ID', 'FRAME', 'x_anim', 'y_anim', 't', 'state', 'generation', 'root', 'parent', 'class_id',
816
813
  'class', 't0', 'POSITION_X', 'POSITION_Y', 'position', 'well', 'well_index', 'well_name',
817
814
  'pos_name', 'index','class_color','status_color']
@@ -840,7 +837,6 @@ class SignalAnnotator(QMainWindow, Styles):
840
837
  self.lines[i].set_xdata([])
841
838
  self.lines[i].set_ydata([])
842
839
  else:
843
- print(f'plot signal {signal_choice} for cell {self.track_of_interest}')
844
840
  xdata = self.df_tracks.loc[self.df_tracks['TRACK_ID'] == self.track_of_interest, 'FRAME'].to_numpy()
845
841
  ydata = self.df_tracks.loc[
846
842
  self.df_tracks['TRACK_ID'] == self.track_of_interest, signal_choice].to_numpy()
@@ -867,7 +863,7 @@ class SignalAnnotator(QMainWindow, Styles):
867
863
  self.cell_ax.legend()
868
864
  self.cell_fcanvas.canvas.draw()
869
865
  except Exception as e:
870
- print(f"Plot signals: {e=}")
866
+ pass
871
867
 
872
868
  if len(range_values)>0:
873
869
  range_values = np.array(range_values)
@@ -901,12 +897,10 @@ class SignalAnnotator(QMainWindow, Styles):
901
897
  Load settings from config or set default values.
902
898
  """
903
899
 
904
- print('Reading instructions..')
905
900
  if os.path.exists(self.instructions_path):
906
901
  with open(self.instructions_path, 'r') as f:
907
902
 
908
903
  instructions = json.load(f)
909
- print(f'Reading instructions: {instructions}')
910
904
 
911
905
  if 'rgb_mode' in instructions:
912
906
  self.rgb_mode = instructions['rgb_mode']
@@ -949,7 +943,8 @@ class SignalAnnotator(QMainWindow, Styles):
949
943
 
950
944
  self.img_num_channels = _get_img_num_per_channel(self.channels, self.len_movie, self.nbr_channels)
951
945
  self.stack = []
952
- for ch in tqdm(self.target_channels, desc="channel"):
946
+ disable_tqdm = not len(self.target_channels)>1
947
+ for ch in tqdm(self.target_channels, desc="channel",disable=disable_tqdm):
953
948
  target_ch_name = ch[0]
954
949
  if self.percentile_mode:
955
950
  normalize_kwargs = {"percentiles": (ch[1], ch[2]), "values": None}
@@ -981,8 +976,6 @@ class SignalAnnotator(QMainWindow, Styles):
981
976
  if self.log_option:
982
977
  self.stack[np.where(self.stack > 0.)] = np.log(self.stack[np.where(self.stack > 0.)])
983
978
 
984
- print(f'Load stack of shape: {self.stack.shape}.')
985
-
986
979
  def closeEvent(self, event):
987
980
 
988
981
  self.stop()
@@ -1034,8 +1027,8 @@ class SignalAnnotator(QMainWindow, Styles):
1034
1027
 
1035
1028
  def create_cell_signal_canvas(self):
1036
1029
 
1037
- self.cell_fig, self.cell_ax = plt.subplots()
1038
- self.cell_fcanvas = FigureCanvas(self.cell_fig, interactive=False)
1030
+ self.cell_fig, self.cell_ax = plt.subplots(tight_layout=True)
1031
+ self.cell_fcanvas = FigureCanvas(self.cell_fig, interactive=True)
1039
1032
  self.cell_ax.clear()
1040
1033
 
1041
1034
  spacing = 0.5
@@ -1066,6 +1059,9 @@ class SignalAnnotator(QMainWindow, Styles):
1066
1059
 
1067
1060
  def on_scatter_pick(self, event):
1068
1061
 
1062
+ self.correct_btn.disconnect()
1063
+ self.correct_btn.clicked.connect(self.show_annotation_buttons)
1064
+
1069
1065
  ind = event.ind
1070
1066
 
1071
1067
  if len(ind) > 1:
@@ -1085,7 +1081,7 @@ class SignalAnnotator(QMainWindow, Styles):
1085
1081
  self.no_event_shortcut.setEnabled(True)
1086
1082
 
1087
1083
  self.track_of_interest = self.tracks[self.framedata][ind]
1088
- print(f'You selected track {self.track_of_interest}.')
1084
+ print(f'You selected cell #{self.track_of_interest}...')
1089
1085
  self.give_cell_information()
1090
1086
  self.plot_signals()
1091
1087
 
@@ -1135,7 +1131,7 @@ class SignalAnnotator(QMainWindow, Styles):
1135
1131
  if len(min_values) > 0:
1136
1132
  self.cell_ax.set_ylim(np.amin(min_values), np.amax(max_values))
1137
1133
  except Exception as e:
1138
- print('Ylim error:',e)
1134
+ pass
1139
1135
 
1140
1136
  def draw_frame(self, framedata):
1141
1137
 
@@ -1196,7 +1192,7 @@ class SignalAnnotator(QMainWindow, Styles):
1196
1192
 
1197
1193
  self.df_tracks = self.df_tracks.drop(self.df_tracks[self.df_tracks[self.class_name] > 2].index)
1198
1194
  self.df_tracks.to_csv(self.trajectories_path, index=False)
1199
- print('table saved.')
1195
+ print('Table successfully exported...')
1200
1196
  self.extract_scatter_from_trajectories()
1201
1197
 
1202
1198
  # self.give_cell_information()
@@ -1217,7 +1213,6 @@ class SignalAnnotator(QMainWindow, Styles):
1217
1213
  while len(np.where(self.stack[self.last_key].flatten() == 0)[0]) > 0.99 * len(
1218
1214
  self.stack[self.last_key].flatten()):
1219
1215
  self.last_key -= 1
1220
- print(f'Last frame is {len(self.stack) - 1}; last not black is {self.last_key}')
1221
1216
  self.anim._drawn_artists = self.draw_frame(self.last_key)
1222
1217
  self.anim._drawn_artists = sorted(self.anim._drawn_artists, key=lambda x: x.get_zorder())
1223
1218
  for a in self.anim._drawn_artists:
@@ -1238,7 +1233,6 @@ class SignalAnnotator(QMainWindow, Styles):
1238
1233
  self.first_frame_btn.disconnect()
1239
1234
 
1240
1235
  self.first_key = 0
1241
- print(f'First frame is {0}')
1242
1236
  self.anim._drawn_artists = self.draw_frame(0)
1243
1237
  self.anim._drawn_artists = sorted(self.anim._drawn_artists, key=lambda x: x.get_zorder())
1244
1238
  for a in self.anim._drawn_artists:
@@ -1275,8 +1269,6 @@ class SignalAnnotator(QMainWindow, Styles):
1275
1269
  # Here auto add all available channels
1276
1270
  training_set.append(signals)
1277
1271
 
1278
- print(training_set)
1279
-
1280
1272
  pathsave = QFileDialog.getSaveFileName(self, "Select file name", self.exp_dir + auto_dataset_name, ".npy")[0]
1281
1273
  if pathsave != '':
1282
1274
  if not pathsave.endswith(".npy"):
@@ -1361,10 +1353,10 @@ class MeasureAnnotator(SignalAnnotator):
1361
1353
  self.locate_stack()
1362
1354
 
1363
1355
  data, properties, graph, labels, _ = load_napari_data(self.pos, prefix=None, population=self.mode,return_stack=False)
1364
- if data is not None:
1365
- self.labels = relabel_segmentation(labels,data,properties)
1366
- else:
1367
- self.labels = labels
1356
+ # if data is not None:
1357
+ # self.labels = relabel_segmentation(labels,data,properties)
1358
+ # else:
1359
+ self.labels = labels
1368
1360
 
1369
1361
  self.current_channel = 0
1370
1362
 
@@ -1420,10 +1412,10 @@ class MeasureAnnotator(SignalAnnotator):
1420
1412
  self.cell_fcanvas = FigureCanvas(self.cell_fig, interactive=False)
1421
1413
  self.cell_ax.clear()
1422
1414
 
1423
- spacing = 0.5
1424
- minorLocator = MultipleLocator(1)
1425
- self.cell_ax.xaxis.set_minor_locator(minorLocator)
1426
- self.cell_ax.xaxis.set_major_locator(MultipleLocator(5))
1415
+ # spacing = 0.5
1416
+ # minorLocator = MultipleLocator(1)
1417
+ # self.cell_ax.xaxis.set_minor_locator(minorLocator)
1418
+ # self.cell_ax.xaxis.set_major_locator(MultipleLocator(5))
1427
1419
  self.cell_ax.grid(which='major')
1428
1420
  self.cell_ax.set_xlabel("time [frame]")
1429
1421
  self.cell_ax.set_ylabel("signal")
@@ -1526,7 +1518,7 @@ class MeasureAnnotator(SignalAnnotator):
1526
1518
  for i in range(len(self.signal_choice_cb)):
1527
1519
  signal_choice = self.signal_choice_cb[i].currentText()
1528
1520
  if signal_choice != "--":
1529
- print(f'plot signal {signal_choice} for cell {self.track_of_interest} at frame {current_frame}')
1521
+ #print(f'plot signal {signal_choice} for cell {self.track_of_interest} at frame {current_frame}')
1530
1522
  if 'TRACK_ID' in self.df_tracks.columns:
1531
1523
  ydata = self.df_tracks.loc[
1532
1524
  (self.df_tracks['TRACK_ID'] == self.track_of_interest) &
@@ -1560,7 +1552,7 @@ class MeasureAnnotator(SignalAnnotator):
1560
1552
  self.del_shortcut.setEnabled(True)
1561
1553
  self.no_event_shortcut.setEnabled(True)
1562
1554
  self.track_of_interest = self.tracks[self.framedata][ind]
1563
- print(f'You selected track {self.track_of_interest}.')
1555
+ print(f'You selected cell #{self.track_of_interest}...')
1564
1556
  self.give_cell_information()
1565
1557
  if len(self.cell_ax.lines) > 0:
1566
1558
  self.cell_ax.lines[-1].remove() # Remove the last line (red points) from the plot
@@ -1600,20 +1592,23 @@ class MeasureAnnotator(SignalAnnotator):
1600
1592
  self.button_widget.setLayout(main_layout)
1601
1593
 
1602
1594
  main_layout.setContentsMargins(30, 30, 30, 30)
1595
+
1603
1596
  self.left_panel = QVBoxLayout()
1604
- self.left_panel.setContentsMargins(30, 30, 30, 30)
1605
- self.left_panel.setSpacing(10)
1597
+ self.left_panel.setContentsMargins(30, 5, 30, 5)
1598
+ #self.left_panel.setSpacing(3)
1606
1599
 
1607
1600
  self.right_panel = QVBoxLayout()
1608
1601
 
1609
1602
  class_hbox = QHBoxLayout()
1603
+ class_hbox.setContentsMargins(0,0,0,0)
1604
+ class_hbox.setSpacing(0)
1605
+
1610
1606
  class_hbox.addWidget(QLabel('characteristic \n group: '), 25)
1611
1607
  self.class_choice_cb = QComboBox()
1612
1608
 
1613
1609
  cols = np.array(self.df_tracks.columns)
1614
1610
  self.class_cols = np.array([c.startswith('group') or c.startswith('status') for c in list(self.df_tracks.columns)])
1615
1611
  self.class_cols = list(cols[self.class_cols])
1616
- print(self.class_cols)
1617
1612
 
1618
1613
  try:
1619
1614
  self.class_cols.remove('group_id')
@@ -1644,13 +1639,15 @@ class MeasureAnnotator(SignalAnnotator):
1644
1639
  self.del_class_btn.clicked.connect(self.del_event_class)
1645
1640
  class_hbox.addWidget(self.del_class_btn, 5)
1646
1641
 
1647
- self.left_panel.addLayout(class_hbox)
1642
+ self.left_panel.addLayout(class_hbox,5)
1648
1643
 
1649
1644
  self.cell_info = QLabel('')
1650
- self.left_panel.addWidget(self.cell_info)
1645
+ self.left_panel.addWidget(self.cell_info,5)
1651
1646
 
1652
1647
  time_option_hbox = QHBoxLayout()
1653
- time_option_hbox.setContentsMargins(100, 30, 100, 30)
1648
+ time_option_hbox.setContentsMargins(100, 0, 100, 0)
1649
+ time_option_hbox.setSpacing(0)
1650
+
1654
1651
  self.time_of_interest_label = QLabel('phenotype: ')
1655
1652
  time_option_hbox.addWidget(self.time_of_interest_label, 30)
1656
1653
  self.time_of_interest_le = QLineEdit()
@@ -1663,9 +1660,12 @@ class MeasureAnnotator(SignalAnnotator):
1663
1660
  self.del_cell_btn.setIconSize(QSize(20, 20))
1664
1661
  self.del_cell_btn.clicked.connect(self.del_cell)
1665
1662
  time_option_hbox.addWidget(self.del_cell_btn)
1666
- self.left_panel.addLayout(time_option_hbox)
1663
+ self.left_panel.addLayout(time_option_hbox,5)
1667
1664
 
1668
1665
  main_action_hbox = QHBoxLayout()
1666
+ main_action_hbox.setContentsMargins(0,0,0,0)
1667
+ main_action_hbox.setSpacing(0)
1668
+
1669
1669
  self.correct_btn = QPushButton('correct')
1670
1670
  self.correct_btn.setIcon(icon(MDI6.redo_variant, color="white"))
1671
1671
  self.correct_btn.setIconSize(QSize(20, 20))
@@ -1680,7 +1680,7 @@ class MeasureAnnotator(SignalAnnotator):
1680
1680
  self.cancel_btn.setEnabled(False)
1681
1681
  self.cancel_btn.clicked.connect(self.cancel_selection)
1682
1682
  main_action_hbox.addWidget(self.cancel_btn)
1683
- self.left_panel.addLayout(main_action_hbox)
1683
+ self.left_panel.addLayout(main_action_hbox,5)
1684
1684
 
1685
1685
  self.annotation_btns_to_hide = [self.time_of_interest_label,
1686
1686
  self.time_of_interest_le,
@@ -1697,7 +1697,8 @@ class MeasureAnnotator(SignalAnnotator):
1697
1697
  self.no_event_shortcut.setEnabled(False)
1698
1698
 
1699
1699
  # Cell signals
1700
- self.left_panel.addWidget(self.cell_fcanvas)
1700
+ self.cell_fcanvas.setMinimumHeight(int(0.2*self.screen_height))
1701
+ self.left_panel.addWidget(self.cell_fcanvas,90)
1701
1702
 
1702
1703
  plot_buttons_hbox = QHBoxLayout()
1703
1704
  plot_buttons_hbox.setContentsMargins(0, 0, 0, 0)
@@ -1723,7 +1724,7 @@ class MeasureAnnotator(SignalAnnotator):
1723
1724
  self.log_btn.clicked.connect(self.switch_to_log)
1724
1725
  plot_buttons_hbox.addWidget(self.log_btn, 5)
1725
1726
 
1726
- self.left_panel.addLayout(plot_buttons_hbox)
1727
+ self.left_panel.addLayout(plot_buttons_hbox,5)
1727
1728
 
1728
1729
  signal_choice_vbox = QVBoxLayout()
1729
1730
  signal_choice_vbox.setContentsMargins(30, 0, 30, 50)
@@ -1738,14 +1739,13 @@ class MeasureAnnotator(SignalAnnotator):
1738
1739
  # self.log_btns[i].setStyleSheet(self.parent.parent.parent.button_select_all)
1739
1740
  # self.log_btns[i].clicked.connect(lambda ch, i=i: self.switch_to_log(i))
1740
1741
 
1741
- self.left_panel.addLayout(signal_choice_vbox)
1742
+ self.left_panel.addLayout(signal_choice_vbox,10)
1742
1743
 
1743
1744
  btn_hbox = QHBoxLayout()
1744
1745
  self.save_btn = QPushButton('Save')
1745
1746
  self.save_btn.setStyleSheet(self.button_style_sheet)
1746
1747
  self.save_btn.clicked.connect(self.save_trajectories)
1747
1748
  btn_hbox.addWidget(self.save_btn, 90)
1748
- self.left_panel.addLayout(btn_hbox)
1749
1749
 
1750
1750
  self.export_btn = QPushButton('')
1751
1751
  self.export_btn.setStyleSheet(self.button_select_all)
@@ -1753,7 +1753,7 @@ class MeasureAnnotator(SignalAnnotator):
1753
1753
  self.export_btn.setIcon(icon(MDI6.export, color="black"))
1754
1754
  self.export_btn.setIconSize(QSize(25, 25))
1755
1755
  btn_hbox.addWidget(self.export_btn, 10)
1756
- self.left_panel.addLayout(btn_hbox)
1756
+ self.left_panel.addLayout(btn_hbox,5)
1757
1757
 
1758
1758
  # Animation
1759
1759
  animation_buttons_box = QHBoxLayout()
@@ -1805,8 +1805,6 @@ class MeasureAnnotator(SignalAnnotator):
1805
1805
  self.contrast_slider.setSingleStep(0.001)
1806
1806
  self.contrast_slider.setTickInterval(0.001)
1807
1807
  self.contrast_slider.setOrientation(1)
1808
- print('range: ',
1809
- [np.nanpercentile(self.img.flatten(), 0.001), np.nanpercentile(self.img.flatten(), 99.999)])
1810
1808
  self.contrast_slider.setRange(
1811
1809
  *[np.nanpercentile(self.img, 0.001), np.nanpercentile(self.img, 99.999)])
1812
1810
  self.contrast_slider.setValue(
@@ -1961,9 +1959,8 @@ class MeasureAnnotator(SignalAnnotator):
1961
1959
  cell_status = f"phenotype: {self.df_tracks.loc[self.df_tracks['ID'] == self.track_of_interest, self.status_name].to_numpy()[0]}\n"
1962
1960
  self.cell_info.setText(cell_selected + cell_status)
1963
1961
  except Exception as e:
1964
- print('Cell info:',e)
1965
- print(self.track_of_interest, self.status_name)
1966
-
1962
+ print(e)
1963
+
1967
1964
  def create_new_event_class(self):
1968
1965
 
1969
1966
  # display qwidget to name the event
@@ -2051,7 +2048,7 @@ class MeasureAnnotator(SignalAnnotator):
2051
2048
  try:
2052
2049
  self.status_scatter.set_edgecolors(self.colors[self.framedata][:, 0])
2053
2050
  except Exception as e:
2054
- print('L1993: ',e)
2051
+ pass
2055
2052
 
2056
2053
  self.current_label = self.labels[self.current_frame]
2057
2054
  self.current_label = contour_of_instance_segmentation(self.current_label, 5)
@@ -2067,7 +2064,6 @@ class MeasureAnnotator(SignalAnnotator):
2067
2064
  self.status_name=self.target_class
2068
2065
  else:
2069
2066
  self.status_name = self.class_choice_cb.currentText()
2070
- print('selection and expected names: ', self.status_name)
2071
2067
 
2072
2068
  if self.status_name not in self.df_tracks.columns:
2073
2069
  self.make_status_column()
@@ -2103,7 +2099,6 @@ class MeasureAnnotator(SignalAnnotator):
2103
2099
  if self.status_name == "state_firstdetection":
2104
2100
  pass
2105
2101
  else:
2106
- print('remaking the group column')
2107
2102
  self.df_tracks.loc[:, self.status_name] = 0
2108
2103
  all_states = self.df_tracks.loc[:, self.status_name].tolist()
2109
2104
  all_states = np.array(all_states)
@@ -2303,8 +2298,6 @@ class MeasureAnnotator(SignalAnnotator):
2303
2298
  self.current_stack[np.where(self.current_stack > 0.)] = np.log(
2304
2299
  self.current_stack[np.where(self.current_stack > 0.)])
2305
2300
 
2306
- print(f'Load stack of shape: {self.current_stack.shape}.')
2307
-
2308
2301
  def changed_channel(self):
2309
2302
 
2310
2303
  self.reload_frame()
@@ -2342,7 +2335,7 @@ class MeasureAnnotator(SignalAnnotator):
2342
2335
  pass
2343
2336
 
2344
2337
  self.df_tracks.to_csv(self.trajectories_path, index=False)
2345
- print('table saved.')
2338
+ print('Table successfully exported...')
2346
2339
  self.update_frame()
2347
2340
 
2348
2341
 
@@ -2399,9 +2392,8 @@ class MeasureAnnotator(SignalAnnotator):
2399
2392
 
2400
2393
  """
2401
2394
 
2402
- print("this is the loaded position: ", self.pos)
2403
2395
  if isinstance(self.pos, str):
2404
- movies = glob(self.pos + f"movie/{self.parent_window.parent_window.movie_prefix}*.tif")
2396
+ movies = glob(self.pos + os.sep.join(['movie',f"{self.parent_window.parent_window.movie_prefix}*.tif"]))
2405
2397
 
2406
2398
  else:
2407
2399
  msgBox = QMessageBox()
@@ -2437,8 +2429,6 @@ class MeasureAnnotator(SignalAnnotator):
2437
2429
  self.nbr_channels = len(self.channels)
2438
2430
  self.current_channel = 0
2439
2431
  self.img = load_frames(0, self.stack_path, normalize_input=False)
2440
- print(self.img.shape)
2441
- print(f'{self.stack_path} successfully located.')
2442
2432
 
2443
2433
  def reload_frame(self):
2444
2434
 
@@ -1,14 +1,11 @@
1
- import copy
2
-
3
1
  from PyQt5.QtWidgets import QMainWindow, QComboBox, QLabel, QRadioButton, QLineEdit, QFileDialog, QApplication, \
4
- QPushButton, QWidget, QVBoxLayout, QHBoxLayout, QMessageBox, QAction, QShortcut, QLineEdit, QTabWidget, \
5
- QButtonGroup, QGridLayout, QSlider, QCheckBox, QToolButton
2
+ QPushButton, QWidget, QVBoxLayout, QHBoxLayout, QMessageBox, QShortcut, QLineEdit, \
3
+ QButtonGroup
6
4
  from PyQt5.QtCore import Qt, QSize
7
5
  from PyQt5.QtGui import QKeySequence
8
- from matplotlib.collections import LineCollection
9
- from celldetective.gui import SignalAnnotator, Styles
10
- from celldetective.gui.gui_utils import center_window, QHSeperationLine, FilterChoice
11
- from superqt import QLabeledDoubleSlider, QLabeledDoubleRangeSlider, QLabeledSlider, QSearchableComboBox
6
+ from celldetective.gui import Styles
7
+ from celldetective.gui.gui_utils import center_window
8
+ from superqt import QLabeledDoubleRangeSlider, QSearchableComboBox
12
9
  from celldetective.utils import extract_experiment_channels, get_software_location, _get_img_num_per_channel
13
10
  from celldetective.io import auto_load_number_of_frames, load_frames
14
11
  from celldetective.gui.gui_utils import FigureCanvas, color_from_status, color_from_class
@@ -18,7 +15,6 @@ from superqt.fonticon import icon
18
15
  from fonticon_mdi6 import MDI6
19
16
  import os
20
17
  from glob import glob
21
- from natsort import natsorted
22
18
  import matplotlib.pyplot as plt
23
19
  from matplotlib.ticker import MultipleLocator
24
20
  from tqdm import tqdm
@@ -1869,15 +1865,15 @@ class SignalAnnotator2(QMainWindow,Styles):
1869
1865
 
1870
1866
 
1871
1867
  if self.df_targets is not None:
1872
- self.target_status_scatter = self.ax.scatter(self.target_positions[0][:,0], self.target_positions[0][:,1], marker="x", c=self.target_colors[0][:,1], s=50, picker=True, pickradius=10)
1873
- self.target_class_scatter = self.ax.scatter(self.target_positions[0][:,0], self.target_positions[0][:,1], marker='o', facecolors='none',edgecolors=self.target_colors[0][:,0], s=200)
1868
+ self.target_status_scatter = self.ax.scatter(self.target_positions[0][:,0], self.target_positions[0][:,1], marker="x", c=self.target_colors[0][:,1], s=50, picker=True, pickradius=10, zorder=10)
1869
+ self.target_class_scatter = self.ax.scatter(self.target_positions[0][:,0], self.target_positions[0][:,1], marker='o', facecolors='none',edgecolors=self.target_colors[0][:,0], s=200, zorder=10)
1874
1870
  else:
1875
1871
  self.target_status_scatter = self.ax.scatter([],[], marker="x", s=50, picker=True, pickradius=10)
1876
1872
  self.target_class_scatter = self.ax.scatter([],[], marker='o', facecolors='none', s=200)
1877
1873
 
1878
1874
  if self.df_effectors is not None:
1879
- self.effector_status_scatter = self.ax.scatter(self.effector_positions[0][:,0], self.effector_positions[0][:,1], marker="x", c=self.effector_colors[0][:,1], s=50, picker=True, pickradius=10)
1880
- self.effector_class_scatter = self.ax.scatter(self.effector_positions[0][:,0], self.effector_positions[0][:,1], marker='^', facecolors='none',edgecolors=self.effector_colors[0][:,0], s=200)
1875
+ self.effector_status_scatter = self.ax.scatter(self.effector_positions[0][:,0], self.effector_positions[0][:,1], marker="x", c=self.effector_colors[0][:,1], s=50, picker=True, pickradius=10, zorder=10)
1876
+ self.effector_class_scatter = self.ax.scatter(self.effector_positions[0][:,0], self.effector_positions[0][:,1], marker='^', facecolors='none',edgecolors=self.effector_colors[0][:,0], s=200, zorder=10)
1881
1877
  else:
1882
1878
  self.effector_status_scatter = self.ax.scatter([], [], marker="x", s=50, picker=True, pickradius=10)
1883
1879
  self.effector_class_scatter = self.ax.scatter([],[], marker='^', facecolors='none', s=200)