celldetective 1.3.5__py3-none-any.whl → 1.3.6.post2__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.
@@ -27,9 +27,10 @@ from pathlib import Path
27
27
 
28
28
  from celldetective.gui.viewers import CellEdgeVisualizer, SpotDetectionVisualizer
29
29
  from celldetective.gui.layouts import ProtocolDesignerLayout, BackgroundFitCorrectionLayout, LocalCorrectionLayout
30
- from celldetective.gui.gui_utils import ThresholdLineEdit
30
+ from celldetective.gui.gui_utils import ThresholdLineEdit, PreprocessingLayout2
31
31
  from celldetective.gui import Styles
32
32
 
33
+
33
34
  class ConfigMeasurements(QMainWindow, Styles):
34
35
  """
35
36
  UI to set measurement instructions.
@@ -477,6 +478,8 @@ class ConfigMeasurements(QMainWindow, Styles):
477
478
  Write the selected options in a json file for later reading by the software.
478
479
  """
479
480
 
481
+ print(f"{self.spot_preprocessing.list.items=}")
482
+
480
483
  print('Writing instructions...')
481
484
  measurement_options = {}
482
485
  background_correction = self.protocol_layout.protocols
@@ -508,8 +511,11 @@ class ConfigMeasurements(QMainWindow, Styles):
508
511
  'isotropic_operations': isotropic_operations})
509
512
  spot_detection = None
510
513
  if self.spot_check.isChecked():
514
+ image_preprocessing = self.spot_preprocessing.list.items
515
+ if image_preprocessing==[]:
516
+ image_preprocessing = None
511
517
  spot_detection = {'channel': self.spot_channel.currentText(), 'diameter': float(self.diameter_value.text().replace(',','.')),
512
- 'threshold': float(self.threshold_value.text().replace(',','.'))}
518
+ 'threshold': float(self.threshold_value.text().replace(',','.')), 'image_preprocessing': image_preprocessing}
513
519
  measurement_options.update({'spot_detection': spot_detection})
514
520
  if self.clear_previous_btn.isChecked():
515
521
  self.clear_previous = True
@@ -518,7 +524,6 @@ class ConfigMeasurements(QMainWindow, Styles):
518
524
  measurement_options.update({'clear_previous': self.clear_previous})
519
525
 
520
526
 
521
-
522
527
  print('Measurement instructions: ', measurement_options)
523
528
  file_name = self.measure_instructions_path
524
529
  with open(file_name, 'w') as f:
@@ -589,7 +594,13 @@ class ConfigMeasurements(QMainWindow, Styles):
589
594
  self.spot_channel.setCurrentText(idx)
590
595
  self.diameter_value.setText(str(spot_detection['diameter']))
591
596
  self.threshold_value.setText(str(spot_detection['threshold']))
592
-
597
+ if 'image_preprocessing' in spot_detection:
598
+ items = spot_detection['image_preprocessing']
599
+ if items is not None:
600
+ items_for_list = [a[0] for a in items]
601
+ for it in items_for_list:
602
+ self.spot_preprocessing.list.addItemToList(it)
603
+ self.spot_preprocessing.list.items = items
593
604
 
594
605
  if 'border_distances' in measurement_instructions:
595
606
  border_distances = measurement_instructions['border_distances']
@@ -886,43 +897,81 @@ class ConfigMeasurements(QMainWindow, Styles):
886
897
 
887
898
  def populate_spot_detection(self):
888
899
 
889
- layout = QGridLayout(self.spot_detection_frame)
900
+ layout = QVBoxLayout(self.spot_detection_frame)
901
+
890
902
  self.spot_detection_lbl = QLabel("SPOT DETECTION")
891
903
  self.spot_detection_lbl.setStyleSheet("""font-weight: bold;padding: 0px;""")
892
- layout.addWidget(self.spot_detection_lbl, 0, 0, 1, 2, alignment=Qt.AlignCenter)
893
- self.spot_check= QCheckBox('Perform spot detection')
904
+ layout.addWidget(self.spot_detection_lbl, alignment=Qt.AlignCenter)
905
+
906
+ perform_hbox = QHBoxLayout()
907
+ self.spot_check = QCheckBox('Perform spot detection')
894
908
  self.spot_check.toggled.connect(self.enable_spot_detection)
895
- layout.addWidget(self.spot_check, 1, 0)
896
- self.spot_channel_lbl = QLabel("Choose channel for spot detection: ")
909
+ perform_hbox.addWidget(self.spot_check, 95)
910
+
911
+ self.spot_viewer_btn = QPushButton()
912
+ self.spot_viewer_btn.clicked.connect(self.spot_preview)
913
+ self.spot_viewer_btn.setIcon(icon(MDI6.image_check, color="k"))
914
+ self.spot_viewer_btn.setStyleSheet(self.button_select_all)
915
+ self.spot_viewer_btn.setToolTip('Set detection parameters visually.')
916
+ perform_hbox.addWidget(self.spot_viewer_btn, 5)
917
+ layout.addLayout(perform_hbox)
918
+
919
+ channel_hbox = QHBoxLayout()
920
+ self.spot_channel_lbl = QLabel("Channel: ")
897
921
  self.spot_channel = QComboBox()
