spacr 0.4.1__py3-none-any.whl → 0.4.3__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.
- spacr/core.py +31 -3
- spacr/gui_core.py +319 -46
- spacr/gui_elements.py +131 -0
- spacr/gui_utils.py +24 -20
- spacr/io.py +221 -8
- spacr/measure.py +11 -12
- spacr/settings.py +156 -48
- spacr/submodules.py +1 -1
- spacr/utils.py +99 -17
- {spacr-0.4.1.dist-info → spacr-0.4.3.dist-info}/METADATA +2 -1
- {spacr-0.4.1.dist-info → spacr-0.4.3.dist-info}/RECORD +15 -15
- {spacr-0.4.1.dist-info → spacr-0.4.3.dist-info}/LICENSE +0 -0
- {spacr-0.4.1.dist-info → spacr-0.4.3.dist-info}/WHEEL +0 -0
- {spacr-0.4.1.dist-info → spacr-0.4.3.dist-info}/entry_points.txt +0 -0
- {spacr-0.4.1.dist-info → spacr-0.4.3.dist-info}/top_level.txt +0 -0
spacr/settings.py
CHANGED
@@ -86,7 +86,7 @@ def set_default_settings_preprocess_generate_masks(settings={}):
|
|
86
86
|
settings.setdefault('fps', 2)
|
87
87
|
settings.setdefault('timelapse_displacement', None)
|
88
88
|
settings.setdefault('timelapse_memory', 3)
|
89
|
-
settings.setdefault('timelapse_frame_limits',
|
89
|
+
settings.setdefault('timelapse_frame_limits', [5,])
|
90
90
|
settings.setdefault('timelapse_remove_transient', False)
|
91
91
|
settings.setdefault('timelapse_mode', 'trackpy')
|
92
92
|
settings.setdefault('timelapse_objects', None)
|
@@ -256,7 +256,13 @@ def get_measure_crop_settings(settings={}):
|
|
256
256
|
settings.setdefault('homogeneity', True)
|
257
257
|
settings.setdefault('homogeneity_distances', [8,16,32])
|
258
258
|
|
259
|
-
# Cropping settings
|
259
|
+
# Cropping settings # Cropping settings
|
260
|
+
settings.setdefault('save_arrays', False)
|
261
|
+
settings.setdefault('save_png',True)
|
262
|
+
settings.setdefault('use_bounding_box',False)
|
263
|
+
settings.setdefault('png_size',[224,224])
|
264
|
+
settings.setdefault('png_dims',[0,1,2])
|
265
|
+
settings.setdefault('normalize',False) # Cropping settings
|
260
266
|
settings.setdefault('save_arrays', False)
|
261
267
|
settings.setdefault('save_png',True)
|
262
268
|
settings.setdefault('use_bounding_box',False)
|
@@ -277,9 +283,9 @@ def get_measure_crop_settings(settings={}):
|
|
277
283
|
settings.setdefault('n_jobs', os.cpu_count()-2)
|
278
284
|
|
279
285
|
# Object settings
|
280
|
-
settings.setdefault('cell_mask_dim',
|
281
|
-
settings.setdefault('nucleus_mask_dim',
|
282
|
-
settings.setdefault('pathogen_mask_dim',
|
286
|
+
settings.setdefault('cell_mask_dim',4)
|
287
|
+
settings.setdefault('nucleus_mask_dim',5)
|
288
|
+
settings.setdefault('pathogen_mask_dim',6)
|
283
289
|
settings.setdefault('cytoplasm',False)
|
284
290
|
settings.setdefault('uninfected',True)
|
285
291
|
settings.setdefault('cell_min_size',0)
|
@@ -473,7 +479,7 @@ def get_train_test_model_settings(settings):
|
|
473
479
|
return settings
|
474
480
|
|
475
481
|
def get_analyze_recruitment_default_settings(settings):
|
476
|
-
settings.setdefault('src','path')
|
482
|
+
settings.setdefault('src', 'path')
|
477
483
|
settings.setdefault('target','protein')
|
478
484
|
settings.setdefault('cell_types',['HeLa'])
|
479
485
|
settings.setdefault('cell_plate_metadata',None)
|
@@ -672,6 +678,7 @@ expected_types = {
|
|
672
678
|
"timelapse_displacement": int,
|
673
679
|
"timelapse_memory": int,
|
674
680
|
"timelapse_frame_limits": (list, type(None)), # This can be a list of lists
|
681
|
+
#"timelapse_frame_limits": (list, type(None)), # This can be a list of lists
|
675
682
|
"timelapse_remove_transient": bool,
|
676
683
|
"timelapse_mode": str,
|
677
684
|
"timelapse_objects": list,
|
@@ -944,13 +951,13 @@ expected_types = {
|
|
944
951
|
}
|
945
952
|
|
946
953
|
categories = {"Paths":[ "src", "grna", "barcodes", "custom_model_path", "dataset","model_path","grna_csv","row_csv","column_csv", "metadata_files", "score_data","count_data"],
|
947
|
-
"General": ["metadata_type", "custom_regex", "experiment", "channels", "magnification", "channel_dims", "apply_model_to_dataset", "generate_training_dataset", "train_DL_model", "segmentation_mode", "delete_intermediate"],
|
954
|
+
"General": ["cell_mask_dim", "cytoplasm", "cell_chann_dim", "cell_channel", "nucleus_chann_dim", "nucleus_channel", "nucleus_mask_dim", "pathogen_mask_dim", "pathogen_chann_dim", "pathogen_channel", "test_mode", "plot", "metadata_type", "custom_regex", "experiment", "channels", "magnification", "channel_dims", "apply_model_to_dataset", "generate_training_dataset", "train_DL_model", "segmentation_mode", "delete_intermediate", "uninfected", ],
|
948
955
|
"Cellpose":["fill_in","from_scratch", "n_epochs", "width_height", "model_name", "custom_model", "resample", "rescale", "CP_prob", "flow_threshold", "percentiles", "invert", "diameter", "grayscale", "Signal_to_noise", "resize", "target_height", "target_width"],
|
949
|
-
"Cell": ["cell_diamiter","cell_intensity_range", "cell_size_range", "
|
950
|
-
"Nucleus": ["nucleus_diamiter","nucleus_intensity_range", "nucleus_size_range", "
|
951
|
-
"Pathogen": ["pathogen_diamiter","pathogen_intensity_range", "pathogen_size_range", "
|
956
|
+
"Cell": ["cell_diamiter","cell_intensity_range", "cell_size_range", "cell_background", "cell_Signal_to_noise", "cell_CP_prob", "cell_FT", "remove_background_cell", "cell_min_size", "cytoplasm_min_size", "adjust_cells", "cells", "cell_loc"],
|
957
|
+
"Nucleus": ["nucleus_diamiter","nucleus_intensity_range", "nucleus_size_range", "nucleus_background", "nucleus_Signal_to_noise", "nucleus_CP_prob", "nucleus_FT", "remove_background_nucleus", "nucleus_min_size", "nucleus_loc"],
|
958
|
+
"Pathogen": ["pathogen_diamiter","pathogen_intensity_range", "pathogen_size_range", "pathogen_background", "pathogen_Signal_to_noise", "pathogen_CP_prob", "pathogen_FT", "pathogen_model", "remove_background_pathogen", "pathogen_min_size", "pathogens", "pathogen_loc", "pathogen_types", "pathogen_plate_metadata", ],
|
952
959
|
"Measurements": ["remove_image_canvas", "remove_highly_correlated", "homogeneity", "homogeneity_distances", "radial_dist", "calculate_correlation", "manders_thresholds", "save_measurements", "tables", "image_nr", "dot_size", "filter_by", "remove_highly_correlated_features", "remove_low_variance_features", "channel_of_interest"],
|
953
|
-
"Object Image": ["save_png", "dialate_pngs", "dialate_png_ratios", "png_size", "png_dims", "save_arrays", "normalize_by", "crop_mode", "
|
960
|
+
"Object Image": ["save_png", "dialate_pngs", "dialate_png_ratios", "png_size", "png_dims", "save_arrays", "normalize_by", "crop_mode", "use_bounding_box"],
|
954
961
|
"Sequencing": ["outlier_detection","offset_start","chunk_size","single_direction", "signal_direction","mode","comp_level","comp_type","save_h5","expected_end","offset","target_sequence","regex", "highlight"],
|
955
962
|
"Generate Dataset":["save_to_db","file_metadata","class_metadata", "annotation_column","annotated_classes", "dataset_mode", "metadata_type_by","custom_measurement", "sample", "size"],
|
956
963
|
"Hyperparamiters (Training)": ["png_type", "score_threshold","file_type", "train_channels", "epochs", "loss_type", "optimizer_type","image_size","val_split","learning_rate","weight_decay","dropout_rate", "init_weights", "train", "classes", "augment", "amsgrad","use_checkpoint","gradient_accumulation","gradient_accumulation_steps","intermedeate_save","pin_memory"],
|
@@ -959,11 +966,10 @@ categories = {"Paths":[ "src", "grna", "barcodes", "custom_model_path", "dataset
|
|
959
966
|
"Hyperparamiters (Regression)":["cross_validation","prune_features","reg_lambda","reg_alpha","cov_type", "class_1_threshold", "plate", "other", "fraction_threshold", "alpha", "random_row_column_effects", "regression_type", "min_cell_count", "agg_type", "transform", "dependent_variable"],
|
960
967
|
"Hyperparamiters (Activation)":["cam_type", "overlay", "correlation", "target_layer", "normalize_input"],
|
961
968
|
"Annotation": ["filter_column", "filter_value","volcano", "toxo", "controls", "nc_loc", "pc_loc", "nc", "pc", "cell_plate_metadata","treatment_plate_metadata", "metadata_types", "cell_types", "target","positive_control","negative_control", "location_column", "treatment_loc", "channel_of_interest", "measurement", "treatments", "um_per_pixel", "nr_imgs", "exclude", "exclude_conditions", "mix", "pos", "neg"],
|
962
|
-
"Plot": ["
|
963
|
-
"Test": ["test_mode", "test_images", "random_test", "test_nr", "test", "test_split"],
|
969
|
+
"Plot": ["split_axis_lims", "x_lim","log_x","log_y", "plot_control", "plot_nr", "examples_to_plot", "normalize_plots", "cmap", "figuresize", "plot_cluster_grids", "img_zoom", "row_limit", "color_by", "plot_images", "smooth_lines", "plot_points", "plot_outlines", "black_background", "plot_by_cluster", "heatmap_feature","grouping","min_max","cmap","save_figure"],
|
964
970
|
"Timelapse": ["timelapse", "fps", "timelapse_displacement", "timelapse_memory", "timelapse_frame_limits", "timelapse_remove_transient", "timelapse_mode", "timelapse_objects", "compartments"],
|
965
|
-
"Advanced": ["target_unique_count","threshold_multiplier", "threshold_method", "min_n","shuffle", "target_intensity_min", "cells_per_well", "nuclei_limit", "pathogen_limit", "background", "backgrounds", "schedule", "test_size","exclude","n_repeats","top_features", "model_type_ml", "model_type","minimum_cell_count","n_estimators","preprocess", "remove_background", "normalize", "lower_percentile", "merge_pathogens", "batch_size", "filter", "save", "masks", "verbose", "randomize", "n_jobs"],
|
966
|
-
"
|
971
|
+
"Advanced": ["merge_edge_pathogen_cells", "test_images", "random_test", "test_nr", "test", "test_split", "normalize", "target_unique_count","threshold_multiplier", "threshold_method", "min_n","shuffle", "target_intensity_min", "cells_per_well", "nuclei_limit", "pathogen_limit", "background", "backgrounds", "schedule", "test_size","exclude","n_repeats","top_features", "model_type_ml", "model_type","minimum_cell_count","n_estimators","preprocess", "remove_background", "normalize", "lower_percentile", "merge_pathogens", "batch_size", "filter", "save", "masks", "verbose", "randomize", "n_jobs"],
|
972
|
+
"Beta": ["all_to_mip", "pick_slice", "skip_mode", "upscale", "upscale_factor"]
|
967
973
|
}
|
968
974
|
|
969
975
|
|
@@ -972,6 +978,127 @@ category_keys = list(categories.keys())
|
|
972
978
|
def check_settings(vars_dict, expected_types, q=None):
|
973
979
|
from .gui_utils import parse_list
|
974
980
|
|
981
|
+
if q is None:
|
982
|
+
from multiprocessing import Queue
|
983
|
+
q = Queue()
|
984
|
+
|
985
|
+
settings = {}
|
986
|
+
errors = [] # Collect errors instead of stopping at the first one
|
987
|
+
|
988
|
+
for key, (label, widget, var, _) in vars_dict.items():
|
989
|
+
if key not in expected_types and key not in category_keys:
|
990
|
+
errors.append(f"Warning: Key '{key}' not found in expected types.")
|
991
|
+
continue
|
992
|
+
|
993
|
+
value = var.get()
|
994
|
+
if value in ['None', '']:
|
995
|
+
value = None
|
996
|
+
|
997
|
+
expected_type = expected_types.get(key, str)
|
998
|
+
|
999
|
+
try:
|
1000
|
+
if key in ["cell_plate_metadata", "timelapse_frame_limits", "png_size", "png_dims", "pathogen_plate_metadata", "treatment_plate_metadata", "class_metadata", "crop_mode"]:
|
1001
|
+
if value is None:
|
1002
|
+
parsed_value = None
|
1003
|
+
else:
|
1004
|
+
try:
|
1005
|
+
parsed_value = ast.literal_eval(value)
|
1006
|
+
except (ValueError, SyntaxError):
|
1007
|
+
raise ValueError(f"Expected a list or list of lists but got an invalid format: {value}")
|
1008
|
+
|
1009
|
+
if isinstance(parsed_value, list):
|
1010
|
+
if all(isinstance(i, list) for i in parsed_value) or all(not isinstance(i, list) for i in parsed_value):
|
1011
|
+
settings[key] = parsed_value
|
1012
|
+
else:
|
1013
|
+
raise ValueError(f"Invalid format: '{key}' contains mixed types (single values and lists).")
|
1014
|
+
|
1015
|
+
else:
|
1016
|
+
raise ValueError(f"Expected a list for '{key}', but got {type(parsed_value).__name__}.")
|
1017
|
+
|
1018
|
+
elif expected_type == list:
|
1019
|
+
settings[key] = parse_list(value) if value else None
|
1020
|
+
|
1021
|
+
if isinstance(settings[key], list) and len(settings[key]) == 1:
|
1022
|
+
settings[key] = settings[key][0]
|
1023
|
+
|
1024
|
+
elif expected_type == bool:
|
1025
|
+
settings[key] = value.lower() in ['true', '1', 't', 'y', 'yes'] if isinstance(value, str) else bool(value)
|
1026
|
+
|
1027
|
+
elif expected_type == (int, type(None)):
|
1028
|
+
if value is None or str(value).isdigit():
|
1029
|
+
settings[key] = int(value) if value is not None else None
|
1030
|
+
else:
|
1031
|
+
raise ValueError(f"Expected an integer or None for '{key}', but got '{value}'.")
|
1032
|
+
|
1033
|
+
elif expected_type == (float, type(None)):
|
1034
|
+
if value is None or (isinstance(value, str) and value.replace(".", "", 1).isdigit()):
|
1035
|
+
settings[key] = float(value) if value is not None else None
|
1036
|
+
else:
|
1037
|
+
raise ValueError(f"Expected a float or None for '{key}', but got '{value}'.")
|
1038
|
+
|
1039
|
+
elif expected_type == (int, float):
|
1040
|
+
try:
|
1041
|
+
settings[key] = float(value) if '.' in str(value) else int(value)
|
1042
|
+
except ValueError:
|
1043
|
+
raise ValueError(f"Expected an integer or float for '{key}', but got '{value}'.")
|
1044
|
+
|
1045
|
+
elif expected_type == (str, type(None)):
|
1046
|
+
settings[key] = str(value) if value is not None else None
|
1047
|
+
|
1048
|
+
elif expected_type == (str, type(None), list):
|
1049
|
+
if isinstance(value, list):
|
1050
|
+
settings[key] = parse_list(value) if value else None
|
1051
|
+
elif isinstance(value, str):
|
1052
|
+
settings[key] = str(value)
|
1053
|
+
else:
|
1054
|
+
settings[key] = None
|
1055
|
+
|
1056
|
+
elif expected_type == dict:
|
1057
|
+
try:
|
1058
|
+
if isinstance(value, str):
|
1059
|
+
parsed_dict = ast.literal_eval(value)
|
1060
|
+
else:
|
1061
|
+
raise ValueError("Expected a string representation of a dictionary.")
|
1062
|
+
|
1063
|
+
if not isinstance(parsed_dict, dict):
|
1064
|
+
raise ValueError(f"Expected a dictionary for '{key}', but got {type(parsed_dict).__name__}.")
|
1065
|
+
|
1066
|
+
settings[key] = parsed_dict
|
1067
|
+
except (ValueError, SyntaxError) as e:
|
1068
|
+
settings[key] = {}
|
1069
|
+
errors.append(f"Error: Invalid dictionary format for '{key}'. Expected type: dict. Error: {e}")
|
1070
|
+
|
1071
|
+
elif isinstance(expected_type, tuple):
|
1072
|
+
for typ in expected_type:
|
1073
|
+
try:
|
1074
|
+
settings[key] = typ(value) if value else None
|
1075
|
+
break
|
1076
|
+
except (ValueError, TypeError):
|
1077
|
+
continue
|
1078
|
+
else:
|
1079
|
+
raise ValueError(f"Value '{value}' for '{key}' does not match any expected types: {expected_type}.")
|
1080
|
+
|
1081
|
+
else:
|
1082
|
+
try:
|
1083
|
+
settings[key] = expected_type(value) if value else None
|
1084
|
+
except (ValueError, TypeError):
|
1085
|
+
raise ValueError(f"Expected type {expected_type.__name__} for '{key}', but got '{value}'.")
|
1086
|
+
|
1087
|
+
except (ValueError, SyntaxError) as e:
|
1088
|
+
expected_type_name = ' or '.join([t.__name__ for t in expected_type]) if isinstance(expected_type, tuple) else expected_type.__name__
|
1089
|
+
errors.append(f"Error: '{key}' has invalid format. Expected type: {expected_type_name}. Got value: '{value}'. Error: {e}")
|
1090
|
+
|
1091
|
+
# Send all collected errors to the queue
|
1092
|
+
for error in errors:
|
1093
|
+
q.put(error)
|
1094
|
+
|
1095
|
+
|
1096
|
+
|
1097
|
+
return settings, errors
|
1098
|
+
|
1099
|
+
def check_settings_v1(vars_dict, expected_types, q=None):
|
1100
|
+
from .gui_utils import parse_list
|
1101
|
+
|
975
1102
|
if q is None:
|
976
1103
|
from multiprocessing import Queue
|
977
1104
|
q = Queue()
|
@@ -984,22 +1111,26 @@ def check_settings(vars_dict, expected_types, q=None):
|
|
984
1111
|
q.put(f"Key {key} not found in expected types.")
|
985
1112
|
continue
|
986
1113
|
|
987
|
-
value = var.get()
|
988
|
-
if value
|
1114
|
+
value = var.get()
|
1115
|
+
if value in ['None', '']:
|
989
1116
|
value = None
|
990
1117
|
|
991
1118
|
expected_type = expected_types.get(key, str)
|
992
1119
|
|
993
1120
|
try:
|
994
|
-
if key in ["cell_plate_metadata", "timelapse_frame_limits", "png_size", "pathogen_loc", "treatment_loc", "pathogen_plate_metadata", "treatment_plate_metadata", "barcode_coordinates", "class_metadata"]:
|
995
|
-
|
1121
|
+
#if key in ["cell_plate_metadata", "timelapse_frame_limits", "png_size", "pathogen_loc", "treatment_loc", "pathogen_plate_metadata", "treatment_plate_metadata", "barcode_coordinates", "class_metadata"]:
|
1122
|
+
if key in ["cell_plate_metadata", "timelapse_frame_limits", "png_size", "png_dims", "pathogen_plate_metadata", "treatment_plate_metadata", "class_metadata", "crop_mode"]:
|
1123
|
+
|
1124
|
+
if value is None:
|
1125
|
+
parsed_value = None
|
1126
|
+
else:
|
1127
|
+
parsed_value = ast.literal_eval(value) if isinstance(value, str) and value.strip() else None
|
1128
|
+
|
996
1129
|
if isinstance(parsed_value, list):
|
997
1130
|
if all(isinstance(i, list) for i in parsed_value) or all(not isinstance(i, list) for i in parsed_value):
|
998
1131
|
settings[key] = parsed_value
|
999
1132
|
else:
|
1000
1133
|
raise ValueError("Invalid format: Mixed list and list of lists")
|
1001
|
-
#elif parsed_value == None:
|
1002
|
-
# settings[key] = None
|
1003
1134
|
else:
|
1004
1135
|
raise ValueError("Invalid format for list or list of lists")
|
1005
1136
|
|
@@ -1180,30 +1311,7 @@ def generate_fields(variables, scrollable_frame):
|
|
1180
1311
|
"n_epochs": "(int) - Number of epochs for training the Cellpose model.",
|
1181
1312
|
"n_jobs": "(int) - The number of n_jobs to use for processing the images. This will determine how many images are processed in parallel. Increase to speed up processing.",
|
1182
1313
|
"n_neighbors": "(int) - Number of neighbors for UMAP.",
|
1183
|
-
"n_repeats": "(int) - Number of repeats for
|
1184
|
-
"normalize": "(list) - The percentiles to use for normalizing the images. This will be used to determine the range of intensities to normalize images to. If None, no normalization is done.",
|
1185
|
-
"normalize_by": "(str) - Whether to normalize the images by field of view (fov) or by PNG image (png).",
|
1186
|
-
"normalize_plots": "(bool) - Whether to normalize the plots.",
|
1187
|
-
"nr_imgs": "(int) - The number of images to plot.",
|
1188
|
-
"nucleus_CP_prob": "(float) - The cellpose probability threshold for the nucleus channel. This will be used to segment the nucleus.",
|
1189
|
-
"nucleus_FT": "(float) - The flow threshold for nucleus objects. This will be used in nucleus segmentation.",
|
1190
|
-
"nucleus_background": "(float) - The background intensity for the nucleus channel. This will be used to remove background noise.",
|
1191
|
-
"nucleus_chann_dim": "(int) - Dimension of the channel to use for nucleus segmentation.",
|
1192
|
-
"nucleus_channel": "(int) - The channel to use for the nucleus. If None, the nucleus will not be segmented.",
|
1193
|
-
"nucleus_intensity_range": "(list) - Intensity range for nucleus segmentation.",
|
1194
|
-
"nucleus_loc": "(str) - Location of the nucleus in the images.",
|
1195
|
-
"nucleus_mask_dim": "(int) - The dimension of the array the nucleus mask is saved in.",
|
1196
|
-
"nucleus_min_size": "(int) - The minimum size of nucleus objects in pixels^2.",
|
1197
|
-
"nucleus_Signal_to_noise": "(float) - The signal-to-noise ratio for the nucleus channel. This will be used to determine the range of intensities to normalize images to for nucleus segmentation.",
|
1198
|
-
"nucleus_size_range": "(list) - Size range for nucleus segmentation.",
|
1199
|
-
"optimizer_type": "(str) - Type of optimizer to use.",
|
1200
|
-
"other": "(dict) - Additional parameters for the regression analysis.",
|
1201
|
-
"pathogen_CP_prob": "(float) - The cellpose probability threshold for the pathogen channel. This will be used to segment the pathogen.",
|
1202
|
-
"pathogen_FT": "(float) - The flow threshold for pathogen objects. This will be used in pathogen segmentation.",
|
1203
|
-
"pathogen_background": "(float) - The background intensity for the pathogen channel. This will be used to remove background noise.",
|
1204
|
-
"pathogen_chann_dim": "(int) - Dimension of the channel to use for pathogen segmentation.",
|
1205
|
-
"pathogen_channel": "(int) - The channel to use for the pathogen. If None, the pathogen will not be segmented.",
|
1206
|
-
"pathogen_intensity_range": "(str) - Metadata for the pathogen plate.",
|
1314
|
+
"n_repeats": "(int) - Number of repeats for the pathogen plate.",
|
1207
1315
|
"pathogen_Signal_to_noise": "(float) - The signal-to-noise ratio for the pathogen channel. This will be used to determine the range of intensities to normalize images to for pathogen segmentation.",
|
1208
1316
|
"pathogen_size_range": "(list) - Size range for pathogen segmentation.",
|
1209
1317
|
"pathogen_types": "(list) - Types of pathogens to include in the analysis.",
|
@@ -1222,7 +1330,7 @@ def generate_fields(variables, scrollable_frame):
|
|
1222
1330
|
"plot_nr": "(int) - Number of plots to generate.",
|
1223
1331
|
"plot_outlines": "(bool) - Whether to plot outlines of segmented objects.",
|
1224
1332
|
"png_dims": "(list) - The dimensions of the PNG images to save. This will determine the dimensions of the saved images. Maximum of 3 dimensions e.g. [1,2,3].",
|
1225
|
-
"png_size": "(
|
1333
|
+
"png_size": "(list) - The size of the PNG images to save. This will determine the size of the saved images.",
|
1226
1334
|
"positive_control": "(str) - Identifier for the positive control.",
|
1227
1335
|
"preprocess": "(bool) - Whether to preprocess the images before segmentation. This includes background removal and normalization. Set to False only if this step has already been done.",
|
1228
1336
|
"radial_dist": "(list) - Radial distances for measuring features.",
|
@@ -1385,8 +1493,8 @@ def set_annotate_default_settings(settings):
|
|
1385
1493
|
settings.setdefault('normalize', 'False')
|
1386
1494
|
settings.setdefault('normalize_channels', "r,g,b")
|
1387
1495
|
settings.setdefault('percentiles', [2, 98])
|
1388
|
-
settings.setdefault('measurement', '')#'cytoplasm_channel_3_mean_intensity,pathogen_channel_3_mean_intensity')
|
1389
|
-
settings.setdefault('threshold', '')#'2')
|
1496
|
+
settings.setdefault('measurement', '') #'cytoplasm_channel_3_mean_intensity,pathogen_channel_3_mean_intensity')
|
1497
|
+
settings.setdefault('threshold', '') #'2')
|
1390
1498
|
return settings
|
1391
1499
|
|
1392
1500
|
def set_default_generate_barecode_mapping(settings={}):
|
spacr/submodules.py
CHANGED
@@ -21,7 +21,7 @@ from sklearn.metrics import mean_absolute_error
|
|
21
21
|
import matplotlib.pyplot as plt
|
22
22
|
from natsort import natsorted
|
23
23
|
|
24
|
-
def analyze_recruitment(settings
|
24
|
+
def analyze_recruitment(settings):
|
25
25
|
"""
|
26
26
|
Analyze recruitment data by grouping the DataFrame by well coordinates and plotting controls and recruitment data.
|
27
27
|
|
spacr/utils.py
CHANGED
@@ -319,7 +319,6 @@ def load_settings(csv_file_path, show=False, setting_key='setting_key', setting_
|
|
319
319
|
|
320
320
|
return result_dict
|
321
321
|
|
322
|
-
|
323
322
|
def save_settings(settings, name='settings', show=False):
|
324
323
|
|
325
324
|
settings_df = pd.DataFrame(list(settings.items()), columns=['Key', 'Value'])
|
@@ -328,14 +327,19 @@ def save_settings(settings, name='settings', show=False):
|
|
328
327
|
|
329
328
|
if isinstance(settings['src'], list):
|
330
329
|
src = settings['src'][0]
|
331
|
-
#if os.path.exists(src):
|
332
|
-
|
333
330
|
name = f"{name}_list"
|
334
331
|
else:
|
335
332
|
src = settings['src']
|
333
|
+
|
334
|
+
if 'test_mode' in settings.keys():
|
335
|
+
settings['test_mode'] = False
|
336
|
+
|
337
|
+
if 'plot' in settings.keys():
|
338
|
+
settings['plot'] = False
|
336
339
|
|
337
340
|
settings_csv = os.path.join(src,'settings',f'{name}.csv')
|
338
341
|
os.makedirs(os.path.join(src,'settings'), exist_ok=True)
|
342
|
+
print(f"Saving settings to {settings_csv}")
|
339
343
|
settings_df.to_csv(settings_csv, index=False)
|
340
344
|
|
341
345
|
def print_progress(files_processed, files_to_process, n_jobs, time_ls=None, batch_size=None, operation_type=""):
|
@@ -1145,7 +1149,7 @@ def _masks_to_masks_stack(masks):
|
|
1145
1149
|
mask_stack.append(mask)
|
1146
1150
|
return mask_stack
|
1147
1151
|
|
1148
|
-
def
|
1152
|
+
def _get_diam_v1(mag, obj):
|
1149
1153
|
|
1150
1154
|
if mag == 20:
|
1151
1155
|
if obj == 'cell':
|
@@ -1176,11 +1180,28 @@ def _get_diam(mag, obj):
|
|
1176
1180
|
diamiter = 60
|
1177
1181
|
else:
|
1178
1182
|
raise ValueError("Invalid magnification: Use 20, 40 or 60")
|
1183
|
+
|
1179
1184
|
else:
|
1180
1185
|
raise ValueError("Invalid magnification: Use 20, 40 or 60")
|
1181
1186
|
|
1182
1187
|
return diamiter
|
1183
1188
|
|
1189
|
+
def _get_diam(mag, obj):
|
1190
|
+
|
1191
|
+
if obj == 'cell':
|
1192
|
+
diamiter = 2 * mag + 80
|
1193
|
+
|
1194
|
+
if obj == 'cell_large':
|
1195
|
+
diamiter = 2 * mag + 120
|
1196
|
+
|
1197
|
+
if obj == 'nucleus':
|
1198
|
+
diamiter = 0.75 * mag + 45
|
1199
|
+
|
1200
|
+
if obj == 'pathogen':
|
1201
|
+
diamiter = mag
|
1202
|
+
|
1203
|
+
return int(diamiter)
|
1204
|
+
|
1184
1205
|
def _get_object_settings(object_type, settings):
|
1185
1206
|
object_settings = {}
|
1186
1207
|
|
@@ -1333,20 +1354,25 @@ def annotate_conditions(df, cells=None, cell_loc=None, pathogens=None, pathogen_
|
|
1333
1354
|
def _map_or_default(column_name, values, loc, df):
|
1334
1355
|
"""
|
1335
1356
|
Consolidates the logic for mapping values or assigning defaults when loc is None.
|
1336
|
-
|
1357
|
+
|
1337
1358
|
Args:
|
1338
1359
|
column_name (str): The column in the DataFrame to annotate.
|
1339
1360
|
values (list/str): The list of values or a single string to annotate.
|
1340
1361
|
loc (list of lists): Location mapping for the values, or None if not used.
|
1341
1362
|
df (pandas.DataFrame): The DataFrame to modify.
|
1342
1363
|
"""
|
1343
|
-
if isinstance(values, str)
|
1344
|
-
#
|
1345
|
-
df[column_name] = values
|
1364
|
+
if isinstance(values, str) and loc is None:
|
1365
|
+
# If a single string is provided and loc is None, assign the value to all rows
|
1366
|
+
df[column_name] = values
|
1367
|
+
|
1368
|
+
elif isinstance(values, list) and loc is None:
|
1369
|
+
# If a list of values is provided but no loc, assign the first value to all rows
|
1370
|
+
df[column_name] = values[0]
|
1371
|
+
|
1346
1372
|
elif values is not None and loc is not None:
|
1347
|
-
# Perform
|
1373
|
+
# Perform location-based mapping
|
1348
1374
|
value_dict = {val: key for key, loc_list in zip(values, loc) for val in loc_list}
|
1349
|
-
df[column_name] = np.nan
|
1375
|
+
df[column_name] = np.nan # Start with NaN
|
1350
1376
|
for val, key in value_dict.items():
|
1351
1377
|
loc_type = _get_type(val)
|
1352
1378
|
if loc_type:
|
@@ -3099,12 +3125,8 @@ def _get_regex(metadata_type, img_format, custom_regex=None):
|
|
3099
3125
|
regex = f'(?P<plateID>.*)_(?P<wellID>.*)_T(?P<timeID>.*)F(?P<fieldID>.*)L(?P<laserID>..)A(?P<AID>..)Z(?P<sliceID>.*)C(?P<chanID>.*){img_format}'
|
3100
3126
|
elif metadata_type == 'cq1':
|
3101
3127
|
regex = f'W(?P<wellID>.*)F(?P<fieldID>.*)T(?P<timeID>.*)Z(?P<sliceID>.*)C(?P<chanID>.*){img_format}'
|
3102
|
-
elif metadata_type == '
|
3103
|
-
regex = f'(?P<plateID>.*)_(?P<wellID>.*)_T(?P<timeID>.*)F(?P<fieldID>.*)L(?P<laserID
|
3104
|
-
elif metadata_type == 'zeis':
|
3105
|
-
regex = f'(?P<plateID>.*)_(?P<wellID>.*)_T(?P<timeID>.*)F(?P<fieldID>.*)L(?P<laserID>..)A(?P<AID>..)Z(?P<sliceID>.*)C(?P<chanID>.*){img_format}'
|
3106
|
-
elif metadata_type == 'leica':
|
3107
|
-
regex = f'(?P<plateID>.*)_(?P<wellID>.*)_T(?P<timeID>.*)F(?P<fieldID>.*)L(?P<laserID>..)A(?P<AID>..)Z(?P<sliceID>.*)C(?P<chanID>.*){img_format}'
|
3128
|
+
elif metadata_type == 'auto':
|
3129
|
+
regex = f'(?P<plateID>.*)_(?P<wellID>.*)_T(?P<timeID>.*)F(?P<fieldID>.*)L(?P<laserID>.*)C(?P<chanID>.*).tif'
|
3108
3130
|
elif metadata_type == 'custom':
|
3109
3131
|
regex = f'({custom_regex}){img_format}'
|
3110
3132
|
|
@@ -4945,7 +4967,7 @@ def download_models(repo_id="einarolafsson/models", retries=5, delay=5):
|
|
4945
4967
|
if not os.path.exists(local_dir):
|
4946
4968
|
os.makedirs(local_dir)
|
4947
4969
|
elif len(os.listdir(local_dir)) > 0:
|
4948
|
-
print(f"Models already downloaded to: {local_dir}")
|
4970
|
+
#print(f"Models already downloaded to: {local_dir}")
|
4949
4971
|
return local_dir
|
4950
4972
|
|
4951
4973
|
attempt = 0
|
@@ -5337,3 +5359,63 @@ def calculate_shortest_distance(df, object1, object2):
|
|
5337
5359
|
df[f'{object1}_{object2}_shortest_distance'] = np.maximum(shortest_distance, 0)
|
5338
5360
|
|
5339
5361
|
return df
|
5362
|
+
|
5363
|
+
def format_path_for_system(path):
|
5364
|
+
"""
|
5365
|
+
Takes a file path and reformats it to be compatible with the current operating system.
|
5366
|
+
|
5367
|
+
Args:
|
5368
|
+
path (str): The file path to be formatted.
|
5369
|
+
|
5370
|
+
Returns:
|
5371
|
+
str: The formatted path for the current operating system.
|
5372
|
+
"""
|
5373
|
+
system = platform.system()
|
5374
|
+
|
5375
|
+
# Convert Windows-style paths to Unix-style (Linux/macOS)
|
5376
|
+
if system in ["Linux", "Darwin"]: # Darwin is macOS
|
5377
|
+
formatted_path = path.replace("\\", "/")
|
5378
|
+
|
5379
|
+
# Convert Unix-style paths to Windows-style
|
5380
|
+
elif system == "Windows":
|
5381
|
+
formatted_path = path.replace("/", "\\")
|
5382
|
+
|
5383
|
+
else:
|
5384
|
+
raise ValueError(f"Unsupported OS: {system}")
|
5385
|
+
|
5386
|
+
# Normalize path to ensure consistency
|
5387
|
+
new_path = os.path.normpath(formatted_path)
|
5388
|
+
if os.path.exists(new_path):
|
5389
|
+
print(f"Found path: {new_path}")
|
5390
|
+
else:
|
5391
|
+
print(f"Path not found: {new_path}")
|
5392
|
+
|
5393
|
+
return new_path
|
5394
|
+
|
5395
|
+
|
5396
|
+
def normalize_src_path(src):
|
5397
|
+
"""
|
5398
|
+
Ensures that the 'src' value is properly formatted as either a list of strings or a single string.
|
5399
|
+
|
5400
|
+
Args:
|
5401
|
+
src (str or list): The input source path(s).
|
5402
|
+
|
5403
|
+
Returns:
|
5404
|
+
list or str: A correctly formatted list if the input was a list (or string representation of a list),
|
5405
|
+
otherwise a single string.
|
5406
|
+
"""
|
5407
|
+
if isinstance(src, list):
|
5408
|
+
return src # Already a list, return as-is
|
5409
|
+
|
5410
|
+
if isinstance(src, str):
|
5411
|
+
try:
|
5412
|
+
# Check if it is a string representation of a list
|
5413
|
+
evaluated_src = ast.literal_eval(src)
|
5414
|
+
if isinstance(evaluated_src, list) and all(isinstance(item, str) for item in evaluated_src):
|
5415
|
+
return evaluated_src # Convert to real list
|
5416
|
+
except (SyntaxError, ValueError):
|
5417
|
+
pass # Not a valid list, treat as a string
|
5418
|
+
|
5419
|
+
return src # Return as a string if not a list
|
5420
|
+
|
5421
|
+
raise ValueError(f"Invalid type for 'src': {type(src).__name__}, expected str or list")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: spacr
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.3
|
4
4
|
Summary: Spatial phenotype analysis of crisp screens (SpaCr)
|
5
5
|
Home-page: https://github.com/EinarOlafsson/spacr
|
6
6
|
Author: Einar Birnir Olafsson
|
@@ -41,6 +41,7 @@ Requires-Dist: pillow<11.0,>=10.2.0
|
|
41
41
|
Requires-Dist: tifffile>=2023.4.12
|
42
42
|
Requires-Dist: nd2reader<4.0,>=3.3.0
|
43
43
|
Requires-Dist: czifile
|
44
|
+
Requires-Dist: readlif
|
44
45
|
Requires-Dist: imageio<3.0,>=2.34.0
|
45
46
|
Requires-Dist: pingouin<1.0,>=0.5.5
|
46
47
|
Requires-Dist: umap-learn<1.0,>=0.5.6
|
@@ -9,28 +9,28 @@ spacr/app_sequencing.py,sha256=DjG26jy4cpddnV8WOOAIiExtOe9MleVMY4MFa5uTo5w,157
|
|
9
9
|
spacr/app_umap.py,sha256=ZWAmf_OsIKbYvolYuWPMYhdlVe-n2CADoJulAizMiEo,153
|
10
10
|
spacr/cellpose.py,sha256=RBHMs2vwXcfkj0xqAULpALyzJYXddSRycgZSzmwI7v0,14755
|
11
11
|
spacr/chat_bot.py,sha256=n3Fhqg3qofVXHmh3H9sUcmfYy9MmgRnr48663MVdY9E,1244
|
12
|
-
spacr/core.py,sha256=
|
12
|
+
spacr/core.py,sha256=2VPM-nemOoYI3dbDudsvFGg4F_y2OlCcXKos5vWNKeU,50422
|
13
13
|
spacr/deep_spacr.py,sha256=WN64EaQqF87JZg3Uan46t5Y28xsAGD2KMjr2ht6CyDs,54563
|
14
14
|
spacr/gui.py,sha256=ARyn9Q_g8HoP-cXh1nzMLVFCKqthY4v2u9yORyaQqQE,8230
|
15
|
-
spacr/gui_core.py,sha256=
|
16
|
-
spacr/gui_elements.py,sha256=
|
17
|
-
spacr/gui_utils.py,sha256=
|
18
|
-
spacr/io.py,sha256=
|
15
|
+
spacr/gui_core.py,sha256=qMHQPY7LZEKQ5c7dIQtRyVBy03xNmwYWO8S85btVeEw,60170
|
16
|
+
spacr/gui_elements.py,sha256=Or38I_X9-lJRsyIAtbEfZPXzls0IORagf7vEe6IlI5Y,152647
|
17
|
+
spacr/gui_utils.py,sha256=dWVPFwDj793Z3ERG4mMC0hI0MKkOrvXJpUYlcjpCBsU,41357
|
18
|
+
spacr/io.py,sha256=R_cIPJYzzd1clpQ3mpYOXaSLPYsaU7apx1739RC27Dw,147018
|
19
19
|
spacr/logger.py,sha256=lJhTqt-_wfAunCPl93xE65Wr9Y1oIHJWaZMjunHUeIw,1538
|
20
|
-
spacr/measure.py,sha256=
|
20
|
+
spacr/measure.py,sha256=Z3u4BU5RzcY82IZuboQ0OsxuXaPVwOlH65Rw6FrL5z4,55045
|
21
21
|
spacr/mediar.py,sha256=FwLvbLQW5LQzPgvJZG8Lw7GniA2vbZx6Jv6vIKu7I5c,14743
|
22
22
|
spacr/ml.py,sha256=MrIAtUUxMOibWVL1SjCUnYlizawCp3l3SeY4Y9yEsPw,97251
|
23
23
|
spacr/openai.py,sha256=5vBZ3Jl2llYcW3oaTEXgdyCB2aJujMUIO5K038z7w_A,1246
|
24
24
|
spacr/plot.py,sha256=Q5TbsR2NUWhA7z4HyF_2_FAEBFSNMU-G3UNDbRzW6mM,169485
|
25
25
|
spacr/sequencing.py,sha256=ClUfwPPK6rNUbUuiEkzcwakzVyDKKUMv9ricrxT8qQY,25227
|
26
|
-
spacr/settings.py,sha256=
|
26
|
+
spacr/settings.py,sha256=72bhOwr0U83uoWwaKtSNZucYhpgwTP1_GItRk9f6A6c,87592
|
27
27
|
spacr/sim.py,sha256=1xKhXimNU3ukzIw-3l9cF3Znc_brW8h20yv8fSTzvss,71173
|
28
28
|
spacr/sp_stats.py,sha256=mbhwsyIqt5upsSD346qGjdCw7CFBa0tIS7zHU9e0jNI,9536
|
29
29
|
spacr/stats.py,sha256=mbhwsyIqt5upsSD346qGjdCw7CFBa0tIS7zHU9e0jNI,9536
|
30
|
-
spacr/submodules.py,sha256=
|
30
|
+
spacr/submodules.py,sha256=jFlJeVNuIEf63TtCOpTlOZ4iiSLr238kRBiGAAAgKE4,67626
|
31
31
|
spacr/timelapse.py,sha256=KGfG4L4-QnFfgbF7L6C5wL_3gd_rqr05Foje6RsoTBg,39603
|
32
32
|
spacr/toxo.py,sha256=TmuhejSIPLBvsgeblsUgSvBFCR1gOkApyTKidooJ5Us,26044
|
33
|
-
spacr/utils.py,sha256=
|
33
|
+
spacr/utils.py,sha256=v13vzgEQwUnQAtQya_akKIkem26-0Nn5j9uhx_NcJXQ,228599
|
34
34
|
spacr/version.py,sha256=axH5tnGwtgSnJHb5IDhiu4Zjk5GhLyAEDRe-rnaoFOA,409
|
35
35
|
spacr/resources/MEDIAR/.gitignore,sha256=Ff1q9Nme14JUd-4Q3jZ65aeQ5X4uttptssVDgBVHYo8,152
|
36
36
|
spacr/resources/MEDIAR/LICENSE,sha256=yEj_TRDLUfDpHDNM0StALXIt6mLqSgaV2hcCwa6_TcY,1065
|
@@ -153,9 +153,9 @@ spacr/resources/icons/umap.png,sha256=dOLF3DeLYy9k0nkUybiZMe1wzHQwLJFRmgccppw-8b
|
|
153
153
|
spacr/resources/images/plate1_E01_T0001F001L01A01Z01C02.tif,sha256=Tl0ZUfZ_AYAbu0up_nO0tPRtF1BxXhWQ3T3pURBCCRo,7958528
|
154
154
|
spacr/resources/images/plate1_E01_T0001F001L01A02Z01C01.tif,sha256=m8N-V71rA1TT4dFlENNg8s0Q0YEXXs8slIn7yObmZJQ,7958528
|
155
155
|
spacr/resources/images/plate1_E01_T0001F001L01A03Z01C03.tif,sha256=Pbhk7xn-KUP6RSIhJsxQcrHFImBm3GEpLkzx7WOc-5M,7958528
|
156
|
-
spacr-0.4.
|
157
|
-
spacr-0.4.
|
158
|
-
spacr-0.4.
|
159
|
-
spacr-0.4.
|
160
|
-
spacr-0.4.
|
161
|
-
spacr-0.4.
|
156
|
+
spacr-0.4.3.dist-info/LICENSE,sha256=SR-2MeGc6SCM1UORJYyarSWY_A-JaOMFDj7ReSs9tRM,1083
|
157
|
+
spacr-0.4.3.dist-info/METADATA,sha256=IAsmOAnJO0zAZ1eMw6KDX2IjKA5w4poSFur3-7GDcMs,6095
|
158
|
+
spacr-0.4.3.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
|
159
|
+
spacr-0.4.3.dist-info/entry_points.txt,sha256=BMC0ql9aNNpv8lUZ8sgDLQMsqaVnX5L535gEhKUP5ho,296
|
160
|
+
spacr-0.4.3.dist-info/top_level.txt,sha256=GJPU8FgwRXGzKeut6JopsSRY2R8T3i9lDgya42tLInY,6
|
161
|
+
spacr-0.4.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|