Comparison with simple baselines on the simulation dataset¶
[ ]:
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "1"
import sys
sys.path.append(r'/import/home2/yzengbj/my_project/code')
sys.path.append(r'/import/home2/share/yqzeng/MacSGP/codes')
import warnings
warnings.filterwarnings("ignore")
import numpy as np
import pandas as pd
import scanpy as sc
import anndata as ad
import scipy.io
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from matplotlib.colors import ListedColormap, BoundaryNorm, TwoSlopeNorm
from matplotlib.ticker import MaxNLocator
import seaborn as sns
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from scipy.stats import pearsonr
from itertools import combinations
import libpysal
from libpysal.weights import KNN
import esda
from spatialdata_plot.pl.utils import set_zero_in_cmap_to_transparent
import SVF
import simulation as construct_st
import MacSGP
[2]:
DATA_PATH = "/import/home2/share/yqzeng/MacSPG/data/simulation/final" # Raw data
SAVE_PATH = "/import/home2/share/yqzeng/MacSPG/results/simulation/final" # Deconvolution results
os.makedirs(os.path.join(DATA_PATH), exist_ok = True)
os.makedirs(os.path.join(SAVE_PATH), exist_ok = True)
Residual pca¶
[ ]:
factor_pattern = 'gradient_y'
factor_celltype = [0]
n_spots = 3000
n_genes = 2000
n_celltypes = 2
n_cells = 500
n_covariates = 1
n_loading_genes = 200
n_groups = 4
ref_noise_ratio = 10
library_size = 5000
prop_confound = True
prop_min = 0.1
prop_max = 0.9
same_tau = True
spots_effects = False
platform_effects = False
shifted = False
c = 1
[ ]:
adata_ref, adata_st, reference, logmu = construct_st.simulate_data_2ct(
seed=20250723,
n_spots=n_spots, n_genes=n_genes,
library_size=np.ones(n_spots) * library_size,
n_celltypes=n_celltypes,
n_cells=n_cells,
n_covariates=n_covariates,
n_groups=n_groups,
ref_noise_ratio=ref_noise_ratio,
same_tau=same_tau,
prop_confound=prop_confound,
prop_min=prop_min, prop_max=prop_max,
spot_effects=spots_effects, platform_effects=platform_effects,
factor=True, n_loading_gene=n_loading_genes,
factor_celltypes=factor_celltype, factor_pattern=factor_pattern,
shifted=False
)
[ ]:
MacSGP.utils.Cal_Spatial_Net(adata_st, mode='KNN', k_cutoff=12)
adata_st, adata_basis = MacSGP.utils.preprocess(adata_st,adata_ref,
celltype_ref_col = "celltype",
n_hvg_group = 1000)
model = MacSGP.model.Model_deconv(adata_st, adata_basis, n_layers =4, training_steps=10000)
model.train(step_interval=1000)
adata_st = model.eval()
model = MacSGP.model.Model(adata_st, adata_basis, n_layers=4, training_steps=3000)
model.train(step_interval=600)
adata_result = model.eval()
[ ]:
import numpy as np
import pandas as pd
from sklearn.decomposition import PCA
count = adata_st.obsm['count']
count = pd.DataFrame(count, index=adata_st.obs_names, columns=adata_st.var_names)
count_deconv = adata_st.obsm['proportion'].dot(adata_basis.X)
count_deconv = pd.DataFrame(count_deconv.values, index=adata_st.obs_names, columns=adata_st.var_names)
count_normalized = count.div(count.sum(axis=1), axis=0)
count_residual = count_deconv - count_normalized
count_residual = count_normalized - count_deconv
pearson_residuals = (count_normalized - count_deconv) / np.sqrt(count_deconv + 1e-6)
X_pca = pearson_residuals
k = 5
pca = PCA(n_components=k, svd_solver='auto', random_state=0)
# Factor scores:
# shape: (n_spots, k)
factor_scores = pca.fit_transform(X_pca)
factor_scores_df = pd.DataFrame(
factor_scores,
index=count_residual.index,
columns=[f'PC{i+1}' for i in range(k)]
)
# Loading matrix:
loadings = pca.components_.T
loadings_df = pd.DataFrame(
loadings,
index=count_residual.columns, # 基因名
columns=[f'PC{i+1}' for i in range(k)]
)
[ ]:
s = 8
proportion = adata_st.obsm['proportion']['celltype_0']
factor_true = adata_st.obsm['simulated_factor']
factor_macsgp = adata_result.obsm['factor']['celltype_0']
factor_pca = factor_scores_df['PC1'].values
sign_m = np.sign(pearsonr(factor_macsgp.values, factor_true.values.reshape(-1))[0])
factor_macsgp_aligned = factor_macsgp * sign_m
sign_p = np.sign(pearsonr(factor_pca, factor_true.values.reshape(-1))[0])
factor_pca_aligned = factor_pca * sign_p
[ ]:
data = proportion
fig, ax = plt.subplots(figsize=(3.5, 3.2))
#norm = mpl.colors.TwoSlopeNorm(vcenter=0.0)
sc = ax.scatter(
x,
y,
c=data,
s=8,
cmap='YlOrBr',
linewidths=0,
#norm=norm
)
cb = fig.colorbar(sc, ax=ax, shrink=0.4, pad=0.02, orientation='horizontal')
cb.locator = MaxNLocator(nbins=1)
cb.update_ticks()
cb.ax.tick_params(labelsize=12)
#cb.set_label('Proportion', fontsize=12)
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_linewidth(False)
ax.spines['bottom'].set_linewidth(False)
ax.set_title('Proportion', fontsize=15)
ax.set_xticks([])
ax.set_yticks([])
ax.set_aspect('equal', adjustable='box')
plt.tight_layout()
plt.show()
[ ]:
data = factor_macsgp_aligned
fig, ax = plt.subplots(figsize=(3.5, 3.2))
norm = mpl.colors.TwoSlopeNorm(vcenter=0.0)
sc = ax.scatter(
x,
y,
c=data,
s=8,
cmap='bwr',
linewidths=0,
#norm=norm
)
cb = fig.colorbar(sc, ax=ax, shrink=0.4, pad=0.02, orientation='horizontal')
#cb.locator = MaxNLocator(nbins=1)
#cb.update_ticks()
#cb.ax.tick_params(labelsize=0)
cb.set_label('Normalized score', fontsize=12)
# no ticks
cb.set_ticks([])
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_linewidth(False)
ax.spines['bottom'].set_linewidth(False)
ax.set_title('MacSGP', fontsize=15)
ax.set_xticks([])
ax.set_yticks([])
ax.set_aspect('equal', adjustable='box')
plt.tight_layout()
[ ]:
data = factor_pca_aligned
fig, ax = plt.subplots(figsize=(3.5, 3.2))
norm = mpl.colors.TwoSlopeNorm(vcenter=0.0)
sc = ax.scatter(
x,
y,
c=data,
s=8,
cmap='bwr',
linewidths=0,
#norm=norm
)
cb = fig.colorbar(sc, ax=ax, shrink=0.4, pad=0.02, orientation='horizontal')
#cb.locator = MaxNLocator(nbins=1)
#cb.update_ticks()
#cb.ax.tick_params(labelsize=0)
cb.set_label('Normalized score', fontsize=12)
# no ticks
cb.set_ticks([])
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_linewidth(False)
ax.spines['bottom'].set_linewidth(False)
ax.set_title('Residual PCA', fontsize=15)
ax.set_xticks([])
ax.set_yticks([])
ax.set_aspect('equal', adjustable='box')
plt.tight_layout()
[ ]:
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
from matplotlib.ticker import MaxNLocator
ct = 'Ext_L23'
data = factor_true.values
fig, ax = plt.subplots(figsize=(3.5, 3.2))
norm = mpl.colors.TwoSlopeNorm(vcenter=0.0)
sc = ax.scatter(
x,
y,
c=data,
s=6,
cmap='bwr',
linewidths=0,
#norm=norm
)
cb = fig.colorbar(sc, ax=ax, shrink=0.4, pad=0.02, orientation='horizontal')
#cb.locator = MaxNLocator(nbins=1)
#cb.update_ticks()
#cb.ax.tick_params(labelsize=0)
cb.set_label('Normalized score', fontsize=12)
# no ticks
cb.set_ticks([])
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_linewidth(False)
ax.spines['bottom'].set_linewidth(False)
ax.set_title('Ground Truth', fontsize=15)
ax.set_xticks([])
ax.set_yticks([])
ax.set_aspect('equal', adjustable='box')
plt.tight_layout()
[ ]:
fig, ax = plt.subplots(figsize=(5, 3.2))
bar_w = 0.3
x_pos = np.arange(2)
bars1 = ax.bar(x_pos - bar_w/2, macsgp_scores, bar_w,
label='MacSGP', color='#4C72B0', edgecolor='white')
bars2 = ax.bar(x_pos + bar_w/2, pca_scores, bar_w,
label='Residual PCA', color='#DD8452', edgecolor='white')
for bar in list(bars1) + list(bars2):
h = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2, h + 0.01,
f'{h:.3f}', ha='center', va='bottom', fontsize=8)
ax.set_xticks(x_pos)
ax.set_xticklabels(['Factor\nCoherence', 'Loading\nCoherence'], fontsize=15)
ax.set_ylim(0, 1.1)
ax.set_ylabel('Coherence', fontsize=15)
#ax.set_title('Coherence Comparison', fontsize=15)
ax.legend(fontsize=8, loc='upper right')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.tight_layout()
plt.show()
Within celltype pca¶
[3]:
factor_pattern = 'gradient_y'
factor_celltype = [0]
n_spots = 3000
n_genes = 2000
n_celltypes = 2
n_cells = 500
n_covariates = 1
n_loading_genes = 200
n_groups = 4
ref_noise_ratio = 10
library_size = 5000
prop_confound = True
prop_min = 0.1
prop_max = 0.9
same_tau = True
spots_effects = False
platform_effects = False
shifted = False
c = 1
[4]:
adata_ref, adata_st, reference, logmu = construct_st.simulate_data_2ct(
seed=20250723,
n_spots=n_spots, n_genes=n_genes,
library_size=np.ones(n_spots) * library_size,
n_celltypes=n_celltypes,
n_cells=n_cells,
n_covariates=n_covariates,
n_groups=n_groups,
ref_noise_ratio=ref_noise_ratio,
same_tau=same_tau,
prop_confound=prop_confound,
prop_min=prop_min, prop_max=prop_max,
spot_effects=spots_effects, platform_effects=platform_effects,
factor=True, n_loading_gene=n_loading_genes,
factor_celltypes=factor_celltype, factor_pattern=factor_pattern,
shifted=False, c = 0.001,
)
Reference generated
Tau generated
Single cell data generated
Coordinates generated
Proportion generated
Covariates generated
mu generated
Lambda generated
Reference data generated
Spatial data generated
[6]:
MacSGP.utils.Cal_Spatial_Net(adata_st, mode='KNN', k_cutoff=12)
Calculating spatial neighbor graph ...
The graph contains 40806 edges, 3000 spots.
13.602 neighbors per spot on average.
[7]:
adata_st, adata_basis = MacSGP.utils.preprocess(adata_st,adata_ref,
celltype_ref_col = "celltype",
n_hvg_group = 1000)
Finding highly variable genes...
2000 highly variable genes selected.
Calculate basis for deconvolution...
Preprocess ST data...
[8]:
model = MacSGP.model.Model_deconv(adata_st, adata_basis, n_layers =4, training_steps=10000)
model.train(step_interval=1000)
adata_st = model.eval()
0%| | 9/10000 [00:02<37:24, 4.45it/s]
Step: 0, Loss: -736.1868, d_loss: -743.5078, f_loss: 73.2095
10%|█ | 1026/10000 [00:11<01:12, 123.85it/s]
Step: 1000, Loss: -930.1940, d_loss: -933.8029, f_loss: 36.0887
20%|██ | 2021/10000 [00:19<01:05, 121.14it/s]
Step: 2000, Loss: -931.1221, d_loss: -934.7235, f_loss: 36.0140
30%|███ | 3022/10000 [00:27<00:55, 125.01it/s]
Step: 3000, Loss: -931.2433, d_loss: -934.8381, f_loss: 35.9480
40%|████ | 4026/10000 [00:36<00:47, 124.64it/s]
Step: 4000, Loss: -931.3071, d_loss: -934.8942, f_loss: 35.8717
50%|█████ | 5021/10000 [00:44<00:40, 124.13it/s]
Step: 5000, Loss: -931.3336, d_loss: -934.9161, f_loss: 35.8255
60%|██████ | 6018/10000 [00:52<00:31, 124.46it/s]
Step: 6000, Loss: -931.3356, d_loss: -934.9124, f_loss: 35.7686
70%|███████ | 7014/10000 [01:00<00:25, 118.34it/s]
Step: 7000, Loss: -931.3438, d_loss: -934.9145, f_loss: 35.7074
80%|████████ | 8013/10000 [01:08<00:16, 123.90it/s]
Step: 8000, Loss: -931.3475, d_loss: -934.9190, f_loss: 35.7148
90%|█████████ | 9022/10000 [01:16<00:07, 137.57it/s]
Step: 9000, Loss: -931.3655, d_loss: -934.9211, f_loss: 35.5562
100%|██████████| 10000/10000 [01:23<00:00, 119.20it/s]
[10]:
adata_st.obs['ct'] = adata_st.obsm['proportion'].idxmax(axis=1)
[12]:
adata_st_ct = adata_st[adata_st.obs['ct']=='celltype_0'].copy()
sc.tl.pca(adata_st_ct, n_comps=min(10, adata_st_ct.n_obs - 1, adata_st_ct.n_vars - 1))
[13]:
model = MacSGP.model.Model(adata_st, adata_basis, n_layers=4, training_steps=3000)
model.train(step_interval=600)
adata_result = model.eval()
0%| | 9/3000 [00:00<01:06, 44.80it/s]
Step: 0, Loss: -927.6000, d_loss: -934.9209, f_loss: 73.2095, reg_loss: 0.0000
20%|██ | 614/3000 [00:08<00:33, 71.42it/s]
Step: 600, Loss: -944.7094, d_loss: -951.2840, f_loss: 36.1229, reg_loss: 0.2669
40%|████ | 1214/3000 [00:16<00:24, 72.88it/s]
Step: 1200, Loss: -949.8668, d_loss: -956.4533, f_loss: 36.0360, reg_loss: 0.2687
60%|██████ | 1810/3000 [00:24<00:16, 70.20it/s]
Step: 1800, Loss: -950.9908, d_loss: -957.4516, f_loss: 36.0039, reg_loss: 0.2577
80%|████████ | 2410/3000 [00:32<00:08, 71.62it/s]
Step: 2400, Loss: -950.9956, d_loss: -957.4464, f_loss: 35.9598, reg_loss: 0.2572
100%|██████████| 3000/3000 [00:40<00:00, 74.00it/s]
[ ]:
adata_result.obs['ct'] = adata_result.obsm['proportion'].idxmax(axis=1)
adata_result.obs['pc1'] = 0.0
adata_result.obs.loc[adata_st_ct.obs_names, 'pc1'] = adata_st_ct.obsm['X_pca'][:, 0]
adata_result.var['pc1'] = adata_st_ct.varm['PCs'][:, 0]
[ ]:
# ============================================================
# Global plot style (Nature Communications standard)
# ============================================================
mpl.rcParams.update({
'font.family': 'Helvetica', # Use Helvetica font
'font.size': 7,
'axes.titlesize': 8,
'axes.labelsize': 7,
'xtick.labelsize': 6.5,
'ytick.labelsize': 6.5,
'axes.linewidth': 0.5,
'xtick.major.width': 0.5,
'ytick.major.width': 0.5,
'xtick.major.size': 2.5,
'ytick.major.size': 2.5,
'pdf.fonttype': 42, # Embed fonts for vector editing
'ps.fonttype': 42,
'savefig.dpi': 300,
'figure.dpi': 150,
})
[ ]:
# Filter spots with low proportions
factor_true = adata_st.obsm['simulated_factor']
factor_macsgp = adata_result.obsm['factor']['celltype_0']
coords = adata_result.obsm['spatial']
w = KNN.from_array(coords, k=20)
w.transform = 'r' # Row standardization
bi = esda.Moran_BV(factor_true, factor_macsgp, w, permutations=999)
print('I:', bi.I, 'p-value:', bi.p_sim)
loading_true = adata_result.varm['simulated_loading'][:, 0]
loading_macsgp = adata_result.varm['loading']['celltype_0']
cor = np.corrcoef(loading_true, loading_macsgp)[0, 1]
print('Correlation of loadings:', cor)
macsgp_scores = [bi.I, cor]
[ ]:
# Filter spots with low proportions
factor_true = adata_st.obsm['simulated_factor'].loc[adata_st_ct.obs_names].values.reshape(-1)
factor_pca = adata_st_ct.obsm['X_pca'][:, 0].reshape(-1) # Use the first principal component as the factor value
# factor_pca = results['celltype_0']['scores'][:, 0] # Weighted by cell-type proportion to amplify spots with high proportion
coords = adata_st_ct.obsm['spatial']
w = KNN.from_array(coords, k=20)
w.transform = 'r' # Row standardization
bi = esda.Moran_BV(factor_true, factor_pca, w, permutations=999)
print('I:', bi.I, 'p-value:', bi.p_sim)
loading_true = adata_result.varm['simulated_loading'][:, 0]
loading_pca = adata_result.var['pc1'].values
# loading_pca = results['celltype_0']['loadings'][0]
cor = np.corrcoef(loading_true, loading_pca)[0, 1]
print('Correlation of loadings:', cor)
pca_scores = [abs(bi.I), cor]
[ ]:
# Shared variables (run once)
s = 8
proportion = adata_st.obsm['proportion']['celltype_0']
factor_true = adata_st.obsm['simulated_factor']
factor_macsgp = adata_result.obsm['factor']['celltype_0']
factor_pca = adata_result.obs['pc1'].values
sign_m = np.sign(pearsonr(factor_macsgp.values, factor_true.values.reshape(-1))[0])
factor_macsgp_aligned = factor_macsgp * sign_m
sign_p = np.sign(pearsonr(factor_pca, factor_true.values.reshape(-1))[0])
factor_pca_aligned = factor_pca * sign_p
[22]:
x = adata_st.obsm['spatial'][:, 0]
y = adata_st.obsm['spatial'][:, 1]
[ ]:
data = proportion
fig, ax = plt.subplots(figsize=(3.5, 3.2))
sc = ax.scatter(
x,
y,
c=data,
s=8,
cmap='YlOrBr',
linewidths=0,
)
cb = fig.colorbar(sc, ax=ax, shrink=0.4, pad=0.02, orientation='horizontal')
cb.locator = MaxNLocator(nbins=1)
cb.update_ticks()
cb.ax.tick_params(labelsize=12)
# Remove spines
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.set_title('Cell type A', fontsize=15)
ax.set_xticks([])
ax.set_yticks([])
ax.set_aspect('equal', adjustable='box')
plt.tight_layout()
plt.show()
[ ]:
data = 1 - proportion
fig, ax = plt.subplots(figsize=(3.5, 3.2))
sc = ax.scatter(
x,
y,
c=data,
s=8,
cmap='Blues',
linewidths=0,
)
cb = fig.colorbar(sc, ax=ax, shrink=0.4, pad=0.02, orientation='horizontal')
cb.locator = MaxNLocator(nbins=1)
cb.update_ticks()
cb.ax.tick_params(labelsize=12)
# Remove spines
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.set_title('Cell type B', fontsize=15)
ax.set_xticks([])
ax.set_yticks([])
ax.set_aspect('equal', adjustable='box')
plt.tight_layout()
plt.show()
[86]:
new_cmap_2 = set_zero_in_cmap_to_transparent(cmap=sns.color_palette("YlOrBr", as_cmap=True))
colors=new_cmap_2(np.arange(new_cmap_2.N))
colors = colors[0:new_cmap_2.N*3//4]
color2 = colors[new_cmap_2.N//2]
[87]:
new_cmap_1 = set_zero_in_cmap_to_transparent(cmap=sns.color_palette("Blues", as_cmap=True))
colors=new_cmap_1(np.arange(new_cmap_1.N))
colors = colors[0:new_cmap_1.N*3//4]
color1 = colors[new_cmap_1.N//2]
[ ]:
data = adata_st.obs['ct']
# Convert categorical data to codes and labels
if hasattr(data, 'cat'):
categories = data.cat.categories.tolist()
codes = data.cat.codes.values
else:
categories = sorted(data.unique())
cat_map = {c: i for i, c in enumerate(categories)}
codes = np.array([cat_map[v] for v in data])
n_cats = len(categories)
# Discrete colormap — specify colors for the two categories explicitly
color_dict = {
'celltype_0': color2, # Cell type A
'celltype_1': color1, # Cell type B
}
# Replace with your actual category names and colors
colors = [color_dict[c] for c in categories]
cmap = ListedColormap(colors)
fig, ax = plt.subplots(figsize=(3.5, 3.2))
sc = ax.scatter(
x,
y,
c=codes,
s=8,
cmap=cmap,
linewidths=0,
)
# Use legend instead of colorbar for categorical data
handles = [
plt.Line2D([0], [0], marker='o', color='w',
markerfacecolor=colors[i], markersize=6, label=categories[i])
for i in range(n_cats)
]
ax.legend(
handles=handles,
fontsize=10,
loc='upper center',
bbox_to_anchor=(0.5, -0.05),
frameon=False,
ncol=2,
handletextpad=0.3,
columnspacing=1.0,
labels=['Cell type A', 'Cell type B']
)
# Remove spines
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.set_title('Assigned Cell Type', fontsize=15)
ax.set_xticks([])
ax.set_yticks([])
ax.set_aspect('equal', adjustable='box')
plt.tight_layout()
plt.show()
[ ]:
data = factor_macsgp_aligned
fig, ax = plt.subplots(figsize=(3.5, 3.2))
sc = ax.scatter(
x,
y,
c=data,
s=8,
cmap='bwr',
linewidths=0,
)
cb = fig.colorbar(sc, ax=ax, shrink=0.4, pad=0.02, orientation='horizontal')
cb.set_label('Normalized score', fontsize=12)
cb.set_ticks([])
# Remove spines
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.set_title('MacSGP', fontsize=15)
ax.set_xticks([])
ax.set_yticks([])
ax.set_aspect('equal', adjustable='box')
plt.tight_layout()
[ ]:
# Color background spots gray
data = factor_pca_aligned
mask = adata_result.obs['ct'] != 'celltype_0' # Only show PCA results for celltype_0; other cells are grayed out
fig, ax = plt.subplots(figsize=(3.5, 3.2))
ax.scatter(
x[mask],
y[mask],
c='lightgray',
s=8,
linewidths=0,
)
sc = ax.scatter(
x[~mask],
y[~mask],
c=data[~mask],
s=8,
cmap='bwr',
linewidths=0,
)
cb = fig.colorbar(sc, ax=ax, shrink=0.4, pad=0.02, orientation='horizontal')
cb.set_label('Normalized score', fontsize=12)
cb.set_ticks([])
# Remove spines
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.set_title('Within-cell-type PCA', fontsize=15)
ax.set_xticks([])
ax.set_yticks([])
ax.set_aspect('equal', adjustable='box')
plt.tight_layout()
[ ]:
data = factor_true.values
fig, ax = plt.subplots(figsize=(3.5, 3.2))
sc = ax.scatter(
x,
y,
c=data,
s=6,
cmap='bwr',
linewidths=0,
)
cb = fig.colorbar(sc, ax=ax, shrink=0.4, pad=0.02, orientation='horizontal')
cb.set_label('Normalized score', fontsize=12)
cb.set_ticks([])
# Remove spines
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.set_title('Ground Truth', fontsize=15)
ax.set_xticks([])
ax.set_yticks([])
ax.set_aspect('equal', adjustable='box')
plt.tight_layout()
[ ]:
# Figure 5: Coherence Comparison
fig, ax = plt.subplots(figsize=(5, 3.2))
bar_w = 0.3
x_pos = np.arange(2)
bars1 = ax.bar(x_pos - bar_w/2, macsgp_scores, bar_w,
label='MacSGP', color='#4C72B0', edgecolor='white')
bars2 = ax.bar(x_pos + bar_w/2, pca_scores, bar_w,
label='Within-cell-type PCA', color='#DD8452', edgecolor='white')
for bar in list(bars1) + list(bars2):
h = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2, h + 0.01,
f'{h:.3f}', ha='center', va='bottom', fontsize=8)
ax.set_xticks(x_pos)
ax.set_xticklabels(['Factor\nCoherence', 'Loading\nCoherence'], fontsize=15)
ax.set_ylim(0, 1.1)
ax.set_ylabel('Coherence', fontsize=15)
ax.legend(fontsize=8, loc='upper right')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.tight_layout()
plt.show()