spacr 0.5.0__py3-none-any.whl → 0.9.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.
- spacr/__init__.py +0 -2
- spacr/__main__.py +3 -3
- spacr/core.py +13 -106
- spacr/gui_core.py +2 -77
- spacr/gui_utils.py +1 -13
- spacr/io.py +24 -25
- spacr/mediar.py +12 -8
- spacr/plot.py +50 -135
- spacr/settings.py +42 -30
- spacr/submodules.py +11 -1
- spacr/timelapse.py +7 -79
- spacr/utils.py +152 -61
- {spacr-0.5.0.dist-info → spacr-0.9.1.dist-info}/METADATA +62 -62
- spacr-0.9.1.dist-info/RECORD +109 -0
- {spacr-0.5.0.dist-info → spacr-0.9.1.dist-info}/WHEEL +1 -1
- spacr/resources/MEDIAR/.gitignore +0 -18
- spacr/resources/MEDIAR/LICENSE +0 -21
- spacr/resources/MEDIAR/README.md +0 -189
- spacr/resources/MEDIAR/SetupDict.py +0 -39
- spacr/resources/MEDIAR/__pycache__/SetupDict.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/__pycache__/evaluate.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/__pycache__/generate_mapping.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/__pycache__/main.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/config/baseline.json +0 -60
- spacr/resources/MEDIAR/config/mediar_example.json +0 -72
- spacr/resources/MEDIAR/config/pred/pred_mediar.json +0 -17
- spacr/resources/MEDIAR/config/step1_pretraining/phase1.json +0 -55
- spacr/resources/MEDIAR/config/step1_pretraining/phase2.json +0 -58
- spacr/resources/MEDIAR/config/step2_finetuning/finetuning1.json +0 -66
- spacr/resources/MEDIAR/config/step2_finetuning/finetuning2.json +0 -66
- spacr/resources/MEDIAR/config/step3_prediction/base_prediction.json +0 -16
- spacr/resources/MEDIAR/config/step3_prediction/ensemble_tta.json +0 -23
- spacr/resources/MEDIAR/core/BasePredictor.py +0 -120
- spacr/resources/MEDIAR/core/BaseTrainer.py +0 -240
- spacr/resources/MEDIAR/core/Baseline/Predictor.py +0 -59
- spacr/resources/MEDIAR/core/Baseline/Trainer.py +0 -113
- spacr/resources/MEDIAR/core/Baseline/__init__.py +0 -2
- spacr/resources/MEDIAR/core/Baseline/__pycache__/Predictor.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/Baseline/__pycache__/Trainer.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/Baseline/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/Baseline/__pycache__/utils.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/Baseline/utils.py +0 -80
- spacr/resources/MEDIAR/core/MEDIAR/EnsemblePredictor.py +0 -105
- spacr/resources/MEDIAR/core/MEDIAR/Predictor.py +0 -234
- spacr/resources/MEDIAR/core/MEDIAR/Trainer.py +0 -172
- spacr/resources/MEDIAR/core/MEDIAR/__init__.py +0 -3
- spacr/resources/MEDIAR/core/MEDIAR/__pycache__/EnsemblePredictor.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/MEDIAR/__pycache__/Predictor.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/MEDIAR/__pycache__/Trainer.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/MEDIAR/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/MEDIAR/__pycache__/utils.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/MEDIAR/utils.py +0 -429
- spacr/resources/MEDIAR/core/__init__.py +0 -2
- spacr/resources/MEDIAR/core/__pycache__/BasePredictor.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/__pycache__/BaseTrainer.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/__pycache__/utils.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/utils.py +0 -40
- spacr/resources/MEDIAR/evaluate.py +0 -71
- spacr/resources/MEDIAR/generate_mapping.py +0 -121
- spacr/resources/MEDIAR/image/examples/img1.tiff +0 -0
- spacr/resources/MEDIAR/image/examples/img2.tif +0 -0
- spacr/resources/MEDIAR/image/failure_cases.png +0 -0
- spacr/resources/MEDIAR/image/mediar_framework.png +0 -0
- spacr/resources/MEDIAR/image/mediar_model.PNG +0 -0
- spacr/resources/MEDIAR/image/mediar_results.png +0 -0
- spacr/resources/MEDIAR/main.py +0 -125
- spacr/resources/MEDIAR/predict.py +0 -70
- spacr/resources/MEDIAR/requirements.txt +0 -14
- spacr/resources/MEDIAR/train_tools/__init__.py +0 -3
- spacr/resources/MEDIAR/train_tools/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/__pycache__/measures.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/__pycache__/utils.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/__init__.py +0 -1
- spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/datasetter.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/transforms.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/utils.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/custom/CellAware.py +0 -88
- spacr/resources/MEDIAR/train_tools/data_utils/custom/LoadImage.py +0 -161
- spacr/resources/MEDIAR/train_tools/data_utils/custom/NormalizeImage.py +0 -77
- spacr/resources/MEDIAR/train_tools/data_utils/custom/__init__.py +0 -3
- spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/CellAware.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/LoadImage.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/NormalizeImage.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/custom/modalities.pkl +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/datasetter.py +0 -208
- spacr/resources/MEDIAR/train_tools/data_utils/transforms.py +0 -148
- spacr/resources/MEDIAR/train_tools/data_utils/utils.py +0 -84
- spacr/resources/MEDIAR/train_tools/measures.py +0 -200
- spacr/resources/MEDIAR/train_tools/models/MEDIARFormer.py +0 -102
- spacr/resources/MEDIAR/train_tools/models/__init__.py +0 -1
- spacr/resources/MEDIAR/train_tools/models/__pycache__/MEDIARFormer.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/models/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/utils.py +0 -70
- spacr-0.5.0.dist-info/RECORD +0 -190
- {spacr-0.5.0.dist-info → spacr-0.9.1.dist-info}/LICENSE +0 -0
- {spacr-0.5.0.dist-info → spacr-0.9.1.dist-info}/entry_points.txt +0 -0
- {spacr-0.5.0.dist-info → spacr-0.9.1.dist-info}/top_level.txt +0 -0
spacr/plot.py
CHANGED
@@ -1241,103 +1241,6 @@ def _display_gif(path):
|
|
1241
1241
|
"""
|
1242
1242
|
with open(path, 'rb') as file:
|
1243
1243
|
display(ipyimage(file.read()))
|
1244
|
-
|
1245
|
-
def _plot_recruitment_v2(df, df_type, channel_of_interest, columns=[], figuresize=10):
|
1246
|
-
"""
|
1247
|
-
Plot recruitment data for different conditions and pathogens.
|
1248
|
-
|
1249
|
-
Args:
|
1250
|
-
df (DataFrame): The input DataFrame containing the recruitment data.
|
1251
|
-
df_type (str): The type of DataFrame (e.g., 'train', 'test').
|
1252
|
-
channel_of_interest (str): The channel of interest for plotting.
|
1253
|
-
target (str): The target variable for plotting.
|
1254
|
-
columns (list, optional): Additional columns to plot. Defaults to an empty list.
|
1255
|
-
figuresize (int, optional): The size of the figure. Defaults to 50.
|
1256
|
-
|
1257
|
-
Returns:
|
1258
|
-
None
|
1259
|
-
"""
|
1260
|
-
|
1261
|
-
color_list = [(55/255, 155/255, 155/255),
|
1262
|
-
(155/255, 55/255, 155/255),
|
1263
|
-
(55/255, 155/255, 255/255),
|
1264
|
-
(255/255, 55/255, 155/255)]
|
1265
|
-
|
1266
|
-
sns.set_palette(sns.color_palette(color_list))
|
1267
|
-
font = figuresize/2
|
1268
|
-
width=figuresize
|
1269
|
-
height=figuresize/4
|
1270
|
-
|
1271
|
-
# Create the subplots
|
1272
|
-
fig, axes = plt.subplots(nrows=1, ncols=4, figsize=(width, height))
|
1273
|
-
|
1274
|
-
# Plot for 'cell_channel' on axes[0]
|
1275
|
-
plotter_cell = spacrGraph(df,grouping_column='condition', data_column=f'cell_channel_{channel_of_interest}_mean_intensity')
|
1276
|
-
plotter_cell.create_plot(ax=axes[0])
|
1277
|
-
axes[0].set_xlabel(f'pathogen {df_type}', fontsize=font)
|
1278
|
-
axes[0].set_ylabel(f'cell_channel_{channel_of_interest}_mean_intensity', fontsize=font)
|
1279
|
-
|
1280
|
-
# Plot for 'nucleus_channel' on axes[1]
|
1281
|
-
plotter_nucleus = spacrGraph(df,grouping_column='condition', data_column=f'nucleus_channel_{channel_of_interest}_mean_intensity')
|
1282
|
-
plotter_nucleus.create_plot(ax=axes[1])
|
1283
|
-
axes[1].set_xlabel(f'pathogen {df_type}', fontsize=font)
|
1284
|
-
axes[1].set_ylabel(f'nucleus_channel_{channel_of_interest}_mean_intensity', fontsize=font)
|
1285
|
-
|
1286
|
-
# Plot for 'cytoplasm_channel' on axes[2]
|
1287
|
-
plotter_cytoplasm = spacrGraph(df, grouping_column='condition', data_column=f'cytoplasm_channel_{channel_of_interest}_mean_intensity')
|
1288
|
-
plotter_cytoplasm.create_plot(ax=axes[2])
|
1289
|
-
axes[2].set_xlabel(f'pathogen {df_type}', fontsize=font)
|
1290
|
-
axes[2].set_ylabel(f'cytoplasm_channel_{channel_of_interest}_mean_intensity', fontsize=font)
|
1291
|
-
|
1292
|
-
# Plot for 'pathogen_channel' on axes[3]
|
1293
|
-
plotter_pathogen = spacrGraph(df, grouping_column='condition', data_column=f'pathogen_channel_{channel_of_interest}_mean_intensity')
|
1294
|
-
plotter_pathogen.create_plot(ax=axes[3])
|
1295
|
-
axes[3].set_xlabel(f'pathogen {df_type}', fontsize=font)
|
1296
|
-
axes[3].set_ylabel(f'pathogen_channel_{channel_of_interest}_mean_intensity', fontsize=font)
|
1297
|
-
|
1298
|
-
#axes[0].legend_.remove()
|
1299
|
-
#axes[1].legend_.remove()
|
1300
|
-
#axes[2].legend_.remove()
|
1301
|
-
#axes[3].legend_.remove()
|
1302
|
-
|
1303
|
-
handles, labels = axes[3].get_legend_handles_labels()
|
1304
|
-
axes[3].legend(handles, labels, bbox_to_anchor=(1.05, 0.5), loc='center left')
|
1305
|
-
for i in [0,1,2,3]:
|
1306
|
-
axes[i].tick_params(axis='both', which='major', labelsize=font)
|
1307
|
-
axes[i].set_xticklabels(axes[i].get_xticklabels(), rotation=45)
|
1308
|
-
|
1309
|
-
plt.tight_layout()
|
1310
|
-
plt.show()
|
1311
|
-
|
1312
|
-
columns = columns + ['pathogen_cytoplasm_mean_mean', 'pathogen_cytoplasm_q75_mean', 'pathogen_periphery_cytoplasm_mean_mean', 'pathogen_outside_cytoplasm_mean_mean', 'pathogen_outside_cytoplasm_q75_mean']
|
1313
|
-
#columns = columns + [f'pathogen_slope_channel_{channel_of_interest}', f'pathogen_cell_distance_channel_{channel_of_interest}', f'nucleus_cell_distance_channel_{channel_of_interest}']
|
1314
|
-
|
1315
|
-
width = figuresize*2
|
1316
|
-
columns_per_row = math.ceil(len(columns) / 2)
|
1317
|
-
height = (figuresize*2)/columns_per_row
|
1318
|
-
|
1319
|
-
fig, axes = plt.subplots(nrows=2, ncols=columns_per_row, figsize=(width, height * 2))
|
1320
|
-
axes = axes.flatten()
|
1321
|
-
|
1322
|
-
print(f'{columns}')
|
1323
|
-
for i, col in enumerate(columns):
|
1324
|
-
ax = axes[i]
|
1325
|
-
plotter_col = spacrGraph(df, grouping_column='condition', data_column=col)
|
1326
|
-
plotter_col.create_plot(ax=ax)
|
1327
|
-
ax.set_xlabel(f'pathogen {df_type}', fontsize=font)
|
1328
|
-
ax.set_ylabel(f'{col}', fontsize=int(font * 2))
|
1329
|
-
#ax.legend_.remove()
|
1330
|
-
ax.tick_params(axis='both', which='major', labelsize=font)
|
1331
|
-
ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
|
1332
|
-
if i <= 5:
|
1333
|
-
ax.set_ylim(1, None)
|
1334
|
-
|
1335
|
-
# Turn off any unused axes
|
1336
|
-
for i in range(len(columns), len(axes)):
|
1337
|
-
axes[i].axis('off')
|
1338
|
-
|
1339
|
-
plt.tight_layout()
|
1340
|
-
plt.show()
|
1341
1244
|
|
1342
1245
|
def _plot_recruitment(df, df_type, channel_of_interest, columns=[], figuresize=10):
|
1343
1246
|
"""
|
@@ -1414,7 +1317,8 @@ def _plot_recruitment(df, df_type, channel_of_interest, columns=[], figuresize=1
|
|
1414
1317
|
sns.barplot(ax=ax, data=df, x='condition', y=f'{col}', hue='pathogen', capsize=.1, ci='sd', dodge=False)
|
1415
1318
|
ax.set_xlabel(f'pathogen {df_type}', fontsize=font)
|
1416
1319
|
ax.set_ylabel(f'{col}', fontsize=int(font*2))
|
1417
|
-
ax.
|
1320
|
+
if ax.get_legend() is not None:
|
1321
|
+
ax.legend_.remove()
|
1418
1322
|
ax.tick_params(axis='both', which='major', labelsize=font)
|
1419
1323
|
ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
|
1420
1324
|
if i <= 5:
|
@@ -1842,31 +1746,6 @@ def print_mask_and_flows(stack, mask, flows, overlay=True, max_size=1000, thickn
|
|
1842
1746
|
fig.tight_layout()
|
1843
1747
|
plt.show()
|
1844
1748
|
|
1845
|
-
def plot_resize_v1(images, resized_images, labels, resized_labels):
|
1846
|
-
# Display an example image and label before and after resizing
|
1847
|
-
fig, ax = plt.subplots(2, 2, figsize=(20, 20))
|
1848
|
-
|
1849
|
-
# Check if the image is grayscale; if so, add a colormap and keep dimensions correct
|
1850
|
-
if images[0].ndim == 2: # Grayscale image
|
1851
|
-
ax[0, 0].imshow(images[0], cmap='gray')
|
1852
|
-
else: # RGB or RGBA image
|
1853
|
-
ax[0, 0].imshow(images[0])
|
1854
|
-
ax[0, 0].set_title('Original Image')
|
1855
|
-
|
1856
|
-
if resized_images[0].ndim == 2: # Grayscale image
|
1857
|
-
ax[0, 1].imshow(resized_images[0], cmap='gray')
|
1858
|
-
else: # RGB or RGBA image
|
1859
|
-
ax[0, 1].imshow(resized_images[0])
|
1860
|
-
ax[0, 1].set_title('Resized Image')
|
1861
|
-
|
1862
|
-
# Assuming labels are always grayscale (most common scenario)
|
1863
|
-
ax[1, 0].imshow(labels[0], cmap='gray')
|
1864
|
-
ax[1, 0].set_title('Original Label')
|
1865
|
-
ax[1, 1].imshow(resized_labels[0], cmap='gray')
|
1866
|
-
ax[1, 1].set_title('Resized Label')
|
1867
|
-
plt.show()
|
1868
|
-
|
1869
|
-
|
1870
1749
|
def plot_resize(images, resized_images, labels, resized_labels):
|
1871
1750
|
def prepare_image(img):
|
1872
1751
|
if img.ndim == 2:
|
@@ -2031,7 +1910,7 @@ def plot_comparison_results(comparison_results):
|
|
2031
1910
|
def plot_object_outlines(src, objects=['nucleus','cell','pathogen'], channels=[0,1,2], max_nr=10):
|
2032
1911
|
|
2033
1912
|
for object_, channel in zip(objects, channels):
|
2034
|
-
folders = [os.path.join(src, '
|
1913
|
+
folders = [os.path.join(src, 'masks', f'{object_}_mask_stack'),
|
2035
1914
|
os.path.join(src,f'{channel+1}')]
|
2036
1915
|
print(folders)
|
2037
1916
|
plot_images_and_arrays(folders,
|
@@ -2597,7 +2476,7 @@ class spacrGraph:
|
|
2597
2476
|
# Group by ['prc', grouping_column]
|
2598
2477
|
group_cols = ['prc', self.grouping_column]
|
2599
2478
|
|
2600
|
-
elif self.representation == '
|
2479
|
+
elif self.representation == 'plate':
|
2601
2480
|
# Make sure 'plateID' exists (split from 'prc' if needed)
|
2602
2481
|
if 'plateID' not in df.columns:
|
2603
2482
|
if 'prc' in df.columns:
|
@@ -2930,6 +2809,7 @@ class spacrGraph:
|
|
2930
2809
|
self.df_melted = pd.melt(self.df, id_vars=[self.grouping_column], value_vars=self.data_column,var_name='Data Column', value_name='Value')
|
2931
2810
|
unique_groups = self.df[self.grouping_column].unique()
|
2932
2811
|
is_normal, normality_results = self.perform_normality_tests()
|
2812
|
+
is_normal = True
|
2933
2813
|
levene_stat, levene_p = self.perform_levene_test(unique_groups)
|
2934
2814
|
test_results = self.perform_statistical_tests(unique_groups, is_normal)
|
2935
2815
|
posthoc_results = self.perform_posthoc_tests(is_normal, unique_groups)
|
@@ -3371,8 +3251,11 @@ class spacrGraph:
|
|
3371
3251
|
return self.fig
|
3372
3252
|
|
3373
3253
|
def plot_data_from_db(settings):
|
3254
|
+
|
3374
3255
|
from .io import _read_db, _read_and_merge_data
|
3375
3256
|
from .utils import annotate_conditions, save_settings
|
3257
|
+
from .settings import set_default_plot_data_from_db
|
3258
|
+
|
3376
3259
|
"""
|
3377
3260
|
Extracts the specified table from the SQLite database and plots a specified column.
|
3378
3261
|
|
@@ -3385,8 +3268,8 @@ def plot_data_from_db(settings):
|
|
3385
3268
|
df (pd.DataFrame): The extracted table as a DataFrame.
|
3386
3269
|
"""
|
3387
3270
|
|
3388
|
-
|
3389
|
-
|
3271
|
+
settings = set_default_plot_data_from_db(settings)
|
3272
|
+
|
3390
3273
|
if isinstance(settings['src'], str):
|
3391
3274
|
srcs = [settings['src']]
|
3392
3275
|
elif isinstance(settings['src'], list):
|
@@ -3403,7 +3286,6 @@ def plot_data_from_db(settings):
|
|
3403
3286
|
|
3404
3287
|
dfs = []
|
3405
3288
|
for i, src in enumerate(srcs):
|
3406
|
-
|
3407
3289
|
db_loc = os.path.join(src, 'measurements', settings['database'][i])
|
3408
3290
|
print(f"Database: {db_loc}")
|
3409
3291
|
if settings['table_names'] in ['saliency_image_correlations']:
|
@@ -3415,7 +3297,7 @@ def plot_data_from_db(settings):
|
|
3415
3297
|
verbose=settings['verbose'],
|
3416
3298
|
nuclei_limit=settings['nuclei_limit'],
|
3417
3299
|
pathogen_limit=settings['pathogen_limit'])
|
3418
|
-
|
3300
|
+
|
3419
3301
|
dft = annotate_conditions(df1,
|
3420
3302
|
cells=settings['cell_types'],
|
3421
3303
|
cell_loc=settings['cell_plate_metadata'],
|
@@ -3436,12 +3318,27 @@ def plot_data_from_db(settings):
|
|
3436
3318
|
|
3437
3319
|
if settings['treatment_plate_metadata'] != None:
|
3438
3320
|
df = df.dropna(subset='treatment')
|
3439
|
-
|
3321
|
+
|
3322
|
+
if settings['data_column'] == 'recruitment':
|
3323
|
+
pahtogen_measurement = df[f"pathogen_channel_{settings['channel_of_interest']}_mean_intensity"]
|
3324
|
+
cytoplasm_measurement = df[f"cytoplasm_channel_{settings['channel_of_interest']}_mean_intensity"]
|
3325
|
+
df['recruitment'] = pahtogen_measurement / cytoplasm_measurement
|
3326
|
+
|
3327
|
+
if settings['data_column'] not in df.columns:
|
3328
|
+
print(f"Data column {settings['data_column']} not found in DataFrame.")
|
3329
|
+
print(f'Please use one of the following columns:')
|
3330
|
+
for col in df.columns:
|
3331
|
+
print(col)
|
3332
|
+
display(df)
|
3333
|
+
return None
|
3334
|
+
|
3440
3335
|
df = df.dropna(subset=settings['data_column'])
|
3441
3336
|
|
3442
3337
|
if settings['grouping_column'] not in df.columns:
|
3443
3338
|
print(f"Grouping column {settings['grouping_column']} not found in DataFrame.")
|
3444
|
-
print(f'Please use one of the following columns:
|
3339
|
+
print(f'Please use one of the following columns:')
|
3340
|
+
for col in df.columns:
|
3341
|
+
print(col)
|
3445
3342
|
display(df)
|
3446
3343
|
return None
|
3447
3344
|
|
@@ -3480,7 +3377,8 @@ def plot_data_from_db(settings):
|
|
3480
3377
|
|
3481
3378
|
def plot_data_from_csv(settings):
|
3482
3379
|
from .io import _read_db, _read_and_merge_data
|
3483
|
-
from .utils import annotate_conditions, save_settings
|
3380
|
+
from .utils import annotate_conditions, save_settings, remove_outliers_by_group
|
3381
|
+
from .settings import get_plot_data_from_csv_default_settings
|
3484
3382
|
"""
|
3485
3383
|
Extracts the specified table from the SQLite database and plots a specified column.
|
3486
3384
|
|
@@ -3492,7 +3390,12 @@ def plot_data_from_csv(settings):
|
|
3492
3390
|
Returns:
|
3493
3391
|
df (pd.DataFrame): The extracted table as a DataFrame.
|
3494
3392
|
"""
|
3393
|
+
|
3495
3394
|
|
3395
|
+
def filter_rows_by_column_values(df: pd.DataFrame, column: str, values: list) -> pd.DataFrame:
|
3396
|
+
"""Return a filtered DataFrame where only rows with the column value in the list are kept."""
|
3397
|
+
return df[df[column].isin(values)].copy()
|
3398
|
+
|
3496
3399
|
if isinstance(settings['src'], str):
|
3497
3400
|
srcs = [settings['src']]
|
3498
3401
|
elif isinstance(settings['src'], list):
|
@@ -3519,15 +3422,27 @@ def plot_data_from_csv(settings):
|
|
3519
3422
|
except Exception as e:
|
3520
3423
|
print(f"Could not split the prc column: {e}")
|
3521
3424
|
|
3522
|
-
|
3523
|
-
|
3524
|
-
|
3425
|
+
if 'keep_groups' in settings.keys():
|
3426
|
+
if isinstance(settings['keep_groups'], str):
|
3427
|
+
settings['keep_groups'] = [settings['keep_groups']]
|
3428
|
+
elif isinstance(settings['keep_groups'], list):
|
3429
|
+
df = filter_rows_by_column_values(df, settings['grouping_column'], settings['keep_groups'])
|
3430
|
+
|
3431
|
+
if settings['remove_outliers']:
|
3432
|
+
df = remove_outliers_by_group(df, settings['grouping_column'], settings['data_column'], method='iqr', threshold=1.5)
|
3433
|
+
|
3434
|
+
if settings['verbose']:
|
3435
|
+
display(df)
|
3436
|
+
|
3525
3437
|
df = df.dropna(subset=settings['data_column'])
|
3526
3438
|
df = df.dropna(subset=settings['grouping_column'])
|
3527
3439
|
src = srcs[0]
|
3528
3440
|
dst = os.path.join(os.path.dirname(src), 'results', settings['graph_name'])
|
3529
3441
|
os.makedirs(dst, exist_ok=True)
|
3530
3442
|
|
3443
|
+
#data_csv = os.path.join(dst, f"{settings['graph_name']}_data.csv")
|
3444
|
+
#df.to_csv(data_csv, index=False)
|
3445
|
+
|
3531
3446
|
spacr_graph = spacrGraph(
|
3532
3447
|
df=df, # Your DataFrame
|
3533
3448
|
grouping_column=settings['grouping_column'], # Column for grouping the data (x-axis)
|
spacr/settings.py
CHANGED
@@ -29,7 +29,6 @@ def set_default_settings_preprocess_generate_masks(settings={}):
|
|
29
29
|
settings.setdefault('denoise', False)
|
30
30
|
settings.setdefault('src', 'path')
|
31
31
|
settings.setdefault('delete_intermediate', False)
|
32
|
-
settings.setdefault('segmentation_mode', 'cellpose')
|
33
32
|
settings.setdefault('preprocess', True)
|
34
33
|
settings.setdefault('masks', True)
|
35
34
|
settings.setdefault('save', True)
|
@@ -100,30 +99,30 @@ def set_default_settings_preprocess_generate_masks(settings={}):
|
|
100
99
|
settings.setdefault('adjust_cells', False)
|
101
100
|
return settings
|
102
101
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
return settings
|
102
|
+
def set_default_plot_data_from_db(settings):
|
103
|
+
settings.setdefault('src', 'path')
|
104
|
+
settings.setdefault('database', 'measurements.db')
|
105
|
+
settings.setdefault('graph_name', 'Figure_1')
|
106
|
+
settings.setdefault('table_names', ['cell', 'cytoplasm', 'nucleus', 'pathogen'])
|
107
|
+
settings.setdefault('data_column', 'recruitment')
|
108
|
+
settings.setdefault('grouping_column', 'condition')
|
109
|
+
settings.setdefault('cell_types', ['Hela'])
|
110
|
+
settings.setdefault('cell_plate_metadata', None)
|
111
|
+
settings.setdefault('pathogen_types', None)
|
112
|
+
settings.setdefault('pathogen_plate_metadata', None)
|
113
|
+
settings.setdefault('treatments', None)
|
114
|
+
settings.setdefault('treatment_plate_metadata', None)
|
115
|
+
settings.setdefault('graph_type', 'jitter')
|
116
|
+
settings.setdefault('theme', 'deep')
|
117
|
+
settings.setdefault('save', True)
|
118
|
+
settings.setdefault('y_lim', [1,1.5])
|
119
|
+
settings.setdefault('verbose', False)
|
120
|
+
settings.setdefault('channel_of_interest', 1)
|
121
|
+
settings.setdefault('nuclei_limit', 2)
|
122
|
+
settings.setdefault('pathogen_limit', 3)
|
123
|
+
settings.setdefault('representation', 'well')
|
124
|
+
settings.setdefault('uninfected', False)
|
125
|
+
return settings
|
127
126
|
|
128
127
|
def set_default_settings_preprocess_img_data(settings):
|
129
128
|
|
@@ -955,7 +954,6 @@ expected_types = {
|
|
955
954
|
"png_type":str,
|
956
955
|
"custom_model_path":str,
|
957
956
|
"generate_training_dataset":bool,
|
958
|
-
"segmentation_mode":str,
|
959
957
|
"train_DL_model":bool,
|
960
958
|
"normalize":bool,
|
961
959
|
"overlay":bool,
|
@@ -1006,7 +1004,7 @@ expected_types = {
|
|
1006
1004
|
}
|
1007
1005
|
|
1008
1006
|
categories = {"Paths":[ "src", "grna", "barcodes", "custom_model_path", "dataset","model_path","grna_csv","row_csv","column_csv", "metadata_files", "score_data","count_data"],
|
1009
|
-
"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", "
|
1007
|
+
"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", "delete_intermediate", "uninfected", ],
|
1010
1008
|
"Cellpose":["denoise","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"],
|
1011
1009
|
"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"],
|
1012
1010
|
"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"],
|
@@ -1217,7 +1215,7 @@ def generate_fields(variables, scrollable_frame):
|
|
1217
1215
|
"nucleus_min_size": "(int) - The minimum size of nucleus objects in pixels^2.",
|
1218
1216
|
"normalize_by": "(str) - Normalize cropped png images by png or by field of view.",
|
1219
1217
|
"dependent_variable": "(str) - The dependent variable for the regression analysis.",
|
1220
|
-
"delete_intermediate": "(bool) - Delete intermediate folders (stack, channel,
|
1218
|
+
"delete_intermediate": "(bool) - Delete intermediate folders (stack, channel, masks).",
|
1221
1219
|
"diameter": "(float) - Diameter of the objects to segment.",
|
1222
1220
|
"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.",
|
1223
1221
|
"dialate_pngs": "(bool) - Whether to dilate the PNG images before saving.",
|
@@ -1337,7 +1335,6 @@ def generate_fields(variables, scrollable_frame):
|
|
1337
1335
|
"skip_mode": "(str) - The mode to use for skipping images. This will determine how to handle images that cannot be processed.",
|
1338
1336
|
"smooth_lines": "(bool) - Whether to smooth lines in the plots.",
|
1339
1337
|
"src": "(str, path) - Path to source directory.",
|
1340
|
-
"segmentation_mode": "(str) - Algorithm to use for segmentation (cellpose or mediar).",
|
1341
1338
|
"target": "(str) - Target variable for the analysis.",
|
1342
1339
|
"target_height": "(int) - Target height for resizing the images.",
|
1343
1340
|
"target_intensity_min": "(float) - Minimum intensity for the target objects.",
|
@@ -1376,7 +1373,6 @@ def generate_fields(variables, scrollable_frame):
|
|
1376
1373
|
"dataset_mode": "str - How to generate train/test dataset.",
|
1377
1374
|
"annotated_classes": "list - list of numbers in annotation column.",
|
1378
1375
|
"um_per_pixel": "(float) - The micrometers per pixel for the images.",
|
1379
|
-
"segmentation_model": "(str) - The segmentation model to use, either cellpose or mediar.",
|
1380
1376
|
"pathogen_model": "(str) - use a custom cellpose model to detect pathogen objects.",
|
1381
1377
|
"timelapse_displacement": "(int) - Displacement for timelapse tracking.",
|
1382
1378
|
"timelapse_memory": "(int) - Memory for timelapse tracking.",
|
@@ -1596,4 +1592,20 @@ def set_analyze_class_proportion_defaults(settings):
|
|
1596
1592
|
settings.setdefault('level','well')
|
1597
1593
|
settings.setdefault('save',False)
|
1598
1594
|
settings.setdefault('verbose', False)
|
1595
|
+
return settings
|
1596
|
+
|
1597
|
+
def get_plot_data_from_csv_default_settings(settings):
|
1598
|
+
settings.setdefault('src','path')
|
1599
|
+
settings.setdefault('data_column','choose column')
|
1600
|
+
settings.setdefault('grouping_column','choose column')
|
1601
|
+
settings.setdefault('graph_type','violin')
|
1602
|
+
settings.setdefault('save',False)
|
1603
|
+
settings.setdefault('y_lim',None)
|
1604
|
+
settings.setdefault('log_y',False)
|
1605
|
+
settings.setdefault('log_x',False)
|
1606
|
+
settings.setdefault('keep_groups',None)
|
1607
|
+
settings.setdefault('representation','well')
|
1608
|
+
settings.setdefault('theme','dark')
|
1609
|
+
settings.setdefault('remove_outliers',False)
|
1610
|
+
settings.setdefault('verbose',False)
|
1599
1611
|
return settings
|
spacr/submodules.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import seaborn as sns
|
2
|
-
import os, random, sqlite3, re, shap, string, time
|
2
|
+
import os, random, sqlite3, re, shap, string, time, shutil
|
3
3
|
import pandas as pd
|
4
4
|
import numpy as np
|
5
5
|
|
@@ -580,6 +580,16 @@ def analyze_recruitment(settings):
|
|
580
580
|
from .settings import get_analyze_recruitment_default_settings
|
581
581
|
|
582
582
|
settings = get_analyze_recruitment_default_settings(settings=settings)
|
583
|
+
|
584
|
+
if settings['src'].endswith('/measurements.db'):
|
585
|
+
src_orig = settings['src']
|
586
|
+
settings['src'] = os.path.dirname(settings['src'])
|
587
|
+
if not settings['src'].endswith('/measurements'):
|
588
|
+
src_mes = os.path.join(settings['src'], 'measurements')
|
589
|
+
if not os.path.exists(src_mes):
|
590
|
+
os.makedirs(src_mes)
|
591
|
+
shutil.move(src_orig, os.path.join(src_mes, 'measurements.db'))
|
592
|
+
|
583
593
|
save_settings(settings, name='recruitment')
|
584
594
|
|
585
595
|
print(f"Cell(s): {settings['cell_types']}, in {settings['cell_plate_metadata']}")
|
spacr/timelapse.py
CHANGED
@@ -255,57 +255,25 @@ def _relabel_masks_based_on_tracks(masks, tracks, mode='btrack'):
|
|
255
255
|
|
256
256
|
return relabeled_masks
|
257
257
|
|
258
|
-
def _prepare_for_tracking_v1(mask_array):
|
259
|
-
"""
|
260
|
-
Prepare the mask array for object tracking.
|
261
|
-
|
262
|
-
Args:
|
263
|
-
mask_array (ndarray): Array of binary masks representing objects.
|
264
|
-
|
265
|
-
Returns:
|
266
|
-
DataFrame: DataFrame containing information about each object in the mask array.
|
267
|
-
The DataFrame has the following columns:
|
268
|
-
- frame: The frame number.
|
269
|
-
- y: The y-coordinate of the object's centroid.
|
270
|
-
- x: The x-coordinate of the object's centroid.
|
271
|
-
- mass: The area of the object.
|
272
|
-
- original_label: The original label of the object.
|
273
|
-
|
274
|
-
"""
|
275
|
-
frames = []
|
276
|
-
for t, frame in enumerate(mask_array):
|
277
|
-
props = regionprops(frame)
|
278
|
-
for obj in props:
|
279
|
-
# Include 'label' in the dictionary to capture the original label of the object
|
280
|
-
frames.append({
|
281
|
-
'frame': t,
|
282
|
-
'y': obj.centroid[0],
|
283
|
-
'x': obj.centroid[1],
|
284
|
-
'mass': obj.area,
|
285
|
-
'original_label': obj.label # Capture the original label
|
286
|
-
})
|
287
|
-
return pd.DataFrame(frames)
|
288
|
-
|
289
258
|
def _prepare_for_tracking(mask_array):
|
290
259
|
frames = []
|
291
260
|
for t, frame in enumerate(mask_array):
|
292
261
|
props = regionprops_table(
|
293
262
|
frame,
|
294
|
-
properties=('label', 'centroid
|
295
|
-
'bbox-0', 'bbox-1', 'bbox-2', 'bbox-3',
|
296
|
-
'eccentricity')
|
263
|
+
properties=('label', 'centroid', 'area', 'bbox', 'eccentricity')
|
297
264
|
)
|
298
265
|
df = pd.DataFrame(props)
|
299
266
|
df = df.rename(columns={
|
300
|
-
'centroid-0': 'y',
|
301
|
-
'
|
267
|
+
'centroid-0': 'y',
|
268
|
+
'centroid-1': 'x',
|
269
|
+
'area': 'mass',
|
270
|
+
'label': 'original_label'
|
302
271
|
})
|
303
272
|
df['frame'] = t
|
304
273
|
frames.append(df[['frame','y','x','mass','original_label',
|
305
274
|
'bbox-0','bbox-1','bbox-2','bbox-3','eccentricity']])
|
306
275
|
return pd.concat(frames, ignore_index=True)
|
307
276
|
|
308
|
-
|
309
277
|
def _track_by_iou(masks, iou_threshold=0.1):
|
310
278
|
"""
|
311
279
|
Build a track table by linking masks frame→frame via IoU.
|
@@ -504,47 +472,7 @@ def _facilitate_trackin_with_adaptive_removal(masks, search_range=None, max_atte
|
|
504
472
|
f"Failed to track after {max_attempts} attempts; last search_range={search_range}"
|
505
473
|
)
|
506
474
|
|
507
|
-
def
|
508
|
-
"""
|
509
|
-
Facilitates object tracking with adaptive removal.
|
510
|
-
|
511
|
-
Args:
|
512
|
-
masks (numpy.ndarray): Array of binary masks representing objects in each frame.
|
513
|
-
search_range (int, optional): Maximum distance objects can move between frames. Defaults to 500.
|
514
|
-
max_attempts (int, optional): Maximum number of attempts to track objects. Defaults to 100.
|
515
|
-
memory (int, optional): Number of frames to remember when linking tracks. Defaults to 3.
|
516
|
-
|
517
|
-
Returns:
|
518
|
-
tuple: A tuple containing the updated masks, features, and tracks_df.
|
519
|
-
masks (numpy.ndarray): Updated array of binary masks.
|
520
|
-
features (pandas.DataFrame): DataFrame containing features for object tracking.
|
521
|
-
tracks_df (pandas.DataFrame): DataFrame containing the tracked object trajectories.
|
522
|
-
|
523
|
-
Raises:
|
524
|
-
Exception: If tracking fails after the maximum number of attempts.
|
525
|
-
|
526
|
-
"""
|
527
|
-
attempts = 0
|
528
|
-
first_frame = masks[0]
|
529
|
-
starting_objects = np.unique(first_frame[first_frame != 0])
|
530
|
-
while attempts < max_attempts:
|
531
|
-
try:
|
532
|
-
masks = _remove_objects_from_first_frame(masks, 10)
|
533
|
-
first_frame = masks[0]
|
534
|
-
objects = np.unique(first_frame[first_frame != 0])
|
535
|
-
print(len(objects))
|
536
|
-
features = _prepare_for_tracking(masks)
|
537
|
-
tracks_df = tp.link(features, search_range=search_range, memory=memory)
|
538
|
-
print(f"Success with {len(objects)} objects, started with {len(starting_objects)} objects")
|
539
|
-
return masks, features, tracks_df
|
540
|
-
except Exception as e: # Consider catching a more specific exception if possible
|
541
|
-
print(f"Retrying with fewer objects. Exception: {e}", flush=True)
|
542
|
-
finally:
|
543
|
-
attempts += 1
|
544
|
-
print(f"Failed to track objects after {max_attempts} attempts. Consider adjusting parameters.")
|
545
|
-
return None, None, None
|
546
|
-
|
547
|
-
def _trackpy_track_cells(src, name, batch_filenames, object_type, masks, timelapse_displacement, timelapse_memory, timelapse_remove_transient, plot, save, mode):
|
475
|
+
def _trackpy_track_cells(src, name, batch_filenames, object_type, masks, timelapse_displacement, timelapse_memory, timelapse_remove_transient, plot, save, mode, track_by_iou):
|
548
476
|
"""
|
549
477
|
Track cells using the Trackpy library.
|
550
478
|
|
@@ -577,7 +505,7 @@ def _trackpy_track_cells(src, name, batch_filenames, object_type, masks, timelap
|
|
577
505
|
if timelapse_displacement is None:
|
578
506
|
timelapse_displacement = 50
|
579
507
|
|
580
|
-
masks, features, tracks_df = _facilitate_trackin_with_adaptive_removal(masks, search_range=timelapse_displacement, max_attempts=100, memory=timelapse_memory)
|
508
|
+
masks, features, tracks_df = _facilitate_trackin_with_adaptive_removal(masks, search_range=timelapse_displacement, max_attempts=100, memory=timelapse_memory, track_by_iou=track_by_iou)
|
581
509
|
|
582
510
|
tracks_df['particle'] += 1
|
583
511
|
|