celldetective 1.3.9.post5__py3-none-any.whl → 1.4.0__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 (57) hide show
  1. celldetective/__init__.py +0 -3
  2. celldetective/_version.py +1 -1
  3. celldetective/events.py +2 -4
  4. celldetective/extra_properties.py +132 -0
  5. celldetective/gui/InitWindow.py +33 -45
  6. celldetective/gui/__init__.py +1 -0
  7. celldetective/gui/about.py +19 -15
  8. celldetective/gui/analyze_block.py +34 -19
  9. celldetective/gui/base_components.py +23 -0
  10. celldetective/gui/btrack_options.py +26 -34
  11. celldetective/gui/classifier_widget.py +68 -81
  12. celldetective/gui/configure_new_exp.py +113 -17
  13. celldetective/gui/control_panel.py +68 -141
  14. celldetective/gui/generic_signal_plot.py +9 -12
  15. celldetective/gui/gui_utils.py +49 -21
  16. celldetective/gui/json_readers.py +5 -4
  17. celldetective/gui/layouts.py +246 -22
  18. celldetective/gui/measurement_options.py +32 -17
  19. celldetective/gui/neighborhood_options.py +10 -13
  20. celldetective/gui/plot_measurements.py +21 -17
  21. celldetective/gui/plot_signals_ui.py +125 -72
  22. celldetective/gui/process_block.py +180 -123
  23. celldetective/gui/processes/compute_neighborhood.py +594 -0
  24. celldetective/gui/processes/measure_cells.py +5 -0
  25. celldetective/gui/processes/segment_cells.py +27 -6
  26. celldetective/gui/processes/track_cells.py +6 -0
  27. celldetective/gui/retrain_segmentation_model_options.py +12 -20
  28. celldetective/gui/retrain_signal_model_options.py +57 -56
  29. celldetective/gui/seg_model_loader.py +21 -62
  30. celldetective/gui/signal_annotator.py +129 -70
  31. celldetective/gui/signal_annotator2.py +431 -635
  32. celldetective/gui/signal_annotator_options.py +8 -11
  33. celldetective/gui/survival_ui.py +49 -95
  34. celldetective/gui/tableUI.py +28 -25
  35. celldetective/gui/thresholds_gui.py +617 -1221
  36. celldetective/gui/viewers.py +106 -39
  37. celldetective/gui/workers.py +9 -3
  38. celldetective/io.py +57 -20
  39. celldetective/measure.py +63 -27
  40. celldetective/neighborhood.py +342 -268
  41. celldetective/preprocessing.py +25 -17
  42. celldetective/relative_measurements.py +50 -29
  43. celldetective/scripts/analyze_signals.py +4 -1
  44. celldetective/scripts/measure_relative.py +4 -1
  45. celldetective/scripts/segment_cells.py +0 -6
  46. celldetective/scripts/track_cells.py +3 -1
  47. celldetective/scripts/train_segmentation_model.py +7 -4
  48. celldetective/signals.py +29 -14
  49. celldetective/tracking.py +7 -2
  50. celldetective/utils.py +36 -8
  51. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/METADATA +24 -16
  52. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/RECORD +57 -55
  53. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/WHEEL +1 -1
  54. tests/test_qt.py +21 -21
  55. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/entry_points.txt +0 -0
  56. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info/licenses}/LICENSE +0 -0
  57. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
- from PyQt5.QtWidgets import QMainWindow, QComboBox, QLabel, QRadioButton, QLineEdit, QFileDialog, QApplication, \
2
- QPushButton, QWidget, QVBoxLayout, QHBoxLayout, QMessageBox, QShortcut, QLineEdit, QSlider, QCheckBox
1
+ from PyQt5.QtWidgets import QComboBox, QLabel, QRadioButton, QLineEdit, QFileDialog, QApplication, \
2
+ QPushButton, QVBoxLayout, QHBoxLayout, QMessageBox, QShortcut, QLineEdit, QSlider, QCheckBox
3
3
  from PyQt5.QtCore import Qt, QSize