898
922
  self.spot_channel.addItems(self.channel_names)
899
- layout.addWidget(self.spot_channel_lbl, 2, 0)
900
- layout.addWidget(self.spot_channel, 2, 1)
923
+ channel_hbox.addWidget(self.spot_channel_lbl, 30)
924
+ channel_hbox.addWidget(self.spot_channel, 70)
925
+ layout.addLayout(channel_hbox)
926
+
927
+ self.spot_preprocessing = PreprocessingLayout2(fraction=30, parent_window=self)
928
+ layout.addLayout(self.spot_preprocessing)
929
+
930
+ # continue switching to VBox + HBox down
931
+ diam_hbox = QHBoxLayout()
901
932
  self.diameter_lbl = QLabel('Spot diameter: ')
902
933
  self.diameter_value = QLineEdit()
903
934
  self.diameter_value.setValidator(self.onlyFloat)
904
935
  self.diameter_value.setText('7')
905
936
  self.diameter_value.textChanged.connect(self.enable_spot_preview)
906
937
 
907
- layout.addWidget(self.diameter_lbl, 3, 0)
908
- layout.addWidget(self.diameter_value, 3, 1)
938
+ diam_hbox.addWidget(self.diameter_lbl,30)
939
+ diam_hbox.addWidget(self.diameter_value, 70)
940
+ layout.addLayout(diam_hbox)
941
+
942
+ thresh_hbox = QHBoxLayout()
909
943
  self.threshold_lbl = QLabel('Spot threshold: ')
910
944
  self.threshold_value = QLineEdit()
911
945
  self.threshold_value.setValidator(self.onlyFloat)
912
946
  self.threshold_value.setText('0')
913
947
  self.threshold_value.textChanged.connect(self.enable_spot_preview)
914
948
 
915
- layout.addWidget(self.threshold_lbl, 4, 0)
916
- layout.addWidget(self.threshold_value, 4, 1)
917
-
918
- self.spot_viewer_btn = QPushButton()
919
- self.spot_viewer_btn.clicked.connect(self.spot_preview)
920
- self.spot_viewer_btn.setIcon(icon(MDI6.image_check, color="k"))
921
- self.spot_viewer_btn.setStyleSheet(self.button_select_all)
922
- self.spot_viewer_btn.setToolTip('Set detection parameters visually.')
923
- layout.addWidget(self.spot_viewer_btn, 1, 1, 1, 1, alignment=Qt.AlignRight)
924
-
925
- self.spot_detection_widgets = [self.spot_channel, self.spot_channel_lbl, self.diameter_value, self.diameter_lbl, self.threshold_value, self.threshold_lbl, self.spot_viewer_btn]
949
+ thresh_hbox.addWidget(self.threshold_lbl, 30)
950
+ thresh_hbox.addWidget(self.threshold_value, 70)
951
+ layout.addLayout(thresh_hbox)
952
+
953
+ # #invert_layout = QHBoxLayout()
954
+ # self.invert_check = QCheckBox('invert')
955
+ # self.invert_value_le = QLineEdit('65535')
956
+ # self.invert_value_le.setValidator(self.onlyFloat)
957
+ # layout.addWidget(self.invert_check, 6, 0)
958
+ # layout.addWidget(self.invert_value_le, 6, 1)
959
+ # #layout.addLayout(invert_layout, 5, 1, 1, 1)
960
+
961
+ self.spot_detection_widgets = [self.spot_channel,
962
+ self.spot_channel_lbl,
963
+ self.diameter_value,
964
+ self.diameter_lbl,
965
+ self.threshold_value,
966
+ self.threshold_lbl,
967
+ self.spot_viewer_btn,
968
+ #self.invert_check,
969
+ #self.invert_value_le,
970
+ self.spot_preprocessing.list,
971
+ self.spot_preprocessing.add_filter_btn,
972
+ self.spot_preprocessing.delete_filter_btn,
973
+ self.spot_preprocessing.preprocess_lbl
974
+ ]
926
975
  for wg in self.spot_detection_widgets:
927
976
  wg.setEnabled(False)
928
977
 
@@ -940,6 +989,13 @@ class ConfigMeasurements(QMainWindow, Styles):
940
989
  if self.test_frame is not None:
941
990
  self.locate_mask()
942
991
  if self.test_mask is not None:
