celldetective 1.3.9.post5__py3-none-any.whl → 1.4.1__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 (94) hide show
  1. celldetective/__init__.py +0 -3
  2. celldetective/_version.py +1 -1
  3. celldetective/events.py +2 -4
  4. celldetective/exceptions.py +11 -0
  5. celldetective/extra_properties.py +132 -0
  6. celldetective/filters.py +7 -1
  7. celldetective/gui/InitWindow.py +37 -46
  8. celldetective/gui/__init__.py +3 -9
  9. celldetective/gui/about.py +19 -15
  10. celldetective/gui/analyze_block.py +34 -19
  11. celldetective/gui/base_annotator.py +786 -0
  12. celldetective/gui/base_components.py +23 -0
  13. celldetective/gui/classifier_widget.py +86 -94
  14. celldetective/gui/configure_new_exp.py +163 -46
  15. celldetective/gui/control_panel.py +76 -146
  16. celldetective/gui/{signal_annotator.py → event_annotator.py} +533 -1438
  17. celldetective/gui/generic_signal_plot.py +11 -13
  18. celldetective/gui/gui_utils.py +54 -23
  19. celldetective/gui/help/neighborhood.json +2 -2
  20. celldetective/gui/json_readers.py +5 -4
  21. celldetective/gui/layouts.py +265 -31
  22. celldetective/gui/{signal_annotator2.py → pair_event_annotator.py} +433 -635
  23. celldetective/gui/plot_measurements.py +21 -17
  24. celldetective/gui/plot_signals_ui.py +125 -72
  25. celldetective/gui/process_block.py +283 -188
  26. celldetective/gui/processes/compute_neighborhood.py +594 -0
  27. celldetective/gui/processes/downloader.py +37 -34
  28. celldetective/gui/processes/measure_cells.py +19 -8
  29. celldetective/gui/processes/segment_cells.py +47 -11
  30. celldetective/gui/processes/track_cells.py +18 -13
  31. celldetective/gui/seg_model_loader.py +21 -62
  32. celldetective/gui/settings/__init__.py +7 -0
  33. celldetective/gui/settings/_settings_base.py +70 -0
  34. celldetective/gui/{retrain_signal_model_options.py → settings/_settings_event_model_training.py} +54 -109
  35. celldetective/gui/{measurement_options.py → settings/_settings_measurements.py} +54 -92
  36. celldetective/gui/{neighborhood_options.py → settings/_settings_neighborhood.py} +10 -13
  37. celldetective/gui/settings/_settings_segmentation.py +49 -0
  38. celldetective/gui/{retrain_segmentation_model_options.py → settings/_settings_segmentation_model_training.py} +38 -92
  39. celldetective/gui/{signal_annotator_options.py → settings/_settings_signal_annotator.py} +78 -103
  40. celldetective/gui/{btrack_options.py → settings/_settings_tracking.py} +85 -116
  41. celldetective/gui/styles.py +2 -1
  42. celldetective/gui/survival_ui.py +49 -95
  43. celldetective/gui/tableUI.py +53 -25
  44. celldetective/gui/table_ops/__init__.py +0 -0
  45. celldetective/gui/table_ops/merge_groups.py +118 -0
  46. celldetective/gui/thresholds_gui.py +617 -1221
  47. celldetective/gui/viewers.py +107 -42
  48. celldetective/gui/workers.py +8 -4
  49. celldetective/io.py +137 -57
  50. celldetective/links/zenodo.json +145 -144
  51. celldetective/measure.py +94 -53
  52. celldetective/neighborhood.py +342 -268
  53. celldetective/preprocessing.py +56 -35
  54. celldetective/regionprops/_regionprops.py +16 -5
  55. celldetective/relative_measurements.py +50 -29
  56. celldetective/scripts/analyze_signals.py +4 -1
  57. celldetective/scripts/measure_cells.py +5 -5
  58. celldetective/scripts/measure_relative.py +20 -12
  59. celldetective/scripts/segment_cells.py +4 -10
  60. celldetective/scripts/segment_cells_thresholds.py +3 -3
  61. celldetective/scripts/track_cells.py +10 -8
  62. celldetective/scripts/train_segmentation_model.py +18 -6
  63. celldetective/signals.py +29 -14
  64. celldetective/tracking.py +14 -3
  65. celldetective/utils.py +91 -62
  66. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/METADATA +24 -16
  67. celldetective-1.4.1.dist-info/RECORD +123 -0
  68. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/WHEEL +1 -1
  69. tests/gui/__init__.py +0 -0
  70. tests/gui/test_new_project.py +228 -0
  71. tests/gui/test_project.py +99 -0
  72. tests/test_preprocessing.py +2 -2
  73. celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -79
  74. celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
  75. celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -37
  76. celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -39
  77. celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
  78. celldetective/models/signal_detection/NucCond/classification_loss.png +0 -0
  79. celldetective/models/signal_detection/NucCond/classifier.h5 +0 -0
  80. celldetective/models/signal_detection/NucCond/config_input.json +0 -1
  81. celldetective/models/signal_detection/NucCond/log_classifier.csv +0 -126
  82. celldetective/models/signal_detection/NucCond/log_regressor.csv +0 -282
  83. celldetective/models/signal_detection/NucCond/regression_loss.png +0 -0
  84. celldetective/models/signal_detection/NucCond/regressor.h5 +0 -0
  85. celldetective/models/signal_detection/NucCond/scores.npy +0 -0
  86. celldetective/models/signal_detection/NucCond/test_confusion_matrix.png +0 -0
  87. celldetective/models/signal_detection/NucCond/test_regression.png +0 -0
  88. celldetective/models/signal_detection/NucCond/validation_confusion_matrix.png +0 -0
  89. celldetective/models/signal_detection/NucCond/validation_regression.png +0 -0
  90. celldetective-1.3.9.post5.dist-info/RECORD +0 -129
  91. tests/test_qt.py +0 -103
  92. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/entry_points.txt +0 -0
  93. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info/licenses}/LICENSE +0 -0
  94. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  from PyQt5.QtWidgets import QMessageBox,QGridLayout, QButtonGroup, \