4
4
  from PyQt5.QtGui import QKeySequence, QIntValidator
5
5
 
@@ -23,10 +23,11 @@ from matplotlib.animation import FuncAnimation
23
23
  from matplotlib.cm import tab10
24
24
  import pandas as pd
25
25
  from sklearn.preprocessing import MinMaxScaler
26
- from celldetective.gui import Styles
26
+ from celldetective.gui import Styles, CelldetectiveWidget, CelldetectiveMainWindow
27
27
  from celldetective.measure import contour_of_instance_segmentation
28
+ from celldetective.utils import pretty_table
28
29
 
29
- class SignalAnnotator(QMainWindow, Styles):
30
+ class SignalAnnotator(CelldetectiveMainWindow):
30
31
  """
31
32
  UI to set tracking parameters for bTrack.
32
33
 
@@ -38,7 +39,6 @@ class SignalAnnotator(QMainWindow, Styles):
38
39
 
39
40
  center_window(self)
40
41
  self.proceed = True
41
- self.setAttribute(Qt.WA_DeleteOnClose)
42
42
 
43
43
  self.parent_window = parent_window
44
44
  self.setWindowTitle("Signal annotator")
@@ -51,12 +51,8 @@ class SignalAnnotator(QMainWindow, Styles):
51
51
  self.recently_modified = False
52
52
  self.selection = []
53
53
 
54
- if self.mode == "targets":
55
- self.instructions_path = self.exp_dir + os.sep.join(['configs', 'signal_annotator_config_targets.json'])
56
- self.trajectories_path = self.pos + os.sep.join(['output','tables','trajectories_targets.csv'])
57
- elif self.mode == "effectors":
58
- self.instructions_path = self.exp_dir + os.sep.join(['configs', 'signal_annotator_config_effectors.json'])
59
- self.trajectories_path = self.pos + os.sep.join(['output','tables','trajectories_effectors.csv'])
54
+ self.instructions_path = self.exp_dir + os.sep.join(['configs', f'signal_annotator_config_{self.mode}.json'])
55
+ self.trajectories_path = self.pos + os.sep.join(['output','tables',f'trajectories_{self.mode}.csv'])
60
56
 
61
57
  self.screen_height = self.parent_window.parent_window.parent_window.screen_height
62
58
  self.screen_width = self.parent_window.parent_window.parent_window.screen_width
@@ -99,7 +95,7 @@ class SignalAnnotator(QMainWindow, Styles):
99
95
 
100
96
  """
101
97
 
102
- self.button_widget = QWidget()
98
+ self.button_widget = CelldetectiveWidget()
103
99
  main_layout = QHBoxLayout()
104
100
  self.button_widget.setLayout(main_layout)
105
101
 
@@ -330,7 +326,7 @@ class SignalAnnotator(QMainWindow, Styles):
330
326
  self.contrast_slider = QLabeledDoubleRangeSlider()
331
327
  self.contrast_slider.setSingleStep(0.001)
332
328
  self.contrast_slider.setTickInterval(0.001)
333
- self.contrast_slider.setOrientation(1)
329
+ self.contrast_slider.setOrientation(Qt.Horizontal)
334
330
  self.contrast_slider.setRange(
335
331
  *[np.nanpercentile(self.stack, 0.001), np.nanpercentile(self.stack, 99.999)])
