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.
- celldetective/__init__.py +0 -3
- celldetective/_version.py +1 -1
- celldetective/events.py +2 -4
- celldetective/exceptions.py +11 -0
- celldetective/extra_properties.py +132 -0
- celldetective/filters.py +7 -1
- celldetective/gui/InitWindow.py +37 -46
- celldetective/gui/__init__.py +3 -9
- celldetective/gui/about.py +19 -15
- celldetective/gui/analyze_block.py +34 -19
- celldetective/gui/base_annotator.py +786 -0
- celldetective/gui/base_components.py +23 -0
- celldetective/gui/classifier_widget.py +86 -94
- celldetective/gui/configure_new_exp.py +163 -46
- celldetective/gui/control_panel.py +76 -146
- celldetective/gui/{signal_annotator.py → event_annotator.py} +533 -1438
- celldetective/gui/generic_signal_plot.py +11 -13
- celldetective/gui/gui_utils.py +54 -23
- celldetective/gui/help/neighborhood.json +2 -2
- celldetective/gui/json_readers.py +5 -4
- celldetective/gui/layouts.py +265 -31
- celldetective/gui/{signal_annotator2.py → pair_event_annotator.py} +433 -635
- celldetective/gui/plot_measurements.py +21 -17
- celldetective/gui/plot_signals_ui.py +125 -72
- celldetective/gui/process_block.py +283 -188
- celldetective/gui/processes/compute_neighborhood.py +594 -0
- celldetective/gui/processes/downloader.py +37 -34
- celldetective/gui/processes/measure_cells.py +19 -8
- celldetective/gui/processes/segment_cells.py +47 -11
- celldetective/gui/processes/track_cells.py +18 -13
- celldetective/gui/seg_model_loader.py +21 -62
- celldetective/gui/settings/__init__.py +7 -0
- celldetective/gui/settings/_settings_base.py +70 -0
- celldetective/gui/{retrain_signal_model_options.py → settings/_settings_event_model_training.py} +54 -109
- celldetective/gui/{measurement_options.py → settings/_settings_measurements.py} +54 -92
- celldetective/gui/{neighborhood_options.py → settings/_settings_neighborhood.py} +10 -13
- celldetective/gui/settings/_settings_segmentation.py +49 -0
- celldetective/gui/{retrain_segmentation_model_options.py → settings/_settings_segmentation_model_training.py} +38 -92
- celldetective/gui/{signal_annotator_options.py → settings/_settings_signal_annotator.py} +78 -103
- celldetective/gui/{btrack_options.py → settings/_settings_tracking.py} +85 -116
- celldetective/gui/styles.py +2 -1
- celldetective/gui/survival_ui.py +49 -95
- celldetective/gui/tableUI.py +53 -25
- celldetective/gui/table_ops/__init__.py +0 -0
- celldetective/gui/table_ops/merge_groups.py +118 -0
- celldetective/gui/thresholds_gui.py +617 -1221
- celldetective/gui/viewers.py +107 -42
- celldetective/gui/workers.py +8 -4
- celldetective/io.py +137 -57
- celldetective/links/zenodo.json +145 -144
- celldetective/measure.py +94 -53
- celldetective/neighborhood.py +342 -268
- celldetective/preprocessing.py +56 -35
- celldetective/regionprops/_regionprops.py +16 -5
- celldetective/relative_measurements.py +50 -29
- celldetective/scripts/analyze_signals.py +4 -1
- celldetective/scripts/measure_cells.py +5 -5
- celldetective/scripts/measure_relative.py +20 -12
- celldetective/scripts/segment_cells.py +4 -10
- celldetective/scripts/segment_cells_thresholds.py +3 -3
- celldetective/scripts/track_cells.py +10 -8
- celldetective/scripts/train_segmentation_model.py +18 -6
- celldetective/signals.py +29 -14
- celldetective/tracking.py +14 -3
- celldetective/utils.py +91 -62
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/METADATA +24 -16
- celldetective-1.4.1.dist-info/RECORD +123 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/WHEEL +1 -1
- tests/gui/__init__.py +0 -0
- tests/gui/test_new_project.py +228 -0
- tests/gui/test_project.py +99 -0
- tests/test_preprocessing.py +2 -2
- celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -79
- celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
- celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -37
- celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -39
- celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
- celldetective/models/signal_detection/NucCond/classification_loss.png +0 -0
- celldetective/models/signal_detection/NucCond/classifier.h5 +0 -0
- celldetective/models/signal_detection/NucCond/config_input.json +0 -1
- celldetective/models/signal_detection/NucCond/log_classifier.csv +0 -126
- celldetective/models/signal_detection/NucCond/log_regressor.csv +0 -282
- celldetective/models/signal_detection/NucCond/regression_loss.png +0 -0
- celldetective/models/signal_detection/NucCond/regressor.h5 +0 -0
- celldetective/models/signal_detection/NucCond/scores.npy +0 -0
- celldetective/models/signal_detection/NucCond/test_confusion_matrix.png +0 -0
- celldetective/models/signal_detection/NucCond/test_regression.png +0 -0
- celldetective/models/signal_detection/NucCond/validation_confusion_matrix.png +0 -0
- celldetective/models/signal_detection/NucCond/validation_regression.png +0 -0
- celldetective-1.3.9.post5.dist-info/RECORD +0 -129
- tests/test_qt.py +0 -103
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info/licenses}/LICENSE +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/top_level.txt +0 -0
celldetective/measure.py
CHANGED
|
@@ -17,16 +17,25 @@ from math import ceil
|
|
|
17
17
|
from skimage.draw import disk as dsk
|
|
18
18
|
from skimage.feature import blob_dog, blob_log
|
|
19
19
|
|
|
20
|
+
from celldetective.exceptions import EmptyQueryError, MissingColumnsError, QueryError
|
|
20
21
|
from celldetective.utils import rename_intensity_column, create_patch_mask, remove_redundant_features, \
|
|
21
22
|
remove_trajectory_measurements, contour_of_instance_segmentation, extract_cols_from_query, step_function, interpolate_nan, _remove_invalid_cols
|
|
22
23
|
from celldetective.preprocessing import field_correction
|
|
23
|
-
|
|
24
|
+
|
|
25
|
+
# try:
|
|
26
|
+
# from celldetective.extra_properties import *
|
|
27
|
+
# extra_props = True
|
|
28
|
+
# except Exception as e:
|
|
29
|
+
# print(f"The module extra_properties seems corrupted: {e}... Skip...")
|
|
30
|
+
# extra_props = False
|
|
31
|
+
|
|
24
32
|
from inspect import getmembers, isfunction
|
|
25
33
|
from skimage.morphology import disk
|
|
26
34
|
from scipy.signal import find_peaks, peak_widths
|
|
27
35
|
|
|
28
36
|
from celldetective.segmentation import filter_image
|
|
29
37
|
from celldetective.regionprops import regionprops_table
|
|
38
|
+
from celldetective.utils import pretty_table
|
|
30
39
|
|
|
31
40
|
abs_path = os.sep.join([os.path.split(os.path.dirname(os.path.realpath(__file__)))[0], 'celldetective'])
|
|
32
41
|
|
|
@@ -211,7 +220,7 @@ def measure(stack=None, labels=None, trajectories=None, channel_names=None,
|
|
|
211
220
|
measurements = measurements.sort_values(by=[column_labels['track'],column_labels['time']])
|
|
212
221
|
measurements = measurements.dropna(subset=[column_labels['track']])
|
|
213
222
|
else:
|
|
214
|
-
measurements['ID'] = np.arange(len(
|
|
223
|
+
measurements['ID'] = np.arange(len(measurements))
|
|
215
224
|
|
|
216
225
|
measurements = measurements.reset_index(drop=True)
|
|
217
226
|
measurements = _remove_invalid_cols(measurements)
|
|
@@ -365,26 +374,35 @@ def measure_features(img, label, features=['area', 'intensity_mean'], channels=N
|
|
|
365
374
|
corrected_image = field_correction(img[:,:,ind].copy(), threshold_on_std=norm['threshold_on_std'], operation=norm['operation'], model=norm['model'], clip=norm['clip'])
|
|
366
375
|
img[:, :, ind] = corrected_image
|
|
367
376
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
377
|
+
try:
|
|
378
|
+
import celldetective.extra_properties as extra_props
|
|
379
|
+
extraprops = True
|
|
380
|
+
except Exception as e:
|
|
381
|
+
print(f"The module extra_properties seems corrupted: {e}... Skip...")
|
|
382
|
+
extraprops = False
|
|
383
|
+
|
|
384
|
+
if extraprops:
|
|
385
|
+
extra = getmembers(extra_props, isfunction)
|
|
386
|
+
extra = [extra[i][0] for i in range(len(extra))]
|
|
387
|
+
|
|
388
|
+
extra_props_list = []
|
|
389
|
+
feats = features.copy()
|
|
390
|
+
for f in features:
|
|
391
|
+
if f in extra:
|
|
392
|
+
feats.remove(f)
|
|
393
|
+
extra_props_list.append(getattr(extra_props, f))
|
|
394
|
+
|
|
395
|
+
# Add intensity nan mean if need to measure mean intensities
|
|
396
|
+
if measure_mean_intensities:
|
|
397
|
+
extra_props_list.append(getattr(extra_props, 'intensity_nanmean'))
|
|
398
|
+
|
|
399
|
+
if len(extra_props_list) == 0:
|
|
400
|
+
extra_props_list = None
|
|
401
|
+
else:
|
|
402
|
+
extra_props_list = tuple(extra_props_list)
|
|
386
403
|
else:
|
|
387
|
-
extra_props_list =
|
|
404
|
+
extra_props_list = []
|
|
405
|
+
feats = features.copy()
|
|
388
406
|
|
|
389
407
|
props = regionprops_table(label, intensity_image=img, properties=feats, extra_properties=extra_props_list, channel_names=channels)
|
|
390
408
|
df_props = pd.DataFrame(props)
|
|
@@ -837,17 +855,32 @@ def local_normalisation(image, labels, background_intensity, measurement='intens
|
|
|
837
855
|
|
|
838
856
|
def normalise_by_cell(image, labels, distance=5, model='median', operation='subtract', clip=False):
|
|
839
857
|
|
|
840
|
-
|
|
858
|
+
try:
|
|
859
|
+
import celldetective.extra_properties as extra_props
|
|
860
|
+
extraprops = True
|
|
861
|
+
except Exception as e:
|
|
862
|
+
print(f"The module extra_properties seems corrupted: {e}... Skip...")
|
|
863
|
+
extraprops = False
|
|
841
864
|
|
|
842
865
|
border = contour_of_instance_segmentation(label=labels, distance=distance * (-1))
|
|
843
866
|
if model == 'mean':
|
|
867
|
+
|
|
844
868
|
measurement = 'intensity_nanmean'
|
|
845
|
-
|
|
869
|
+
if extraprops:
|
|
870
|
+
extra_props = [getattr(extra_props, measurement)]
|
|
871
|
+
else:
|
|
872
|
+
extra_props = []
|
|
873
|
+
|
|
846
874
|
background_intensity = regionprops_table(intensity_image=image, label_image=border,
|
|
847
875
|
extra_properties=extra_props)
|
|
848
876
|
elif model == 'median':
|
|
877
|
+
|
|
849
878
|
measurement = 'intensity_median'
|
|
850
|
-
|
|
879
|
+
if extraprops:
|
|
880
|
+
extra_props = [getattr(extra_props, measurement)]
|
|
881
|
+
else:
|
|
882
|
+
extra_props = []
|
|
883
|
+
|
|
851
884
|
background_intensity = regionprops_table(intensity_image=image, label_image=border,
|
|
852
885
|
extra_properties=extra_props)
|
|
853
886
|
|
|
@@ -1250,16 +1283,20 @@ def classify_irreversible_events(data, class_attr, r2_threshold=0.5, percentile_
|
|
|
1250
1283
|
# ambiguity, possible transition, use `unique_state` technique after
|
|
1251
1284
|
df.loc[indices, class_attr] = 2
|
|
1252
1285
|
|
|
1253
|
-
print("
|
|
1286
|
+
print("Number of cells per class after the initial pass: ")
|
|
1287
|
+
pretty_table(df.loc[df['FRAME']==0,class_attr].value_counts().to_dict())
|
|
1254
1288
|
|
|
1255
1289
|
df.loc[df[class_attr]!=2, class_attr.replace('class', 't')] = -1
|
|
1256
1290
|
# Try to fit time on class 2 cells (ambiguous)
|
|
1257
1291
|
df = estimate_time(df, class_attr, model='step_function', class_of_interest=[2], r2_threshold=r2_threshold)
|
|
1258
|
-
|
|
1292
|
+
|
|
1293
|
+
print("Number of cells per class after conditional signal fit: ")
|
|
1294
|
+
pretty_table(df.loc[df['FRAME']==0,class_attr].value_counts().to_dict())
|
|
1259
1295
|
|
|
1260
1296
|
# Revisit class 2 cells to classify as neg/pos with percentile tolerance
|
|
1261
1297
|
df.loc[df[class_attr]==2,:] = classify_unique_states(df.loc[df[class_attr]==2,:].copy(), class_attr, percentile_recovery)
|
|
1262
|
-
print("
|
|
1298
|
+
print("Number of cells per class after recovery pass (median state): ")
|
|
1299
|
+
pretty_table(df.loc[df['FRAME']==0,class_attr].value_counts().to_dict())
|
|
1263
1300
|
|
|
1264
1301
|
return df
|
|
1265
1302
|
|
|
@@ -1396,35 +1433,39 @@ def classify_cells_from_query(df, status_attr, query):
|
|
|
1396
1433
|
If the query is invalid or if there are issues with the DataFrame or query syntax, an error message is printed, and `None` is returned.
|
|
1397
1434
|
|
|
1398
1435
|
"""
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
status_attr = 'status_'+status_attr
|
|
1404
|
-
|
|
1436
|
+
|
|
1437
|
+
if not status_attr.startswith("status_"):
|
|
1438
|
+
status_attr = "status_" + status_attr
|
|
1439
|
+
|
|
1405
1440
|
df = df.copy()
|
|
1406
|
-
df.
|
|
1441
|
+
df = df.replace([np.inf, -np.inf, None], np.nan)
|
|
1442
|
+
#df = df.convert_dtypes()
|
|
1443
|
+
|
|
1444
|
+
df.loc[:, status_attr] = 0
|
|
1407
1445
|
df[status_attr] = df[status_attr].astype(float)
|
|
1408
|
-
|
|
1446
|
+
|
|
1409
1447
|
cols = extract_cols_from_query(query)
|
|
1410
|
-
print(f"{cols=}")
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1448
|
+
print(f"The following DataFrame measurements were identified in the query: {cols=}...")
|
|
1449
|
+
|
|
1450
|
+
if query.strip() == "":
|
|
1451
|
+
raise EmptyQueryError("The provided query is empty.")
|
|
1452
|
+
|
|
1453
|
+
missing_cols = [c for c in cols if c not in df.columns]
|
|
1454
|
+
if missing_cols:
|
|
1455
|
+
raise MissingColumnsError(missing_cols)
|
|
1456
|
+
|
|
1457
|
+
try:
|
|
1458
|
+
sub_df = df.dropna(subset=cols)
|
|
1459
|
+
if len(sub_df) > 0:
|
|
1460
|
+
selection = sub_df.query(query).index
|
|
1461
|
+
null_selection = df[df.loc[:, cols].isna().any(axis=1)].index
|
|
1462
|
+
df.loc[null_selection, status_attr] = np.nan
|
|
1463
|
+
df.loc[selection, status_attr] = 1
|
|
1464
|
+
else:
|
|
1465
|
+
df.loc[:, status_attr] = np.nan
|
|
1466
|
+
except Exception as e:
|
|
1467
|
+
raise QueryError(f"The query could not be understood: {e}")
|
|
1468
|
+
|
|
1428
1469
|
return df.copy()
|
|
1429
1470
|
|
|
1430
1471
|
def classify_tracks_from_query(df, event_name, query, irreversible_event=True, unique_state=False, r2_threshold=0.5, percentile_recovery=50):
|