2
- QCheckBox, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton, \
2
+ QCheckBox, QLineEdit, QVBoxLayout, QLabel, QHBoxLayout, QPushButton, \
3
3
  QRadioButton
4
4
  from PyQt5.QtCore import Qt, QSize
5
5
  from PyQt5.QtGui import QDoubleValidator
@@ -18,13 +18,13 @@ import matplotlib.pyplot as plt
18
18
  plt.rcParams['svg.fonttype'] = 'none'
19
19
  from glob import glob
20
20
  from matplotlib.cm import tab10
21
- from celldetective.gui import Styles
21
+ from celldetective.gui import CelldetectiveWidget
22
22
  import matplotlib.cm as mcm
23
23
  import pandas as pd
24
24
 
25
25
  from lifelines.utils import qth_survival_times
26
26
 
27
- class GenericSignalPlotWidget(QWidget, Styles):
27
+ class GenericSignalPlotWidget(CelldetectiveWidget):
28
28
 
29
29
  def __init__(self, df = None, df_pos_info = None, df_well_info = None, feature_selected = None, parent_window=None, title='plot', *args, **kwargs):
30
30
 
@@ -33,7 +33,6 @@ class GenericSignalPlotWidget(QWidget, Styles):
33
33
 
34
34
  self.parent_window = parent_window
35
35
  self.setWindowTitle(title)
36
- self.setWindowIcon(self.celldetective_icon)
37
36
 
38
37
  self.show_ci = False
39
38
  self.legend_visible = True
@@ -60,8 +59,6 @@ class GenericSignalPlotWidget(QWidget, Styles):
60
59
 
61
60
  self.fig.tight_layout()
62
61
  self.setLayout(self.layout)
63
- self.setAttribute(Qt.WA_DeleteOnClose)
64
-
65
62
 
66
63
  def populate_widget(self):
67
64
 
