celldetective 1.4.2__py3-none-any.whl → 1.5.0b0__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 (151) hide show
  1. celldetective/__init__.py +25 -0
  2. celldetective/__main__.py +62 -43
  3. celldetective/_version.py +1 -1
  4. celldetective/extra_properties.py +477 -399
  5. celldetective/filters.py +192 -97
  6. celldetective/gui/InitWindow.py +541 -411
  7. celldetective/gui/__init__.py +0 -15
  8. celldetective/gui/about.py +44 -39
  9. celldetective/gui/analyze_block.py +120 -84
  10. celldetective/gui/base/__init__.py +0 -0
  11. celldetective/gui/base/channel_norm_generator.py +335 -0
  12. celldetective/gui/base/components.py +249 -0
  13. celldetective/gui/base/feature_choice.py +92 -0
  14. celldetective/gui/base/figure_canvas.py +52 -0
  15. celldetective/gui/base/list_widget.py +133 -0
  16. celldetective/gui/{styles.py → base/styles.py} +92 -36
  17. celldetective/gui/base/utils.py +33 -0
  18. celldetective/gui/base_annotator.py +900 -767
  19. celldetective/gui/classifier_widget.py +6 -22
  20. celldetective/gui/configure_new_exp.py +777 -671
  21. celldetective/gui/control_panel.py +635 -524
  22. celldetective/gui/dynamic_progress.py +449 -0
  23. celldetective/gui/event_annotator.py +2023 -1662
  24. celldetective/gui/generic_signal_plot.py +1292 -944
  25. celldetective/gui/gui_utils.py +899 -1289
  26. celldetective/gui/interactions_block.py +658 -0
  27. celldetective/gui/interactive_timeseries_viewer.py +447 -0
  28. celldetective/gui/json_readers.py +48 -15
  29. celldetective/gui/layouts/__init__.py +5 -0
  30. celldetective/gui/layouts/background_model_free_layout.py +537 -0
  31. celldetective/gui/layouts/channel_offset_layout.py +134 -0
  32. celldetective/gui/layouts/local_correction_layout.py +91 -0
  33. celldetective/gui/layouts/model_fit_layout.py +372 -0
  34. celldetective/gui/layouts/operation_layout.py +68 -0
  35. celldetective/gui/layouts/protocol_designer_layout.py +96 -0
  36. celldetective/gui/pair_event_annotator.py +3130 -2435
  37. celldetective/gui/plot_measurements.py +586 -267
  38. celldetective/gui/plot_signals_ui.py +724 -506
  39. celldetective/gui/preprocessing_block.py +395 -0
  40. celldetective/gui/process_block.py +1678 -1831
  41. celldetective/gui/seg_model_loader.py +580 -473
  42. celldetective/gui/settings/__init__.py +0 -7
  43. celldetective/gui/settings/_cellpose_model_params.py +181 -0
  44. celldetective/gui/settings/_event_detection_model_params.py +95 -0
  45. celldetective/gui/settings/_segmentation_model_params.py +159 -0
  46. celldetective/gui/settings/_settings_base.py +77 -65
  47. celldetective/gui/settings/_settings_event_model_training.py +752 -526
  48. celldetective/gui/settings/_settings_measurements.py +1133 -964
  49. celldetective/gui/settings/_settings_neighborhood.py +574 -488
  50. celldetective/gui/settings/_settings_segmentation_model_training.py +779 -564
  51. celldetective/gui/settings/_settings_signal_annotator.py +329 -305
  52. celldetective/gui/settings/_settings_tracking.py +1304 -1094
  53. celldetective/gui/settings/_stardist_model_params.py +98 -0
  54. celldetective/gui/survival_ui.py +422 -312
  55. celldetective/gui/tableUI.py +1665 -1701
  56. celldetective/gui/table_ops/_maths.py +295 -0
  57. celldetective/gui/table_ops/_merge_groups.py +140 -0
  58. celldetective/gui/table_ops/_merge_one_hot.py +95 -0
  59. celldetective/gui/table_ops/_query_table.py +43 -0
  60. celldetective/gui/table_ops/_rename_col.py +44 -0
  61. celldetective/gui/thresholds_gui.py +382 -179
  62. celldetective/gui/viewers/__init__.py +0 -0
  63. celldetective/gui/viewers/base_viewer.py +700 -0
  64. celldetective/gui/viewers/channel_offset_viewer.py +331 -0
  65. celldetective/gui/viewers/contour_viewer.py +394 -0
  66. celldetective/gui/viewers/size_viewer.py +153 -0
  67. celldetective/gui/viewers/spot_detection_viewer.py +341 -0
  68. celldetective/gui/viewers/threshold_viewer.py +309 -0
  69. celldetective/gui/workers.py +304 -126
  70. celldetective/log_manager.py +92 -0
  71. celldetective/measure.py +1895 -1478
  72. celldetective/napari/__init__.py +0 -0
  73. celldetective/napari/utils.py +1025 -0
  74. celldetective/neighborhood.py +1914 -1448
  75. celldetective/preprocessing.py +1620 -1220
  76. celldetective/processes/__init__.py +0 -0
  77. celldetective/processes/background_correction.py +271 -0
  78. celldetective/processes/compute_neighborhood.py +894 -0
  79. celldetective/processes/detect_events.py +246 -0
  80. celldetective/processes/measure_cells.py +565 -0
  81. celldetective/processes/segment_cells.py +760 -0
  82. celldetective/processes/track_cells.py +435 -0
  83. celldetective/processes/train_segmentation_model.py +694 -0
  84. celldetective/processes/train_signal_model.py +265 -0
  85. celldetective/processes/unified_process.py +292 -0
  86. celldetective/regionprops/_regionprops.py +358 -317
  87. celldetective/relative_measurements.py +987 -710
  88. celldetective/scripts/measure_cells.py +313 -212
  89. celldetective/scripts/measure_relative.py +90 -46
  90. celldetective/scripts/segment_cells.py +165 -104
  91. celldetective/scripts/segment_cells_thresholds.py +96 -68
  92. celldetective/scripts/track_cells.py +198 -149
  93. celldetective/scripts/train_segmentation_model.py +324 -201
  94. celldetective/scripts/train_signal_model.py +87 -45
  95. celldetective/segmentation.py +844 -749
  96. celldetective/signals.py +3514 -2861
  97. celldetective/tracking.py +30 -15
  98. celldetective/utils/__init__.py +0 -0
  99. celldetective/utils/cellpose_utils/__init__.py +133 -0
  100. celldetective/utils/color_mappings.py +42 -0
  101. celldetective/utils/data_cleaning.py +630 -0
  102. celldetective/utils/data_loaders.py +450 -0
  103. celldetective/utils/dataset_helpers.py +207 -0
  104. celldetective/utils/downloaders.py +197 -0
  105. celldetective/utils/event_detection/__init__.py +8 -0
  106. celldetective/utils/experiment.py +1782 -0
  107. celldetective/utils/image_augmenters.py +308 -0
  108. celldetective/utils/image_cleaning.py +74 -0
  109. celldetective/utils/image_loaders.py +926 -0
  110. celldetective/utils/image_transforms.py +335 -0
  111. celldetective/utils/io.py +62 -0
  112. celldetective/utils/mask_cleaning.py +348 -0
  113. celldetective/utils/mask_transforms.py +5 -0
  114. celldetective/utils/masks.py +184 -0
  115. celldetective/utils/maths.py +351 -0
  116. celldetective/utils/model_getters.py +325 -0
  117. celldetective/utils/model_loaders.py +296 -0
  118. celldetective/utils/normalization.py +380 -0
  119. celldetective/utils/parsing.py +465 -0
  120. celldetective/utils/plots/__init__.py +0 -0
  121. celldetective/utils/plots/regression.py +53 -0
  122. celldetective/utils/resources.py +34 -0
  123. celldetective/utils/stardist_utils/__init__.py +104 -0
  124. celldetective/utils/stats.py +90 -0
  125. celldetective/utils/types.py +21 -0
  126. {celldetective-1.4.2.dist-info → celldetective-1.5.0b0.dist-info}/METADATA +1 -1
  127. celldetective-1.5.0b0.dist-info/RECORD +187 -0
  128. {celldetective-1.4.2.dist-info → celldetective-1.5.0b0.dist-info}/WHEEL +1 -1
  129. tests/gui/test_new_project.py +129 -117
  130. tests/gui/test_project.py +127 -79
  131. tests/test_filters.py +39 -15
  132. tests/test_notebooks.py +8 -0
  133. tests/test_tracking.py +232 -13
  134. tests/test_utils.py +123 -77
  135. celldetective/gui/base_components.py +0 -23
  136. celldetective/gui/layouts.py +0 -1602
  137. celldetective/gui/processes/compute_neighborhood.py +0 -594
  138. celldetective/gui/processes/measure_cells.py +0 -360
  139. celldetective/gui/processes/segment_cells.py +0 -499
  140. celldetective/gui/processes/track_cells.py +0 -303
  141. celldetective/gui/processes/train_segmentation_model.py +0 -270
  142. celldetective/gui/processes/train_signal_model.py +0 -108
  143. celldetective/gui/table_ops/merge_groups.py +0 -118
  144. celldetective/gui/viewers.py +0 -1354
  145. celldetective/io.py +0 -3663
  146. celldetective/utils.py +0 -3108
  147. celldetective-1.4.2.dist-info/RECORD +0 -123
  148. /celldetective/{gui/processes → processes}/downloader.py +0 -0
  149. {celldetective-1.4.2.dist-info → celldetective-1.5.0b0.dist-info}/entry_points.txt +0 -0
  150. {celldetective-1.4.2.dist-info → celldetective-1.5.0b0.dist-info}/licenses/LICENSE +0 -0
  151. {celldetective-1.4.2.dist-info → celldetective-1.5.0b0.dist-info}/top_level.txt +0 -0
