spacr 0.4.2__py3-none-any.whl → 0.4.4__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 +22 -4
- spacr/gui_core.py +37 -19
- spacr/io.py +75 -135
- spacr/settings.py +24 -9
- spacr/utils.py +2 -2
- {spacr-0.4.2.dist-info → spacr-0.4.4.dist-info}/METADATA +1 -1
- {spacr-0.4.2.dist-info → spacr-0.4.4.dist-info}/RECORD +11 -11
- {spacr-0.4.2.dist-info → spacr-0.4.4.dist-info}/LICENSE +0 -0
- {spacr-0.4.2.dist-info → spacr-0.4.4.dist-info}/WHEEL +0 -0
- {spacr-0.4.2.dist-info → spacr-0.4.4.dist-info}/entry_points.txt +0 -0
- {spacr-0.4.2.dist-info → spacr-0.4.4.dist-info}/top_level.txt +0 -0
spacr/core.py
CHANGED
@@ -9,7 +9,7 @@ warnings.filterwarnings("ignore", message="3D stack used, but stitch_threshold=0
|
|
9
9
|
|
10
10
|
def preprocess_generate_masks(settings):
|
11
11
|
|
12
|
-
from .io import preprocess_img_data, _load_and_concatenate_arrays, convert_to_yokogawa
|
12
|
+
from .io import preprocess_img_data, _load_and_concatenate_arrays, convert_to_yokogawa, convert_separate_files_to_yokogawa
|
13
13
|
from .plot import plot_image_mask_overlay, plot_arrays
|
14
14
|
from .utils import _pivot_counts_table, check_mask_folder, adjust_cell_masks, print_progress, save_settings, delete_intermedeate_files, format_path_for_system, normalize_src_path
|
15
15
|
from .settings import set_default_settings_preprocess_generate_masks
|
@@ -30,16 +30,34 @@ def preprocess_generate_masks(settings):
|
|
30
30
|
if isinstance(settings['src'], list):
|
31
31
|
source_folders = settings['src']
|
32
32
|
for source_folder in source_folders:
|
33
|
-
print(f'Processing folder: {source_folder}')
|
34
33
|
|
35
|
-
|
36
|
-
convert_to_yokogawa(folder=source_folder)
|
34
|
+
print(f'Processing folder: {source_folder}')
|
37
35
|
|
38
36
|
source_folder = format_path_for_system(source_folder)
|
39
37
|
settings['src'] = source_folder
|
40
38
|
src = source_folder
|
41
39
|
settings = set_default_settings_preprocess_generate_masks(settings)
|
42
40
|
|
41
|
+
if settings['metadata_type'] == 'auto':
|
42
|
+
if settings['custom_regex'] != None:
|
43
|
+
try:
|
44
|
+
print(f"using regex: {settings['custom_regex']}")
|
45
|
+
convert_separate_files_to_yokogawa(folder=source_folder, regex=settings['custom_regex'])
|
46
|
+
except:
|
47
|
+
try:
|
48
|
+
convert_to_yokogawa(folder=source_folder)
|
49
|
+
except Exception as e:
|
50
|
+
print(f"Error: Tried to convert image files and image file name metadata with regex {settings['custom_regex']} then without regex but failed both.")
|
51
|
+
print(f'Error: {e}')
|
52
|
+
return
|
53
|
+
else:
|
54
|
+
try:
|
55
|
+
convert_to_yokogawa(folder=source_folder)
|
56
|
+
except Exception as e:
|
57
|
+
print(f"Error: Tried to convert image files and image file name metadata without regex but failed.")
|
58
|
+
print(f'Error: {e}')
|
59
|
+
return
|
60
|
+
|
43
61
|
if settings['cell_channel'] is None and settings['nucleus_channel'] is None and settings['pathogen_channel'] is None:
|
44
62
|
print(f'Error: At least one of cell_channel, nucleus_channel or pathogen_channel must be defined')
|
45
63
|
return
|
spacr/gui_core.py
CHANGED
@@ -913,34 +913,52 @@ def check_src_folders_files(settings, settings_type, q):
|
|
913
913
|
conditions = [pictures_continue, folder_chan_continue, folder_stack_continue, folder_npz_continue]
|
914
914
|
|
915
915
|
if settings_type == 'measure':
|
916
|
+
if not os.path.basename(path) == 'merged':
|
917
|
+
path = os.path.join(path, "merged")
|
916
918
|
npy_continue = _folder_has_images(path, image_extensions={".npy"})
|
917
919
|
conditions = [npy_continue]
|
918
920
|
|
919
|
-
if settings_type == 'recruitment':
|
920
|
-
|
921
|
-
|
921
|
+
#if settings_type == 'recruitment':
|
922
|
+
# if not os.path.basename(path) == 'measurements':
|
923
|
+
# path = os.path.join(path, "measurements")
|
924
|
+
# db_continue = _folder_has_images(path, image_extensions={".db"})
|
925
|
+
# conditions = [db_continue]
|
922
926
|
|
923
|
-
if settings_type == 'umap':
|
924
|
-
|
925
|
-
|
927
|
+
#if settings_type == 'umap':
|
928
|
+
# if not os.path.basename(path) == 'measurements':
|
929
|
+
# path = os.path.join(path, "measurements")
|
930
|
+
# db_continue = _folder_has_images(path, image_extensions={".db"})
|
931
|
+
# conditions = [db_continue]
|
926
932
|
|
927
|
-
if settings_type == 'analyze_plaques':
|
928
|
-
|
933
|
+
#if settings_type == 'analyze_plaques':
|
934
|
+
# if not os.path.basename(path) == 'measurements':
|
935
|
+
# path = os.path.join(path, "measurements")
|
936
|
+
# db_continue = _folder_has_images(path, image_extensions={".db"})
|
937
|
+
# conditions = [db_continue]
|
929
938
|
|
930
|
-
if settings_type == 'map_barcodes':
|
931
|
-
|
939
|
+
#if settings_type == 'map_barcodes':
|
940
|
+
# if not os.path.basename(path) == 'measurements':
|
941
|
+
# path = os.path.join(path, "measurements")
|
942
|
+
# db_continue = _folder_has_images(path, image_extensions={".db"})
|
943
|
+
# conditions = [db_continue]
|
932
944
|
|
933
|
-
if settings_type == 'regression':
|
934
|
-
|
935
|
-
|
945
|
+
#if settings_type == 'regression':
|
946
|
+
# if not os.path.basename(path) == 'measurements':
|
947
|
+
# path = os.path.join(path, "measurements")
|
948
|
+
# db_continue = _folder_has_images(path, image_extensions={".db"})
|
949
|
+
# conditions = [db_continue]
|
936
950
|
|
937
|
-
if settings_type == 'classify':
|
938
|
-
|
939
|
-
|
951
|
+
#if settings_type == 'classify':
|
952
|
+
# if not os.path.basename(path) == 'measurements':
|
953
|
+
# path = os.path.join(path, "measurements")
|
954
|
+
# db_continue = _folder_has_images(path, image_extensions={".db"})
|
955
|
+
# conditions = [db_continue]
|
940
956
|
|
941
|
-
if settings_type == 'analyze_plaques':
|
942
|
-
|
943
|
-
|
957
|
+
#if settings_type == 'analyze_plaques':
|
958
|
+
# if not os.path.basename(path) == 'measurements':
|
959
|
+
# path = os.path.join(path, "measurements")
|
960
|
+
# db_continue = _folder_has_images(path, image_extensions={".db"})
|
961
|
+
# conditions = [db_continue]
|
944
962
|
|
945
963
|
if not any(conditions):
|
946
964
|
q.put(f"Error: The following path(s) is missing images or folders: {path}")
|
spacr/io.py
CHANGED
@@ -647,7 +647,7 @@ def load_images_from_paths(images_by_key):
|
|
647
647
|
|
648
648
|
return images_dict
|
649
649
|
|
650
|
-
#@log_function_call
|
650
|
+
#@log_function_call
|
651
651
|
def _rename_and_organize_image_files(src, regex, batch_size=100, pick_slice=False, skip_mode='01', metadata_type='', img_format='.tif'):
|
652
652
|
"""
|
653
653
|
Convert z-stack images to maximum intensity projection (MIP) images.
|
@@ -664,13 +664,16 @@ def _rename_and_organize_image_files(src, regex, batch_size=100, pick_slice=Fals
|
|
664
664
|
None
|
665
665
|
"""
|
666
666
|
|
667
|
+
if isinstance(img_format, str):
|
668
|
+
img_format = [img_format]
|
669
|
+
|
667
670
|
from .utils import _extract_filename_metadata, print_progress
|
668
671
|
|
669
672
|
regular_expression = re.compile(regex)
|
670
673
|
stack_path = os.path.join(src, 'stack')
|
671
674
|
files_processed = 0
|
672
675
|
if not os.path.exists(stack_path) or (os.path.isdir(stack_path) and len(os.listdir(stack_path)) == 0):
|
673
|
-
all_filenames = [filename for filename in os.listdir(src) if filename.endswith(img_format)]
|
676
|
+
all_filenames = [filename for filename in os.listdir(src) if any(filename.endswith(ext) for ext in img_format)]
|
674
677
|
print(f'All files: {len(all_filenames)} in {src}')
|
675
678
|
time_ls = []
|
676
679
|
image_paths_by_key = _extract_filename_metadata(all_filenames, src, regular_expression, metadata_type, pick_slice, skip_mode)
|
@@ -729,11 +732,11 @@ def _rename_and_organize_image_files(src, regex, batch_size=100, pick_slice=Fals
|
|
729
732
|
images_by_key.clear()
|
730
733
|
|
731
734
|
# Move original images to a new directory
|
732
|
-
valid_exts = [img_format]
|
733
735
|
newpath = os.path.join(src, 'orig')
|
734
736
|
os.makedirs(newpath, exist_ok=True)
|
735
737
|
for filename in os.listdir(src):
|
736
|
-
|
738
|
+
#print(f"{filename}: {os.path.splitext(filename)[1]}")
|
739
|
+
if os.path.splitext(filename)[1] in img_format:
|
737
740
|
move = os.path.join(newpath, filename)
|
738
741
|
if os.path.exists(move):
|
739
742
|
print(f'WARNING: A file with the same name already exists at location {move}')
|
@@ -1628,6 +1631,7 @@ def preprocess_img_data(settings):
|
|
1628
1631
|
if timelapse:
|
1629
1632
|
_move_to_chan_folder(src, regex, timelapse, metadata_type)
|
1630
1633
|
else:
|
1634
|
+
img_format = ['.tif', '.tiff', '.png', '.jpg', '.jpeg', '.bmp', '.nd2', '.czi', '.lif']
|
1631
1635
|
_rename_and_organize_image_files(src, regex, batch_size, pick_slice, skip_mode, metadata_type, img_format)
|
1632
1636
|
|
1633
1637
|
#Make sure no batches will be of only one image
|
@@ -3104,160 +3108,96 @@ def generate_dataset_from_lists(dst, class_data, classes, test_split=0.1):
|
|
3104
3108
|
|
3105
3109
|
return os.path.join(dst, 'train'), os.path.join(dst, 'test')
|
3106
3110
|
|
3107
|
-
def
|
3108
|
-
"""
|
3109
|
-
Detects file type in the folder and converts them
|
3110
|
-
to Yokogawa-style naming with Maximum Intensity Projection (MIP).
|
3111
|
-
"""
|
3111
|
+
def convert_separate_files_to_yokogawa(folder, regex):
|
3112
3112
|
|
3113
|
+
ROWS = "ABCDEFGHIJKLMNOP"
|
3114
|
+
COLS = [f"{i:02d}" for i in range(1, 25)]
|
3115
|
+
WELLS = [f"{r}{c}" for r in ROWS for c in COLS]
|
3116
|
+
|
3113
3117
|
def _get_next_well(used_wells):
|
3114
|
-
"""
|
3115
|
-
Determines the next available well position in a 384-well format.
|
3116
|
-
Iterates wells, and after P24, switches to plate2.
|
3117
|
-
"""
|
3118
3118
|
plate = 1
|
3119
3119
|
for well in WELLS:
|
3120
3120
|
well_name = f"plate{plate}_{well}"
|
3121
3121
|
if well_name not in used_wells:
|
3122
3122
|
return well_name
|
3123
|
-
if well == "P24":
|
3124
|
-
plate += 1
|
3123
|
+
if well == "P24":
|
3124
|
+
plate += 1
|
3125
3125
|
return f"plate{plate}_A01"
|
3126
3126
|
|
3127
|
-
|
3128
|
-
ROWS = "ABCDEFGHIJKLMNOP"
|
3129
|
-
COLS = [f"{i:02d}" for i in range(1, 25)]
|
3130
|
-
WELLS = [f"{r}{c}" for r in ROWS for c in COLS]
|
3127
|
+
pattern = re.compile(regex, re.I)
|
3131
3128
|
|
3132
|
-
|
3129
|
+
files_by_region = {}
|
3133
3130
|
rename_log = []
|
3134
3131
|
csv_path = os.path.join(folder, "rename_log.csv")
|
3135
|
-
used_wells = set(
|
3132
|
+
used_wells = set()
|
3133
|
+
region_to_well = {}
|
3136
3134
|
|
3135
|
+
# Group files by (plateID, wellID, fieldID, timeID, chanID)
|
3137
3136
|
for file in os.listdir(folder):
|
3138
|
-
|
3139
|
-
|
3140
|
-
|
3141
|
-
|
3142
|
-
if ext == 'nd2':
|
3143
|
-
nd2 = ND2Reader(path)
|
3144
|
-
metadata = nd2.metadata
|
3145
|
-
|
3146
|
-
timepoints = metadata.get("frames", [0])
|
3147
|
-
fields = metadata.get("fields_of_view", [0])
|
3148
|
-
z_levels = list(metadata.get("z_levels", range(1)))
|
3149
|
-
channels = metadata.get("channels", [])
|
3150
|
-
|
3151
|
-
for t_idx in timepoints:
|
3152
|
-
for f_idx in fields:
|
3153
|
-
for c_idx, channel in enumerate(channels):
|
3154
|
-
well = _get_next_well(used_wells)
|
3155
|
-
|
3156
|
-
z_stack = [nd2.get_frame_2D(t=t_idx, v=f_idx, z=z_idx, c=c_idx) for z_idx in z_levels]
|
3157
|
-
mip_image = np.max(np.stack(z_stack), axis=0)
|
3158
|
-
dtype = z_stack[0].dtype
|
3159
|
-
|
3160
|
-
filename = f"{well}_T{t_idx+1:04d}F{f_idx+1:03d}L01C{c_idx+1:02d}.tif"
|
3161
|
-
filepath = os.path.join(folder, filename)
|
3162
|
-
tifffile.imwrite(filepath, mip_image.astype(dtype))
|
3163
|
-
used_wells.add(well)
|
3164
|
-
rename_log.append({"Original File": file, "Renamed TIFF": filename})
|
3165
|
-
|
3166
|
-
### **Process Zeiss CZI Files**
|
3167
|
-
elif ext == 'czi':
|
3168
|
-
with czifile.CziFile(path) as czi:
|
3169
|
-
shape = czi.shape
|
3170
|
-
|
3171
|
-
timepoints = range(shape[0])
|
3172
|
-
z_levels = range(shape[1])
|
3173
|
-
channels = range(shape[2])
|
3174
|
-
|
3175
|
-
for t_idx in timepoints:
|
3176
|
-
for c_idx in channels:
|
3177
|
-
well = _get_next_well(used_wells)
|
3178
|
-
|
3179
|
-
z_stack = [czi.asarray()[t_idx, z_idx, c_idx] for z_idx in z_levels]
|
3180
|
-
mip_image = np.max(np.stack(z_stack), axis=0)
|
3181
|
-
dtype = z_stack[0].dtype
|
3182
|
-
|
3183
|
-
filename = f"{well}_T{t_idx+1:04d}F001L01C{c_idx+1:02d}.tif"
|
3184
|
-
filepath = os.path.join(folder, filename)
|
3185
|
-
tifffile.imwrite(filepath, mip_image.astype(dtype))
|
3186
|
-
used_wells.add(well)
|
3187
|
-
rename_log.append({"Original File": file, "Renamed TIFF": filename})
|
3188
|
-
|
3189
|
-
### **Process Leica LIF Files**
|
3190
|
-
elif ext == 'lif':
|
3191
|
-
lif_file = readlif.Reader(path)
|
3192
|
-
|
3193
|
-
for image in lif_file.getIterImage():
|
3194
|
-
timepoints = range(image.dims.t)
|
3195
|
-
z_levels = range(image.dims.z)
|
3196
|
-
channels = range(image.dims.c)
|
3197
|
-
|
3198
|
-
for t_idx in timepoints:
|
3199
|
-
for c_idx in channels:
|
3200
|
-
well = _get_next_well(used_wells)
|
3201
|
-
|
3202
|
-
z_stack = [image.getFrame(z=z_idx, t=t_idx, c=c_idx) for z_idx in z_levels]
|
3203
|
-
mip_image = np.max(np.stack(z_stack), axis=0)
|
3204
|
-
dtype = z_stack[0].dtype
|
3205
|
-
|
3206
|
-
filename = f"{well}_T{t_idx+1:04d}F001L01C{c_idx+1:02d}.tif"
|
3207
|
-
filepath = os.path.join(folder, filename)
|
3208
|
-
tifffile.imwrite(filepath, mip_image.astype(dtype))
|
3209
|
-
used_wells.add(well)
|
3210
|
-
rename_log.append({"Original File": file, "Renamed TIFF": filename})
|
3211
|
-
|
3212
|
-
### **Process Standard Images (.tif, .tiff, .png, .jpg, .bmp, etc.)**
|
3213
|
-
elif ext in ['tif', 'tiff', 'png', 'jpg', 'jpeg', 'bmp'] and not file.startswith("plate"):
|
3214
|
-
with tifffile.TiffFile(path) as tif:
|
3215
|
-
well = _get_next_well(used_wells)
|
3216
|
-
num_pages = len(tif.pages)
|
3137
|
+
match = pattern.match(file)
|
3138
|
+
if not match:
|
3139
|
+
print(f"Skipping {file}: does not match regex.")
|
3140
|
+
continue
|
3217
3141
|
|
3218
|
-
|
3219
|
-
# Assume multi-channel or z-stack
|
3220
|
-
images = tif.asarray()
|
3221
|
-
if images.ndim == 4: # (T, Z, C, Y, X)
|
3222
|
-
timepoints = range(images.shape[0])
|
3223
|
-
z_levels = range(images.shape[1])
|
3224
|
-
channels = range(images.shape[2])
|
3142
|
+
meta = match.groupdict()
|
3225
3143
|
|
3226
|
-
|
3227
|
-
|
3228
|
-
|
3229
|
-
|
3230
|
-
|
3231
|
-
|
3232
|
-
|
3233
|
-
|
3234
|
-
|
3235
|
-
|
3144
|
+
# Mandatory metadata
|
3145
|
+
if 'wellID' not in meta or meta['wellID'] is None:
|
3146
|
+
print(f"Skipping {file}: missing mandatory wellID.")
|
3147
|
+
continue
|
3148
|
+
wellID = meta['wellID']
|
3149
|
+
|
3150
|
+
# Optional metadata with defaults
|
3151
|
+
plateID = meta.get('plateID', '1') or '1'
|
3152
|
+
fieldID = meta.get('fieldID', '1') or '1'
|
3153
|
+
timeID = int(meta.get('timeID', 1) or 1)
|
3154
|
+
chanID = int(meta.get('chanID', 1) or 1)
|
3155
|
+
sliceID = meta.get('sliceID')
|
3156
|
+
sliceID = int(sliceID) if sliceID is not None else None
|
3157
|
+
|
3158
|
+
region_key = (plateID, wellID, fieldID, timeID, chanID)
|
3159
|
+
|
3160
|
+
files_by_region.setdefault(region_key, []).append((file, sliceID))
|
3161
|
+
|
3162
|
+
# Assign wells and process files per region
|
3163
|
+
for region, file_list in files_by_region.items():
|
3164
|
+
if region[:3] not in region_to_well:
|
3165
|
+
next_well = _get_next_well(used_wells)
|
3166
|
+
region_to_well[region[:3]] = next_well
|
3167
|
+
used_wells.add(next_well)
|
3168
|
+
|
3169
|
+
assigned_well = region_to_well[region[:3]]
|
3170
|
+
plateID, wellID, fieldID, timeID, chanID = region
|
3171
|
+
|
3172
|
+
# Check if multiple slices exist and are meaningful
|
3173
|
+
slice_ids = [sid for _, sid in file_list if sid is not None]
|
3174
|
+
unique_slices = set(slice_ids)
|
3175
|
+
|
3176
|
+
images = []
|
3177
|
+
for filename, _ in sorted(file_list, key=lambda x: x[1] or 1):
|
3178
|
+
img = tifffile.imread(os.path.join(folder, filename))
|
3179
|
+
images.append(img)
|
3180
|
+
|
3181
|
+
# Perform MIP only if multiple unique slices are present
|
3182
|
+
if len(unique_slices) > 1:
|
3183
|
+
img_to_save = np.max(np.stack(images), axis=0)
|
3184
|
+
else:
|
3185
|
+
img_to_save = images[0]
|
3236
3186
|
|
3237
|
-
|
3238
|
-
z_stack = images if images.shape[0] > 1 else [images]
|
3239
|
-
mip_image = np.max(np.stack(z_stack), axis=0)
|
3240
|
-
dtype = images.dtype
|
3187
|
+
dtype = img_to_save.dtype
|
3241
3188
|
|
3242
|
-
|
3243
|
-
|
3244
|
-
|
3245
|
-
used_wells.add(well)
|
3246
|
-
rename_log.append({"Original File": file, "Renamed TIFF": filename})
|
3247
|
-
else:
|
3248
|
-
image = tif.pages[0].asarray()
|
3249
|
-
dtype = image.dtype
|
3189
|
+
new_filename = f"{assigned_well}_T{timeID:04d}F{int(fieldID):03d}L01C{chanID:02d}.tif"
|
3190
|
+
new_filepath = os.path.join(folder, new_filename)
|
3191
|
+
tifffile.imwrite(new_filepath, img_to_save.astype(dtype))
|
3250
3192
|
|
3251
|
-
|
3252
|
-
|
3253
|
-
|
3254
|
-
used_wells.add(well)
|
3255
|
-
rename_log.append({"Original File": file, "Renamed TIFF": filename})
|
3193
|
+
# Log original filenames involved in MIP or single file rename
|
3194
|
+
original_files = ";".join(f[0] for f in file_list)
|
3195
|
+
rename_log.append({"Original File(s)": original_files, "Renamed TIFF": new_filename})
|
3256
3196
|
|
3257
|
-
# Save rename log as CSV
|
3258
3197
|
pd.DataFrame(rename_log).to_csv(csv_path, index=False)
|
3259
3198
|
print(f"Processing complete. Files saved in {folder} and rename log saved as {csv_path}.")
|
3260
3199
|
|
3200
|
+
|
3261
3201
|
def convert_to_yokogawa(folder):
|
3262
3202
|
"""
|
3263
3203
|
Detects file type in the folder and converts them
|
spacr/settings.py
CHANGED
@@ -1213,16 +1213,25 @@ def generate_fields(variables, scrollable_frame):
|
|
1213
1213
|
"black_background": "(bool) - Whether to use a black background for plots.",
|
1214
1214
|
"calculate_correlation": "(bool) - Whether to calculate correlations between features.",
|
1215
1215
|
"cell_CP_prob": "(float) - The cellpose probability threshold for the cell channel. This will be used in cell segmentation.",
|
1216
|
+
"nucleus_CP_prob": "(float) - The cellpose probability threshold for the nucleus channel. This will be used in cell segmentation.",
|
1217
|
+
"pathogen_CP_prob": "(float) - The cellpose probability threshold for the pathogen channel. This will be used in cell segmentation.",
|
1216
1218
|
"cell_FT": "(float) - The flow threshold for cell objects. This will be used to segment the cells.",
|
1217
|
-
"
|
1219
|
+
"nucleus_FT": "(float) - The flow threshold for nucleus objects. This will be used to segment the cells.",
|
1220
|
+
"pathogen_FT": "(float) - The flow threshold for pathogen objects. This will be used to segment the cells.",
|
1221
|
+
"cell_background": "(int) - The background intensity for the cell channel. This will be used to remove background noise.",
|
1222
|
+
"nucleus_background": "(int) - The background intensity for the nucleus channel. This will be used to remove background noise.",
|
1223
|
+
"pathogen_background": "(int) - The background intensity for the pathogen channel. This will be used to remove background noise.",
|
1218
1224
|
"cell_chann_dim": "(int) - Dimension of the channel to use for cell segmentation.",
|
1219
|
-
"cell_channel": "(int) - The channel to use for
|
1225
|
+
"cell_channel": "(int) - The channel to use for generatin cell masks. If None, cell masks will not be generated.",
|
1226
|
+
"nucleus_channel": "(int) - The channel to use for generatin nucleus masks. If None, nucleus masks will not be generated.",
|
1227
|
+
"pathogen_channel": "(int) - The channel to use for generatin pathogen masks. If None, pathogen masks will not be generated.",
|
1220
1228
|
"cell_intensity_range": "(list) - Intensity range for cell segmentation.",
|
1221
1229
|
"cell_loc": "(list) - The locations of the cell types in the images.",
|
1222
|
-
"cell_mask_dim": "(int) - The dimension of the array the cell mask is saved in.",
|
1230
|
+
"cell_mask_dim": "(int) - The dimension of the array the cell mask is saved in (array order:channels,cell, nucleus, pathogen, cytoplasm) array starts at dimension 0.",
|
1231
|
+
"nucleus_mask_dim": "(int) - The dimension of the array the nucleus mask is saved in (array order:channels,cell, nucleus, pathogen, cytoplasm) array starts at dimension 0.",
|
1223
1232
|
"cell_min_size": "(int) - The minimum size of cell objects in pixels^2.",
|
1224
1233
|
"cell_plate_metadata": "(str) - Metadata for the cell plate.",
|
1225
|
-
"cell_Signal_to_noise": "(
|
1234
|
+
"cell_Signal_to_noise": "(int) - The signal-to-noise ratio for the cell channel. This will be used to determine the range of intensities to normalize images to for cell segmentation.",
|
1226
1235
|
"cell_size_range": "(list) - Size range for cell segmentation.",
|
1227
1236
|
"cell_types": "(list) - Types of cells to include in the analysis.",
|
1228
1237
|
"cells": "(list of lists) - The cell types to include in the analysis.",
|
@@ -1240,10 +1249,13 @@ def generate_fields(variables, scrollable_frame):
|
|
1240
1249
|
"CP_prob": "(float) - Cellpose probability threshold for segmentation.",
|
1241
1250
|
"crop_mode": "(str) - Mode to use for cropping images (cell, nucleus, pathogen, cytoplasm).",
|
1242
1251
|
"custom_model": "(str) - Path to a custom Cellpose model.",
|
1243
|
-
"custom_regex": "(str) - Custom regex pattern to extract metadata from the image names. This will only be used if 'custom' is selected for 'metadata_type'.",
|
1252
|
+
"custom_regex": "(str) - Custom regex pattern to extract metadata from the image names. This will only be used if 'custom' or 'auto' is selected for 'metadata_type'.",
|
1244
1253
|
"cytoplasm": "(bool) - Whether to segment the cytoplasm (Cell - Nucleus + Pathogen).",
|
1245
1254
|
"cytoplasm_min_size": "(int) - The minimum size of cytoplasm objects in pixels^2.",
|
1255
|
+
"nucleus_min_size": "(int) - The minimum size of nucleus objects in pixels^2.",
|
1256
|
+
"normalize_by": "(str) - Normalize cropped png images by png or by field of view.",
|
1246
1257
|
"dependent_variable": "(str) - The dependent variable for the regression analysis.",
|
1258
|
+
"delete_intermediate": "(bool) - Delete intermediate folders (stack, channel, norm_channel_stack).",
|
1247
1259
|
"diameter": "(float) - Diameter of the objects to segment.",
|
1248
1260
|
"dialate_png_ratios": "(list) - The ratios to use for dilating the PNG images. This will determine the amount of dilation applied to the images before cropping.",
|
1249
1261
|
"dialate_pngs": "(bool) - Whether to dilate the PNG images before saving.",
|
@@ -1291,7 +1303,7 @@ def generate_fields(variables, scrollable_frame):
|
|
1291
1303
|
"manders_thresholds": "(list) - Thresholds for Manders' coefficients.",
|
1292
1304
|
"mask": "(bool) - Whether to generate masks for the segmented objects. If True, masks will be generated for the nucleus, cell, and pathogen.",
|
1293
1305
|
"measurement": "(str) - The measurement to use for the analysis.",
|
1294
|
-
"metadata_type": "(str) - Type of metadata to expect in the images.
|
1306
|
+
"metadata_type": "(str) - Type of metadata to expect in the images. If 'custom' is selected, you can provide a custom regex pattern to extract metadata from the image names. auto will attempt to automatically extract metadata from the image names. cellvoyager and cq1 will use the default metadata extraction for CellVoyager and CQ1 images.",
|
1295
1307
|
"metadata_types": "(list) - Types of metadata to include in the analysis.",
|
1296
1308
|
"merge_edge_pathogen_cells": "(bool) - Whether to merge cells that share pathogen objects.",
|
1297
1309
|
"merge_pathogens": "(bool) - Whether to merge pathogen objects that share more than 75 percent of their perimeter.",
|
@@ -1312,7 +1324,8 @@ def generate_fields(variables, scrollable_frame):
|
|
1312
1324
|
"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.",
|
1313
1325
|
"n_neighbors": "(int) - Number of neighbors for UMAP.",
|
1314
1326
|
"n_repeats": "(int) - Number of repeats for the pathogen plate.",
|
1315
|
-
"pathogen_Signal_to_noise": "(
|
1327
|
+
"pathogen_Signal_to_noise": "(int) - 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.",
|
1328
|
+
"nucleus_Signal_to_noise": "(int) - 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.",
|
1316
1329
|
"pathogen_size_range": "(list) - Size range for pathogen segmentation.",
|
1317
1330
|
"pathogen_types": "(list) - Types of pathogens to include in the analysis.",
|
1318
1331
|
"pc": "(str) - Positive control identifier.",
|
@@ -1359,10 +1372,11 @@ def generate_fields(variables, scrollable_frame):
|
|
1359
1372
|
"save_measurements": "(bool) - Whether to save the measurements to disk.",
|
1360
1373
|
"save_png": "(bool) - Whether to save the segmented objects as PNG images.",
|
1361
1374
|
"schedule": "(str) - Schedule for processing the data.",
|
1362
|
-
"Signal_to_noise": "(
|
1375
|
+
"Signal_to_noise": "(int) - Signal-to-noise ratio for the images.",
|
1363
1376
|
"skip_mode": "(str) - The mode to use for skipping images. This will determine how to handle images that cannot be processed.",
|
1364
1377
|
"smooth_lines": "(bool) - Whether to smooth lines in the plots.",
|
1365
1378
|
"src": "(str, path) - Path to source directory.",
|
1379
|
+
"segmentation_mode": "(str) - Algorithm to use for segmentation (cellpose or mediar).",
|
1366
1380
|
"target": "(str) - Target variable for the analysis.",
|
1367
1381
|
"target_height": "(int) - Target height for resizing the images.",
|
1368
1382
|
"target_intensity_min": "(float) - Minimum intensity for the target objects.",
|
@@ -1412,7 +1426,7 @@ def generate_fields(variables, scrollable_frame):
|
|
1412
1426
|
"masks": "(bool) - Whether to generate masks for the segmented objects.",
|
1413
1427
|
"timelapse": "(bool) - Whether to analyze images as a timelapse.",
|
1414
1428
|
"pathogen_min_size": "(int) - The minimum size of pathogen objects in pixels^2.",
|
1415
|
-
"pathogen_mask_dim": "(int) - The dimension of the array the pathogen mask is saved in.",
|
1429
|
+
"pathogen_mask_dim": "(int) - The dimension of the array the pathogen mask is saved in (array order:channels,cell, nucleus, pathogen, cytoplasm) array starts at dimension 0.",
|
1416
1430
|
"use_bounding_box": "(bool) - Whether to use the bounding box for cropping the images.",
|
1417
1431
|
"plot_points": "(bool) - Whether to plot scatterplot points.",
|
1418
1432
|
"embedding_by_controls": "(bool) - Use the controlls to greate the embedding, then apply this embedding to all of the data.",
|
@@ -1442,6 +1456,7 @@ def generate_fields(variables, scrollable_frame):
|
|
1442
1456
|
"shuffle": "(bool) - Shuffle the dataset bufore generating the activation maps",
|
1443
1457
|
"correlation": "(bool) - Calculate correlation between image channels and activation maps. Data is saved to .db.",
|
1444
1458
|
"normalize_input": "(bool) - Normalize the input images before passing them to the model.",
|
1459
|
+
"normalize_plots": "(bool) - Normalize images before plotting.",
|
1445
1460
|
}
|
1446
1461
|
|
1447
1462
|
for key, (var_type, options, default_value) in variables.items():
|
spacr/utils.py
CHANGED
@@ -554,7 +554,7 @@ def _get_cellpose_batch_size():
|
|
554
554
|
def _extract_filename_metadata(filenames, src, regular_expression, metadata_type='cellvoyager', pick_slice=False, skip_mode='01'):
|
555
555
|
|
556
556
|
images_by_key = defaultdict(list)
|
557
|
-
|
557
|
+
|
558
558
|
for filename in filenames:
|
559
559
|
match = regular_expression.match(filename)
|
560
560
|
if match:
|
@@ -597,7 +597,7 @@ def _extract_filename_metadata(filenames, src, regular_expression, metadata_type
|
|
597
597
|
except IndexError:
|
598
598
|
print(f"Could not extract information from filename {filename} using provided regex")
|
599
599
|
else:
|
600
|
-
print(f"Filename {filename} did not match provided regex")
|
600
|
+
print(f"Filename {filename} did not match provided regex: {regular_expression}")
|
601
601
|
continue
|
602
602
|
|
603
603
|
return images_by_key
|
@@ -9,13 +9,13 @@ 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=KYPG28Z-AX1nzZ2Fd6F5RrBU_canp_vyEzZINLYpElw,50496
|
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=
|
15
|
+
spacr/gui_core.py,sha256=qMHQPY7LZEKQ5c7dIQtRyVBy03xNmwYWO8S85btVeEw,60170
|
16
16
|
spacr/gui_elements.py,sha256=Or38I_X9-lJRsyIAtbEfZPXzls0IORagf7vEe6IlI5Y,152647
|
17
17
|
spacr/gui_utils.py,sha256=dWVPFwDj793Z3ERG4mMC0hI0MKkOrvXJpUYlcjpCBsU,41357
|
18
|
-
spacr/io.py,sha256=
|
18
|
+
spacr/io.py,sha256=bkpBQiLsd69w4GpvrY2NNbZbqHfuRCrbjELlkXBIok8,148414
|
19
19
|
spacr/logger.py,sha256=lJhTqt-_wfAunCPl93xE65Wr9Y1oIHJWaZMjunHUeIw,1538
|
20
20
|
spacr/measure.py,sha256=Z3u4BU5RzcY82IZuboQ0OsxuXaPVwOlH65Rw6FrL5z4,55045
|
21
21
|
spacr/mediar.py,sha256=FwLvbLQW5LQzPgvJZG8Lw7GniA2vbZx6Jv6vIKu7I5c,14743
|
@@ -23,14 +23,14 @@ 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=mEei8vZXMtUXVRliLGHEXbNWqgrFXA6AX3Tv6s4RmUY,89796
|
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
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=jjNCA3O7nF-Y_2c2OsAkAm5WdyD1SZ6eqV7PI3WcLdo,228617
|
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.4.dist-info/LICENSE,sha256=SR-2MeGc6SCM1UORJYyarSWY_A-JaOMFDj7ReSs9tRM,1083
|
157
|
+
spacr-0.4.4.dist-info/METADATA,sha256=EhQ8CvDWMbq7bJ18Pt_cAcz2uiRz1X7PH5gzwZdw5gw,6095
|
158
|
+
spacr-0.4.4.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
|
159
|
+
spacr-0.4.4.dist-info/entry_points.txt,sha256=BMC0ql9aNNpv8lUZ8sgDLQMsqaVnX5L535gEhKUP5ho,296
|
160
|
+
spacr-0.4.4.dist-info/top_level.txt,sha256=GJPU8FgwRXGzKeut6JopsSRY2R8T3i9lDgya42tLInY,6
|
161
|
+
spacr-0.4.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|