celldetective 1.3.9.post4__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 +320 -24
- 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 +71 -80
- 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 +131 -75
- 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 +139 -72
- 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 +73 -27
- 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.post4.dist-info → celldetective-1.4.0.dist-info}/METADATA +24 -16
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/RECORD +57 -55
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/WHEEL +1 -1
- tests/test_qt.py +21 -21
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info/licenses}/LICENSE +0 -0
- {celldetective-1.3.9.post4.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())
|
|
@@ -807,8 +805,6 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
807
805
|
cols_to_remove += time_cols
|
|
808
806
|
#cols_to_remove.extend(self.df_tracks.select_dtypes(include=['object']).columns)
|
|
809
807
|
|
|
810
|
-
print(f"{cols_to_remove=}")
|
|
811
|
-
|
|
812
808
|
for tr in cols_to_remove:
|
|
813
809
|
try:
|
|
814
810
|
self.columns_to_rescale.remove(tr)
|
|
@@ -831,12 +827,14 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
831
827
|
cclass = group[self.class_name].to_numpy()[0]
|
|
832
828
|
timeline = group['FRAME'].to_numpy()
|
|
833
829
|
status = np.zeros_like(timeline)
|
|
830
|
+
|
|
834
831
|
if t0 > 0:
|
|
835
|
-
status[timeline >= t0] = 1.
|
|
836
|
-
if cclass == 2:
|
|
837
|
-
|
|
832
|
+
status[timeline >= t0] = 1.
|
|
833
|
+
# if cclass == 2:
|
|
834
|
+
# status[:] = 1.
|
|
838
835
|
if cclass > 2:
|
|
839
836
|
status[:] = 42
|
|
837
|
+
|
|
840
838
|
status_color = [color_from_status(s) for s in status]
|
|
841
839
|
class_color = [color_from_class(cclass) for i in range(len(status))]
|
|
842
840
|
|
|
@@ -854,7 +852,17 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
854
852
|
|
|
855
853
|
to_remove = ['TRACK_ID', 'FRAME', 'x_anim', 'y_anim', 't', 'state', 'generation', 'root', 'parent', 'class_id',
|
|
856
854
|
'class', 't0', 'POSITION_X', 'POSITION_Y', 'position', 'well', 'well_index', 'well_name',
|
|
857
|
-
'pos_name', 'index','class_color','status_color']
|
|
855
|
+
'pos_name', 'index','class_color','status_color','dummy','group_color']
|
|
856
|
+
|
|
857
|
+
meta = get_experiment_metadata(self.exp_dir)
|
|
858
|
+
if meta is not None:
|
|
859
|
+
keys = list(meta.keys())
|
|
860
|
+
to_remove.extend(keys)
|
|
861
|
+
|
|
862
|
+
labels = get_experiment_labels(self.exp_dir)
|
|
863
|
+
if labels is not None:
|
|
864
|
+
keys = list(labels.keys())
|
|
865
|
+
to_remove.extend(labels)
|
|
858
866
|
|
|
859
867
|
for c in to_remove:
|
|
860
868
|
if c in signals:
|
|
@@ -874,7 +882,11 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
874
882
|
for i in range(len(self.signal_choice_cb)):
|
|
875
883
|
|
|
876
884
|
signal_choice = self.signal_choice_cb[i].currentText()
|
|
877
|
-
|
|
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)
|
|
878
890
|
|
|
879
891
|
if signal_choice == "--":
|
|
880
892
|
self.lines[i].set_xdata([])
|
|
@@ -903,9 +915,10 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
903
915
|
self.line_dt.set_xdata([t0, t0])
|
|
904
916
|
self.line_dt.set_ydata([min_val, max_val])
|
|
905
917
|
|
|
906
|
-
self.cell_ax.legend()
|
|
918
|
+
self.cell_ax.legend(fontsize=8)
|
|
907
919
|
self.cell_fcanvas.canvas.draw()
|
|
908
920
|
except Exception as e:
|
|
921
|
+
print(e)
|
|
909
922
|
pass
|
|
910
923
|
|
|
911
924
|
if len(range_values)>0:
|
|
@@ -1093,7 +1106,7 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
1093
1106
|
self.line_dt, = self.cell_ax.plot([-1, -1], [min_val, max_val], c="k", linestyle="--")
|
|
1094
1107
|
|
|
1095
1108
|
self.cell_ax.set_xlim(0, self.len_movie)
|
|
1096
|
-
self.cell_ax.legend()
|
|
1109
|
+
self.cell_ax.legend(fontsize=8)
|
|
1097
1110
|
self.cell_fcanvas.canvas.draw()
|
|
1098
1111
|
|
|
1099
1112
|
self.plot_signals()
|
|
@@ -1391,7 +1404,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1391
1404
|
|
|
1392
1405
|
def __init__(self, parent_window=None):
|
|
1393
1406
|
|
|
1394
|
-
|
|
1407
|
+
SignalAnnotator.__init__(self)
|
|
1395
1408
|
self.parent_window = parent_window
|
|
1396
1409
|
self.setWindowTitle("Signal annotator")
|
|
1397
1410
|
self.mode = self.parent_window.mode
|
|
@@ -1403,12 +1416,15 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1403
1416
|
self.selection = []
|
|
1404
1417
|
self.int_validator = QIntValidator()
|
|
1405
1418
|
self.current_alpha=0.5
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
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'])
|
|
1412
1428
|
|
|
1413
1429
|
self.screen_height = self.parent_window.parent_window.parent_window.screen_height
|
|
1414
1430
|
self.screen_width = self.parent_window.parent_window.parent_window.screen_width
|
|
@@ -1446,6 +1462,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1446
1462
|
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
1447
1463
|
self.previous_index = None
|
|
1448
1464
|
|
|
1465
|
+
|
|
1449
1466
|
def static_image(self):
|
|
1450
1467
|
|
|
1451
1468
|
"""
|
|
@@ -1515,6 +1532,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1515
1532
|
current_yvalues = []
|
|
1516
1533
|
all_median_values = []
|
|
1517
1534
|
labels = []
|
|
1535
|
+
range_values = []
|
|
1518
1536
|
|
|
1519
1537
|
for i in range(len(self.signal_choice_cb)):
|
|
1520
1538
|
|
|
@@ -1531,6 +1549,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1531
1549
|
all_ydata = self.df_tracks.loc[:, signal_choice].to_numpy()
|
|
1532
1550
|
ydataNaN = ydata
|
|
1533
1551
|
ydata = ydata[ydata == ydata] # remove nan
|
|
1552
|
+
|
|
1534
1553
|
current_ydata = self.df_tracks.loc[
|
|
1535
1554
|
(self.df_tracks['FRAME'] == current_frame), signal_choice].to_numpy()
|
|
1536
1555
|
current_ydata = current_ydata[current_ydata == current_ydata]
|
|
@@ -1538,12 +1557,16 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1538
1557
|
yvalues.extend(ydataNaN)
|
|
1539
1558
|
current_yvalues.append(current_ydata)
|
|
1540
1559
|
all_yvalues.append(all_ydata)
|
|
1560
|
+
range_values.extend(all_ydata)
|
|
1541
1561
|
labels.append(signal_choice)
|
|
1542
1562
|
|
|
1543
1563
|
self.cell_ax.clear()
|
|
1544
1564
|
|
|
1545
1565
|
if len(yvalues) > 0:
|
|
1546
|
-
|
|
1566
|
+
try:
|
|
1567
|
+
self.cell_ax.boxplot(all_yvalues, showfliers=self.show_fliers)
|
|
1568
|
+
except Exception as e:
|
|
1569
|
+
print(f"{e=}")
|
|
1547
1570
|
ylim = self.cell_ax.get_ylim()
|
|
1548
1571
|
self.cell_ax.set_ylim(ylim)
|
|
1549
1572
|
x_pos = np.arange(len(all_yvalues)) + 1
|
|
@@ -1556,6 +1579,20 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1556
1579
|
|
|
1557
1580
|
self.cell_ax.plot(x_pos, yvalues, marker='H', linestyle='None', color=tab10.colors[3], alpha=1)
|
|
1558
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)
|
|
1559
1596
|
|
|
1560
1597
|
else:
|
|
1561
1598
|
self.cell_ax.text(0.5, 0.5, "No data available", horizontalalignment='center',
|
|
@@ -1661,7 +1698,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1661
1698
|
|
|
1662
1699
|
"""
|
|
1663
1700
|
|
|
1664
|
-
self.button_widget =
|
|
1701
|
+
self.button_widget = CelldetectiveWidget()
|
|
1665
1702
|
main_layout = QHBoxLayout()
|
|
1666
1703
|
self.button_widget.setLayout(main_layout)
|
|
1667
1704
|
|
|
@@ -1684,14 +1721,12 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1684
1721
|
self.class_cols = np.array([c.startswith('group') or c.startswith('status') for c in list(self.df_tracks.columns)])
|
|
1685
1722
|
self.class_cols = list(cols[self.class_cols])
|
|
1686
1723
|
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
except Exception:
|
|
1694
|
-
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
|
|
1695
1730
|
|
|
1696
1731
|
self.class_choice_cb.addItems(self.class_cols)
|
|
1697
1732
|
self.class_choice_cb.currentIndexChanged.connect(self.changed_class)
|
|
@@ -1878,7 +1913,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1878
1913
|
|
|
1879
1914
|
self.contrast_slider.setSingleStep(0.001)
|
|
1880
1915
|
self.contrast_slider.setTickInterval(0.001)
|
|
1881
|
-
self.contrast_slider.setOrientation(
|
|
1916
|
+
self.contrast_slider.setOrientation(Qt.Horizontal)
|
|
1882
1917
|
self.contrast_slider.setRange(
|
|
1883
1918
|
*[np.nanpercentile(self.img, 0.001), np.nanpercentile(self.img, 99.999)])
|
|
1884
1919
|
self.contrast_slider.setValue(
|
|
@@ -1889,7 +1924,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1889
1924
|
self.right_panel.addLayout(contrast_hbox, 5)
|
|
1890
1925
|
self.alpha_slider = QLabeledDoubleSlider()
|
|
1891
1926
|
self.alpha_slider.setSingleStep(0.001)
|
|
1892
|
-
self.alpha_slider.setOrientation(
|
|
1927
|
+
self.alpha_slider.setOrientation(Qt.Horizontal)
|
|
1893
1928
|
self.alpha_slider.setRange(0, 1)
|
|
1894
1929
|
self.alpha_slider.setValue(self.current_alpha)
|
|
1895
1930
|
self.alpha_slider.setDecimals(3)
|
|
@@ -1949,7 +1984,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1949
1984
|
print(f"Error {e}...")
|
|
1950
1985
|
|
|
1951
1986
|
def set_next_frame(self):
|
|
1952
|
-
|
|
1987
|
+
|
|
1953
1988
|
self.current_frame = self.current_frame + 1
|
|
1954
1989
|
if self.current_frame > self.len_movie - 1:
|
|
1955
1990
|
self.current_frame == self.len_movie - 1
|
|
@@ -1958,7 +1993,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1958
1993
|
self.start_btn.setShortcut(QKeySequence("f"))
|
|
1959
1994
|
|
|
1960
1995
|
def set_previous_frame(self):
|
|
1961
|
-
|
|
1996
|
+
|
|
1962
1997
|
self.current_frame = self.current_frame - 1
|
|
1963
1998
|
if self.current_frame < 0:
|
|
1964
1999
|
self.current_frame == 0
|
|
@@ -1990,8 +2025,10 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1990
2025
|
self.class_choice_cb.clear()
|
|
1991
2026
|
cols = np.array(self.df_tracks.columns)
|
|
1992
2027
|
self.class_cols = np.array([c.startswith('group') for c in list(self.df_tracks.columns)])
|
|
2028
|
+
|
|
1993
2029
|
self.class_cols = list(cols[self.class_cols])
|
|
1994
2030
|
self.class_cols.remove('group_color')
|
|
2031
|
+
|
|
1995
2032
|
self.class_choice_cb.addItems(self.class_cols)
|
|
1996
2033
|
idx = self.class_choice_cb.findText(self.target_class)
|
|
1997
2034
|
self.status_name = self.target_class
|
|
@@ -2038,7 +2075,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2038
2075
|
def create_new_event_class(self):
|
|
2039
2076
|
|
|
2040
2077
|
# display qwidget to name the event
|
|
2041
|
-
self.newClassWidget =
|
|
2078
|
+
self.newClassWidget = CelldetectiveWidget()
|
|
2042
2079
|
self.newClassWidget.setWindowTitle('Create new characteristic group')
|
|
2043
2080
|
|
|
2044
2081
|
layout = QVBoxLayout()
|
|
@@ -2105,6 +2142,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2105
2142
|
self.fcanvas.canvas.draw()
|
|
2106
2143
|
|
|
2107
2144
|
def assign_color_state(self, state):
|
|
2145
|
+
|
|
2108
2146
|
if np.isnan(state):
|
|
2109
2147
|
state = "nan"
|
|
2110
2148
|
return self.state_color_map[state]
|
|
@@ -2133,23 +2171,23 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2133
2171
|
return (self.im, self.status_scatter,self.im_mask,)
|
|
2134
2172
|
|
|
2135
2173
|
def compute_status_and_colors(self):
|
|
2136
|
-
|
|
2174
|
+
|
|
2137
2175
|
if self.class_choice_cb.currentText() == '':
|
|
2138
2176
|
self.status_name=self.target_class
|
|
2139
2177
|
else:
|
|
2140
2178
|
self.status_name = self.class_choice_cb.currentText()
|
|
2141
2179
|
|
|
2142
|
-
print(f'{self.status_name=}')
|
|
2143
2180
|
if self.status_name not in self.df_tracks.columns:
|
|
2144
|
-
print('
|
|
2181
|
+
print('Creating a new status for visualization...')
|
|
2145
2182
|
self.make_status_column()
|
|
2146
2183
|
else:
|
|
2184
|
+
print(f'Generating per-state colors for the status "{self.status_name}"...')
|
|
2147
2185
|
all_states = self.df_tracks.loc[:, self.status_name].tolist()
|
|
2148
2186
|
all_states = np.array(all_states)
|
|
2149
2187
|
self.state_color_map = color_from_state(all_states, recently_modified=False)
|
|
2150
|
-
print(f'{self.
|
|
2188
|
+
print(f'Color mapping for "{self.status_name}":')
|
|
2189
|
+
pretty_table(self.state_color_map)
|
|
2151
2190
|
self.df_tracks['group_color'] = self.df_tracks[self.status_name].apply(self.assign_color_state)
|
|
2152
|
-
print(self.df_tracks['group_color'])
|
|
2153
2191
|
|
|
2154
2192
|
def del_event_class(self):
|
|
2155
2193
|
|
|
@@ -2209,16 +2247,23 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2209
2247
|
self.df_tracks = self.df_tracks.sort_values(by=['ID', 'FRAME'])
|
|
2210
2248
|
|
|
2211
2249
|
cols = np.array(self.df_tracks.columns)
|
|
2212
|
-
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)])
|
|
2213
2251
|
self.class_cols = list(cols[self.class_cols])
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
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
|
|
2222
2267
|
if len(self.class_cols) > 0:
|
|
2223
2268
|
self.status = self.class_cols[0]
|
|
2224
2269
|
|
|
@@ -2278,7 +2323,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2278
2323
|
# print(self.columns_to_rescale)
|
|
2279
2324
|
|
|
2280
2325
|
cols_to_remove = ['group', 'group_color', 'status', 'status_color', 'class_color', 'TRACK_ID', 'FRAME',
|
|
2281
|
-
'x_anim', 'y_anim', 't',
|
|
2326
|
+
'x_anim', 'y_anim', 't','dummy','group_color',
|
|
2282
2327
|
'state', 'generation', 'root', 'parent', 'class_id', 'class', 't0', 'POSITION_X',
|
|
2283
2328
|
'POSITION_Y', 'position', 'well', 'well_index', 'well_name', 'pos_name', 'index',
|
|
2284
2329
|
'concentration', 'cell_type', 'antibody', 'pharmaceutical_agent', 'ID'] + self.class_cols
|
|
@@ -2340,6 +2385,10 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2340
2385
|
self.modify()
|
|
2341
2386
|
|
|
2342
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
|
+
|
|
2343
2392
|
self.fcanvas.canvas.draw()
|
|
2344
2393
|
self.plot_signals()
|
|
2345
2394
|
|
|
@@ -2435,7 +2484,6 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2435
2484
|
all_states = self.df_tracks.loc[:, self.status_name].tolist()
|
|
2436
2485
|
all_states = np.array(all_states)
|
|
2437
2486
|
self.state_color_map = color_from_state(all_states, recently_modified=False)
|
|
2438
|
-
print(f'{self.state_color_map=}')
|
|
2439
2487
|
|
|
2440
2488
|
self.df_tracks['group_color'] = self.df_tracks[self.status_name].apply(self.assign_color_state)
|
|
2441
2489
|
|
|
@@ -2530,13 +2578,26 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2530
2578
|
"""
|
|
2531
2579
|
|
|
2532
2580
|
# self.clear_post_threshold_options()
|
|
2533
|
-
|
|
2581
|
+
self.previous_channel = self.current_channel
|
|
2534
2582
|
self.current_channel = self.choose_channel.currentIndex()
|
|
2535
2583
|
|
|
2536
2584
|
t = int(self.frame_slider.value())
|
|
2537
2585
|
idx = t * self.nbr_channels + self.current_channel
|
|
2538
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
|
+
|
|
2539
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
|
|
2540
2601
|
self.refresh_imshow()
|
|
2541
2602
|
# self.redo_histogram()
|
|
2542
2603
|
else:
|
|
@@ -2550,13 +2611,19 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2550
2611
|
|
|
2551
2612
|
"""
|
|
2552
2613
|
|
|
2553
|
-
self.
|
|
2554
|
-
self.vmax = np.nanpercentile(self.img.flatten(), 99.)
|
|
2614
|
+
if self.previous_channel != self.current_channel:
|
|
2555
2615
|
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
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)
|
|
2560
2627
|
|
|
2561
2628
|
self.im.set_data(self.img)
|
|
2562
2629
|
|