@@ -1,7 +0,0 @@
1
- from ._settings_measurements import SettingsMeasurements
2
- from ._settings_segmentation import SettingsSegmentation
3
- from ._settings_tracking import SettingsTracking
4
- from ._settings_segmentation_model_training import SettingsSegmentationModelTraining
5
- from ._settings_event_model_training import SettingsEventDetectionModelTraining
6
- from ._settings_signal_annotator import SettingsSignalAnnotator
7
- from ._settings_neighborhood import SettingsNeighborhood
@@ -0,0 +1,181 @@
1
+ from typing import List
2
+
3
+ import numpy as np
4
+ from PyQt5.QtCore import QSize, Qt
5
+ from PyQt5.QtWidgets import QVBoxLayout, QPushButton, QComboBox, QHBoxLayout, QLabel
6
+ from fonticon_mdi6 import MDI6
7
+ from superqt import QLabeledDoubleSlider
8
+ from superqt.fonticon import icon
9
+
10
+ from celldetective.gui.base.components import CelldetectiveWidget
11
+ from celldetective.gui.base.utils import center_window
12
+ from celldetective.gui.gui_utils import ThresholdLineEdit
13
+ from celldetective.gui.viewers.size_viewer import CellSizeViewer
14
+
15
+
16
+ class CellposeParamsWidget(CelldetectiveWidget):
17
+ """
18
+ A widget to configure parameters for Cellpose segmentation, allowing users to set the cell diameter,
19
+ select imaging channels, and adjust flow and cell probability thresholds for cell detection.
20
+
21
+ This widget is designed for estimating cell diameters and configuring parameters for Cellpose,
22
+ a deep learning-based segmentation tool. It also provides functionality to preview the image stack with a scale bar.
23
+
24
+ Parameters
25
+ ----------
26
+ parent_window : QWidget, optional
27
+ The parent window that hosts the widget (default is None).
28
+ model_name : str, optional
29
+ The name of the Cellpose model being used, typically 'CP_cyto2' for cytoplasm or 'CP_nuclei' for nuclei segmentation
30
+ (default is 'CP_cyto2').
31
+
32
+ Notes
33
+ -----
34
+ - This widget assumes that the parent window or one of its ancestor windows has access to the experiment channels
35
+ and can locate the current image stack via `locate_image()`.
36
+ - This class integrates sliders for flow and cell probability thresholds, as well as a channel selection for running
37
+ Cellpose segmentation.
38
+ - The `view_current_stack_with_scale_bar()` method opens a new window where the user can visually inspect the
39
+ image stack with a superimposed scale bar, to better estimate the cell diameter.
40
+
41
+ """
42
+
43
+ view_diameter_btn: QPushButton = QPushButton()
44
+ diameter_le: ThresholdLineEdit
45
+ viewer: CellSizeViewer
46
+ cellpose_channel_cb: List[QComboBox]
47
+ cellpose_channel_template: List[str]
48
+ flow_slider: QLabeledDoubleSlider = QLabeledDoubleSlider()
49
+ set_cellpose_scale_btn: QPushButton = QPushButton("set")
50
+ cellprob_slider: QLabeledDoubleSlider = QLabeledDoubleSlider()
51
+
52
+ def __init__(self, parent_window=None, model_name="CP_cyto2", *args):
53
+
54
+ super().__init__(*args)
55
+ self.setWindowTitle("Estimate diameter")
56
+ self.parent_window = parent_window
57
+ self.model_name = model_name
58
+
59
+ # Setting up references to parent window attributes
60
+ if hasattr(self.parent_window.parent_window, "locate_image"):
61
+ self.attr_parent = self.parent_window.parent_window
62
+ elif hasattr(self.parent_window.parent_window.parent_window, "locate_image"):
63
+ self.attr_parent = self.parent_window.parent_window.parent_window
64
+ else:
65
+ self.attr_parent = (
66
+ self.parent_window.parent_window.parent_window.parent_window
67
+ )
68
+
69
+ # Layout and widgets setup
70
+ self.layout = QVBoxLayout()
71
+ self.populate_widgets()
72
+ self.setLayout(self.layout)
73
+ center_window(self)
74
+
75
+ def populate_widgets(self):
76
+ """
77
+ Populates the widget with UI elements such as buttons, sliders, and comboboxes to allow configuration
78
+ of Cellpose segmentation parameters.
79
+ """
80
+
81
+ # Button to view the current stack with a scale bar
82
+ self.view_diameter_btn.setStyleSheet(self.button_select_all)
83
+ self.view_diameter_btn.setIcon(icon(MDI6.image_check, color="black"))
84
+ self.view_diameter_btn.setToolTip("View stack.")
85
+ self.view_diameter_btn.setIconSize(QSize(20, 20))
86
+ self.view_diameter_btn.clicked.connect(self.view_current_stack_with_scale_bar)
87
+
88
+ # Line edit for entering cell diameter
89
+ self.diameter_le = ThresholdLineEdit(
90
+ init_value=40,
91
+ connected_buttons=[self.view_diameter_btn],
92
+ placeholder="cell diameter in pixels",
93
+ value_type="float",
94
+ )
95
+
96
+ # Comboboxes for selecting imaging channels
97
+ self.cellpose_channel_cb = [QComboBox() for _ in range(2)]
98
+ self.cellpose_channel_template = ["brightfield_channel", "live_nuclei_channel"]
99
+ if self.model_name == "CP_nuclei":
100
+ self.cellpose_channel_template = ["live_nuclei_channel", "None"]
101
+
102
+ for k in range(2):
103
+ hbox_channel = QHBoxLayout()
104
+ hbox_channel.addWidget(QLabel(f"channel {k+1}: "))
105
+ hbox_channel.addWidget(self.cellpose_channel_cb[k])
106
+ if k == 1:
107
+ self.cellpose_channel_cb[k].addItems(
108
+ list(self.attr_parent.exp_channels) + ["None"]
109
+ )
110
+ else:
111
+ self.cellpose_channel_cb[k].addItems(
112
+ list(self.attr_parent.exp_channels)
113
+ )
114
+ idx = self.cellpose_channel_cb[k].findText(
115
+ self.cellpose_channel_template[k]
116
+ )
117
+ if idx > 0:
118
+ self.cellpose_channel_cb[k].setCurrentIndex(idx)
119
+ else:
120
+ self.cellpose_channel_cb[k].setCurrentIndex(0)
121
+
122
+ if k == 1:
123
+ idx = self.cellpose_channel_cb[k].findText("None")
124
+ self.cellpose_channel_cb[k].setCurrentIndex(idx)
125
+
126
+ self.layout.addLayout(hbox_channel)
127
+
128
+ # Layout for diameter input and button
129
+ hbox = QHBoxLayout()
130
+ hbox.addWidget(QLabel("diameter [px]: "), 33)
131
+ hbox.addWidget(self.diameter_le, 61)
132
+ hbox.addWidget(self.view_diameter_btn)
133
+ self.layout.addLayout(hbox)
134
+
135
+ # Flow threshold slider
136
+ self.flow_slider.setOrientation(Qt.Horizontal)
137
+ self.flow_slider.setRange(-6, 6)
138
+ self.flow_slider.setValue(0.4)
139
+ hbox = QHBoxLayout()
140
+ hbox.addWidget(QLabel("flow threshold: "), 33)
141
+ hbox.addWidget(self.flow_slider, 66)
142
+ self.layout.addLayout(hbox)
143
+
144
+ # Cell probability threshold slider
145
+ self.cellprob_slider.setOrientation(Qt.Horizontal)
146
+ self.cellprob_slider.setRange(-6, 6)
147
+ self.cellprob_slider.setValue(0.0)
148
+ hbox = QHBoxLayout()
149
+ hbox.addWidget(QLabel("cellprob threshold: "), 33)
150
+ hbox.addWidget(self.cellprob_slider, 66)
151
+ self.layout.addLayout(hbox)
152
+
153
+ # Button to set the scale for Cellpose segmentation
154
+ self.set_cellpose_scale_btn.setStyleSheet(self.button_style_sheet)
155
+ self.set_cellpose_scale_btn.clicked.connect(
156
+ self.parent_window.set_cellpose_scale
157
+ )
158
+ self.layout.addWidget(self.set_cellpose_scale_btn)
159
+
160
+ def view_current_stack_with_scale_bar(self):
161
+ """
162
+ Displays the current image stack with a scale bar, allowing users to visually estimate cell diameters.
163
+ """
164
+
165
+ self.attr_parent.locate_image()
166
+ if self.attr_parent.current_stack is not None:
167
+ max_size = np.amax([self.attr_parent.shape_x, self.attr_parent.shape_y])
168
+ self.viewer = CellSizeViewer(
169
+ initial_diameter=float(self.diameter_le.text().replace(",", ".")),
170
+ parent_le=self.diameter_le,
171
+ stack_path=self.attr_parent.current_stack,
172
+ window_title=f"Position {self.attr_parent.position_list.currentText()}",
173
+ diameter_slider_range=(0, max_size),
174
+ frame_slider=True,
175
+ contrast_slider=True,
176
+ channel_cb=True,
177
+ channel_names=self.attr_parent.exp_channels,
178
+ n_channels=self.attr_parent.nbr_channels,
179
+ PxToUm=1,
180
+ )
181
+ self.viewer.show()
@@ -0,0 +1,95 @@
1
+ import json
2
+ import os
3
+
4
+ from PyQt5.QtCore import Qt
5
+ from PyQt5.QtGui import QDoubleValidator
6
+ from PyQt5.QtWidgets import QVBoxLayout, QComboBox, QHBoxLayout, QLabel, QPushButton
7
+
8
+ from celldetective.gui.base.components import CelldetectiveWidget
9
+ from celldetective.gui.base.utils import center_window
10
+ from celldetective.utils.model_loaders import locate_signal_model
11
+
12
+
13
+ class SignalModelParamsWidget(CelldetectiveWidget):
14
+
15
+ def __init__(self, parent_window=None, model_name=None, *args, **kwargs):
16
+
17
+ super().__init__(*args)
18
+ self.setWindowTitle("Signals")
19
+ self.parent_window = parent_window
20
+ self.model_name = model_name
21
+ self.locate_model_path()
22
+ self.required_channels = self.input_config["channels"]
23
+ self.onlyFloat = QDoubleValidator()
24
+
25
+ # Setting up references to parent window attributes
26
+ if hasattr(self.parent_window.parent_window, "locate_image"):
27
+ self.attr_parent = self.parent_window.parent_window
28
+ elif hasattr(self.parent_window.parent_window.parent_window, "locate_image"):
29
+ self.attr_parent = self.parent_window.parent_window.parent_window
30
+ else:
31
+ self.attr_parent = (
32
+ self.parent_window.parent_window.parent_window.parent_window
33
+ )
34
+
35
+ # Set up layout and widgets
36
+ self.layout = QVBoxLayout()
37
+ self.populate_widgets()
38
+ self.setLayout(self.layout)
39
+ center_window(self)
40
+
41
+ def locate_model_path(self):
42
+
43
+ self.model_complete_path = locate_signal_model(self.model_name)
44
+ if self.model_complete_path is None:
45
+ raise ValueError(f"Model {self.model_name} could not be found.")
46
+ else:
47
+ print(f"Model path: {self.model_complete_path}...")
48
+
49
+ config_path = os.path.join(self.model_complete_path, "config_input.json")
50
+ if not os.path.exists(config_path):
51
+ raise ValueError(
52
+ f"The configuration for the inputs to the model could not be located at {config_path}."
53
+ )
54
+
55
+ with open(config_path) as config_file:
56
+ self.input_config = json.load(config_file)
57
+
58
+ def populate_widgets(self):
59
+
60
+ self.n_channels = len(self.required_channels)
61
+ self.channel_cbs = [QComboBox() for i in range(self.n_channels)]
62
+
63
+ self.parent_window.load_available_tables()
64
+ available_channels = list(self.parent_window.signals) + ["None"]
65
+ # Populate the comboboxes with available channels from the experiment
66
+ for k in range(self.n_channels):
67
+ hbox_channel = QHBoxLayout()
68
+ hbox_channel.addWidget(QLabel(f"channel {k+1}: "), 33)
69
+
70
+ ch_vbox = QVBoxLayout()
71
+ ch_vbox.addWidget(
72
+ QLabel(f"Req: {self.required_channels[k]}"), alignment=Qt.AlignLeft
73
+ )
74
+ ch_vbox.addWidget(self.channel_cbs[k])
75
+
76
+ self.channel_cbs[k].addItems(
77
+ available_channels
78
+ ) # Give none option for more than one channel input
79
+ idx = self.channel_cbs[k].findText(self.required_channels[k])
80
+
81
+ if idx >= 0:
82
+ self.channel_cbs[k].setCurrentIndex(idx)
83
+ else:
84
+ self.channel_cbs[k].setCurrentIndex(len(available_channels) - 1)
85
+
86
+ hbox_channel.addLayout(ch_vbox, 66)
87
+ self.layout.addLayout(hbox_channel)
88
+
89
+ # Button to apply the StarDist settings
90
+ self.set_btn = QPushButton("set")
91
+ self.set_btn.setStyleSheet(self.button_style_sheet)
92
+ self.set_btn.clicked.connect(
93
+ self.parent_window.set_selected_signals_for_event_detection
94
+ )
95
+ self.layout.addWidget(self.set_btn)
@@ -0,0 +1,159 @@
1
+ import json
2
+ import os
3
+
4
+ import numpy as np
5
+ from PyQt5.QtCore import QSize, Qt
6
+ from PyQt5.QtGui import QDoubleValidator
7
+ from PyQt5.QtWidgets import QVBoxLayout, QComboBox, QPushButton, QHBoxLayout, QLabel
8
+ from fonticon_mdi6 import MDI6
9
+ from superqt.fonticon import icon
10
+
11
+ from celldetective.gui.base.components import CelldetectiveWidget
12
+ from celldetective.gui.base.utils import center_window
13
+ from celldetective.gui.gui_utils import ThresholdLineEdit
14
+ from celldetective.gui.viewers.size_viewer import CellSizeViewer
15
+ from celldetective.utils.model_loaders import locate_segmentation_model
16
+
17
+
18
+ class SegModelParamsWidget(CelldetectiveWidget):
19
+
20
+ def __init__(
21
+ self, parent_window=None, model_name="SD_versatile_fluo", *args, **kwargs
22
+ ):
23
+
24
+ super().__init__(*args)
25
+ self.setWindowTitle("Channels")
26
+ self.parent_window = parent_window
27
+ self.model_name = model_name
28
+ self.locate_model_path()
29
+ self.required_channels = self.input_config["channels"]
30
+ self.onlyFloat = QDoubleValidator()
31
+
32
+ # Setting up references to parent window attributes
33
+ if hasattr(self.parent_window.parent_window, "locate_image"):
34
+ self.attr_parent = self.parent_window.parent_window
35
+ elif hasattr(self.parent_window.parent_window.parent_window, "locate_image"):
36
+ self.attr_parent = self.parent_window.parent_window.parent_window
37
+ else:
38
+ self.attr_parent = (
39
+ self.parent_window.parent_window.parent_window.parent_window
40
+ )
41
+
42
+ # Set up layout and widgets
43
+ self.layout = QVBoxLayout()
44
+ self.populate_widgets()
45
+ self.setLayout(self.layout)
46
+ center_window(self)
47
+
48
+ def locate_model_path(self):
49
+
50
+ self.model_complete_path = locate_segmentation_model(self.model_name)
51
+ if self.model_complete_path is None:
52
+ print("Model could not be found. Abort.")
53
+ self.abort_process()
54
+ else:
55
+ print(f"Model path: {self.model_complete_path}...")
56
+
57
+ if not os.path.exists(self.model_complete_path + "config_input.json"):
58
+ print(
59
+ "The configuration for the inputs to the model could not be located. Abort."
60
+ )
61
+ self.abort_process()
62
+
63
+ with open(self.model_complete_path + "config_input.json") as config_file:
64
+ self.input_config = json.load(config_file)
65
+
66
+ def populate_widgets(self):
67
+
68
+ self.n_channels = len(self.required_channels)
69
+ self.channel_cbs = [QComboBox() for i in range(self.n_channels)]
70
+
71
+ # Button to view the current stack with a scale bar
72
+ self.view_diameter_btn = QPushButton()
73
+ self.view_diameter_btn.setStyleSheet(self.button_select_all)
74
+ self.view_diameter_btn.setIcon(icon(MDI6.image_check, color="black"))
75
+ self.view_diameter_btn.setToolTip("View stack.")
76
+ self.view_diameter_btn.setIconSize(QSize(20, 20))
77
+ self.view_diameter_btn.clicked.connect(self.view_current_stack_with_scale_bar)
78
+
79
+ # Line edit for entering cell diameter
80
+ self.diameter_le = ThresholdLineEdit(
81
+ init_value=40,
82
+ connected_buttons=[self.view_diameter_btn],
83
+ placeholder="cell diameter in µm",
84
+ value_type="float",
85
+ )
86
+
87
+ available_channels = list(self.attr_parent.exp_channels) + ["None"]
88
+ # Populate the comboboxes with available channels from the experiment
89
+ for k in range(self.n_channels):
90
+ hbox_channel = QHBoxLayout()
91
+ hbox_channel.addWidget(QLabel(f"channel {k+1}: "), 33)
92
+
93
+ ch_vbox = QVBoxLayout()
94
+ ch_vbox.addWidget(
95
+ QLabel(f"Req: {self.required_channels[k]}"), alignment=Qt.AlignLeft
96
+ )
97
+ ch_vbox.addWidget(self.channel_cbs[k])
98
+
99
+ self.channel_cbs[k].addItems(
100
+ available_channels
101
+ ) # Give none option for more than one channel input
102
+ idx = self.channel_cbs[k].findText(self.required_channels[k])
103
+
104
+ if idx >= 0:
105
+ self.channel_cbs[k].setCurrentIndex(idx)
106
+ else:
107
+ self.channel_cbs[k].setCurrentIndex(len(available_channels) - 1)
108
+
109
+ hbox_channel.addLayout(ch_vbox, 66)
110
+ self.layout.addLayout(hbox_channel)
111
+
112
+ if "cell_size_um" in self.input_config:
113
+
114
+ # Layout for diameter input and button
115
+ hbox = QHBoxLayout()
116
+ hbox.addWidget(QLabel("cell size [µm]: "), 33)
117
+ hbox.addWidget(self.diameter_le, 61)
118
+ hbox.addWidget(self.view_diameter_btn)
119
+ self.layout.addLayout(hbox)
120
+
121
+ self.diameter_le.set_threshold(self.input_config["cell_size_um"])
122
+
123
+ # size_hbox = QHBoxLayout()
124
+ # size_hbox.addWidget(QLabel('cell size [µm]: '), 33)
125
+ # self.size_le = QLineEdit(str(self.input_config['cell_size_um']).replace('.',','))
126
+ # self.size_le.setValidator(self.onlyFloat)
127
+ # size_hbox.addWidget(self.size_le, 66)
128
+ # self.layout.addLayout(size_hbox)
129
+
130
+ # Button to apply the StarDist settings
131
+ self.set_btn = QPushButton("set")
132
+ self.set_btn.setStyleSheet(self.button_style_sheet)
133
+ self.set_btn.clicked.connect(
134
+ self.parent_window.set_selected_channels_for_segmentation
135
+ )
136
+ self.layout.addWidget(self.set_btn)
137
+
138
+ def view_current_stack_with_scale_bar(self):
139
+ """
140
+ Displays the current image stack with a scale bar, allowing users to visually estimate cell diameters.
141
+ """
142
+
143
+ self.attr_parent.locate_image()
144
+ if self.attr_parent.current_stack is not None:
145
+ max_size = np.amax([self.attr_parent.shape_x, self.attr_parent.shape_y])
146
+ self.viewer = CellSizeViewer(
147
+ initial_diameter=float(self.diameter_le.text().replace(",", ".")),
148
+ parent_le=self.diameter_le,
149
+ stack_path=self.attr_parent.current_stack,
150
+ window_title=f"Position {self.attr_parent.position_list.currentText()}",
151
+ diameter_slider_range=(0, max_size * self.attr_parent.PxToUm),
152
+ frame_slider=True,
153
+ contrast_slider=True,
154
+ channel_cb=True,
155
+ channel_names=self.attr_parent.exp_channels,
156
+ n_channels=self.attr_parent.nbr_channels,
157
+ PxToUm=self.attr_parent.PxToUm,
158
+ )
159
+ self.viewer.show()
@@ -1,70 +1,82 @@
1
1
  from abc import abstractmethod