336
332
  self.contrast_slider.setValue(
@@ -345,7 +341,7 @@ class SignalAnnotator(QMainWindow, Styles):
345
341
  # self.interval_slider = QLabeledSlider()
346
342
  # self.interval_slider.setSingleStep(1)
347
343
  # self.interval_slider.setTickInterval(1)
348
- # self.interval_slider.setOrientation(1)
344
+ # self.interval_slider.setOrientation(Qt.Horizontal)
349
345
  # self.interval_slider.setRange(1, 10000)
350
346
  # self.interval_slider.setValue(self.speed)
351
347
  # self.interval_slider.valueChanged.connect(self.interval_slider_action)
@@ -394,7 +390,7 @@ class SignalAnnotator(QMainWindow, Styles):
394
390
  def create_new_event_class(self):
395
391
 
396
392
  # display qwidget to name the event
397
- self.newClassWidget = QWidget()
393
+ self.newClassWidget = CelldetectiveWidget()
398
394
  self.newClassWidget.setWindowTitle('Create new event class')
399
395
 
400
396
  layout = QVBoxLayout()
@@ -787,10 +783,12 @@ class SignalAnnotator(QMainWindow, Styles):
787
783
  # self.columns_to_rescale = [col for t,col in zip(is_number_test,self.df_tracks.columns) if t]
788
784
  # print(self.columns_to_rescale)
789
785
 
790
- cols_to_remove = ['status', 'status_color', 'class_color', 'TRACK_ID', 'FRAME', 'x_anim', 'y_anim', 't',
786
+ cols_to_remove = ['group', 'group_color', 'status', 'status_color', 'class_color', 'TRACK_ID', 'FRAME',
787
+ 'x_anim', 'y_anim', 't','dummy','group_color',
791
788
  'state', 'generation', 'root', 'parent', 'class_id', 'class', 't0', 'POSITION_X',
792
- 'POSITION_Y', 'position', 'well', 'well_index', 'well_name', 'pos_name', 'index',] + self.class_cols
793
-
789
+ 'POSITION_Y', 'position', 'well', 'well_index', 'well_name', 'pos_name', 'index',
790
+ 'concentration', 'cell_type', 'antibody', 'pharmaceutical_agent', 'ID'] + self.class_cols
791
+
794
792
  meta = get_experiment_metadata(self.exp_dir)
795
793
  if meta is not None:
796
794
  keys = list(meta.keys())
@@ -829,12 +827,14 @@ class SignalAnnotator(QMainWindow, Styles):
829
827
  cclass = group[self.class_name].to_numpy()[0]
830
828
  timeline = group['FRAME'].to_numpy()
831
829
  status = np.zeros_like(timeline)
830
+
832
831
  if t0 > 0:
833
- status[timeline >= t0] = 1.
834
- if cclass == 2:
835
- status[:] = 2
832
+ status[timeline >= t0] = 1.
833
+ # if cclass == 2:
834
+ # status[:] = 1.
836
835
  if cclass > 2:
837
836
  status[:] = 42
837
+
838
838
  status_color = [color_from_status(s) for s in status]
839
839
  class_color = [color_from_class(cclass) for i in range(len(status))]
840
840
 
@@ -852,7 +852,7 @@ class SignalAnnotator(QMainWindow, Styles):
852
852
 
853
853
  to_remove = ['TRACK_ID', 'FRAME', 'x_anim', 'y_anim', 't', 'state', 'generation', 'root', 'parent', 'class_id',
854
854
  'class', 't0', 'POSITION_X', 'POSITION_Y', 'position', 'well', 'well_index', 'well_name',
855
- 'pos_name', 'index','class_color','status_color']
855
+ 'pos_name', 'index','class_color','status_color','dummy','group_color']
856
856
 
857
857
  meta = get_experiment_metadata(self.exp_dir)
858
858
  if meta is not None:
@@ -882,7 +882,11 @@ class SignalAnnotator(QMainWindow, Styles):
882
882
  for i in range(len(self.signal_choice_cb)):
883
883
 
884
884
  signal_choice = self.signal_choice_cb[i].currentText()
885
- self.lines[i].set_label(signal_choice)
885
+ lbl = signal_choice
886
+ n_cut = 35
887
+ if len(lbl)>n_cut:
888
+ lbl = lbl[:(n_cut-3)]+'...'
889
+ self.lines[i].set_label(lbl)
886
890
 