992
+
993
+ # invert_value = self.invert_value_le.text().replace(',','.')
994
+ # if invert_value != '':
995
+ # invert_value = float(invert_value)
996
+ # else:
997
+ # invert_value = None
998
+
943
999
  self.spot_visual = SpotDetectionVisualizer(frame_slider=True,
944
1000
  contrast_slider=True,
945
1001
  cell_type=self.mode,
@@ -952,6 +1008,10 @@ class ConfigMeasurements(QMainWindow, Styles):
952
1008
  parent_channel_cb=self.spot_channel,
953
1009
  parent_diameter_le=self.diameter_value,
954
1010
  parent_threshold_le=self.threshold_value,
1011
+ parent_preprocessing_list=self.spot_preprocessing.list,
1012
+ #parent_invert_check=self.invert_check,
1013
+ #invert = self.invert_check.isChecked(),
1014
+ #invert_value = self.invert_value_le.text().replace(',','.'),
955
1015
  PxToUm = 1,)
956
1016
  self.spot_visual.show()
957
1017
  #self.spot_visual = ThresholdSpot(current_channel=self.spot_channel.currentIndex(), img=self.test_frame,
@@ -400,7 +400,7 @@ class ConfigNeighborhoods(QWidget, Styles):
400
400
 
401
401
  status_options = [self.reference_population_status_cb.currentText(), self.neighbor_population_status_cb.currentText()]
402
402
  for k in range(2):
403
- if status_options[k]=='--':
403
+ if status_options[k]=='--' or status_options[k]=='':
404
404
  status_options[k] = None
405
405
  if pop[0]!=pop[1]:
406
406
  mode = 'two-pop'
@@ -7,7 +7,7 @@ from celldetective.gui.gui_utils import center_window, color_from_state
7
7
  from superqt import QLabeledDoubleSlider, QLabeledDoubleRangeSlider, QSearchableComboBox
8
8
  from celldetective.utils import extract_experiment_channels, get_software_location, _get_img_num_per_channel
9
9
  from celldetective.io import auto_load_number_of_frames, load_frames, \
10
- load_napari_data
10
+ load_napari_data, get_experiment_metadata
11
11
  from celldetective.gui.gui_utils import FigureCanvas, color_from_status, color_from_class, ExportPlotBtn
12
12
  import json
13
13
  import numpy as np
@@ -781,6 +781,11 @@ class SignalAnnotator(QMainWindow, Styles):
781
781
  'state', 'generation', 'root', 'parent', 'class_id', 'class', 't0', 'POSITION_X',
782
782
  'POSITION_Y', 'position', 'well', 'well_index', 'well_name', 'pos_name', 'index',
783
783
  'concentration', 'cell_type', 'antibody', 'pharmaceutical_agent'] + self.class_cols
784
+ meta = get_experiment_metadata(self.exp_dir)
785
+ if meta is not None:
786
+ keys = list(meta.keys())
787
+ cols_to_remove.extend(keys)
788
+
784
789
  cols = np.array(list(self.df_tracks.columns))
785
790
  time_cols = np.array([c.startswith('t_') for c in cols])
786
791
  time_cols = list(cols[time_cols])
@@ -7,7 +7,7 @@ from celldetective.gui import Styles
7
7
  from celldetective.gui.gui_utils import center_window
8
8
  from superqt import QLabeledDoubleRangeSlider, QSearchableComboBox
9
9
  from celldetective.utils import extract_experiment_channels, get_software_location, _get_img_num_per_channel
10
- from celldetective.io import auto_load_number_of_frames, load_frames
10
+ from celldetective.io import auto_load_number_of_frames, load_frames, get_experiment_metadata
11
11
  from celldetective.gui.gui_utils import FigureCanvas, color_from_status, color_from_class
12
12
  import json
13
13
  import numpy as np
@@ -66,7 +66,10 @@ class SignalAnnotator2(QMainWindow,Styles):
66
66
  't0', 'POSITION_X', 'POSITION_Y', 'position', 'well', 'well_index', 'well_name', 'pos_name',
67
67
  'index', 'relxy', 'tc', 'nk', 'concentration', 'antibody', 'cell_type', 'pharmaceutical_agent',
68
68
  'reference_population', 'neighbor_population']
69
-
69
+ meta = get_experiment_metadata(self.exp_dir)
70
+ if meta is not None:
71
+ keys = list(meta.keys())
72
+ self.cols_to_remove.extend(keys)
70
73
 
71
74
  # Read instructions from target block for now...
72
75
  self.mode = "neighborhood"
@@ -202,14 +205,14 @@ class SignalAnnotator2(QMainWindow,Styles):
202
205
 
203
206
  self.cell_events_hbox = QHBoxLayout()
204
207
  self.cell_events_hbox.setContentsMargins(0,0,0,0)
205
- self.cell_events_hbox.addWidget(QLabel('reference event: '), 25)
208
+ self.cell_events_hbox.addWidget(QLabel('Event: '), 25)
206
209
  self.reference_event_choice_cb = QComboBox()
