celldetective 1.4.0__py3-none-any.whl → 1.4.1.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/_version.py +1 -1
- celldetective/exceptions.py +11 -0
- celldetective/filters.py +7 -1
- celldetective/gui/InitWindow.py +4 -1
- celldetective/gui/__init__.py +2 -9
- celldetective/gui/about.py +2 -2
- celldetective/gui/base_annotator.py +786 -0
- celldetective/gui/classifier_widget.py +18 -13
- celldetective/gui/configure_new_exp.py +51 -30
- celldetective/gui/control_panel.py +10 -7
- celldetective/gui/{signal_annotator.py → event_annotator.py} +473 -1437
- celldetective/gui/generic_signal_plot.py +2 -1
- celldetective/gui/gui_utils.py +5 -2
- celldetective/gui/help/neighborhood.json +2 -2
- celldetective/gui/layouts.py +21 -11
- celldetective/gui/{signal_annotator2.py → pair_event_annotator.py} +3 -1
- celldetective/gui/process_block.py +129 -91
- celldetective/gui/processes/downloader.py +37 -34
- celldetective/gui/processes/measure_cells.py +14 -8
- celldetective/gui/processes/segment_cells.py +438 -314
- celldetective/gui/processes/track_cells.py +12 -13
- 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} +35 -91
- celldetective/gui/{measurement_options.py → settings/_settings_measurements.py} +28 -81
- celldetective/gui/{neighborhood_options.py → settings/_settings_neighborhood.py} +1 -1
- celldetective/gui/settings/_settings_segmentation.py +49 -0
- celldetective/gui/{retrain_segmentation_model_options.py → settings/_settings_segmentation_model_training.py} +33 -79
- celldetective/gui/{signal_annotator_options.py → settings/_settings_signal_annotator.py} +73 -95
- celldetective/gui/{btrack_options.py → settings/_settings_tracking.py} +64 -87
- celldetective/gui/styles.py +2 -1
- celldetective/gui/survival_ui.py +1 -1
- celldetective/gui/tableUI.py +25 -0
- celldetective/gui/table_ops/__init__.py +0 -0
- celldetective/gui/table_ops/merge_groups.py +118 -0
- celldetective/gui/viewers.py +3 -5
- celldetective/gui/workers.py +0 -2
- celldetective/io.py +98 -55
- celldetective/links/zenodo.json +145 -144
- celldetective/measure.py +31 -26
- celldetective/preprocessing.py +34 -21
- celldetective/regionprops/_regionprops.py +16 -5
- celldetective/scripts/measure_cells.py +5 -5
- celldetective/scripts/measure_relative.py +16 -11
- celldetective/scripts/segment_cells.py +4 -4
- celldetective/scripts/segment_cells_thresholds.py +3 -3
- celldetective/scripts/track_cells.py +7 -7
- celldetective/scripts/train_segmentation_model.py +10 -1
- celldetective/tracking.py +10 -4
- celldetective/utils.py +59 -58
- {celldetective-1.4.0.dist-info → celldetective-1.4.1.post1.dist-info}/METADATA +1 -1
- celldetective-1.4.1.post1.dist-info/RECORD +123 -0
- tests/gui/__init__.py +0 -0
- tests/gui/test_new_project.py +228 -0
- tests/{test_qt.py → gui/test_project.py} +22 -26
- 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.4.0.dist-info/RECORD +0 -131
- {celldetective-1.4.0.dist-info → celldetective-1.4.1.post1.dist-info}/WHEEL +0 -0
- {celldetective-1.4.0.dist-info → celldetective-1.4.1.post1.dist-info}/entry_points.txt +0 -0
- {celldetective-1.4.0.dist-info → celldetective-1.4.1.post1.dist-info}/licenses/LICENSE +0 -0
- {celldetective-1.4.0.dist-info → celldetective-1.4.1.post1.dist-info}/top_level.txt +0 -0
|
@@ -10,6 +10,7 @@ import numpy as np
|
|
|
10
10
|
import matplotlib.pyplot as plt
|
|
11
11
|
import json
|
|
12
12
|
|
|
13
|
+
from celldetective.exceptions import EmptyQueryError, MissingColumnsError, QueryError
|
|
13
14
|
from celldetective.gui.gui_utils import FigureCanvas, center_window, color_from_status, help_generic
|
|
14
15
|
from celldetective.gui.base_components import CelldetectiveWidget
|
|
15
16
|
from celldetective.utils import get_software_location
|
|
@@ -351,26 +352,30 @@ class ClassifierWidget(CelldetectiveWidget):
|
|
|
351
352
|
self.propscanvas.canvas.draw_idle()
|
|
352
353
|
|
|
353
354
|
except Exception as e:
|
|
354
|
-
|
|
355
|
+
print("Exception L355 ", e)
|
|
356
|
+
|
|
357
|
+
def show_warning(self, message: str):
|
|
358
|
+
msgBox = QMessageBox()
|
|
359
|
+
msgBox.setIcon(QMessageBox.Warning)
|
|
360
|
+
link = "https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.query.html"
|
|
361
|
+
msgBox.setText(f"{message}<br><br>See <a href='{link}'>documentation</a>.")
|
|
362
|
+
msgBox.setWindowTitle("Warning")
|
|
363
|
+
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
364
|
+
msgBox.exec()
|
|
355
365
|
|
|
356
366
|
def apply_property_query(self):
|
|
357
367
|
|
|
358
368
|
query = self.property_query_le.text()
|
|
359
|
-
|
|
360
369
|
try:
|
|
361
370
|
self.df = classify_cells_from_query(self.df, self.name_le.text(), query)
|
|
371
|
+
except EmptyQueryError as e:
|
|
372
|
+
self.show_warning(str(e))
|
|
373
|
+
except MissingColumnsError as e:
|
|
374
|
+
self.show_warning(f"{e}. Please check your column names.")
|
|
375
|
+
except QueryError as e:
|
|
376
|
+
self.show_warning(f"{e}. Wrap features in backticks if needed.")
|
|
362
377
|
except Exception as e:
|
|
363
|
-
|
|
364
|
-
msgBox.setIcon(QMessageBox.Warning)
|
|
365
|
-
link = "https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.query.html"
|
|
366
|
-
msg = "The query could not be understood. Please write a valid query following <a href='%s'>the documentation</a>. Wrap features in backticks (e.g. `feature` > 1) to facilitate query interpretation. " % link
|
|
367
|
-
msgBox.setText(msg)
|
|
368
|
-
msgBox.setWindowTitle("Warning")
|
|
369
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
370
|
-
returnValue = msgBox.exec()
|
|
371
|
-
if returnValue == QMessageBox.Ok:
|
|
372
|
-
self.auto_close = False
|
|
373
|
-
return None
|
|
378
|
+
self.show_warning(f"Unexpected error: {e}")
|
|
374
379
|
|
|
375
380
|
self.class_name = "status_"+self.name_le.text()
|
|
376
381
|
if self.df is None:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import QApplication, QMessageBox, QHBoxLayout, QFileDialog, QVBoxLayout, QScrollArea, QCheckBox, QGridLayout, QLabel, QLineEdit, QPushButton
|
|
1
|
+
from PyQt5.QtWidgets import QApplication,QWidget, QMessageBox, QHBoxLayout, QFileDialog, QVBoxLayout, QScrollArea, QCheckBox, QGridLayout, QLabel, QLineEdit, QPushButton
|
|
2
2
|
from PyQt5.QtGui import QIntValidator, QDoubleValidator
|
|
3
3
|
from celldetective.gui.gui_utils import center_window, help_generic
|
|
4
4
|
from celldetective.utils import get_software_location
|
|
@@ -169,7 +169,7 @@ class ConfigNewExperiment(CelldetectiveMainWindow):
|
|
|
169
169
|
self.movie_length.setToolTip('Optional: depending on how the movies are encoded, the automatic extraction of the number of frames can be difficult.\nThe software will then rely on this value.')
|
|
170
170
|
self.ms_grid.addWidget(self.movie_length,9, 0, 1, 3)
|
|
171
171
|
self.MovieLengthSlider = QLabeledSlider(Qt.Horizontal, self)
|
|
172
|
-
self.MovieLengthSlider.setMinimum(
|
|
172
|
+
self.MovieLengthSlider.setMinimum(1)
|
|
173
173
|
#self.MovieLengthSlider.setMaximum(128)
|
|
174
174
|
self.ms_grid.addWidget(self.MovieLengthSlider, 10, 0, 1, 3)
|
|
175
175
|
|
|
@@ -566,30 +566,69 @@ class SetupConditionLabels(CelldetectiveWidget):
|
|
|
566
566
|
self.parent_window = parent_window
|
|
567
567
|
self.n_wells = n_wells
|
|
568
568
|
self.setWindowTitle("Well conditions")
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
self.
|
|
569
|
+
|
|
570
|
+
# --- Outer layout ---
|
|
571
|
+
self.outer_layout = QVBoxLayout(self)
|
|
572
|
+
self.outer_layout.setContentsMargins(10, 10, 10, 10)
|
|
573
|
+
|
|
574
|
+
# --- Scroll area ---
|
|
575
|
+
self.scroll = QScrollArea(self)
|
|
576
|
+
self.scroll.setWidgetResizable(True)
|
|
577
|
+
self.outer_layout.addWidget(self.scroll, stretch=1) # takes most space
|
|
578
|
+
|
|
579
|
+
# Container inside scroll
|
|
580
|
+
self.container = QWidget()
|
|
581
|
+
self.scroll.setWidget(self.container)
|
|
582
|
+
|
|
583
|
+
# Content layout (scrollable part)
|
|
584
|
+
self.layout = QVBoxLayout(self.container)
|
|
585
|
+
self.layout.setContentsMargins(30, 30, 30, 30)
|
|
586
|
+
|
|
572
587
|
self.onlyFloat = QDoubleValidator()
|
|
573
588
|
self.populate()
|
|
589
|
+
|
|
590
|
+
self.concentration_units_le = QLineEdit('pM')
|
|
591
|
+
self.concentration_units_le.setPlaceholderText('concentration units')
|
|
592
|
+
|
|
593
|
+
concentration_units_layout = QHBoxLayout()
|
|
594
|
+
concentration_units_layout.addWidget(QLabel('concentration\nunits: '), 5, alignment=Qt.AlignLeft)
|
|
595
|
+
concentration_units_layout.addWidget(self.concentration_units_le, 10)
|
|
596
|
+
concentration_units_layout.addWidget(QLabel(''), 85)
|
|
597
|
+
self.outer_layout.addLayout(concentration_units_layout)
|
|
598
|
+
|
|
599
|
+
# --- Fixed button row (not scrollable) ---
|
|
600
|
+
btn_hbox = QHBoxLayout()
|
|
601
|
+
btn_hbox.setContentsMargins(0, 15, 0, 0)
|
|
602
|
+
|
|
603
|
+
self.skip_btn = QPushButton('Skip')
|
|
604
|
+
self.skip_btn.setStyleSheet(self.button_style_sheet_2)
|
|
605
|
+
self.skip_btn.clicked.connect(self.set_default_values)
|
|
606
|
+
btn_hbox.addWidget(self.skip_btn)
|
|
607
|
+
|
|
608
|
+
self.submit_btn = QPushButton('Submit')
|
|
609
|
+
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
610
|
+
self.submit_btn.clicked.connect(self.set_user_values)
|
|
611
|
+
btn_hbox.addWidget(self.submit_btn)
|
|
612
|
+
|
|
613
|
+
self.outer_layout.addLayout(btn_hbox) # outside scroll
|
|
614
|
+
self.setMinimumWidth(int(0.6 * self.parent_window.parent_window.screen_width))
|
|
615
|
+
|
|
574
616
|
center_window(self)
|
|
575
617
|
|
|
576
618
|
def populate(self):
|
|
577
|
-
|
|
578
619
|
self.cell_type_cbs = [QLineEdit() for i in range(self.n_wells)]
|
|
579
620
|
self.antibodies_cbs = [QLineEdit() for i in range(self.n_wells)]
|
|
580
621
|
self.concentrations_cbs = [QLineEdit() for i in range(self.n_wells)]
|
|
581
622
|
self.pharmaceutical_agents_cbs = [QLineEdit() for i in range(self.n_wells)]
|
|
582
|
-
self.concentration_units_le = QLineEdit('pM')
|
|
583
|
-
self.concentration_units_le.setPlaceholderText('concentration units')
|
|
584
623
|
|
|
585
624
|
for i in range(self.n_wells):
|
|
586
625
|
hbox = QHBoxLayout()
|
|
587
|
-
hbox.setContentsMargins(15,5,15,5)
|
|
626
|
+
hbox.setContentsMargins(15, 5, 15, 5)
|
|
588
627
|
hbox.addWidget(QLabel(f'well {i+1}'), 5, alignment=Qt.AlignLeft)
|
|
589
628
|
hbox.addWidget(QLabel('cell type: '), 5)
|
|
590
629
|
hbox.addWidget(self.cell_type_cbs[i], 10)
|
|
591
630
|
self.cell_type_cbs[i].setPlaceholderText('e.g. T-cell, NK')
|
|
592
|
-
|
|
631
|
+
|
|
593
632
|
hbox.addWidget(QLabel('antibody: '), 5)
|
|
594
633
|
hbox.addWidget(self.antibodies_cbs[i], 10)
|
|
595
634
|
self.antibodies_cbs[i].setPlaceholderText('e.g. anti-CD4')
|
|
@@ -602,27 +641,9 @@ class SetupConditionLabels(CelldetectiveWidget):
|
|
|
602
641
|
hbox.addWidget(QLabel('pharmaceutical agents: '), 5)
|
|
603
642
|
hbox.addWidget(self.pharmaceutical_agents_cbs[i], 10)
|
|
604
643
|
self.pharmaceutical_agents_cbs[i].setPlaceholderText('e.g. dextran')
|
|
605
|
-
|
|
644
|
+
|
|
606
645
|
self.layout.addLayout(hbox)
|
|
607
|
-
|
|
608
|
-
concentration_units_layout = QHBoxLayout()
|
|
609
|
-
concentration_units_layout.addWidget(QLabel('concentration\nunits: '),5,alignment=Qt.AlignLeft)
|
|
610
|
-
concentration_units_layout.addWidget(self.concentration_units_le,10)
|
|
611
|
-
concentration_units_layout.addWidget(QLabel(''), 85)
|
|
612
|
-
self.layout.addLayout(concentration_units_layout)
|
|
613
|
-
|
|
614
|
-
btn_hbox = QHBoxLayout()
|
|
615
|
-
btn_hbox.setContentsMargins(0,20,0,0)
|
|
616
|
-
self.skip_btn = QPushButton('Skip')
|
|
617
|
-
self.skip_btn.setStyleSheet(self.button_style_sheet_2)
|
|
618
|
-
self.skip_btn.clicked.connect(self.set_default_values)
|
|
619
|
-
btn_hbox.addWidget(self.skip_btn)
|
|
620
|
-
|
|
621
|
-
self.submit_btn = QPushButton('Submit')
|
|
622
|
-
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
623
|
-
self.submit_btn.clicked.connect(self.set_user_values)
|
|
624
|
-
btn_hbox.addWidget(self.submit_btn)
|
|
625
|
-
self.layout.addLayout(btn_hbox)
|
|
646
|
+
|
|
626
647
|
|
|
627
648
|
def set_default_values(self):
|
|
628
649
|
|
|
@@ -4,7 +4,7 @@ from celldetective.gui import CelldetectiveMainWindow, CelldetectiveWidget
|
|
|
4
4
|
|
|
5
5
|
from PyQt5.QtCore import Qt, QSize
|
|
6
6
|
from celldetective.gui.gui_utils import center_window, QHSeperationLine, QCheckableComboBox, generic_message
|
|
7
|
-
from celldetective.utils import _extract_labels_from_config,
|
|
7
|
+
from celldetective.utils import _extract_labels_from_config, config_section_to_dict, extract_identity_col
|
|
8
8
|
from celldetective.gui import ConfigEditor, ProcessPanel, PreprocessingPanel, AnalysisPanel, NeighPanel
|
|
9
9
|
from celldetective.io import extract_position_name, get_experiment_wells, get_config, get_spatial_calibration, get_temporal_calibration, get_experiment_concentrations, get_experiment_cell_types, get_experiment_antibodies, get_experiment_pharmaceutical_agents, get_experiment_populations, extract_well_name_and_number
|
|
10
10
|
from natsort import natsorted
|
|
@@ -318,10 +318,10 @@ class ControlPanel(CelldetectiveMainWindow):
|
|
|
318
318
|
self.FrameToMin = get_temporal_calibration(self.exp_dir)
|
|
319
319
|
|
|
320
320
|
|
|
321
|
-
self.len_movie = int(
|
|
322
|
-
self.shape_x = int(
|
|
323
|
-
self.shape_y = int(
|
|
324
|
-
self.movie_prefix =
|
|
321
|
+
self.len_movie = int(config_section_to_dict(self.exp_config, "MovieSettings")["len_movie"])
|
|
322
|
+
self.shape_x = int(config_section_to_dict(self.exp_config, "MovieSettings")["shape_x"])
|
|
323
|
+
self.shape_y = int(config_section_to_dict(self.exp_config, "MovieSettings")["shape_y"])
|
|
324
|
+
self.movie_prefix = config_section_to_dict(self.exp_config, "MovieSettings")["movie_prefix"]
|
|
325
325
|
|
|
326
326
|
# Read channels
|
|
327
327
|
self.exp_channels, channel_indices = extract_experiment_channels(self.exp_dir)
|
|
@@ -335,7 +335,7 @@ class ControlPanel(CelldetectiveMainWindow):
|
|
|
335
335
|
self.antibodies = get_experiment_antibodies(self.exp_dir)
|
|
336
336
|
self.pharmaceutical_agents = get_experiment_pharmaceutical_agents(self.exp_dir)
|
|
337
337
|
|
|
338
|
-
self.metadata =
|
|
338
|
+
self.metadata = config_section_to_dict(self.exp_config, "Metadata")
|
|
339
339
|
print('Experiment configuration successfully read...')
|
|
340
340
|
|
|
341
341
|
def closeEvent(self, event):
|
|
@@ -505,7 +505,10 @@ class ControlPanel(CelldetectiveMainWindow):
|
|
|
505
505
|
for i,p in enumerate(self.ProcessPopulations):
|
|
506
506
|
p.check_seg_btn.setEnabled(True)
|
|
507
507
|
if os.path.exists(os.sep.join([self.pos,'output','tables',f'trajectories_{self.populations[i]}.csv'])):
|
|
508
|
-
|
|
508
|
+
try:
|
|
509
|
+
df = pd.read_csv(os.sep.join([self.pos,'output','tables',f'trajectories_{self.populations[i]}.csv']), nrows=1)
|
|
510
|
+
except Exception as e:
|
|
511
|
+
continue
|
|
509
512
|
id_col = extract_identity_col(df)
|
|
510
513
|
p.check_measurements_btn.setEnabled(True)
|
|
511
514
|
|