@@ -170,7 +167,7 @@ class GenericSignalPlotWidget(QWidget, Styles):
170
167
  self.ci_btn.clicked.connect(self.switch_ci)
171
168
  self.cell_lines_btn.clicked.connect(self.switch_cell_lines)
172
169
 
173
- self.class_selection_widget = QWidget()
170
+ self.class_selection_widget = CelldetectiveWidget()
174
171
 
175
172
  self.class_selection_lbl = QLabel('class of interest:')
176
173
  class_hbox = QHBoxLayout()
@@ -197,7 +194,7 @@ class GenericSignalPlotWidget(QWidget, Styles):
197
194
  self.layout.addWidget(self.class_selection_widget) #Layout(class_hbox)
198
195
 
199
196
  # Rescale
200
- self.rescale_widget = QWidget()
197
+ self.rescale_widget = CelldetectiveWidget()
201
198
 
202
199
  scale_hbox = QHBoxLayout()
203
200
  self.rescale_widget.setLayout(scale_hbox)
@@ -216,7 +213,7 @@ class GenericSignalPlotWidget(QWidget, Styles):
216
213
 
217
214
 
218
215
  # Rescale
219
- self.cell_lines_alpha_wdg = QWidget()
216
+ self.cell_lines_alpha_wdg = CelldetectiveWidget()
220
217
  alpha_hbox = QHBoxLayout()
221
218
 
222
219
  self.alpha_slider = QLabeledDoubleSlider()
@@ -225,7 +222,7 @@ class GenericSignalPlotWidget(QWidget, Styles):
225
222
  slider_initial_value=self.alpha_setting,
226
223
  slider_range=(0,1),
227
224
  decimal_option=True,
228
- precision=1.0E-05,
225
+ precision=5,
229
226
  )
230
227
  self.alpha_slider.valueChanged.connect(self.submit_alpha)
231
228
  self.cell_lines_alpha_wdg.setLayout(alpha_hbox)
@@ -343,7 +340,7 @@ class GenericSignalPlotWidget(QWidget, Styles):
343
340
  thresh = 20
344
341
  self.well_name_truncated = [w[:thresh - 3]+'...' if len(w)>thresh else w for w in self.usable_well_labels]
345
342
 
346
- self.line_choice_widget = QWidget()
343
+ self.line_choice_widget = CelldetectiveWidget()
347
344
  self.line_check_vbox = QGridLayout()
348
345
  self.line_choice_widget.setLayout(self.line_check_vbox)
349
346
 
@@ -507,7 +504,8 @@ class GenericSignalPlotWidget(QWidget, Styles):
507
504
  # Spines
508
505
  self.ax.spines['top'].set_visible(False)
509
506
  self.ax.spines['right'].set_visible(False)
510
-
507
+ self.ax.grid(which='major', color='black', linestyle='-', linewidth=0.8, alpha=0.2)
508
+ self.ax.grid(which='minor', color='lightgray', linestyle='--', linewidth=0.5, alpha=0.1)
511
509
  # Lims
512
510
  safe_df = self.df.dropna(subset=self.feature_selected)
513
511
  values = safe_df[self.feature_selected].values
@@ -828,7 +826,7 @@ class SurvivalPlotWidget(GenericSignalPlotWidget):
828
826
 
829
827
  def set_table_options(self):
830
828
 
831
- self.config_table_wg = QWidget()
829
+ self.config_table_wg = CelldetectiveWidget()
832
830
  self.config_table_wg.setMinimumWidth(480)
833
831
  self.config_table_wg.setWindowTitle('Survival data')
834
832
 
@@ -1,23 +1,48 @@
1
- import numpy as np
2
- from PyQt5.QtWidgets import QGridLayout, QApplication, QMessageBox, QFrame, QSizePolicy, QWidget, QLineEdit, QListWidget, QVBoxLayout, QComboBox, \
1
+ import os
2
+
3
+ from PyQt5.QtWidgets import QGridLayout, QApplication, QMessageBox, QFrame, QSizePolicy, QLineEdit, QListWidget, QVBoxLayout, QComboBox, \
3
4
  QPushButton, QLabel, QHBoxLayout, QCheckBox, QFileDialog, QToolButton, QMenu, QStylePainter, QStyleOptionComboBox, QStyle