207
210
  self.cell_events_hbox.addWidget(self.reference_event_choice_cb, 75)
208
211
 
209
212
  #if 'self' not in self.neighborhood_choice_cb.currentText():
210
213
  self.neigh_cell_events_hbox = QHBoxLayout()
211
214
  self.neigh_cell_events_hbox.setContentsMargins(0,0,0,0)
212
- self.neigh_lab=QLabel('neighbor event: ')
215
+ self.neigh_lab=QLabel('Event: ')
213
216
  self.neigh_cell_events_hbox.addWidget(self.neigh_lab, 25)
214
217
  self.neighbor_event_choice_cb = QComboBox()
215
218
  self.neigh_cell_events_hbox.addWidget(self.neighbor_event_choice_cb, 75)
@@ -230,7 +233,7 @@ class SignalAnnotator2(QMainWindow,Styles):
230
233
  neighbor_layout.addLayout(self.neigh_cell_events_hbox)
231
234
 
232
235
  self.cell_info_hbox.addLayout(reference_layout, 33)
233
- self.cell_info_hbox.addWidget(self.pair_info, 33, alignment=Qt.AlignCenter)
236
+ self.cell_info_hbox.addWidget(self.pair_info, 33)
234
237
  self.cell_info_hbox.addLayout(neighbor_layout, 33)
235
238
 
236
239
  self.left_panel.addLayout(self.cell_info_hbox)
@@ -2375,41 +2378,41 @@ class SignalAnnotator2(QMainWindow,Styles):
2375
2378
 
2376
2379
  df_reference = self.dataframes[self.reference_population]
2377
2380
  if self.reference_track_of_interest is not None:
2378
- reference_cell_selected = f"reference cell: {self.reference_track_of_interest}\n"
2379
- reference_cell_population = f"population: {self.reference_population}\n"
2381
+ reference_cell_selected = f"Ref #{self.reference_track_of_interest}\n"
2382
+ reference_cell_population = f"Pop: {self.reference_population}\n"
2380
2383
  #reference_cell_class = f"class: {df_reference[df_reference['TRACK_ID']==self.reference_track_of_interest, self.reference_event_choice_cb.currentText()].values[0]}\n"
2381
2384
  #reference_cell_time = f"time of interest: {df_reference[df_reference['TRACK_ID']==self.reference_track_of_interest, ''].values[0]}\n"
2382
2385
  self.reference_cell_info.setText(reference_cell_selected+reference_cell_population)
2383
2386
  else:
2384
- reference_cell_selected = f"reference cell: None\n"
2385
- reference_cell_population = f"population: {self.reference_population}\n"
2387
+ reference_cell_selected = f"Ref: None\n"
2388
+ reference_cell_population = f"Pop: {self.reference_population}\n"
2386
2389
  self.reference_cell_info.setText(reference_cell_selected+reference_cell_population)
2387
2390
 
2388
2391
  def give_neighbor_cell_information(self):
2389
2392
 
2390
2393
  if self.neighbor_track_of_interest is not None:
2391
- neighbor_cell_selected = f"neighbor cell: {self.neighbor_track_of_interest}\n"
2392
- neighbor_cell_population = f"population: {self.neighbor_population}\n"
2394
+ neighbor_cell_selected = f"Neigh #{self.neighbor_track_of_interest}\n"
2395
+ neighbor_cell_population = f"Pop: {self.neighbor_population}\n"
2393
2396
  #neighbor_cell_time = f"time of interest: {self.df_relative.loc[(self.df_relative['REFERENCE_ID']==self.reference_track_of_interest)&(self.df_relative['NEIGHBOR_ID']==self.neighbor_track_of_interest), self.pair_time_name].to_numpy()[0]}\n"
2394
2397
  #neighbor_cell_class = f"class: {self.df_relative.loc[(self.df_relative['REFERENCE_ID']==self.reference_track_of_interest)&(self.df_relative['NEIGHBOR_ID']==self.neighbor_track_of_interest), self.pair_class_name].to_numpy()[0]}\n"
2395
2398
  self.neighbor_cell_info.setText(neighbor_cell_selected+neighbor_cell_population) #neighbor_cell_class+neighbor_cell_time
2396
2399
  else:
2397
- neighbor_cell_selected = f"neighbor cell: None\n"
2398
- neighbor_cell_population = f"population: {self.neighbor_population}\n"
2400
+ neighbor_cell_selected = f"Neigh: None\n"
2401
+ neighbor_cell_population = f"Pop: {self.neighbor_population}\n"
2399
2402
  self.neighbor_cell_info.setText(neighbor_cell_selected+neighbor_cell_population)
2400
2403
 
2401
2404
  def give_pair_information(self):
2402
2405
 
2403
2406
  if self.neighbor_track_of_interest is not None and self.reference_track_of_interest is not None:
2404
- pair_selected = f"(reference/neighbor) pair: ({self.reference_track_of_interest},{self.neighbor_track_of_interest})\n"
2405
- pair_populations = f"populations: ({self.reference_population}, {self.neighbor_population})\n"
2407
+ pair_selected = f"Pair: ({self.reference_track_of_interest},{self.neighbor_track_of_interest})\n"
2408
+ pair_populations = "" #f"populations: ({self.reference_population}, {self.neighbor_population})\n"
2406
2409
  current_class = self.relative_class_choice_cb.currentText()
2407
- pair_class = f"interaction event class: {self.df_relative.loc[(self.df_relative['REFERENCE_ID']==self.reference_track_of_interest)&(self.df_relative['NEIGHBOR_ID']==self.neighbor_track_of_interest)&(self.df_relative['reference_population']==self.reference_population)&(self.df_relative['neighbor_population']==self.neighbor_population)&(~self.df_relative['status_'+self.current_neighborhood].isnull()), current_class].values[0]}\n"
2408
- pair_time = f"time of interest: {self.df_relative.loc[(self.df_relative['REFERENCE_ID']==self.reference_track_of_interest)&(self.df_relative['NEIGHBOR_ID']==self.neighbor_track_of_interest)&(self.df_relative['reference_population']==self.reference_population)&(self.df_relative['neighbor_population']==self.neighbor_population)&(~self.df_relative['status_'+self.current_neighborhood].isnull()), self.pair_time_name].values[0]}\n"
2410
+ pair_class = f"Event class: {self.df_relative.loc[(self.df_relative['REFERENCE_ID']==self.reference_track_of_interest)&(self.df_relative['NEIGHBOR_ID']==self.neighbor_track_of_interest)&(self.df_relative['reference_population']==self.reference_population)&(self.df_relative['neighbor_population']==self.neighbor_population)&(~self.df_relative['status_'+self.current_neighborhood].isnull()), current_class].values[0]}\n"
2411
+ pair_time = f"Time: {self.df_relative.loc[(self.df_relative['REFERENCE_ID']==self.reference_track_of_interest)&(self.df_relative['NEIGHBOR_ID']==self.neighbor_track_of_interest)&(self.df_relative['reference_population']==self.reference_population)&(self.df_relative['neighbor_population']==self.neighbor_population)&(~self.df_relative['status_'+self.current_neighborhood].isnull()), self.pair_time_name].values[0]}\n"
2409
2412
  self.pair_info.setText(pair_selected+pair_populations+pair_class+pair_time)
2410
2413
  else:
2411
- pair_selected = f"(reference/neighbor) pair: None\n"
2412
- pair_populations = f"populations: ({self.reference_population}, {self.neighbor_population})\n"
2414
+ pair_selected = f"Pair: None\n"
2415
+ pair_populations = "" #f"populations: ({self.reference_population}, {self.neighbor_population})\n"
2413
2416
  self.pair_info.setText(pair_selected+pair_populations)
2414
2417
 
2415
2418
 
@@ -11,11 +11,9 @@ import os
11
11
  import matplotlib.pyplot as plt
12
12
  plt.rcParams['svg.fonttype'] = 'none'
13
13
  from glob import glob
14
- import pandas as pd
15
14
  from celldetective.gui import Styles
16
15
  from matplotlib import colormaps
17
16
  from celldetective.events import compute_survival
18
- from natsort import natsorted
19
17
  from celldetective.relative_measurements import expand_pair_table
20
18
  import matplotlib.cm
21
19
  from celldetective.neighborhood import extract_neighborhood_in_pair_table
@@ -3,7 +3,8 @@ from PyQt5.QtWidgets import QAction, QMenu, QMainWindow, QMessageBox, QLabel, QW
3
3
  from PyQt5.QtGui import QDoubleValidator, QIntValidator
4
4
 
5
5
  from celldetective.filters import std_filter, gauss_filter
6
- from celldetective.gui.gui_utils import center_window, FigureCanvas, ListWidget, FilterChoice, color_from_class, help_generic
6
+ from celldetective.gui.gui_utils import center_window, FigureCanvas, color_from_class, help_generic
7
+ from celldetective.gui.gui_utils import PreprocessingLayout
7
8
  from celldetective.utils import get_software_location, extract_experiment_channels, rename_intensity_column, estimate_unreliable_edge
8
9
  from celldetective.io import auto_load_number_of_frames, load_frames
9
10
  from celldetective.segmentation import threshold_image, identify_markers_from_binary, apply_watershed
@@ -23,6 +24,7 @@ import os
23
24
 
24
25
  from celldetective.gui import Styles
25
26
 
27
+
26
28
  class ThresholdConfigWizard(QMainWindow, Styles):