887
891
  if signal_choice == "--":
888
892
  self.lines[i].set_xdata([])
@@ -911,9 +915,10 @@ class SignalAnnotator(QMainWindow, Styles):
911
915
  self.line_dt.set_xdata([t0, t0])
912
916
  self.line_dt.set_ydata([min_val, max_val])
913
917
 
914
- self.cell_ax.legend()
918
+ self.cell_ax.legend(fontsize=8)
915
919
  self.cell_fcanvas.canvas.draw()
916
920
  except Exception as e:
921
+ print(e)
917
922
  pass
918
923
 
919
924
  if len(range_values)>0:
@@ -1101,7 +1106,7 @@ class SignalAnnotator(QMainWindow, Styles):
1101
1106
  self.line_dt, = self.cell_ax.plot([-1, -1], [min_val, max_val], c="k", linestyle="--")
1102
1107
 
1103
1108
  self.cell_ax.set_xlim(0, self.len_movie)
1104
- self.cell_ax.legend()
1109
+ self.cell_ax.legend(fontsize=8)
1105
1110
  self.cell_fcanvas.canvas.draw()
1106
1111
 
1107
1112
  self.plot_signals()
@@ -1399,7 +1404,7 @@ class MeasureAnnotator(SignalAnnotator):
1399
1404
 
1400
1405
  def __init__(self, parent_window=None):
1401
1406
 
1402
- QMainWindow.__init__(self)
1407
+ SignalAnnotator.__init__(self)
1403
1408
  self.parent_window = parent_window
1404
1409
  self.setWindowTitle("Signal annotator")
1405
1410
  self.mode = self.parent_window.mode
@@ -1411,12 +1416,15 @@ class MeasureAnnotator(SignalAnnotator):
1411
1416
  self.selection = []
1412
1417
  self.int_validator = QIntValidator()
1413
1418
  self.current_alpha=0.5
1414
- if self.mode == "targets":
1415
- self.instructions_path = self.exp_dir + os.sep.join(['configs','signal_annotator_config_targets.json'])
1416
- self.trajectories_path = self.pos + os.sep.join(['output','tables','trajectories_targets.csv'])
1417
- elif self.mode == "effectors":
1418
- self.instructions_path = self.exp_dir + os.sep.join(['configs','signal_annotator_config_effectors.json'])
1419
- self.trajectories_path = self.pos + os.sep.join(['output','tables','trajectories_effectors.csv'])
1419
+ self.value_magnitude = 1
1420
+
1421
+ epsilon = 0.01
1422
+ self.observed_min_intensity = 0
1423
+ self.observed_max_intensity = 0 + epsilon
1424
+
1425
+
1426
+ self.instructions_path = self.exp_dir + os.sep.join(['configs',f'signal_annotator_config_{self.mode}.json'])
1427
+ self.trajectories_path = self.pos + os.sep.join(['output','tables',f'trajectories_{self.mode}.csv'])
1420
1428
 
1421
1429
  self.screen_height = self.parent_window.parent_window.parent_window.screen_height
1422
1430
  self.screen_width = self.parent_window.parent_window.parent_window.screen_width
@@ -1454,6 +1462,7 @@ class MeasureAnnotator(SignalAnnotator):
1454
1462
  self.setAttribute(Qt.WA_DeleteOnClose)
1455
1463
  self.previous_index = None
1456
1464
 
1465
+
1457
1466
  def static_image(self):
1458
1467
 
