spacr 0.3.43__py3-none-any.whl → 0.3.45__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/cellpose.py +63 -71
- spacr/io.py +6 -16
- spacr/ml.py +4 -3
- spacr/plot.py +264 -10
- spacr/settings.py +7 -15
- spacr/submodules.py +113 -68
- spacr/toxo.py +5 -116
- spacr/utils.py +37 -5
- {spacr-0.3.43.dist-info → spacr-0.3.45.dist-info}/METADATA +1 -1
- {spacr-0.3.43.dist-info → spacr-0.3.45.dist-info}/RECORD +14 -14
- {spacr-0.3.43.dist-info → spacr-0.3.45.dist-info}/LICENSE +0 -0
- {spacr-0.3.43.dist-info → spacr-0.3.45.dist-info}/WHEEL +0 -0
- {spacr-0.3.43.dist-info → spacr-0.3.45.dist-info}/entry_points.txt +0 -0
- {spacr-0.3.43.dist-info → spacr-0.3.45.dist-info}/top_level.txt +0 -0
spacr/submodules.py
CHANGED
@@ -141,14 +141,13 @@ def analyze_plaques(settings):
|
|
141
141
|
|
142
142
|
settings = get_analyze_plaque_settings(settings)
|
143
143
|
save_settings(settings, name='analyze_plaques', show=True)
|
144
|
+
settings['dst'] = os.path.join(settings['src'], 'masks')
|
144
145
|
|
145
146
|
if settings['masks']:
|
146
|
-
settings['dst'] = os.path.join(settings['src'], 'masks')
|
147
|
-
display(settings)
|
148
147
|
identify_masks_finetune(settings)
|
149
148
|
folder = settings['dst']
|
150
149
|
else:
|
151
|
-
folder = settings['
|
150
|
+
folder = settings['dst']
|
152
151
|
|
153
152
|
summary_data = []
|
154
153
|
details_data = []
|
@@ -156,9 +155,9 @@ def analyze_plaques(settings):
|
|
156
155
|
|
157
156
|
for filename in os.listdir(folder):
|
158
157
|
filepath = os.path.join(folder, filename)
|
159
|
-
|
160
|
-
|
161
|
-
|
158
|
+
|
159
|
+
if filepath.endswith('.tif') and os.path.isfile(filepath):
|
160
|
+
print(f"Analyzing: {filepath}")
|
162
161
|
image = cellpose.io.imread(filepath)
|
163
162
|
labeled_image = label(image)
|
164
163
|
regions = regionprops(labeled_image)
|
@@ -241,7 +240,6 @@ def train_cellpose(settings):
|
|
241
240
|
label_files,
|
242
241
|
settings['channels'],
|
243
242
|
settings['percentiles'],
|
244
|
-
settings['circular'],
|
245
243
|
settings['invert'],
|
246
244
|
settings['verbose'],
|
247
245
|
settings['remove_background'],
|
@@ -258,7 +256,6 @@ def train_cellpose(settings):
|
|
258
256
|
test_label_files,
|
259
257
|
settings['channels'],
|
260
258
|
settings['percentiles'],
|
261
|
-
settings['circular'],
|
262
259
|
settings['invert'],
|
263
260
|
settings['verbose'],
|
264
261
|
settings['remove_background'],
|
@@ -269,13 +266,12 @@ def train_cellpose(settings):
|
|
269
266
|
test_images = [np.squeeze(img) if img.shape[-1] == 1 else img for img in test_images]
|
270
267
|
|
271
268
|
else:
|
272
|
-
images, masks, image_names, mask_names = _load_images_and_labels(img_src, mask_src, settings['
|
269
|
+
images, masks, image_names, mask_names = _load_images_and_labels(img_src, mask_src, settings['invert'])
|
273
270
|
images = [np.squeeze(img) if img.shape[-1] == 1 else img for img in images]
|
274
271
|
|
275
272
|
if settings['test']:
|
276
273
|
test_images, test_masks, test_image_names, test_mask_names = _load_images_and_labels(test_img_src,
|
277
274
|
test_mask_src,
|
278
|
-
settings['circular'],
|
279
275
|
settings['invert'])
|
280
276
|
|
281
277
|
test_images = [np.squeeze(img) if img.shape[-1] == 1 else img for img in test_images]
|
@@ -320,7 +316,6 @@ def train_cellpose(settings):
|
|
320
316
|
SGD=False,
|
321
317
|
channels=cp_channels,
|
322
318
|
channel_axis=None,
|
323
|
-
#rgb=False,
|
324
319
|
normalize=False,
|
325
320
|
compute_flows=False,
|
326
321
|
save_path=model_save_path,
|
@@ -375,7 +370,10 @@ def count_phenotypes(settings):
|
|
375
370
|
|
376
371
|
return
|
377
372
|
|
378
|
-
def compare_reads_to_scores(reads_csv, scores_csv, empirical_dict={
|
373
|
+
def compare_reads_to_scores(reads_csv, scores_csv, empirical_dict={'r1':(90,10),'r2':(90,10),'r3':(80,20),'r4':(80,20),'r5':(70,30),'r6':(70,30),'r7':(60,40),'r8':(60,40),'r9':(50,50),'r10':(50,50),'r11':(40,60),'r12':(40,60),'r13':(30,70),'r14':(30,70),'r15':(20,80),'r16':(20,80)},
|
374
|
+
pc_grna='TGGT1_220950_1', nc_grna='TGGT1_233460_4',
|
375
|
+
y_columns=['class_1_fraction', 'TGGT1_220950_1_fraction', 'nc_fraction'],
|
376
|
+
column='column', value='c3', plate=None, save_paths=None):
|
379
377
|
|
380
378
|
def calculate_well_score_fractions(df, class_columns='cv_predictions'):
|
381
379
|
if all(col in df.columns for col in ['plate', 'row', 'column']):
|
@@ -392,34 +390,74 @@ def compare_reads_to_scores(reads_csv, scores_csv, empirical_dict={}, column='co
|
|
392
390
|
summary_df['class_0_fraction'] = summary_df['class_0'] / summary_df['total_rows']
|
393
391
|
summary_df['class_1_fraction'] = summary_df['class_1'] / summary_df['total_rows']
|
394
392
|
return summary_df
|
395
|
-
|
396
|
-
def plot_line(df, x_column, y_columns, group_column=None,
|
397
|
-
|
398
|
-
save_path=None):
|
393
|
+
|
394
|
+
def plot_line(df, x_column, y_columns, group_column=None, xlabel=None, ylabel=None,
|
395
|
+
title=None, figsize=(10, 6), save_path=None, theme='deep'):
|
399
396
|
"""
|
400
397
|
Create a line plot that can handle multiple y-columns, each becoming a separate line.
|
401
398
|
"""
|
402
|
-
df = df.loc[natsorted(df.index, key=lambda x: df.loc[x, x_column])]
|
403
399
|
|
404
|
-
|
400
|
+
def _set_theme(theme):
|
401
|
+
"""Set the Seaborn theme and reorder colors if necessary."""
|
402
|
+
|
403
|
+
def __set_reordered_theme(theme='deep', order=None, n_colors=100, show_theme=False):
|
404
|
+
"""Set and reorder the Seaborn color palette."""
|
405
|
+
palette = sns.color_palette(theme, n_colors)
|
406
|
+
if order:
|
407
|
+
reordered_palette = [palette[i] for i in order]
|
408
|
+
else:
|
409
|
+
reordered_palette = palette
|
410
|
+
if show_theme:
|
411
|
+
sns.palplot(reordered_palette)
|
412
|
+
plt.show()
|
413
|
+
return reordered_palette
|
414
|
+
|
415
|
+
integer_list = list(range(1, 81))
|
416
|
+
color_order = [7, 9, 4, 0, 3, 6, 2] + integer_list
|
417
|
+
sns_palette = __set_reordered_theme(theme, color_order, 100)
|
418
|
+
return sns_palette
|
419
|
+
|
420
|
+
sns_palette = _set_theme(theme)
|
421
|
+
|
422
|
+
# Sort the DataFrame based on the x_column
|
423
|
+
df = df.loc[natsorted(df.index, key=lambda x: df.loc[x, x_column])]
|
424
|
+
|
425
|
+
fig, ax = plt.subplots(figsize=figsize)
|
405
426
|
|
427
|
+
# Handle multiple y-columns, each as a separate line
|
406
428
|
if isinstance(y_columns, list):
|
407
|
-
for y_col in y_columns:
|
408
|
-
sns.lineplot(
|
429
|
+
for idx, y_col in enumerate(y_columns):
|
430
|
+
sns.lineplot(
|
431
|
+
data=df, x=x_column, y=y_col, ax=ax, label=y_col,
|
432
|
+
color=sns_palette[idx % len(sns_palette)], linewidth=1
|
433
|
+
)
|
409
434
|
else:
|
410
|
-
sns.lineplot(
|
411
|
-
|
412
|
-
|
413
|
-
|
435
|
+
sns.lineplot(
|
436
|
+
data=df, x=x_column, y=y_columns, hue=group_column, ax=ax,
|
437
|
+
palette=sns_palette, linewidth=2
|
438
|
+
)
|
439
|
+
|
440
|
+
# Set axis labels and title
|
441
|
+
ax.set_xlabel(xlabel if xlabel else x_column)
|
442
|
+
ax.set_ylabel(ylabel if ylabel else 'Value')
|
443
|
+
ax.set_title(title if title else 'Line Plot')
|
444
|
+
|
445
|
+
# Remove top and right spines
|
446
|
+
sns.despine(ax=ax)
|
447
|
+
|
448
|
+
# Ensure legend only appears when needed and place it to the right
|
414
449
|
if group_column or isinstance(y_columns, list):
|
415
|
-
|
450
|
+
ax.legend(title='Legend', loc='center left', bbox_to_anchor=(1, 0.5))
|
416
451
|
|
417
452
|
plt.tight_layout()
|
418
453
|
|
454
|
+
# Save the plot if a save path is provided
|
419
455
|
if save_path:
|
420
|
-
plt.savefig(save_path, format='
|
456
|
+
plt.savefig(save_path, format='pdf', dpi=600, bbox_inches='tight')
|
421
457
|
print(f"Plot saved to {save_path}")
|
458
|
+
|
422
459
|
plt.show()
|
460
|
+
return fig
|
423
461
|
|
424
462
|
def calculate_grna_fraction_ratio(df, grna1='TGGT1_220950_1', grna2='TGGT1_233460_4'):
|
425
463
|
# Filter relevant grna_names within each prc and group them
|
@@ -437,12 +475,9 @@ def compare_reads_to_scores(reads_csv, scores_csv, empirical_dict={}, column='co
|
|
437
475
|
f'count_{grna2}': f'{grna2}_count'
|
438
476
|
})
|
439
477
|
result = grouped.reset_index()[['prc', f'{grna1}_count', f'{grna2}_count', 'fraction_ratio']]
|
440
|
-
|
441
478
|
result['total_reads'] = result[f'{grna1}_count'] + result[f'{grna2}_count']
|
442
|
-
|
443
479
|
result[f'{grna1}_fraction'] = result[f'{grna1}_count'] / result['total_reads']
|
444
480
|
result[f'{grna2}_fraction'] = result[f'{grna2}_count'] / result['total_reads']
|
445
|
-
|
446
481
|
return result
|
447
482
|
|
448
483
|
def calculate_well_read_fraction(df, count_column='count'):
|
@@ -456,53 +491,63 @@ def compare_reads_to_scores(reads_csv, scores_csv, empirical_dict={}, column='co
|
|
456
491
|
df['fraction'] = df['count'] / df['total_counts']
|
457
492
|
return df
|
458
493
|
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
494
|
+
if isinstance(reads_csv, list):
|
495
|
+
if len(reads_csv) == len(scores_csv):
|
496
|
+
reads_ls = []
|
497
|
+
scores_ls = []
|
498
|
+
for i, reads_csv_temp in enumerate(reads_csv):
|
499
|
+
reads_df_temp = pd.read_csv(reads_csv_temp)
|
500
|
+
scores_df_temp = pd.read_csv(scores_csv[i])
|
501
|
+
reads_df_temp['plate'] = f"plate{i+1}"
|
502
|
+
scores_df_temp['plate'] = f"plate{i+1}"
|
503
|
+
|
504
|
+
if 'col' in reads_df_temp.columns:
|
505
|
+
reads_df_temp = reads_df_temp.rename(columns={'col': 'column'})
|
506
|
+
if 'column_name' in reads_df_temp.columns:
|
507
|
+
reads_df_temp = reads_df_temp.rename(columns={'column_name': 'column'})
|
508
|
+
if 'col' in scores_df_temp.columns:
|
509
|
+
scores_df_temp = scores_df_temp.rename(columns={'col': 'column'})
|
510
|
+
if 'column_name' in scores_df_temp.columns:
|
511
|
+
scores_df_temp = scores_df_temp.rename(columns={'column_name': 'column'})
|
512
|
+
if 'row_name' in reads_df_temp.columns:
|
513
|
+
reads_df_temp = reads_df_temp.rename(columns={'row_name': 'row'})
|
514
|
+
if 'row_name' in scores_df_temp.columns:
|
515
|
+
scores_df_temp = scores_df_temp.rename(columns={'row_name': 'row'})
|
516
|
+
|
517
|
+
reads_ls.append(reads_df_temp)
|
518
|
+
scores_ls.append(scores_df_temp)
|
519
|
+
|
520
|
+
reads_df = pd.concat(reads_ls, axis=0)
|
521
|
+
scores_df = pd.concat(scores_ls, axis=0)
|
522
|
+
print(f"Reads: {len(reads_df)} Scores: {len(scores_df)}")
|
523
|
+
else:
|
524
|
+
print(f"reads_csv and scores_csv must contain the same number of elements if reads_csv is a list")
|
525
|
+
else:
|
526
|
+
reads_df = pd.read_csv(reads_csv)
|
527
|
+
scores_df = pd.read_csv(scores_csv)
|
528
|
+
if plate != None:
|
529
|
+
reads_df['plate'] = plate
|
530
|
+
scores_df['plate'] = plate
|
531
|
+
|
479
532
|
reads_df = calculate_well_read_fraction(reads_df)
|
480
533
|
scores_df = calculate_well_score_fractions(scores_df)
|
481
534
|
reads_col_df = reads_df[reads_df[column]==value]
|
482
535
|
scores_col_df = scores_df[scores_df[column]==value]
|
483
536
|
|
484
|
-
|
485
|
-
reads_col_df = calculate_grna_fraction_ratio(reads_col_df, grna1='TGGT1_220950_1', grna2='TGGT1_233460_4')
|
537
|
+
reads_col_df = calculate_grna_fraction_ratio(reads_col_df, grna1=pc_grna, grna2=nc_grna)
|
486
538
|
df = pd.merge(reads_col_df, scores_col_df, on='prc')
|
487
539
|
|
540
|
+
df_emp = pd.DataFrame([(key, val[0], val[1], val[0] / (val[0] + val[1]), val[1] / (val[0] + val[1])) for key, val in empirical_dict.items()],columns=['key', 'value1', 'value2', 'pc_fraction', 'nc_fraction'])
|
488
541
|
|
489
|
-
# Convert the dictionary to a DataFrame and calculate fractions
|
490
|
-
df_emp = pd.DataFrame(
|
491
|
-
[(key, val[0], val[1], val[0] / (val[0] + val[1]), val[1] / (val[0] + val[1]))
|
492
|
-
for key, val in empirical_dict.items()],
|
493
|
-
columns=['key', 'value1', 'value2', 'fraction1', 'fraction2']
|
494
|
-
)
|
495
|
-
|
496
542
|
df = pd.merge(df, df_emp, left_on='row', right_on='key')
|
497
|
-
display(df)
|
498
|
-
y_columns = ['class_1_fraction', 'TGGT1_220950_1_fraction', 'fraction2']
|
499
543
|
|
500
|
-
|
501
|
-
|
502
|
-
|
544
|
+
if any in y_columns not in df.columns:
|
545
|
+
print(f"columns in dataframe:")
|
546
|
+
for col in df.columns:
|
547
|
+
print(col)
|
548
|
+
return
|
549
|
+
display(df)
|
550
|
+
fig_1 = plot_line(df, x_column = 'pc_fraction', y_columns=y_columns, group_column=None, xlabel=None, ylabel='Fraction', title=None, figsize=(10, 6), save_path=save_paths[0])
|
551
|
+
fig_2 = plot_line(df, x_column = 'nc_fraction', y_columns=y_columns, group_column=None, xlabel=None, ylabel='Fraction', title=None, figsize=(10, 6), save_path=save_paths[1])
|
503
552
|
|
504
|
-
|
505
|
-
|
506
|
-
plot_line(df, x_column='row', y_columns=y_columns, group_column=None,
|
507
|
-
xlabel=None, ylabel=None, title=None, figsize=(10, 6),
|
508
|
-
save_path=None)
|
553
|
+
return [fig_1, fig_2]
|
spacr/toxo.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import os
|
1
2
|
import matplotlib.pyplot as plt
|
2
3
|
import seaborn as sns
|
3
4
|
import numpy as np
|
@@ -6,125 +7,13 @@ import pandas as pd
|
|
6
7
|
from scipy.stats import fisher_exact
|
7
8
|
from IPython.display import display
|
8
9
|
|
9
|
-
def
|
10
|
-
"""
|
11
|
-
Create a volcano plot with the ability to control the shape of points based on a categorical column,
|
12
|
-
color points based on a string list, annotate specific points based on p-value and coefficient thresholds,
|
13
|
-
and control the size of points.
|
14
|
-
|
15
|
-
Parameters:
|
16
|
-
- data_path: Path to the data CSV file.
|
17
|
-
- metadata_path: Path to the metadata CSV file.
|
18
|
-
- metadata_column: Column name in the metadata to control point shapes.
|
19
|
-
- string_list: List of strings to color points differently if present in 'coefficient' names.
|
20
|
-
- point_size: Fixed value to control the size of points.
|
21
|
-
- figsize: Width of the plot (height is half the width).
|
22
|
-
"""
|
23
|
-
|
24
|
-
|
25
|
-
filename = 'volcano_plot.pdf'
|
26
|
-
|
27
|
-
# Load the data
|
28
|
-
|
29
|
-
if isinstance(data_path, pd.DataFrame):
|
30
|
-
data = data_path
|
31
|
-
else:
|
32
|
-
data = pd.read_csv(data_path)
|
33
|
-
data['variable'] = data['feature'].str.extract(r'\[(.*?)\]')
|
34
|
-
data['variable'].fillna(data['feature'], inplace=True)
|
35
|
-
split_columns = data['variable'].str.split('_', expand=True)
|
36
|
-
data['gene_nr'] = split_columns[0]
|
37
|
-
|
38
|
-
# Load metadata
|
39
|
-
if isinstance(metadata_path, pd.DataFrame):
|
40
|
-
metadata = metadata_path
|
41
|
-
else:
|
42
|
-
metadata = pd.read_csv(metadata_path)
|
43
|
-
|
44
|
-
metadata['gene_nr'] = metadata['gene_nr'].astype(str)
|
45
|
-
data['gene_nr'] = data['gene_nr'].astype(str)
|
46
|
-
|
47
|
-
|
48
|
-
# Merge data and metadata on 'gene_nr'
|
49
|
-
merged_data = pd.merge(data, metadata[['gene_nr', 'tagm_location']], on='gene_nr', how='left')
|
50
|
-
|
51
|
-
merged_data.loc[merged_data['gene_nr'].str.startswith('4'), metadata_column] = 'GT1_gene'
|
52
|
-
merged_data.loc[merged_data['gene_nr'] == 'Intercept', metadata_column] = 'Intercept'
|
53
|
-
|
54
|
-
# Create the volcano plot
|
55
|
-
figsize_2 = figsize / 2
|
56
|
-
plt.figure(figsize=(figsize_2, figsize))
|
57
|
-
|
58
|
-
palette = {
|
59
|
-
'pc': 'red',
|
60
|
-
'nc': 'green',
|
61
|
-
'control': 'black',
|
62
|
-
'other': 'gray'
|
63
|
-
}
|
64
|
-
|
65
|
-
merged_data['condition'] = pd.Categorical(
|
66
|
-
merged_data['condition'],
|
67
|
-
categories=['pc', 'nc', 'control', 'other'],
|
68
|
-
ordered=True
|
69
|
-
)
|
70
|
-
|
71
|
-
display(merged_data)
|
72
|
-
|
73
|
-
# Create the scatter plot with fixed point size
|
74
|
-
sns.scatterplot(
|
75
|
-
data=merged_data,
|
76
|
-
x='coefficient',
|
77
|
-
y='-log10(p_value)',
|
78
|
-
hue='condition', # Controls color
|
79
|
-
style=metadata_column if metadata_column else None, # Controls point shape
|
80
|
-
s=point_size, # Fixed size for all points
|
81
|
-
palette=palette, # Color palette
|
82
|
-
alpha=1.0 # Transparency
|
83
|
-
)
|
84
|
-
|
85
|
-
# Set the plot title and labels
|
86
|
-
plt.title('Custom Volcano Plot of Coefficients')
|
87
|
-
plt.xlabel('Coefficient')
|
88
|
-
plt.ylabel('-log10(p-value)')
|
89
|
-
|
90
|
-
if threshold > 0:
|
91
|
-
plt.gca().axvline(x=-abs(threshold), linestyle='--', color='black')
|
92
|
-
plt.gca().axvline(x=abs(threshold), linestyle='--', color='black')
|
93
|
-
|
94
|
-
# Horizontal line at p-value threshold (0.05)
|
95
|
-
plt.axhline(y=-np.log10(0.05), color='black', linestyle='--')
|
96
|
-
|
97
|
-
texts = []
|
98
|
-
for i, row in merged_data.iterrows():
|
99
|
-
if row['p_value'] <= 0.05 and abs(row['coefficient']) >= abs(threshold):
|
100
|
-
texts.append(plt.text(
|
101
|
-
row['coefficient'],
|
102
|
-
-np.log10(row['p_value']),
|
103
|
-
row['variable'],
|
104
|
-
fontsize=8
|
105
|
-
))
|
106
|
-
|
107
|
-
# Adjust text positions to avoid overlap
|
108
|
-
adjust_text(texts, arrowprops=dict(arrowstyle='-', color='black'))
|
109
|
-
|
110
|
-
# Move the legend outside the plot
|
111
|
-
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
|
112
|
-
|
113
|
-
# Save the plot
|
114
|
-
plt.savefig(filename, format='pdf', bbox_inches='tight') # bbox_inches ensures the legend doesn't get cut off
|
115
|
-
print(f'Saved Volcano plot: {filename}')
|
116
|
-
|
117
|
-
# Show the plot
|
118
|
-
plt.show()
|
119
|
-
|
120
|
-
def custom_volcano_plot(data_path, metadata_path, metadata_column='tagm_location', point_size=50, figsize=20, threshold=0, split_axis_lims = [10, None, None, 10]):
|
10
|
+
def custom_volcano_plot(data_path, metadata_path, metadata_column='tagm_location', point_size=50, figsize=20, threshold=0, split_axis_lims = [10, None, None, 10], save_path=None):
|
121
11
|
"""
|
122
12
|
Create a volcano plot with the ability to control the shape of points based on a categorical column,
|
123
13
|
color points based on a condition, annotate specific points based on p-value and coefficient thresholds,
|
124
14
|
and control the size of points.
|
125
15
|
"""
|
126
|
-
|
127
|
-
filename = 'volcano_plot.pdf'
|
16
|
+
volcano_path = save_path
|
128
17
|
|
129
18
|
# Load the data
|
130
19
|
if isinstance(data_path, pd.DataFrame):
|
@@ -297,8 +186,8 @@ def custom_volcano_plot(data_path, metadata_path, metadata_column='tagm_location
|
|
297
186
|
fig.suptitle('Custom Volcano Plot of Coefficients', y=1.02, fontsize=16) # Title above the top plot
|
298
187
|
|
299
188
|
# Save the plot as PDF
|
300
|
-
plt.savefig(
|
301
|
-
print(f'Saved Volcano plot: {
|
189
|
+
plt.savefig(volcano_path, format='pdf', bbox_inches='tight')
|
190
|
+
print(f'Saved Volcano plot: {volcano_path}')
|
302
191
|
|
303
192
|
# Show the plot
|
304
193
|
plt.show()
|
spacr/utils.py
CHANGED
@@ -51,7 +51,8 @@ from scipy.stats import fisher_exact, f_oneway, kruskal
|
|
51
51
|
from scipy.ndimage.filters import gaussian_filter
|
52
52
|
from scipy.spatial import ConvexHull
|
53
53
|
from scipy.interpolate import splprep, splev
|
54
|
-
from scipy
|
54
|
+
from scipy import ndimage
|
55
|
+
from scipy.ndimage import binary_dilation, binary_fill_holes
|
55
56
|
|
56
57
|
from skimage.exposure import rescale_intensity
|
57
58
|
from sklearn.metrics import auc, precision_recall_curve
|
@@ -706,6 +707,7 @@ def _update_database_with_merged_info(db_path, df, table='png_list', columns=['p
|
|
706
707
|
conn.close()
|
707
708
|
|
708
709
|
def _generate_representative_images(db_path, cells=['HeLa'], cell_loc=None, pathogens=['rh'], pathogen_loc=None, treatments=['cm'], treatment_loc=None, channel_of_interest=1, compartments = ['pathogen','cytoplasm'], measurement = 'mean_intensity', nr_imgs=16, channel_indices=[0,1,2], um_per_pixel=0.1, scale_bar_length_um=10, plot=False, fontsize=12, show_filename=True, channel_names=None, update_db=True):
|
710
|
+
|
709
711
|
"""
|
710
712
|
Generates representative images based on the provided parameters.
|
711
713
|
|
@@ -4480,6 +4482,7 @@ def cluster_feature_analysis(all_df, cluster_col='cluster'):
|
|
4480
4482
|
return combined_df
|
4481
4483
|
|
4482
4484
|
def _merge_cells_based_on_parasite_overlap(parasite_mask, cell_mask, nuclei_mask, overlap_threshold=5, perimeter_threshold=30):
|
4485
|
+
|
4483
4486
|
"""
|
4484
4487
|
Merge cells in cell_mask if a parasite in parasite_mask overlaps with more than one cell,
|
4485
4488
|
and if cells share more than a specified perimeter percentage.
|
@@ -4607,9 +4610,9 @@ def adjust_cell_masks(parasite_folder, cell_folder, nuclei_folder, overlap_thres
|
|
4607
4610
|
if not (os.path.exists(cell_path) and os.path.exists(nuclei_path)):
|
4608
4611
|
raise ValueError(f"Corresponding cell or nuclei mask file for {file_name} not found.")
|
4609
4612
|
# Load the masks
|
4610
|
-
parasite_mask = np.load(parasite_path)
|
4611
|
-
cell_mask = np.load(cell_path)
|
4612
|
-
nuclei_mask = np.load(nuclei_path)
|
4613
|
+
parasite_mask = np.load(parasite_path, allow_pickle=True)
|
4614
|
+
cell_mask = np.load(cell_path, allow_pickle=True)
|
4615
|
+
nuclei_mask = np.load(nuclei_path, allow_pickle=True)
|
4613
4616
|
# Merge and relabel cells
|
4614
4617
|
merged_cell_mask = _merge_cells_based_on_parasite_overlap(parasite_mask, cell_mask, nuclei_mask, overlap_threshold, perimeter_threshold)
|
4615
4618
|
|
@@ -5177,4 +5180,33 @@ def add_column_to_database(settings):
|
|
5177
5180
|
conn.commit()
|
5178
5181
|
conn.close()
|
5179
5182
|
|
5180
|
-
print(f"Updated '{new_column_name}' in '{settings['table_name']}' using '{settings['match_column']}'.")
|
5183
|
+
print(f"Updated '{new_column_name}' in '{settings['table_name']}' using '{settings['match_column']}'.")
|
5184
|
+
|
5185
|
+
def fill_holes_in_mask(mask):
|
5186
|
+
"""
|
5187
|
+
Fill holes in each object in the mask while keeping objects separated.
|
5188
|
+
|
5189
|
+
Args:
|
5190
|
+
mask (np.ndarray): A labeled mask where each object has a unique integer value.
|
5191
|
+
|
5192
|
+
Returns:
|
5193
|
+
np.ndarray: A mask with holes filled and original labels preserved.
|
5194
|
+
"""
|
5195
|
+
# Ensure the mask is integer-labeled
|
5196
|
+
labeled_mask, num_features = ndimage.label(mask)
|
5197
|
+
|
5198
|
+
# Create an empty mask to store the result
|
5199
|
+
filled_mask = np.zeros_like(labeled_mask)
|
5200
|
+
|
5201
|
+
# Fill holes for each labeled object independently
|
5202
|
+
for i in range(1, num_features + 1):
|
5203
|
+
# Create a binary mask for the current object
|
5204
|
+
object_mask = (labeled_mask == i)
|
5205
|
+
|
5206
|
+
# Fill holes within this object
|
5207
|
+
filled_object = binary_fill_holes(object_mask)
|
5208
|
+
|
5209
|
+
# Assign the original label back to the filled object
|
5210
|
+
filled_mask[filled_object] = i
|
5211
|
+
|
5212
|
+
return filled_mask
|
@@ -7,27 +7,27 @@ spacr/app_mask.py,sha256=l-dBY8ftzCMdDe6-pXc2Nh_u-idNL9G7UOARiLJBtds,153
|
|
7
7
|
spacr/app_measure.py,sha256=_K7APYIeOKpV6e_LcqabBjvEi7mfq9Fch8175x1x0k8,162
|
8
8
|
spacr/app_sequencing.py,sha256=DjG26jy4cpddnV8WOOAIiExtOe9MleVMY4MFa5uTo5w,157
|
9
9
|
spacr/app_umap.py,sha256=ZWAmf_OsIKbYvolYuWPMYhdlVe-n2CADoJulAizMiEo,153
|
10
|
-
spacr/cellpose.py,sha256=
|
10
|
+
spacr/cellpose.py,sha256=RBHMs2vwXcfkj0xqAULpALyzJYXddSRycgZSzmwI7v0,14755
|
11
11
|
spacr/core.py,sha256=dW9RrAKFLfVsFhX0-kaVMc2T7b47Ky0pTXK-CEVOeWQ,48235
|
12
12
|
spacr/deep_spacr.py,sha256=HdOcNU8cHcE_19nP7_5uTz-ih3E169ffr2Hm--NvMvA,43255
|
13
13
|
spacr/gui.py,sha256=ARyn9Q_g8HoP-cXh1nzMLVFCKqthY4v2u9yORyaQqQE,8230
|
14
14
|
spacr/gui_core.py,sha256=N7R7yvfK_dJhOReM_kW3Ci8Bokhi1OzsxeKqvSGdvV4,41460
|
15
15
|
spacr/gui_elements.py,sha256=w-S1MZdyxt5O3DsNAHNNXy_WGfwBPg0NhwQtCsJeiao,137071
|
16
16
|
spacr/gui_utils.py,sha256=KDWDWsi7UdZVhXk1ZWGx3ZqJMIxCUm3lGfjrVhbk52s,45463
|
17
|
-
spacr/io.py,sha256=
|
17
|
+
spacr/io.py,sha256=1rIdJ_8dyn7W4D2zXjaOqlgyo_Y5Z7X86aRp4hNYWCU,144194
|
18
18
|
spacr/logger.py,sha256=lJhTqt-_wfAunCPl93xE65Wr9Y1oIHJWaZMjunHUeIw,1538
|
19
19
|
spacr/measure.py,sha256=KdboGXoi85BO5-_6er7932FgjFI7G7tuaQDnWSiEuew,54817
|
20
20
|
spacr/mediar.py,sha256=FwLvbLQW5LQzPgvJZG8Lw7GniA2vbZx6Jv6vIKu7I5c,14743
|
21
|
-
spacr/ml.py,sha256=
|
21
|
+
spacr/ml.py,sha256=bPcKVk1camnOhv8jQglj6EYyipAxxmiB1QJ2Fdo3dEM,50654
|
22
22
|
spacr/openai.py,sha256=5vBZ3Jl2llYcW3oaTEXgdyCB2aJujMUIO5K038z7w_A,1246
|
23
|
-
spacr/plot.py,sha256=
|
23
|
+
spacr/plot.py,sha256=c7PYi4p-ARjHjHCoSn-8ZEXAit0WcTRVxAcAs47tLms,145287
|
24
24
|
spacr/sequencing.py,sha256=t18mgpK6rhWuB1LtFOsPxqgpFXxuUmrD06ecsaVQ0Gw,19655
|
25
|
-
spacr/settings.py,sha256=
|
25
|
+
spacr/settings.py,sha256=3ygnAY6uLtkzFQdK8TMBbWV6zXEX-G_wV19YLyjCBeM,77668
|
26
26
|
spacr/sim.py,sha256=1xKhXimNU3ukzIw-3l9cF3Znc_brW8h20yv8fSTzvss,71173
|
27
|
-
spacr/submodules.py,sha256=
|
27
|
+
spacr/submodules.py,sha256=3C5M4UbI9Ral1MX4PTpucaAaqhL3RADuCOCqaHhMyUg,28048
|
28
28
|
spacr/timelapse.py,sha256=FSYpUtAVy6xc3lwprRYgyDTT9ysUhfRQ4zrP9_h2mvg,39465
|
29
|
-
spacr/toxo.py,sha256=
|
30
|
-
spacr/utils.py,sha256=
|
29
|
+
spacr/toxo.py,sha256=X62hKFcSzFhIxFYlhL2AZb0qNpvtjLs3y1HldReAQEY,12880
|
30
|
+
spacr/utils.py,sha256=K36BxYr4GN956V4S7IkNty2sP4Y265WS7yMzAw8Tqeg,220451
|
31
31
|
spacr/version.py,sha256=axH5tnGwtgSnJHb5IDhiu4Zjk5GhLyAEDRe-rnaoFOA,409
|
32
32
|
spacr/resources/MEDIAR/.gitignore,sha256=Ff1q9Nme14JUd-4Q3jZ65aeQ5X4uttptssVDgBVHYo8,152
|
33
33
|
spacr/resources/MEDIAR/LICENSE,sha256=yEj_TRDLUfDpHDNM0StALXIt6mLqSgaV2hcCwa6_TcY,1065
|
@@ -150,9 +150,9 @@ spacr/resources/icons/umap.png,sha256=dOLF3DeLYy9k0nkUybiZMe1wzHQwLJFRmgccppw-8b
|
|
150
150
|
spacr/resources/images/plate1_E01_T0001F001L01A01Z01C02.tif,sha256=Tl0ZUfZ_AYAbu0up_nO0tPRtF1BxXhWQ3T3pURBCCRo,7958528
|
151
151
|
spacr/resources/images/plate1_E01_T0001F001L01A02Z01C01.tif,sha256=m8N-V71rA1TT4dFlENNg8s0Q0YEXXs8slIn7yObmZJQ,7958528
|
152
152
|
spacr/resources/images/plate1_E01_T0001F001L01A03Z01C03.tif,sha256=Pbhk7xn-KUP6RSIhJsxQcrHFImBm3GEpLkzx7WOc-5M,7958528
|
153
|
-
spacr-0.3.
|
154
|
-
spacr-0.3.
|
155
|
-
spacr-0.3.
|
156
|
-
spacr-0.3.
|
157
|
-
spacr-0.3.
|
158
|
-
spacr-0.3.
|
153
|
+
spacr-0.3.45.dist-info/LICENSE,sha256=SR-2MeGc6SCM1UORJYyarSWY_A-JaOMFDj7ReSs9tRM,1083
|
154
|
+
spacr-0.3.45.dist-info/METADATA,sha256=eUCjysKj_sil9xg7E1ZQzIUGN8mCTYd1uw64MEY7cbo,5949
|
155
|
+
spacr-0.3.45.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
|
156
|
+
spacr-0.3.45.dist-info/entry_points.txt,sha256=BMC0ql9aNNpv8lUZ8sgDLQMsqaVnX5L535gEhKUP5ho,296
|
157
|
+
spacr-0.3.45.dist-info/top_level.txt,sha256=GJPU8FgwRXGzKeut6JopsSRY2R8T3i9lDgya42tLInY,6
|
158
|
+
spacr-0.3.45.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|