27
29
  """
28
30
  UI to create a threshold pipeline for segmentation.
@@ -140,53 +142,8 @@ class ThresholdConfigWizard(QMainWindow, Styles):
140
142
 
141
143
  def populate_left_panel(self):
142
144
 
143
- self.filters_qlist = ListWidget(FilterChoice, [])
144
-
145
- grid_preprocess = QGridLayout()
146
- grid_preprocess.setContentsMargins(20, 20, 20, 20)
147
-
148
- filter_list_option_grid = QHBoxLayout()
149
- section_preprocess = QLabel("Preprocessing")
150
- section_preprocess.setStyleSheet("font-weight: bold;")
151
- filter_list_option_grid.addWidget(section_preprocess, 90, alignment=Qt.AlignLeft)
152
-
153
- self.delete_filter = QPushButton("")
154
- self.delete_filter.setStyleSheet(self.button_select_all)
155
- self.delete_filter.setIcon(icon(MDI6.trash_can, color="black"))
156
- self.delete_filter.setToolTip("Remove filter")
157
- self.delete_filter.setIconSize(QSize(20, 20))
158
- self.delete_filter.clicked.connect(self.filters_qlist.removeSel)
159
-
160
- self.add_filter = QPushButton("")
161
- self.add_filter.setStyleSheet(self.button_select_all)
162
- self.add_filter.setIcon(icon(MDI6.filter_plus, color="black"))
163
- self.add_filter.setToolTip("Add filter")
164
- self.add_filter.setIconSize(QSize(20, 20))
165
- self.add_filter.clicked.connect(self.filters_qlist.addItem)
166
-
167
- self.help_prefilter_btn = QPushButton()
168
- self.help_prefilter_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
169
- self.help_prefilter_btn.setIconSize(QSize(20, 20))
170
- self.help_prefilter_btn.clicked.connect(self.help_prefilter)
171
- self.help_prefilter_btn.setStyleSheet(self.button_select_all)
172
- self.help_prefilter_btn.setToolTip("Help.")
173
-
174
- # filter_list_option_grid.addWidget(QLabel(""),90)
175
- filter_list_option_grid.addWidget(self.delete_filter, 5)
176
- filter_list_option_grid.addWidget(self.add_filter, 5)
177
- filter_list_option_grid.addWidget(self.help_prefilter_btn, 5)
178
-
179
- grid_preprocess.addLayout(filter_list_option_grid, 0, 0, 1, 3)
180
- grid_preprocess.addWidget(self.filters_qlist, 1, 0, 1, 3)
181
-
182
- self.apply_filters_btn = QPushButton("Apply")
183
- self.apply_filters_btn.setIcon(icon(MDI6.filter_cog_outline, color="white"))
184
- self.apply_filters_btn.setIconSize(QSize(20, 20))
185
- self.apply_filters_btn.setStyleSheet(self.button_style_sheet)
186
- self.apply_filters_btn.clicked.connect(self.preprocess_image)
187
- grid_preprocess.addWidget(self.apply_filters_btn, 2, 0, 1, 3)
188
-
189
- self.left_panel.addLayout(grid_preprocess)
145
+ self.preprocessing = PreprocessingLayout(self)
146
+ self.left_panel.addLayout(self.preprocessing)
190
147
 
191
148
  ###################
192
149
  # THRESHOLD SECTION
@@ -484,7 +441,7 @@ class ThresholdConfigWizard(QMainWindow, Styles):
484
441
  self.fcanvas = FigureCanvas(self.fig, interactive=True)
485
442
  self.ax.clear()
486
443
 
487
- self.im = self.ax.imshow(self.img, cmap='gray')
444
+ self.im = self.ax.imshow(self.img, cmap='gray', interpolation='none')
488
445
 
489
446
  self.binary = threshold_image(self.img, self.threshold_slider.value()[0], self.threshold_slider.value()[1],
490
447
  foreground_value=1., fill_holes=True, edge_exclusion=None)
@@ -640,7 +597,7 @@ class ThresholdConfigWizard(QMainWindow, Styles):
640
597
  """
641
598
 
642
599
  self.reload_frame()
643
- filters = self.filters_qlist.items
600
+ filters = self.preprocessing.list.items
644
601
  self.edge = estimate_unreliable_edge(filters)
645
602
  self.img = filter_image(self.img, filters)
646
603
  self.refresh_imshow()