1459
1468
  """
@@ -1523,6 +1532,7 @@ class MeasureAnnotator(SignalAnnotator):
1523
1532
  current_yvalues = []
1524
1533
  all_median_values = []
1525
1534
  labels = []
1535
+ range_values = []
1526
1536
 
1527
1537
  for i in range(len(self.signal_choice_cb)):
1528
1538
 
@@ -1539,6 +1549,7 @@ class MeasureAnnotator(SignalAnnotator):
1539
1549
  all_ydata = self.df_tracks.loc[:, signal_choice].to_numpy()
1540
1550
  ydataNaN = ydata
1541
1551
  ydata = ydata[ydata == ydata] # remove nan
1552
+
1542
1553
  current_ydata = self.df_tracks.loc[
1543
1554
  (self.df_tracks['FRAME'] == current_frame), signal_choice].to_numpy()
1544
1555
  current_ydata = current_ydata[current_ydata == current_ydata]
@@ -1546,12 +1557,16 @@ class MeasureAnnotator(SignalAnnotator):
1546
1557
  yvalues.extend(ydataNaN)
1547
1558
  current_yvalues.append(current_ydata)
1548
1559
  all_yvalues.append(all_ydata)
1560
+ range_values.extend(all_ydata)
1549
1561
  labels.append(signal_choice)
1550
1562
 
1551
1563
  self.cell_ax.clear()
1552
1564
 
1553
1565
  if len(yvalues) > 0:
1554
- self.cell_ax.boxplot(all_yvalues, showfliers=self.show_fliers)
1566
+ try:
1567
+ self.cell_ax.boxplot(all_yvalues, showfliers=self.show_fliers)
1568
+ except Exception as e:
1569
+ print(f"{e=}")
1555
1570
  ylim = self.cell_ax.get_ylim()
1556
1571
  self.cell_ax.set_ylim(ylim)
1557
1572
  x_pos = np.arange(len(all_yvalues)) + 1
@@ -1564,6 +1579,20 @@ class MeasureAnnotator(SignalAnnotator):
1564
1579
 
1565
1580
  self.cell_ax.plot(x_pos, yvalues, marker='H', linestyle='None', color=tab10.colors[3], alpha=1)
1566
1581
 
1582
+ range_values = np.array(range_values)
1583
+ if len(range_values[range_values==range_values])>0:
1584
+
1585
+ if len(range_values[range_values>0])>0:
1586
+ self.value_magnitude = np.nanmin(range_values[range_values>0]) - 0.03*(np.nanmax(range_values[range_values>0]) - np.nanmin(range_values[range_values>0]))
1587
+ else:
1588
+ self.value_magnitude = 1
1589
+
1590
+ self.non_log_ymin = np.nanmin(range_values) - 0.03*(np.nanmax(range_values) - np.nanmin(range_values))
1591
+ self.non_log_ymax = np.nanmax(range_values) + 0.03*(np.nanmax(range_values) - np.nanmin(range_values))
1592
+ if self.cell_ax.get_yscale()=='linear':
1593
+ self.cell_ax.set_ylim(self.non_log_ymin, self.non_log_ymax)
1594
+ else:
1595
+ self.cell_ax.set_ylim(self.value_magnitude, self.non_log_ymax)
1567
1596
 
1568
1597
  else:
1569
1598
  self.cell_ax.text(0.5, 0.5, "No data available", horizontalalignment='center',
@@ -1669,7 +1698,7 @@ class MeasureAnnotator(SignalAnnotator):
1669
1698
 
1670
1699
  """
1671
1700
 
1672
- self.button_widget = QWidget()
1701
+ self.button_widget = CelldetectiveWidget()
1673
1702
  main_layout = QHBoxLayout()
1674
1703
  self.button_widget.setLayout(main_layout)
1675
1704
 
@@ -1692,14 +1721,12 @@ class MeasureAnnotator(SignalAnnotator):
1692
1721
  self.class_cols = np.array([c.startswith('group') or c.startswith('status') for c in list(self.df_tracks.columns)])
1693
1722
  self.class_cols = list(cols[self.class_cols])
1694
1723
 
1695
- try:
1696
- self.class_cols.remove('group_id')
1697
- except Exception:
1698
- pass
1699
- try:
1700
- self.class_cols.remove('group_color')
1701
- except Exception:
1702
- pass
1724
+ to_remove = ['group_id','group_color','class_id','class_color']
1725
+ for col in to_remove:
1726
+ try:
1727
+ self.class_cols.remove(col)
1728
+ except Exception:
1729
+ pass
1703
1730
 
