celldetective 1.3.5__py3-none-any.whl → 1.3.6.post1__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,
@@ -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"
@@ -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):
celldetective/io.py CHANGED
@@ -25,7 +25,7 @@ from magicgui import magicgui
25
25
  from pathlib import Path, PurePath
26
26
  from shutil import copyfile, rmtree
27
27
 
28
- from celldetective.utils import ConfigSectionMap, extract_experiment_channels, _extract_labels_from_config, get_zenodo_files, download_zenodo_file, interpolate_nan
28
+ from celldetective.utils import ConfigSectionMap, extract_experiment_channels, _extract_labels_from_config, get_zenodo_files, download_zenodo_file
29
29
  from celldetective.utils import _estimate_scale_factor, _extract_channel_indices_from_config, _extract_channel_indices, _extract_nbr_channels_from_config, _get_img_num_per_channel, normalize_per_channel
30
30
 
31
31
  from stardist import fill_label_holes
@@ -211,7 +211,15 @@ def collect_experiment_metadata(pos_path=None, well_path=None):
211
211
  antibodies = get_experiment_antibodies(experiment)
212
212
  pharmaceutical_agents = get_experiment_pharmaceutical_agents(experiment)
213
213
 
214
- return {"pos_path": pos_path, "position": pos_path, "pos_name": pos_name, "well_path": well_path, "well_name": well_name, "well_nbr": well_nbr, "experiment": experiment, "antibody": antibodies[idx], "concentration": concentrations[idx], "cell_type": cell_types[idx], "pharmaceutical_agent": pharmaceutical_agents[idx]}
214
+ dico = {"pos_path": pos_path, "position": pos_path, "pos_name": pos_name, "well_path": well_path, "well_name": well_name, "well_nbr": well_nbr, "experiment": experiment, "antibody": antibodies[idx], "concentration": concentrations[idx], "cell_type": cell_types[idx], "pharmaceutical_agent": pharmaceutical_agents[idx]}
215
+
216
+ meta = get_experiment_metadata(experiment) # None or dict of metadata
217
+ if meta is not None:
218
+ keys = list(meta.keys())
219
+ for k in keys:
220
+ dico.update({k: meta[k]})
221
+
222
+ return dico
215
223
 
216
224
 
217
225
  def get_experiment_wells(experiment):
@@ -379,6 +387,12 @@ def get_temporal_calibration(experiment):
379
387
 
380
388
  return FrameToMin
381
389
 
390
+ def get_experiment_metadata(experiment):
391
+
392
+ config = get_config(experiment)
393
+ metadata = ConfigSectionMap(config, "Metadata")
394
+ return metadata
395
+
382
396
 
383
397
  def get_experiment_concentrations(experiment, dtype=str):
384
398
 
@@ -957,6 +971,7 @@ def load_experiment_tables(experiment, population='targets', well_option='*', po
957
971
  cell_types = get_experiment_cell_types(experiment)
958
972
  antibodies = get_experiment_antibodies(experiment)
959
973
  pharmaceutical_agents = get_experiment_pharmaceutical_agents(experiment)
974
+ metadata = get_experiment_metadata(experiment) # None or dict of metadata
960
975
  well_labels = _extract_labels_from_config(config, len(wells))
961
976
 
962
977
  well_indices, position_indices = interpret_wells_and_positions(experiment, well_option, position_option)
@@ -1011,15 +1026,23 @@ def load_experiment_tables(experiment, population='targets', well_option='*', po
1011
1026
  df_pos['antibody'] = well_antibody
1012
1027
  df_pos['cell_type'] = well_cell_type
1013
1028
  df_pos['pharmaceutical_agent'] = well_pharmaceutical_agent
1029
+ if metadata is not None:
1030
+ keys = list(metadata.keys())
1031
+ for k in keys:
1032
+ df_pos[k] = metadata[k]
1014
1033
 
1015
1034
  df.append(df_pos)
1016
1035
  any_table = True
1017
1036
 
1018
- df_pos_info.append(
1019
- {'pos_path': pos_path, 'pos_index': real_pos_index, 'pos_name': pos_name, 'table_path': table,
1020
- 'stack_path': stack_path,
1021
- 'well_path': well_path, 'well_index': real_well_index, 'well_name': well_name,
1022
- 'well_number': well_number, 'well_alias': well_alias})
1037
+ pos_dict = {'pos_path': pos_path, 'pos_index': real_pos_index, 'pos_name': pos_name, 'table_path': table,
1038
+ 'stack_path': stack_path,'well_path': well_path, 'well_index': real_well_index, 'well_name': well_name,
1039
+ 'well_number': well_number, 'well_alias': well_alias}
1040
+ # if metadata is not None:
1041
+ # keys = list(metadata.keys())
1042
+ # for k in keys:
1043
+ # pos_dict.update({k: metadata[k]})
1044
+
1045
+ df_pos_info.append(pos_dict)
1023
1046
 
1024
1047
  real_pos_index += 1
1025
1048