celldetective 1.2.2.post2__py3-none-any.whl → 1.3.0.post1__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 +1 -0
- celldetective/_version.py +1 -0
- celldetective/events.py +5 -0
- celldetective/gui/about.py +2 -1
- celldetective/gui/classifier_widget.py +43 -33
- celldetective/gui/control_panel.py +33 -23
- celldetective/gui/gui_utils.py +9 -3
- celldetective/gui/measurement_options.py +969 -969
- celldetective/gui/signal_annotator.py +65 -53
- celldetective/gui/tableUI.py +196 -26
- celldetective/io.py +4 -1
- celldetective/links/zenodo.json +359 -168
- celldetective/measure.py +46 -18
- celldetective/segmentation.py +17 -9
- celldetective/utils.py +82 -26
- {celldetective-1.2.2.post2.dist-info → celldetective-1.3.0.post1.dist-info}/METADATA +3 -1
- {celldetective-1.2.2.post2.dist-info → celldetective-1.3.0.post1.dist-info}/RECORD +22 -21
- tests/test_segmentation.py +5 -4
- {celldetective-1.2.2.post2.dist-info → celldetective-1.3.0.post1.dist-info}/LICENSE +0 -0
- {celldetective-1.2.2.post2.dist-info → celldetective-1.3.0.post1.dist-info}/WHEEL +0 -0
- {celldetective-1.2.2.post2.dist-info → celldetective-1.3.0.post1.dist-info}/entry_points.txt +0 -0
- {celldetective-1.2.2.post2.dist-info → celldetective-1.3.0.post1.dist-info}/top_level.txt +0 -0
celldetective/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.3.0.post1"
|
celldetective/events.py
CHANGED
|
@@ -117,6 +117,11 @@ def compute_survival(df, class_of_interest, t_event, t_reference=None, FrameToMi
|
|
|
117
117
|
event_times = df.groupby(['position','TRACK_ID'])[t_event].min().values
|
|
118
118
|
max_times = df.groupby(['position','TRACK_ID'])['FRAME'].max().values
|
|
119
119
|
|
|
120
|
+
if t_reference=="0" or t_reference==0:
|
|
121
|
+
t_reference = None
|
|
122
|
+
left_censored = False
|
|
123
|
+
first_detections = None
|
|
124
|
+
|
|
120
125
|
if t_reference is not None:
|
|
121
126
|
left_censored = True
|
|
122
127
|
assert t_reference in cols,"The reference time cannot be found in the dataframe..."
|
celldetective/gui/about.py
CHANGED
|
@@ -4,6 +4,7 @@ from PyQt5.QtCore import Qt
|
|
|
4
4
|
from celldetective.utils import get_software_location
|
|
5
5
|
import os
|
|
6
6
|
from celldetective.gui.gui_utils import center_window
|
|
7
|
+
from celldetective._version import __version__
|
|
7
8
|
|
|
8
9
|
class AboutWidget(QWidget):
|
|
9
10
|
|
|
@@ -27,7 +28,7 @@ class AboutWidget(QWidget):
|
|
|
27
28
|
""")
|
|
28
29
|
layout.addWidget(self.soft_name, alignment=Qt.AlignCenter)
|
|
29
30
|
|
|
30
|
-
self.version_lbl = QLabel(f"Version
|
|
31
|
+
self.version_lbl = QLabel(f"Version {__version__} <a href=\"https://github.com/remyeltorro/celldetective/releases\">(release notes)</a>")
|
|
31
32
|
self.version_lbl.setOpenExternalLinks(True)
|
|
32
33
|
layout.addWidget(self.version_lbl, alignment=Qt.AlignCenter)
|
|
33
34
|
|
|
@@ -10,7 +10,7 @@ import numpy as np
|
|
|
10
10
|
import matplotlib.pyplot as plt
|
|
11
11
|
import json
|
|
12
12
|
|
|
13
|
-
from celldetective.gui.gui_utils import FigureCanvas, center_window, color_from_status, help_generic
|
|
13
|
+
from celldetective.gui.gui_utils import FigureCanvas, center_window, color_from_status, help_generic, color_from_class
|
|
14
14
|
from celldetective.gui import Styles
|
|
15
15
|
from celldetective.utils import get_software_location
|
|
16
16
|
from celldetective.measure import classify_cells_from_query, interpret_track_classification
|
|
@@ -242,42 +242,50 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
242
242
|
|
|
243
243
|
def update_props_scatter(self, feature_changed=True):
|
|
244
244
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
self.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
self.
|
|
270
|
-
|
|
271
|
-
|
|
245
|
+
class_name = self.class_name
|
|
246
|
+
|
|
247
|
+
try:
|
|
248
|
+
|
|
249
|
+
if not self.project_times:
|
|
250
|
+
self.scat_props.set_offsets(self.df.loc[self.df['FRAME']==self.currentFrame,[self.features_cb[1].currentText(),self.features_cb[0].currentText()]].to_numpy())
|
|
251
|
+
colors = [color_from_status(c) for c in self.df.loc[self.df['FRAME']==self.currentFrame,class_name].to_numpy()]
|
|
252
|
+
self.scat_props.set_facecolor(colors)
|
|
253
|
+
self.scat_props.set_alpha(self.currentAlpha)
|
|
254
|
+
self.ax_props.set_xlabel(self.features_cb[1].currentText())
|
|
255
|
+
self.ax_props.set_ylabel(self.features_cb[0].currentText())
|
|
256
|
+
else:
|
|
257
|
+
self.scat_props.set_offsets(self.df[[self.features_cb[1].currentText(),self.features_cb[0].currentText()]].to_numpy())
|
|
258
|
+
colors = [color_from_status(c) for c in self.df[class_name].to_numpy()]
|
|
259
|
+
self.scat_props.set_facecolor(colors)
|
|
260
|
+
self.scat_props.set_alpha(self.currentAlpha)
|
|
261
|
+
self.ax_props.set_xlabel(self.features_cb[1].currentText())
|
|
262
|
+
self.ax_props.set_ylabel(self.features_cb[0].currentText())
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
feat_x = self.features_cb[1].currentText()
|
|
266
|
+
feat_y = self.features_cb[0].currentText()
|
|
267
|
+
min_x = self.df.dropna(subset=feat_x)[feat_x].min()
|
|
268
|
+
max_x = self.df.dropna(subset=feat_x)[feat_x].max()
|
|
269
|
+
min_y = self.df.dropna(subset=feat_y)[feat_y].min()
|
|
270
|
+
max_y = self.df.dropna(subset=feat_y)[feat_y].max()
|
|
271
|
+
|
|
272
|
+
if min_x==min_x and max_x==max_x:
|
|
273
|
+
self.ax_props.set_xlim(min_x, max_x)
|
|
274
|
+
if min_y==min_y and max_y==max_y:
|
|
275
|
+
self.ax_props.set_ylim(min_y, max_y)
|
|
276
|
+
|
|
277
|
+
if feature_changed:
|
|
278
|
+
self.propscanvas.canvas.toolbar.update()
|
|
279
|
+
self.propscanvas.canvas.draw_idle()
|
|
272
280
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
self.propscanvas.canvas.draw_idle()
|
|
281
|
+
except Exception as e:
|
|
282
|
+
pass
|
|
276
283
|
|
|
277
284
|
def apply_property_query(self):
|
|
278
285
|
|
|
279
286
|
query = self.property_query_le.text()
|
|
280
|
-
self.df = classify_cells_from_query(self.df, self.
|
|
287
|
+
self.df = classify_cells_from_query(self.df, self.name_le.text(), query)
|
|
288
|
+
self.class_name = "status_"+self.name_le.text()
|
|
281
289
|
if self.df is None:
|
|
282
290
|
msgBox = QMessageBox()
|
|
283
291
|
msgBox.setIcon(QMessageBox.Warning)
|
|
@@ -287,7 +295,6 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
287
295
|
returnValue = msgBox.exec()
|
|
288
296
|
if returnValue == QMessageBox.Ok:
|
|
289
297
|
return None
|
|
290
|
-
|
|
291
298
|
self.update_props_scatter()
|
|
292
299
|
|
|
293
300
|
def set_frame(self, value):
|
|
@@ -346,6 +353,7 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
346
353
|
return None
|
|
347
354
|
|
|
348
355
|
name_map = {self.class_name: self.class_name_user}
|
|
356
|
+
print(f"{name_map=}")
|
|
349
357
|
self.df = self.df.drop(list(set(name_map.values()) & set(self.df.columns)), axis=1).rename(columns=name_map)
|
|
350
358
|
self.df.reset_index(inplace=True, drop=True)
|
|
351
359
|
|
|
@@ -374,6 +382,8 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
374
382
|
#self.df[self.group_name_user] = self.df[self.group_name_user].replace({0: 1, 1: 0})
|
|
375
383
|
self.df.reset_index(inplace=True, drop=True)
|
|
376
384
|
|
|
385
|
+
if 'custom' in list(self.df.columns):
|
|
386
|
+
self.df = self.df.drop(['custom'],axis=1)
|
|
377
387
|
|
|
378
388
|
for pos,pos_group in self.df.groupby('position'):
|
|
379
389
|
pos_group.to_csv(pos+os.sep.join(['output', 'tables', f'trajectories_{self.mode}.csv']), index=False)
|
|
@@ -138,14 +138,6 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
138
138
|
self.edit_config_button.clicked.connect(self.open_config_editor)
|
|
139
139
|
self.edit_config_button.setStyleSheet(self.button_select_all)
|
|
140
140
|
|
|
141
|
-
self.exp_options_layout = QHBoxLayout()
|
|
142
|
-
self.exp_options_layout.addWidget(experiment_label, 32, alignment=Qt.AlignRight)
|
|
143
|
-
self.exp_options_layout.addWidget(QLabel(name), 65, alignment=Qt.AlignLeft)
|
|
144
|
-
self.exp_options_layout.addWidget(self.folder_exp_btn, 5, alignment=Qt.AlignRight)
|
|
145
|
-
self.exp_options_layout.addWidget(self.edit_config_button, 5, alignment=Qt.AlignRight)
|
|
146
|
-
self.grid.addLayout(self.exp_options_layout, 0,0,1,3)
|
|
147
|
-
|
|
148
|
-
well_layout = QHBoxLayout()
|
|
149
141
|
self.well_list = QComboBox()
|
|
150
142
|
thresh = 32
|
|
151
143
|
self.well_truncated = [w[:thresh - 3]+'...' if len(w)>thresh else w for w in self.well_labels]
|
|
@@ -156,7 +148,6 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
156
148
|
self.well_list.activated.connect(self.display_positions)
|
|
157
149
|
self.to_disable.append(self.well_list)
|
|
158
150
|
|
|
159
|
-
position_layout = QHBoxLayout()
|
|
160
151
|
self.position_list = QComboBox()
|
|
161
152
|
self.position_list.addItems(["*"])
|
|
162
153
|
self.position_list.addItems(self.positions[0])
|
|
@@ -172,27 +163,46 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
172
163
|
self.view_stack_btn.clicked.connect(self.view_current_stack)
|
|
173
164
|
self.view_stack_btn.setEnabled(False)
|
|
174
165
|
|
|
175
|
-
well_layout.setContentsMargins(0,0,0,0)
|
|
176
166
|
well_lbl = QLabel('Well: ')
|
|
177
167
|
well_lbl.setAlignment(Qt.AlignRight)
|
|
178
|
-
well_layout.addWidget(well_lbl, 32)
|
|
179
|
-
well_layout.addWidget(self.well_list, 68)
|
|
180
|
-
self.grid.addLayout(well_layout, 1, 0, 1, 3)
|
|
181
168
|
|
|
182
|
-
position_layout.setContentsMargins(0,0,0,0)
|
|
183
169
|
pos_lbl = QLabel('Position: ')
|
|
184
170
|
pos_lbl.setAlignment(Qt.AlignRight)
|
|
185
|
-
position_layout.addWidget(pos_lbl, 32)
|
|
186
171
|
|
|
187
|
-
subposition_layout = QHBoxLayout()
|
|
188
|
-
subposition_layout.addWidget(self.position_list, 95)
|
|
189
|
-
subposition_layout.addWidget(self.view_stack_btn, 5)
|
|
190
|
-
position_layout.addLayout(subposition_layout, 68)
|
|
191
|
-
self.grid.addLayout(position_layout, 2, 0, 1, 3)
|
|
192
|
-
|
|
193
|
-
|
|
194
172
|
hsep = QHSeperationLine()
|
|
195
|
-
|
|
173
|
+
|
|
174
|
+
## LAYOUT
|
|
175
|
+
|
|
176
|
+
# Header layout
|
|
177
|
+
vbox = QVBoxLayout()
|
|
178
|
+
self.grid.addLayout(vbox, 0,0,1,3)
|
|
179
|
+
|
|
180
|
+
# Experiment row
|
|
181
|
+
exp_hbox = QHBoxLayout()
|
|
182
|
+
exp_hbox.addWidget(experiment_label, 25, alignment=Qt.AlignRight)
|
|
183
|
+
exp_subhbox = QHBoxLayout()
|
|
184
|
+
exp_subhbox.addWidget(QLabel(name), 90, alignment=Qt.AlignLeft)
|
|
185
|
+
exp_subhbox.addWidget(self.folder_exp_btn, 5, alignment=Qt.AlignRight)
|
|
186
|
+
exp_subhbox.addWidget(self.edit_config_button, 5, alignment=Qt.AlignRight)
|
|
187
|
+
exp_hbox.addLayout(exp_subhbox, 75)
|
|
188
|
+
vbox.addLayout(exp_hbox)
|
|
189
|
+
|
|
190
|
+
# Well row
|
|
191
|
+
well_hbox = QHBoxLayout()
|
|
192
|
+
well_hbox.addWidget(well_lbl, 25, alignment=Qt.AlignVCenter)
|
|
193
|
+
well_hbox.addWidget(self.well_list, 75)
|
|
194
|
+
vbox.addLayout(well_hbox)
|
|
195
|
+
|
|
196
|
+
# Position row
|
|
197
|
+
position_hbox = QHBoxLayout()
|
|
198
|
+
position_hbox.addWidget(pos_lbl, 25, alignment=Qt.AlignVCenter)
|
|
199
|
+
pos_subhbox = QHBoxLayout()
|
|
200
|
+
pos_subhbox.addWidget(self.position_list, 95)
|
|
201
|
+
pos_subhbox.addWidget(self.view_stack_btn, 5)
|
|
202
|
+
position_hbox.addLayout(pos_subhbox, 75)
|
|
203
|
+
vbox.addLayout(position_hbox)
|
|
204
|
+
|
|
205
|
+
vbox.addWidget(hsep)
|
|
196
206
|
|
|
197
207
|
def locate_image(self):
|
|
198
208
|
|
celldetective/gui/gui_utils.py
CHANGED
|
@@ -768,7 +768,7 @@ def color_from_status(status, recently_modified=False):
|
|
|
768
768
|
else:
|
|
769
769
|
return 'k'
|
|
770
770
|
|
|
771
|
-
def color_from_state(state):
|
|
771
|
+
def color_from_state(state, recently_modified=False):
|
|
772
772
|
|
|
773
773
|
"""
|
|
774
774
|
Generate a color map based on unique values in the provided state array.
|
|
@@ -797,9 +797,15 @@ def color_from_state(state):
|
|
|
797
797
|
unique_values = np.unique(state)
|
|
798
798
|
color_map={}
|
|
799
799
|
for value in unique_values:
|
|
800
|
-
|
|
801
|
-
|
|
800
|
+
if np.isnan(value):
|
|
801
|
+
value = "nan"
|
|
802
802
|
color_map[value] = 'k'
|
|
803
|
+
elif value==0:
|
|
804
|
+
color_map[value] = 'tab:blue'
|
|
805
|
+
elif value==1:
|
|
806
|
+
color_map[value] = 'tab:red'
|
|
807
|
+
else:
|
|
808
|
+
color_map[value] = plt.cm.tab10(value)
|
|
803
809
|
|
|
804
810
|
return color_map
|
|
805
811
|
|