4
5
  from PyQt5.QtCore import Qt, QSize, QAbstractTableModel, QEvent, pyqtSignal
5
6
  from PyQt5.QtGui import QDoubleValidator, QIntValidator, QStandardItemModel, QPalette
6
7
 
7
- from celldetective.gui import Styles
8
+ from celldetective.gui import Styles, CelldetectiveWidget
8
9
  from superqt.fonticon import icon
9
10
  from fonticon_mdi6 import MDI6
10
11
 
11
12
  from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
12
13
  from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT
13
14
  import matplotlib.pyplot as plt
14
- import celldetective.extra_properties as extra_properties
15
+
16
+ from celldetective.utils import get_software_location
17
+
18
+ try:
19
+ import celldetective.extra_properties as extra_properties
20
+ extra_props = True
21
+ except Exception as e:
22
+ print(f"The module extra_properties seems corrupted: {e}... Skip...")
23
+ extra_props = False
24
+
15
25
  from inspect import getmembers, isfunction
16
26
  from celldetective.filters import *
17
27
  from os import sep
18
28
  import json
19
29
 
20
30
 
31
+ def generic_message(message, msg_type="warning"):
32
+
33
+ print(message)
34
+ message_box = QMessageBox()
35
+ if msg_type=="warning":
36
+ message_box.setIcon(QMessageBox.Warning)
37
+ elif msg_type=="info":
38
+ message_box.setIcon(QMessageBox.Information)
39
+ elif msg_type=="critical":
40
+ message_box.setIcon(QMessageBox.Critical)
41
+ message_box.setText(message)
42
+ message_box.setWindowTitle(msg_type)
43
+ message_box.setStandardButtons(QMessageBox.Ok)
44
+ _ = message_box.exec()
45
+
21
46
  class PreprocessingLayout(QVBoxLayout, Styles):
22
47
 
23
48
  """
@@ -328,7 +353,7 @@ class PandasModel(QAbstractTableModel):
328
353
  self.dataChanged.emit(ix, ix, (Qt.BackgroundRole,))
329
354
 
330
355
 
331
- class GenericOpColWidget(QWidget, Styles):
356
+ class GenericOpColWidget(CelldetectiveWidget):
332
357
 
333
358
  def __init__(self, parent_window, column=None, title=''):
334
359
 
@@ -415,7 +440,7 @@ class QuickSliderLayout(QHBoxLayout):
415
440
  The slider widget that allows the user to select a value.
416
441
  """
417
442
 
418
- def __init__(self, label=None, slider=None, layout_ratio=(0.25,0.75), slider_initial_value=1, slider_range=(0,1), slider_tooltip=None, decimal_option=True, precision=1.0E-03, *args):
443
+ def __init__(self, label=None, slider=None, layout_ratio=(0.25,0.75), slider_initial_value=1, slider_range=(0,1), slider_tooltip=None, decimal_option=True, precision=3, *args):
419
444
  super().__init__(*args)
420
445
 
421
446
  if label is not None and isinstance(label,str):
@@ -423,10 +448,11 @@ class QuickSliderLayout(QHBoxLayout):
423
448
  self.addWidget(self.qlabel, int(100*layout_ratio[0]))
424
449
 
425
450
  self.slider = slider
426
- self.slider.setOrientation(1)
451
+ self.slider.setOrientation(Qt.Horizontal)
427
452
  if decimal_option:
428
- self.slider.setSingleStep(precision)
429
- self.slider.setTickInterval(precision)
453
+ self.slider.setSingleStep(1.0*(10**(-precision)))
454
+ self.slider.setTickInterval(1.0*(10**(-precision)))
455
+ self.slider.setDecimals(precision)
430
456
  else:
431
457
  self.slider.setSingleStep(1)