@@ -853,7 +810,7 @@ class ThresholdConfigWizard(QMainWindow, Styles):
853
810
  instructions = {
854
811
  "target_channel": self.channels_cb.currentText(), # for now index but would be more universal to use name
855
812
  "thresholds": self.threshold_slider.value(),
856
- "filters": self.filters_qlist.items,
813
+ "filters": self.preprocessing.list.items,
857
814
  "marker_min_distance": self.min_dist,
858
815
  "marker_footprint_size": self.footprint,
859
816
  "feature_queries": [self.property_query_le.text()],
@@ -906,7 +863,7 @@ class ThresholdConfigWizard(QMainWindow, Styles):
906
863
  items_to_add = [f[0] + '_filter' for f in filters]
907
864
  self.filters_qlist.list_widget.clear()
908
865
  self.filters_qlist.list_widget.addItems(items_to_add)
909
- self.filters_qlist.items = filters
866
+ self.preprocessing.list.items = filters
910
867
 
911
868
  self.apply_filters_btn.click()
912
869
 
@@ -14,7 +14,7 @@ import os
14
14
  from PyQt5.QtWidgets import QWidget, QHBoxLayout, QPushButton, QLabel, QComboBox, QLineEdit, QListWidget, QShortcut
15
15
  from PyQt5.QtCore import Qt, QSize
16
16
  from PyQt5.QtGui import QKeySequence, QDoubleValidator
17
- from celldetective.gui.gui_utils import FigureCanvas, center_window, QuickSliderLayout, QHSeperationLine, ThresholdLineEdit
17
+ from celldetective.gui.gui_utils import FigureCanvas, center_window, QuickSliderLayout, QHSeperationLine, ThresholdLineEdit, PreprocessingLayout2
18
18
  from celldetective.gui import Styles
19
19
  from superqt import QLabeledDoubleSlider, QLabeledSlider, QLabeledDoubleRangeSlider
20
20
  from superqt.fonticon import icon
@@ -626,21 +626,26 @@ class CellEdgeVisualizer(StackVisualizer):
626
626
 
627
627
  class SpotDetectionVisualizer(StackVisualizer):
628
628
 
629
- def __init__(self, parent_channel_cb=None, parent_diameter_le=None, parent_threshold_le=None, cell_type='targets', labels=None, *args, **kwargs):
629
+ def __init__(self, parent_channel_cb=None, parent_diameter_le=None, parent_threshold_le=None, parent_preprocessing_list=None, cell_type='targets', labels=None, *args, **kwargs):
630
630
 
631
631
  super().__init__(*args, **kwargs)
632
632
 
633
633
  self.cell_type = cell_type
634
634
  self.labels = labels
635
635
  self.detection_channel = self.target_channel
636
+
636
637
  self.parent_channel_cb = parent_channel_cb
637
638
  self.parent_diameter_le = parent_diameter_le
638
639
  self.parent_threshold_le = parent_threshold_le
639
- self.spot_sizes = []
640
+ self.parent_preprocessing_list = parent_preprocessing_list
640
641
 
642
+ self.spot_sizes = []
641
643
  self.floatValidator = QDoubleValidator()
642
644
  self.init_scatter()
643
- self.generate_detection_channel()
645
+
646
+ self.generate_detection_channel()
647
+ self.detection_channel = self.detection_channel_cb.currentIndex()
648
+
644
649
  self.generate_spot_detection_params()
645
650
  self.generate_add_measurement_btn()
646
651
  self.load_labels()
@@ -663,10 +668,10 @@ class SpotDetectionVisualizer(StackVisualizer):
663
668
 
664
669
  # Data-to-pixel scale
665
670
  ax_width_in_pixels = self.ax.bbox.width
666
- ax_height_in_pixels = self.ax.bbox.height
671
+ ax_height_in_pixels =self.ax.bbox.height
667
672
 
668
- x_scale = (xlim[1] - xlim[0]) / ax_width_in_pixels
669
- y_scale = (ylim[1] - ylim[0]) / ax_height_in_pixels
673
+ x_scale = (float(xlim[1]) - float(xlim[0])) / ax_width_in_pixels
674
+ y_scale = (float(ylim[1]) - float(ylim[0])) / ax_height_in_pixels
670
675
 
671
676
  # Choose the smaller scale for square pixels
672
677
  scale = min(x_scale, y_scale)
@@ -674,7 +679,7 @@ class SpotDetectionVisualizer(StackVisualizer):
674
679
  # Convert radius_px to data units
675
680
  if len(self.spot_sizes)>0:
676
681
 
677
- radius_data_units = self.spot_sizes / scale
682
+ radius_data_units = self.spot_sizes / float(scale)
678
683
 
679
684
  # Convert to scatter `s` size (points squared)
680
685
  radius_pts = radius_data_units * (72. / self.fig.dpi )
@@ -697,8 +702,7 @@ class SpotDetectionVisualizer(StackVisualizer):
697
702
  if self.mode=='virtual':
698
703
  self.init_label = imread(self.mask_paths[value])
699
704
  self.target_img = load_frames(self.img_num_per_channel[self.detection_channel, value],
700
- self.stack_path,
701
- normalize_input=False).astype(float)[:,:,0]
705
+ self.stack_path,normalize_input=False).astype(float)[:,:,0]
702
706
  elif self.mode=='direct':
703
707
  self.init_label = self.labels[value,:,:]
704
708
  self.target_img = self.stack[value,:,:,self.detection_channel].copy()