2
- from PyQt5.QtWidgets import QApplication, QScrollArea, QSizePolicy, QVBoxLayout, QPushButton
2
+ from PyQt5.QtWidgets import (
3
+ QApplication,
4
+ QScrollArea,
5
+ QSizePolicy,
6
+ QVBoxLayout,
7
+ QPushButton,
8
+ )
3
9
  from PyQt5.QtCore import Qt
4
- from celldetective.utils import get_software_location
5
- from celldetective.gui.gui_utils import center_window
6
- from celldetective.gui import CelldetectiveMainWindow, CelldetectiveWidget
10
+ from celldetective import get_software_location
11
+ from celldetective.gui.base.utils import center_window
12
+ from celldetective.gui.base.components import (
13
+ CelldetectiveMainWindow,
14
+ CelldetectiveWidget,
15
+ )
7
16
  from PyQt5.QtGui import QDoubleValidator, QIntValidator
8
17
 
18
+
9
19
  class CelldetectiveSettingsPanel(CelldetectiveMainWindow):
10
-
11
- def __init__(self, title=""):
12
-
13
- super().__init__()
14
- self.setWindowTitle(title)
15
-
16
- self._get_screen_height()
17
- #self.setMinimumWidth(500)
18
- self.setMaximumHeight(int(0.8 * self._screen_height))
19
- self._scroll_area = QScrollArea(self)
20
- self._floatValidator = QDoubleValidator()
21
- self._intValidator = QIntValidator()
22
- self._software_path = get_software_location()
23
-
24
- self._create_widgets()
25
- self._build_layouts()
26
- self.center_window()
27
-
28
- def _create_widgets(self):
29
- self.submit_btn: QPushButton = QPushButton("Save")
30
- self.submit_btn.setStyleSheet(self.button_style_sheet)
31
- self.submit_btn.clicked.connect(self._write_instructions)
32
-
33
- def center_window(self):
34
- return center_window(self)
35
-
36
- def _get_screen_height(self):
37
- app = QApplication.instance()
38
- screen = app.primaryScreen()
39
- geometry = screen.availableGeometry()
40
- self._screen_width, self._screen_height = geometry.getRect()[-2:]
41
-
42
- def _adjustSize(self):
43
- self._widget.adjustSize()
44
- self._scroll_area.adjustSize()
45
- self.adjustSize()
46
-
47
- def _build_layouts(self):
48
-
49
- self._layout: QVBoxLayout = QVBoxLayout()
50
- self._widget: CelldetectiveWidget = CelldetectiveWidget()
51
- self._widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
52
-
53
- # Create button widget and layout
54
- self._widget.setLayout(self._layout)
55
- self._layout.setContentsMargins(30, 30, 30, 30)
56
-
57
- self._scroll_area.setAlignment(Qt.AlignCenter)
58
- self._scroll_area.setWidget(self._widget)
59
- self._scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
60
- self._scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
61
- self._scroll_area.setWidgetResizable(True)
62
- self.setCentralWidget(self._scroll_area)
63
-
64
- QApplication.processEvents()
65
-
66
- @abstractmethod
67
- def _load_previous_instructions(self): pass
68
-
69
- @abstractmethod
70
- def _write_instructions(self): pass
20
+
21
+ def __init__(self, title=""):
22
+
23
+ super().__init__()
24
+ self.setWindowTitle(title)
25
+
26
+ self._get_screen_height()
27
+ # self.setMinimumWidth(500)
28
+ self.setMaximumHeight(int(0.8 * self._screen_height))
29
+ self._scroll_area = QScrollArea(self)
30
+ self._floatValidator = QDoubleValidator()
31
+ self._intValidator = QIntValidator()
32
+ self._software_path = get_software_location()
33
+
34
+ self._create_widgets()
35
+ self._build_layouts()
36
+ self.center_window()
37
+
38
+ def _create_widgets(self):
39
+ self.submit_btn: QPushButton = QPushButton("Save")
40
+ self.submit_btn.setStyleSheet(self.button_style_sheet)
41
+ self.submit_btn.clicked.connect(self._write_instructions)
42
+
43
+ def center_window(self):
44
+ return center_window(self)
45
+
46
+ def _get_screen_height(self):
47
+ app = QApplication.instance()
48
+ screen = app.primaryScreen()
49
+ geometry = screen.availableGeometry()
50
+ self._screen_width, self._screen_height = geometry.getRect()[-2:]
51
+
52
+ def _adjust_size(self):
53
+ self._widget.adjustSize()
54
+ self._scroll_area.adjustSize()
55
+ self.adjustSize()
56
+
57
+ def _build_layouts(self):
58
+
59
+ self._layout: QVBoxLayout = QVBoxLayout()
60
+ self._widget: CelldetectiveWidget = CelldetectiveWidget()
61
+ self._widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
62
+
63
+ # Create button widget and layout
64
+ self._widget.setLayout(self._layout)
65
+ self._layout.setContentsMargins(30, 30, 30, 30)
66
+
67
+ self._scroll_area.setAlignment(Qt.AlignCenter)
68
+ self._scroll_area.setWidget(self._widget)
69
+ self._scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
70
+ self._scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
71
+ self._scroll_area.setWidgetResizable(True)
72
+ self.setCentralWidget(self._scroll_area)
73
+
74
+ QApplication.processEvents()
75
+
76
+ @abstractmethod
77
+ def _load_previous_instructions(self):
78
+ pass
79
+
80
+ @abstractmethod
81
+ def _write_instructions(self):
82
+ pass