432
458
  self.slider.setTickInterval(1)
@@ -546,7 +572,7 @@ class QHSeperationLine(QFrame):
546
572
  self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
547
573
 
548
574
 
549
- class FeatureChoice(QWidget, Styles):
575
+ class FeatureChoice(CelldetectiveWidget):
550
576
 
551
577
  def __init__(self, parent_window):
552
578
  super().__init__()
@@ -575,10 +601,11 @@ class FeatureChoice(QWidget, Styles):
575
601
  "intensity_min",
576
602
  ]
577
603
 
578
- members = getmembers(extra_properties, isfunction)
579
- for o in members:
580
- if isfunction(o[1]) and o[1].__module__=="celldetective.extra_properties":
581
- standard_measurements.append(o[0])
604
+ if extra_props:
605
+ members = getmembers(extra_properties, isfunction)
606
+ for o in members:
607
+ if isfunction(o[1]) and o[1].__module__=="celldetective.extra_properties":
608
+ standard_measurements.append(o[0])
582
609
 
583
610
  self.combo_box.addItems(standard_measurements)
584
611
 
@@ -599,7 +626,7 @@ class FeatureChoice(QWidget, Styles):
599
626
  self.close()
600
627
 
601
628
 
602
- class FilterChoice(QWidget, Styles):
629
+ class FilterChoice(CelldetectiveWidget):
603
630
 
604
631
  def __init__(self, parent_window):
605
632
 
@@ -626,6 +653,7 @@ class FilterChoice(QWidget, Styles):
626
653
  'log_filter': {'blob_size': 30},
627
654
  'tophat_filter': {'size': 4, 'connectivity': 4},
628
655
  'otsu_filter': None,
656
+ 'multiotsu_filter': {'classes': 3},
629
657
  'local_filter': {'block_size': 73, 'method': 'mean', 'offset': 0},
630
658
  'niblack_filter': {'window_size': 15, 'k': 0.2},
631
659
  # 'sauvola_filter': {'window_size': 15, 'k': 0.2}
@@ -707,7 +735,7 @@ class FilterChoice(QWidget, Styles):
707
735
  self.arguments_labels[i].setText('')
708
736
 
709
737
 
710
- class OperationChoice(QWidget):
738
+ class OperationChoice(CelldetectiveWidget):
711
739
  """
712
740
  Mini window to select an operation from numpy to apply on the ROI.
713
741
 
@@ -738,7 +766,7 @@ class OperationChoice(QWidget):
738
766
  self.close()
739
767
 
740
768
 
741
- class GeometryChoice(QWidget):
769
+ class GeometryChoice(CelldetectiveWidget):
742
770
 
743
771
  def __init__(self, parent_window):
744
772
 
@@ -802,7 +830,7 @@ class GeometryChoice(QWidget):
802
830
  self.close()
803
831
 
804
832
 
805
- class DistanceChoice(QWidget):
833
+ class DistanceChoice(CelldetectiveWidget):
806
834
 
807
835
  def __init__(self, parent_window):
808
836
  super().__init__()
@@ -836,7 +864,7 @@ class DistanceChoice(QWidget):
836
864
  self.close()
837
865
 
838
866
 
839
- class ListWidget(QWidget):
867
+ class ListWidget(CelldetectiveWidget):
840
868
 
841
869
  """
842
870
  A customizable widget for displaying and managing a list of items, with the
@@ -963,7 +991,7 @@ class ListWidget(QWidget):
963
991
  del self.items[idx]
964
992
 
965
993
 
966
- class FigureCanvas(QWidget):
994
+ class FigureCanvas(CelldetectiveWidget):
967
995
  """
968
996
  Generic figure canvas.
969
997
  """
