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.
- celldetective/__init__.py +0 -3
- celldetective/_version.py +1 -1
- celldetective/events.py +2 -4
- celldetective/extra_properties.py +132 -0
- celldetective/gui/InitWindow.py +33 -45
- celldetective/gui/__init__.py +1 -0
- celldetective/gui/about.py +19 -15
- celldetective/gui/analyze_block.py +34 -19
- celldetective/gui/base_components.py +23 -0
- celldetective/gui/btrack_options.py +26 -34
- celldetective/gui/classifier_widget.py +68 -81
- celldetective/gui/configure_new_exp.py +113 -17
- celldetective/gui/control_panel.py +68 -141
- celldetective/gui/generic_signal_plot.py +9 -12
- celldetective/gui/gui_utils.py +49 -21
- celldetective/gui/json_readers.py +5 -4
- celldetective/gui/layouts.py +246 -22
- celldetective/gui/measurement_options.py +32 -17
- celldetective/gui/neighborhood_options.py +10 -13
- celldetective/gui/plot_measurements.py +21 -17
- celldetective/gui/plot_signals_ui.py +125 -72
- celldetective/gui/process_block.py +180 -123
- celldetective/gui/processes/compute_neighborhood.py +594 -0
- celldetective/gui/processes/measure_cells.py +5 -0
- celldetective/gui/processes/segment_cells.py +27 -6
- celldetective/gui/processes/track_cells.py +6 -0
- celldetective/gui/retrain_segmentation_model_options.py +12 -20
- celldetective/gui/retrain_signal_model_options.py +57 -56
- celldetective/gui/seg_model_loader.py +21 -62
- celldetective/gui/signal_annotator.py +129 -70
- celldetective/gui/signal_annotator2.py +431 -635
- celldetective/gui/signal_annotator_options.py +8 -11
- celldetective/gui/survival_ui.py +49 -95
- celldetective/gui/tableUI.py +28 -25
- celldetective/gui/thresholds_gui.py +617 -1221
- celldetective/gui/viewers.py +106 -39
- celldetective/gui/workers.py +9 -3
- celldetective/io.py +57 -20
- celldetective/measure.py +63 -27
- celldetective/neighborhood.py +342 -268
- celldetective/preprocessing.py +25 -17
- celldetective/relative_measurements.py +50 -29
- celldetective/scripts/analyze_signals.py +4 -1
- celldetective/scripts/measure_relative.py +4 -1
- celldetective/scripts/segment_cells.py +0 -6
- celldetective/scripts/track_cells.py +3 -1
- celldetective/scripts/train_segmentation_model.py +7 -4
- celldetective/signals.py +29 -14
- celldetective/tracking.py +7 -2
- celldetective/utils.py +36 -8
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/METADATA +24 -16
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/RECORD +57 -55
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/WHEEL +1 -1
- tests/test_qt.py +21 -21
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info/licenses}/LICENSE +0 -0
- {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
|
|
2
|
-
QPushButton,
|
|
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(
|
|
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
|
-
|
|
55
|
-
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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 = ['
|
|
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',
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
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(
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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('
|
|
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.
|
|
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
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
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.
|
|
2562
|
-
self.vmax = np.nanpercentile(self.img.flatten(), 99.)
|
|
2614
|
+
if self.previous_channel != self.current_channel:
|
|
2563
2615
|
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
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
|
|