@@ -707,18 +711,28 @@ class SpotDetectionVisualizer(StackVisualizer):
707
711
 
708
712
  self.reset_detection()
709
713
  self.control_valid_parameters() # set current diam and threshold
710
- blobs_filtered = extract_blobs_in_image(self.target_img, self.init_label,threshold=self.thresh, diameter=self.diameter)
714
+ #self.change_frame(self.frame_slider.value())
715
+ #self.set_detection_channel_index(self.detection_channel_cb.currentIndex())
716
+
717
+ image_preprocessing = self.preprocessing.list.items
718
+ if image_preprocessing==[]:
719
+ image_preprocessing = None
720
+
721
+ blobs_filtered = extract_blobs_in_image(self.target_img, self.init_label,threshold=self.thresh, diameter=self.diameter, image_preprocessing=image_preprocessing)
711
722
  if blobs_filtered is not None:
712
723
  self.spot_positions = np.array([[x,y] for y,x,_ in blobs_filtered])
713
-
714
- self.spot_sizes = np.sqrt(2)*np.array([sig for _,_,sig in blobs_filtered])
715
- print(f"{self.spot_sizes=}")
724
+ if len(self.spot_positions)>0:
725
+ self.spot_sizes = np.sqrt(2)*np.array([sig for _,_,sig in blobs_filtered])
716
726
  #radius_pts = self.spot_sizes * (self.fig.dpi / 72.0)
717
727
  #sizes = np.pi*(radius_pts**2)
718
-
719
- self.spot_scat.set_offsets(self.spot_positions)
728
+ if len(self.spot_positions)>0:
729
+ self.spot_scat.set_offsets(self.spot_positions)
730
+ else:
731
+ empty_offset = np.ma.masked_array([0, 0], mask=True)
732
+ self.spot_scat.set_offsets(empty_offset)
720
733
  #self.spot_scat.set_sizes(sizes)
721
- self.update_marker_sizes()
734
+ if len(self.spot_positions)>0:
735
+ self.update_marker_sizes()
722
736
  self.canvas.canvas.draw()
723
737
 
724
738
  def reset_detection(self):
@@ -778,17 +792,34 @@ class SpotDetectionVisualizer(StackVisualizer):
778
792
  self.detection_channel_cb.addItems(self.channel_names)
779
793
  self.detection_channel_cb.currentIndexChanged.connect(self.set_detection_channel_index)
780
794
  channel_layout.addWidget(self.detection_channel_cb, 75)
795
+
796
+ # self.invert_check = QCheckBox('invert')
797
+ # if self.invert:
798
+ # self.invert_check.setChecked(True)
799
+ # self.invert_check.toggled.connect(self.set_invert)
800
+ # channel_layout.addWidget(self.invert_check, 10)
801
+
781
802
  self.canvas.layout.addLayout(channel_layout)
803
+
804
+ self.preprocessing = PreprocessingLayout2(fraction=25, parent_window=self)
805
+ self.preprocessing.setContentsMargins(15,0,15,0)
806
+ self.canvas.layout.addLayout(self.preprocessing)
807
+
808
+
809
+ # def set_invert(self):
810
+ # if self.invert_check.isChecked():
811
+ # self.invert = True
812
+ # else:
813
+ # self.invert = False
782
814
 
783
815
  def set_detection_channel_index(self, value):
784
816
 
785
817
  self.detection_channel = value
786
818
  if self.mode == 'direct':
787
- self.last_frame = self.stack[-1,:,:,self.target_channel]
819
+ self.target_img = self.stack[-1,:,:,self.detection_channel]
788
820
  elif self.mode == 'virtual':
789
- self.target_img = load_frames(self.img_num_per_channel[self.detection_channel, self.stack_length-1],
790
- self.stack_path,
791
- normalize_input=False).astype(float)[:,:,0]
821
+ self.target_img = load_frames(self.img_num_per_channel[self.detection_channel, self.frame_slider.value()],
822
+ self.stack_path,normalize_input=False).astype(float)[:,:,0]
792
823
 
793
824
  def generate_spot_detection_params(self):
794
825
 
@@ -865,6 +896,12 @@ class SpotDetectionVisualizer(StackVisualizer):
865
896
  self.parent_diameter_le.setText(self.spot_diam_le.text())
866
897
  if self.parent_threshold_le is not None:
867
898
  self.parent_threshold_le.setText(self.spot_thresh_le.text())
899
+ if self.parent_preprocessing_list is not None:
900
+ self.parent_preprocessing_list.clear()
901
+ items = self.preprocessing.list.getItems()
902
+ for item in items:
903
+ self.parent_preprocessing_list.addItemToList(item)
904
+ self.parent_preprocessing_list.items = self.preprocessing.list.items
868
905
  self.close()
869
906
 
870
907
  class CellSizeViewer(StackVisualizer):