@@ -1183,8 +1211,9 @@ def color_from_state(state, recently_modified=False):
1183
1211
  """
1184
1212
 
1185
1213
  unique_values = np.unique(state)
1186
- color_map={}
1214
+ color_map = {}
1187
1215
  for value in unique_values:
1216
+
1188
1217
  if np.isnan(value):
1189
1218
  value = "nan"
1190
1219
  color_map[value] = 'k'
@@ -1192,8 +1221,10 @@ def color_from_state(state, recently_modified=False):
1192
1221
  color_map[value] = 'tab:blue'
1193
1222
  elif value==1:
1194
1223
  color_map[value] = 'tab:red'
1224
+ elif value==99:
1225
+ color_map[value] = 'k'
1195
1226
  else:
1196
- color_map[value] = plt.cm.tab10(value)
1227
+ color_map[value] = plt.cm.tab20(value/20.0)
1197
1228
 
1198
1229
  return color_map
1199
1230
 
@@ -1219,7 +1250,7 @@ def color_from_class(cclass, recently_modified=False):
1219
1250
  return 'k'
1220
1251
 
1221
1252
 
1222
- class ChannelChoice(QWidget):
1253
+ class ChannelChoice(CelldetectiveWidget):
1223
1254
 
1224
1255
  def __init__(self, parent_window):
1225
1256
  super().__init__()
@@ -3,13 +3,13 @@
3
3
  "yes": {
4
4
  "Do you have the complete shape information for both populations?": {
5
5
  "yes": "You can calculate a mask-contact neighborhood. Define the reference and neighbor populations. Adjust the tolerance parameter to control how sensitive the analysis is to contact between reference and neighbor cells.",
6
- "no": "You can use an isotropic distance threshold. Define the reference and neighbor populations. Set a radius \( r > (R_{\text{ref}} + 0.5 \times R_{\text{neigh}}) \), where \( R_{\text{ref}} \) is the average radius of reference cells and \( R_{\text{neigh}} \) is the average radius of neighbor cells."
6
+ "no": "You can use an isotropic distance threshold. Define the reference and neighbor populations. Set a radius ( r > (R_{\text{ref}} + 0.5 \times R_{\text{neigh}}) ), where ( R_{\text{ref}} ) is the average radius of reference cells and ( R_{\text{neigh}} ) is the average radius of neighbor cells."
7
7
  }
8
8
  },
9
9
  "no": {
10
10
  "Do you have the complete shape information for the population of interest?": {
11
11
  "yes": "You can calculate a mask-contact neighborhood. Use the same population as both the reference and neighbor. Adjust the tolerance parameter to control sensitivity to cell-cell contact.",
12
- "no": "You can use an isotropic distance threshold. Use the same population as both the reference and neighbor. Set a radius \( r > 1.5 \times R \), where \( R \) is the average cell radius."
12
+ "no": "You can use an isotropic distance threshold. Use the same population as both the reference and neighbor. Set a radius ( r > 1.5 \times R ), where ( R ) is the average cell radius."
13
13
  }
14
14
  }
15
15
  }
@@ -1,10 +1,11 @@
1
1
  import configparser
2
- from PyQt5.QtWidgets import QWidget, QVBoxLayout, QScrollArea, QLabel, QHBoxLayout, QLineEdit, QPushButton
2
+ from PyQt5.QtWidgets import QVBoxLayout, QScrollArea, QLabel, QHBoxLayout, QLineEdit, QPushButton
3
3
  from PyQt5.QtCore import Qt
4
4
  import configparser
5
- from celldetective.gui import Styles
5
+ from celldetective.gui import CelldetectiveWidget
6
6
 
7
- class ConfigEditor(QWidget, Styles):
7
+
8
+ class ConfigEditor(CelldetectiveWidget):
8
9
 
9
10
  def __init__(self, parent_window):
10
11
 
@@ -27,7 +28,7 @@ class ConfigEditor(QWidget, Styles):
27
28
  # Create a scroll area to contain the main layout
28
29
  scroll = QScrollArea()
29
30
  scroll.setWidgetResizable(True)
30
- scroll_content = QWidget()
31
+ scroll_content = CelldetectiveWidget()
31
32
  self.scroll_layout = QVBoxLayout(scroll_content)
32
33
  scroll_content.setLayout(self.scroll_layout)
33
34
  scroll.setWidget(scroll_content)