1704
1731
  self.class_choice_cb.addItems(self.class_cols)
1705
1732
  self.class_choice_cb.currentIndexChanged.connect(self.changed_class)
@@ -1886,7 +1913,7 @@ class MeasureAnnotator(SignalAnnotator):
1886
1913
 
1887
1914
  self.contrast_slider.setSingleStep(0.001)
1888
1915
  self.contrast_slider.setTickInterval(0.001)
1889
- self.contrast_slider.setOrientation(1)
1916
+ self.contrast_slider.setOrientation(Qt.Horizontal)
1890
1917
  self.contrast_slider.setRange(
1891
1918
  *[np.nanpercentile(self.img, 0.001), np.nanpercentile(self.img, 99.999)])
1892
1919
  self.contrast_slider.setValue(
@@ -1897,7 +1924,7 @@ class MeasureAnnotator(SignalAnnotator):
1897
1924
  self.right_panel.addLayout(contrast_hbox, 5)
1898
1925
  self.alpha_slider = QLabeledDoubleSlider()
1899
1926
  self.alpha_slider.setSingleStep(0.001)
1900
- self.alpha_slider.setOrientation(1)
1927
+ self.alpha_slider.setOrientation(Qt.Horizontal)
1901
1928
  self.alpha_slider.setRange(0, 1)
1902
1929
  self.alpha_slider.setValue(self.current_alpha)
1903
1930
  self.alpha_slider.setDecimals(3)
@@ -1957,7 +1984,7 @@ class MeasureAnnotator(SignalAnnotator):
1957
1984
  print(f"Error {e}...")
1958
1985
 
1959
1986
  def set_next_frame(self):
1960
-
1987
+
1961
1988
  self.current_frame = self.current_frame + 1
1962
1989
  if self.current_frame > self.len_movie - 1:
1963
1990
  self.current_frame == self.len_movie - 1
@@ -1966,7 +1993,7 @@ class MeasureAnnotator(SignalAnnotator):
1966
1993
  self.start_btn.setShortcut(QKeySequence("f"))
1967
1994
 
1968
1995
  def set_previous_frame(self):
1969
-
1996
+
1970
1997
  self.current_frame = self.current_frame - 1
1971
1998
  if self.current_frame < 0:
1972
1999
  self.current_frame == 0
@@ -1998,8 +2025,10 @@ class MeasureAnnotator(SignalAnnotator):
1998
2025
  self.class_choice_cb.clear()
1999
2026
  cols = np.array(self.df_tracks.columns)
2000
2027
  self.class_cols = np.array([c.startswith('group') for c in list(self.df_tracks.columns)])
2028
+
2001
2029
  self.class_cols = list(cols[self.class_cols])
2002
2030
  self.class_cols.remove('group_color')
2031
+
2003
2032
  self.class_choice_cb.addItems(self.class_cols)
2004
2033
  idx = self.class_choice_cb.findText(self.target_class)
2005
2034
  self.status_name = self.target_class
@@ -2046,7 +2075,7 @@ class MeasureAnnotator(SignalAnnotator):
2046
2075
  def create_new_event_class(self):
2047
2076
 
2048
2077
  # display qwidget to name the event
2049
- self.newClassWidget = QWidget()
2078
+ self.newClassWidget = CelldetectiveWidget()
2050
2079
  self.newClassWidget.setWindowTitle('Create new characteristic group')
2051
2080
 
2052
2081
  layout = QVBoxLayout()
@@ -2113,6 +2142,7 @@ class MeasureAnnotator(SignalAnnotator):
2113
2142
  self.fcanvas.canvas.draw()
2114
2143
 
2115
2144
  def assign_color_state(self, state):
2145
+
2116
2146
  if np.isnan(state):
2117
2147
  state = "nan"
2118
2148
  return self.state_color_map[state]
@@ -2141,23 +2171,23 @@ class MeasureAnnotator(SignalAnnotator):
2141
2171
  return (self.im, self.status_scatter,self.im_mask,)
2142
2172
 
2143
2173
  def compute_status_and_colors(self):
2144
- print('compute status and colors!')
2174
+
2145
2175
  if self.class_choice_cb.currentText() == '':
2146
2176
  self.status_name=self.target_class
2147
2177
  else:
2148
2178
  self.status_name = self.class_choice_cb.currentText()
2149
2179
 
2150
- print(f'{self.status_name=}')
2151
2180
  if self.status_name not in self.df_tracks.columns:
2152
- print('not in df, make column')
2181
+ print('Creating a new status for visualization...')
2153
2182
  self.make_status_column()
2154
2183
  else:
2184
+ print(f'Generating per-state colors for the status "{self.status_name}"...')
2155
2185
  all_states = self.df_tracks.loc[:, self.status_name].tolist()
2156
2186
  all_states = np.array(all_states)
2157
2187
  self.state_color_map = color_from_state(all_states, recently_modified=False)
2158
- print(f'{self.state_color_map=}')
2188
+ print(f'Color mapping for "{self.status_name}":')
2189
+ pretty_table(self.state_color_map)
2159
2190
  self.df_tracks['group_color'] = self.df_tracks[self.status_name].apply(self.assign_color_state)
2160
- print(self.df_tracks['group_color'])
2161
2191
 
2162
2192
  def del_event_class(self):
2163
2193
 
@@ -2217,16 +2247,23 @@ class MeasureAnnotator(SignalAnnotator):
2217
2247
  self.df_tracks = self.df_tracks.sort_values(by=['ID', 'FRAME'])
2218
2248
 
2219
2249
  cols = np.array(self.df_tracks.columns)
2220
- self.class_cols = np.array([c.startswith('group') for c in list(self.df_tracks.columns)])
2250
+ self.class_cols = np.array([c.startswith('group') or c.startswith('class') for c in list(self.df_tracks.columns)])
2221
2251
  self.class_cols = list(cols[self.class_cols])
2222
- try:
2223
- self.class_cols.remove('class_id')
2224
- except:
2225
- pass
2226
- try:
2227
- self.class_cols.remove('group_color')
2228
- except:
2229
- pass
2252
+
2253
+ to_remove = ['class_id','group_color','class_color']
2254
+ for col in to_remove:
2255
+ try:
2256
+ self.class_cols.remove(col)
2257
+ except:
2258
+ pass
2259
+ # try:
2260
+ # self.class_cols.remove('class_id')
2261
+ # except:
2262
+ # pass
2263
+ # try:
2264
+ # self.class_cols.remove('group_color')
2265
+ # except:
2266
+ # pass
2230
2267
  if len(self.class_cols) > 0:
2231
2268
  self.status = self.class_cols[0]
2232
2269
 
@@ -2286,7 +2323,7 @@ class MeasureAnnotator(SignalAnnotator):
2286
2323
  # print(self.columns_to_rescale)
2287
2324
 
2288
2325
  cols_to_remove = ['group', 'group_color', 'status', 'status_color', 'class_color', 'TRACK_ID', 'FRAME',
2289
- 'x_anim', 'y_anim', 't',
2326
+ 'x_anim', 'y_anim', 't','dummy','group_color',
2290
2327
  'state', 'generation', 'root', 'parent', 'class_id', 'class', 't0', 'POSITION_X',
2291
2328
  'POSITION_Y', 'position', 'well', 'well_index', 'well_name', 'pos_name', 'index',
2292
2329
  'concentration', 'cell_type', 'antibody', 'pharmaceutical_agent', 'ID'] + self.class_cols
@@ -2348,6 +2385,10 @@ class MeasureAnnotator(SignalAnnotator):
2348
2385
  self.modify()
2349
2386
 
2350
2387
  self.draw_frame(self.current_frame)
2388
+ self.vmin = self.contrast_slider.value()[0]
2389
+ self.vmax = self.contrast_slider.value()[1]
2390
+ self.im.set_clim(vmin=self.vmin, vmax=self.vmax)
2391
+
2351
2392
  self.fcanvas.canvas.draw()
2352
2393
  self.plot_signals()
2353
2394
 
@@ -2443,7 +2484,6 @@ class MeasureAnnotator(SignalAnnotator):
2443
2484
  all_states = self.df_tracks.loc[:, self.status_name].tolist()
2444
2485
  all_states = np.array(all_states)
2445
2486
  self.state_color_map = color_from_state(all_states, recently_modified=False)
2446
- print(f'{self.state_color_map=}')
2447
2487
 
2448
2488
  self.df_tracks['group_color'] = self.df_tracks[self.status_name].apply(self.assign_color_state)
2449
2489
 
@@ -2538,13 +2578,26 @@ class MeasureAnnotator(SignalAnnotator):
2538
2578
  """
2539
2579
 
2540
2580
  # self.clear_post_threshold_options()
2541
-
2581
+ self.previous_channel = self.current_channel
2542
2582
  self.current_channel = self.choose_channel.currentIndex()
2543
2583
 
2544
2584
  t = int(self.frame_slider.value())
2545
2585
  idx = t * self.nbr_channels + self.current_channel
2546
2586
  self.img = load_frames(idx, self.stack_path, normalize_input=False)
2587
+
2588
+ if self.previous_channel != self.current_channel:
2589
+ # reinitialize intensity bounds
2590
+ epsilon = 0.01
2591
+ self.observed_min_intensity = 0
2592
+ self.observed_max_intensity = 0 + epsilon
2593
+
2547
2594
  if self.img is not None:
2595
+ max_img = np.nanmax(self.img)
2596
+ min_img = np.nanmin(self.img)
2597
+ if max_img > self.observed_max_intensity:
2598
+ self.observed_max_intensity = max_img
2599
+ if min_img < self.observed_min_intensity:
2600
+ self.observed_min_intensity = min_img
2548
2601
  self.refresh_imshow()
2549
2602
  # self.redo_histogram()
2550
2603
  else:
@@ -2558,13 +2611,19 @@ class MeasureAnnotator(SignalAnnotator):
2558
2611
 
2559
2612
  """
2560
2613
 
2561
- self.vmin = np.nanpercentile(self.img.flatten(), 1)
2562
- self.vmax = np.nanpercentile(self.img.flatten(), 99.)
2614
+ if self.previous_channel != self.current_channel:
2563
2615
 
2564
- self.contrast_slider.disconnect()
2565
- self.contrast_slider.setRange(np.nanmin(self.img), np.nanmax(self.img))
2566
- self.contrast_slider.setValue([self.vmin, self.vmax])
2567
- self.contrast_slider.valueChanged.connect(self.contrast_slider_action)
2616
+ self.vmin = np.nanpercentile(self.img.flatten(), 1)
2617
+ self.vmax = np.nanpercentile(self.img.flatten(), 99.)
2618
+
2619
+ self.contrast_slider.disconnect()
2620
+ self.contrast_slider.setRange(np.nanmin(self.img), np.nanmax(self.img))
2621
+ self.contrast_slider.setValue([self.vmin, self.vmax])
2622
+ self.contrast_slider.valueChanged.connect(self.contrast_slider_action)
2623
+ else:
2624
+ #self.contrast_slider.disconnect()
2625
+ self.contrast_slider.setRange(self.observed_min_intensity, self.observed_max_intensity)
2626
+ #self.contrast_slider.valueChanged.connect(self.contrast_slider_action)
2568
2627
 
2569
2628
  self.im.set_data(self.img)
2570
2629