Skip to content

Commit a625000

Browse files
committed
adding simple spatial capability
1 parent 31734e8 commit a625000

File tree

3 files changed

+157
-33
lines changed

3 files changed

+157
-33
lines changed

panopticon/analysis.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2095,7 +2095,8 @@ def get_cluster_differential_expression(loom,
20952095
ident2_downsample_size=None,
20962096
min_cluster_size=0,
20972097
gene_alternate_name=None,
2098-
gene_subset_mask=None):
2098+
gene_subset_mask=None,
2099+
alternate_test=None):
20992100
"""
21002101
21012102
Parameters
@@ -2242,6 +2243,8 @@ def get_cluster_differential_expression(loom,
22422243
meanexpexpr2 = np.mean(2**data2, axis=1)
22432244
fracexpr1 = np.mean(data1 > 0, axis=1)
22442245
fracexpr2 = np.mean(data2 > 0, axis=1)
2246+
if alternate_test is not None:
2247+
alternate_test_pvalues = alternate_test(data1, data2, axis=1).pvalue
22452248

22462249

22472250
###
@@ -2255,6 +2258,8 @@ def get_cluster_differential_expression(loom,
22552258
meanexpexpr2 = []
22562259
fracexpr1 = []
22572260
fracexpr2 = []
2261+
if alternate_test is not None:
2262+
alternate_test_pvalues = []
22582263
for igene, gene in enumerate(
22592264
tqdm(genelist, desc='Computing Mann-Whitney p-values')):
22602265
genes.append(gene)
@@ -2273,6 +2278,8 @@ def get_cluster_differential_expression(loom,
22732278
meanexpexpr2.append(np.mean(2**data2[igene, :]))
22742279
fracexpr1.append((data1[igene, :] > 0).mean())
22752280
fracexpr2.append((data2[igene, :] > 0).mean())
2281+
if alternate_test is not None:
2282+
alternate_test_pvalues.append(alternate_test(data1[igene,:], data2[igene,:]).pvalue)
22762283
output = pd.DataFrame(genelist)
22772284
output.columns = ['gene']
22782285
output['pvalue'] = pvalues
@@ -2286,6 +2293,9 @@ def get_cluster_differential_expression(loom,
22862293
meanexpexpr2) / np.log(2)
22872294
output['FracExpr1'] = fracexpr1
22882295
output['FracExpr2'] = fracexpr2
2296+
if alternate_test is not None:
2297+
output['AlternateTestPValue'] = [1 if np.isnan(x) else x for x in alternate_test_pvalues]
2298+
output['AlternateTestQvalue'] = fdrcorrection(output['AlternateTestPValue'],is_sorted=False)[1]
22892299
if gene_alternate_name is not None:
22902300
gene2altname = {
22912301
gene: altname

panopticon/utilities.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ def cohensd(g1, g2):
461461

462462
return (np.mean(g1) - np.mean(g2)) / s
463463

464+
464465
def glassdelta(experimental=None, control=None):
465466
"""Returns Glass' delta for the effect size of group 1 values (g1) over group 2 values (g2). g2 is assumed to be the control group
466467
@@ -477,7 +478,8 @@ def glassdelta(experimental=None, control=None):
477478
478479
"""
479480
if (experimental is None) or (control is None):
480-
raise Exception("experimental and control should be lists or numpy vectors")
481+
raise Exception(
482+
"experimental and control should be lists or numpy vectors")
481483
scontrol = np.std(control, ddof=1)
482484

483485
return (np.mean(experimental) - np.mean(control)) / scontrol
@@ -557,7 +559,9 @@ def convert_10x_h5(path_10x_h5,
557559
gene_whitelist=None,
558560
output_type='loom',
559561
write_chunked=False,
560-
chunk_size=512):
562+
chunk_size=512,
563+
exclude_feature_type=None,
564+
verbose=True):
561565
"""
562566
563567
Parameters
@@ -618,6 +622,30 @@ def convert_10x_h5(path_10x_h5,
618622
ca[labelkey] = [label] * len(barcodes)
619623

620624
m = filtered_feature_bc_matrix.m
625+
626+
feature_types = np.array(filtered_feature_bc_matrix.feature_ref.get_feature_types_excluding_deprecated_probes() )
627+
if exclude_feature_type is not None:
628+
if type(exclude_feature_type)==str:
629+
exclude_feature_type = [exclude_feature_type]
630+
elif type(exclude_feature_type)==tuple:
631+
exclude_feature_type = list(exclude_feature_type)
632+
633+
try:
634+
iterator = iter(exclude_feature_type)
635+
except TypeError:
636+
raise Exception("exclude_feature_type must be iterable or str, is of type {}".format(type(exclude_feature_type)))
637+
feature_type_mask = ~np.isin(feature_types, exclude_feature_type)
638+
feature_types = np.array(feature_types)[np.array(feature_type_mask)]
639+
m = m[feature_type_mask, :]
640+
features = list(np.array(features)[feature_type_mask])
641+
features_common_names = list(np.array(features_common_names)[feature_type_mask])
642+
643+
if verbose:
644+
print("Removing the following feature types: {}".format(
645+
exclude_feature_type))
646+
if verbose:
647+
print(
648+
"Including the following feature types: {}".format(np.unique(feature_types)))
621649
if gene_whitelist is not None:
622650
if len(gene_whitelist) > 0:
623651
mask = np.isin(features, gene_whitelist)

panopticon/visualization.py

Lines changed: 116 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,14 +1030,14 @@ def position_to_xytext_habt_va(position, effect_size, negpval, maxx, maxy,
10301030
"\'{}\': invalid position character selection".format(
10311031
position))
10321032
return xytext, habt, va
1033+
10331034
negpvals = []
10341035
for gene in genemarklist:
10351036
genedf = diffex[diffex[gene_column] == gene]
10361037
negpval = -np.log(genedf.iloc[0][pval_column]) / np.log(10)
10371038
negpvals.append(negpval)
10381039
genemarklist = list(np.array(genemarklist)[np.argsort(negpvals)][::-1])
10391040

1040-
10411041
if positions != 'side':
10421042
if type(positions) == dict:
10431043
positions = [positions[key] for key in genemarklist]
@@ -1052,7 +1052,8 @@ def position_to_xytext_habt_va(position, effect_size, negpval, maxx, maxy,
10521052
effect_size = genedf.iloc[0][effect_size_col]
10531053
ax.scatter(effect_size, negpval, marker='.', color='k')
10541054
xytext, habt, va = position_to_xytext_habt_va(
1055-
position, effect_size, negpval, maxx, maxy, gene_label_offset_scale)
1055+
position, effect_size, negpval, maxx, maxy,
1056+
gene_label_offset_scale)
10561057
anno = ax.annotate(
10571058
gene, (effect_size, negpval),
10581059
xytext,
@@ -1073,37 +1074,46 @@ def position_to_xytext_habt_va(position, effect_size, negpval, maxx, maxy,
10731074
if gene in gene_position_dict_for_side_annotations.keys():
10741075
position = gene_position_dict_for_side_annotations[gene]
10751076
xytext, habt, va = position_to_xytext_habt_va(
1076-
position, effect_size, negpval, maxx, maxy, gene_label_offset_scale)
1077-
anno = ax.annotate(
1078-
gene, (effect_size, negpval),
1079-
xytext,
1080-
va=va,
1081-
ha=habt,
1082-
path_effects=[pe.withStroke(linewidth=2, foreground="white")])
1077+
position, effect_size, negpval, maxx, maxy,
1078+
gene_label_offset_scale)
1079+
anno = ax.annotate(gene, (effect_size, negpval),
1080+
xytext,
1081+
va=va,
1082+
ha=habt,
1083+
path_effects=[
1084+
pe.withStroke(linewidth=2,
1085+
foreground="white")
1086+
])
10831087
else:
1084-
1088+
10851089
if effect_size < no_effect_line:
1086-
xytext = (left_edge + .03 * maxx * side_annotation_gene_label_offset_scale ,
1087-
top_edge - lcounter)
1090+
xytext = (
1091+
left_edge +
1092+
.03 * maxx * side_annotation_gene_label_offset_scale,
1093+
top_edge - lcounter)
10881094
habt = 'left'
1089-
va='center'
1095+
va = 'center'
10901096
lcounter += counterscale
10911097
else:
1092-
xytext = (right_edge - .03 * maxx * side_annotation_gene_label_offset_scale,
1093-
top_edge - rcounter)
1098+
xytext = (
1099+
right_edge -
1100+
.03 * maxx * side_annotation_gene_label_offset_scale,
1101+
top_edge - rcounter)
10941102
habt = 'right'
1095-
va='center'
1103+
va = 'center'
10961104
rcounter += counterscale
1097-
anno = ax.annotate(
1098-
gene, (effect_size, negpval),
1099-
xytext=xytext,
1100-
va=va,
1101-
ha=habt,
1102-
arrowprops=dict(facecolor='black',
1103-
width=0.1,
1104-
headwidth=0,
1105-
alpha=0.25),
1106-
path_effects=[pe.withStroke(linewidth=2, foreground="white")])
1105+
anno = ax.annotate(gene, (effect_size, negpval),
1106+
xytext=xytext,
1107+
va=va,
1108+
ha=habt,
1109+
arrowprops=dict(facecolor='black',
1110+
width=0.1,
1111+
headwidth=0,
1112+
alpha=0.25),
1113+
path_effects=[
1114+
pe.withStroke(linewidth=2,
1115+
foreground="white")
1116+
])
11071117
if draggable_annotations:
11081118
anno.draggable()
11091119
ax.scatter(effect_size, negpval, marker='.', color='k')
@@ -2492,11 +2502,15 @@ def plot_color_coded_embedding(loom,
24922502
y_ca,
24932503
category_ca=None,
24942504
category_as_continuum=False,
2505+
use_gex_as_ca=False,
2506+
gene_ra='gene_common_name',
2507+
gex_layer='log2(TP10k+1)',
24952508
fig=None,
24962509
ax=None,
24972510
color_palette='colorblind',
24982511
legend=True,
2499-
on_figure_annotation=False):
2512+
on_figure_annotation=False,
2513+
s=2):
25002514
import numpy as np
25012515
import seaborn as sns
25022516
if fig is not None:
@@ -2507,10 +2521,15 @@ def plot_color_coded_embedding(loom,
25072521
raise Exception("Both or neither of fig, ax may be None")
25082522
fig, ax = plt.subplots(figsize=(4, 4))
25092523
if category_as_continuum:
2524+
if use_gex_as_ca:
2525+
igene = np.where(loom.ra[gene_ra] == category_ca)[0][0]
2526+
c = loom[gex_layer][igene, :]
2527+
else:
2528+
c = loom.ca[category_ca]
25102529
g = ax.scatter(loom.ca[x_ca],
25112530
loom.ca[y_ca],
2512-
s=2,
2513-
c=loom.ca[category_ca],
2531+
s=s,
2532+
c=c,
25142533
cmap=color_palette)
25152534
plt.colorbar(g, label=category_ca)
25162535
else:
@@ -2531,7 +2550,7 @@ def plot_color_coded_embedding(loom,
25312550
ax.scatter(
25322551
loom.ca[x_ca][shuffle],
25332552
loom.ca[y_ca][shuffle],
2534-
s=2,
2553+
s=s,
25352554
c=[category2color[x] for x in loom.ca[category_ca][shuffle]])
25362555
from matplotlib.lines import Line2D
25372556
legend_elements = [
@@ -2583,3 +2602,70 @@ def plot_color_coded_embedding(loom,
25832602
ax.set_ylabel(y_ca, loc='bottom', fontsize=14)
25842603

25852604
return fig, ax
2605+
2606+
2607+
def gsea_plot(ranking,
2608+
pathway2genelist_dict,
2609+
left_label='Enriched for genes at beginning of ranking',
2610+
right_label='Enriched for genes at end of ranking',
2611+
figsize=(9/2,7/2)
2612+
):
2613+
import matplotlib.pyplot as plt
2614+
import seaborn as sns
2615+
from panopticon.analysis import get_enrichment_score
2616+
import matplotlib
2617+
2618+
palette = sns.color_palette('colorblind', 12)
2619+
fig, axes = plt.subplots(len(pathway2genelist_dict.keys()) + 1,
2620+
1,
2621+
figsize=figsize,
2622+
height_ratios=[20] +
2623+
[1] * len(pathway2genelist_dict.keys()),
2624+
sharex=True)
2625+
mins = []
2626+
maxs = []
2627+
for ikey, key in enumerate([y for y in pathway2genelist_dict.keys()]):
2628+
es = get_enrichment_score(ranking,
2629+
pathway2genelist_dict[key],
2630+
presorted=True,
2631+
return_es_curve=True,
2632+
return_pvalue=True,
2633+
use_fgsea=True)
2634+
axes[0].plot(es.enrichment_score_curve,
2635+
label=key,
2636+
lw=3,
2637+
color=palette[ikey])
2638+
maxs.append(np.max(es.enrichment_score_curve))
2639+
mins.append(np.min(es.enrichment_score_curve))
2640+
2641+
for x in np.where(np.isin(ranking, pathway2genelist_dict[key]))[0]:
2642+
axes[ikey + 1].axvline(x)
2643+
axes[ikey + 1].set_ylabel(key + '\n' * 5,
2644+
rotation=0,
2645+
ha='left',
2646+
va='bottom')
2647+
axes[ikey + 1].set_yticks([])
2648+
axes[ikey + 1].yaxis.set_label_position("right")
2649+
axes[ikey + 1].yaxis.tick_right()
2650+
for side in ['top', 'bottom', 'right', 'left']:
2651+
axes[ikey + 1].spines[side].set_visible(False)
2652+
axes[ikey + 1].set_xticks([])
2653+
if es.p_value == 0:
2654+
key_with_pval = key + ', p<{0:.5g}'.format(1 / 10000)
2655+
else:
2656+
key_with_pval = key + ', p={0:.5g}'.format(es.p_value)
2657+
axes[ikey + 1].set_ylabel(key_with_pval,
2658+
rotation=0,
2659+
ha='left',
2660+
va='center')
2661+
2662+
axes[0].legend(bbox_to_anchor=(1, 1))
2663+
axes[0].set_ylabel('running enrichment score')
2664+
axes[-1].set_xlabel('rank in gene list\n' + r'$\leftarrow$ ' + left_label +
2665+
' ' * 20 + right_label + r' $\rightarrow$')
2666+
axes[0].set_ylim([np.min(mins), np.max(maxs)])
2667+
axes[0].spines['top'].set_position(('data', 0))
2668+
axes[0].spines['bottom'].set_position(('data', 0))
2669+
axes[0].spines['right'].set_visible(False)
2670+
plt.tight_layout()
2671+
return fig, axes

0 commit comments

Comments
 (0)