hello,大家好,今天给大家分享10X空间转录组一个新的分析点,图卷积网络,关于这个,不知道大家对机器学习了解多少,希望认真做科研的人,能够好好学习一些数学方面的知识,对自己大有裨益。
先放一张效果图
今天分享的文章在Integrating gene expression, spatial location and histology to identify spatial domains and spatially variable genes by graph convolutional network,看题目就知道,图卷积网络是把空间的基因表达,空间位置和组织学等多方面的信息结合在一起,从而实现对10X空间转录组新的角度的分析,好了,我们提炼一下关键信息,最后分享示例代码。
Abstract
软件叫SpaGCN,a graph convolutional network approach that integrates gene expression,spatial location and histology in spatial transcriptomics data analysis。
通过图卷积,软件SpaGCN从其相邻spot聚合每个spot的基因表达,从而能够识别具有一致表达和组织学的空间域(这也是我们做空间分析重要的一方面)。 随后的domain引导差异表达分析然后检测在已识别domain中具有丰富表达模式的基因。(也就是说,识别相似的邻域来划分空间区域,基本是在替代普通的聚类)。
Introduction
1、了解组织中不同细胞的相对位置对于理解疾病病理学至关重要,因为空间信息有助于了解细胞的基因表达如何受其周围环境的影响以及相邻区域如何在基因表达水平上相互作用 。(这也是空间转录组最大的意义)。
2、获得空间转录组信息主要有两种策略 (1)single-molecule fluorescence in situ hybridization (smFISH) based techniques, such as MERFISH2 and seqFISH3, which measure expression level for hundreds of genes with 45 subcellular spatial resolution in a single cell 和(2)spatial barcoding followed by next generation sequencing based techniques, such as SLIDE-seq4 and 10X Genomics Visium, which measure the expression level for thousands of genes in captured locations, referred to as spots(当然我们更加关心的是10X的空间转录组)。这些不同的空间转录组学技术使揭示异质组织复杂的转录结构成为可能,并增强了我们对疾病细胞机制的理解。
3、在空间转录组学研究中,一个重要的步骤是确定空间domain,定义为在基因表达和组织学上具有空间一致性的区域。 (这个非常重要,是一切研究的基础)。当然,识别空间区域就会涉及到空间基因表达,空间位置和组织学方面的内容。传统的聚类方法(K-means and Louvain’s method,在10X单细胞的分析中广泛运用)只分析基因表达的特征,很显然这在空间转录组的分析上是不够的,To account for spatial dependency of gene expression, new methods have been developed.专门针对空间的聚类方法现在已经有了stlearn,在聚类之前使用从组织学图像中提取的特征以及相邻点的表达到个空间平滑的基因表达数据 ;还有BayesSpace,运用Bayesian approach通过对物理上靠近的点赋予更高权重的先验进行聚类分析;还有隐马尔可夫随机场方法来模拟基因表达的空间依赖性等等,尽管这些方法已经对空间划分了区域,但是缺少生物学解释。
4、To link spatial domains with biological functions at the gene expression level, it is crucial to identify genes that show enriched expression in the identified domains.由于组织中细胞类型的空间变异,不同domain之间基因表达的差异主要由细胞类型组成的变化驱动。 另一方面,关于空间位置和相应组织学的信息允许构建基于解剖学的组织分类,这为细胞类型组成提供了有用的视角。其中虽然stlearn已经结合了空间基因表达,空间位置和组织学进行聚类,但是细胞类型差异与组织组织结构之间的推定对应关系尚不清楚。而且许多空间区域在细胞类型方面高度混合。如果没有进一步的下游基因水平分析,stlearn检测到的空间domain仍然缺乏可解释性。 最近,Trendsceek、SpatialDE 和SPARK等新方法被开发用于检测空间可变基因 (SVG)。这些方法独立检查每个基因并返回一个 p 值来表示基因的空间变异性。 然而,由于缺乏对组织分类的考虑,这些方法检测到的基因没有保证的空间表达模式,因此很难将这些基因用于进一步的生物学研究(这也是空间高变基因的检出结果很难运用的原因)。
5、不能将空间domian识别和 SVG 检测视为单独的问题,利用软件SpaGCN,这是一种基于图卷积网络的方法,可以联合考虑这两个问题。 使用带有附加迭代聚类层的图卷积网络,SpaGCN 首先通过构建表示数据空间依赖性的无向加权图将基因表达、空间位置和组织学整合在一起来识别空间域。 对于每个空间域,SpaGCN 然后通过域信息引导的差异表达分析检测在域中丰富的 SVG 与其周围区域。 SpaGCN 还可以选择检测在给定域中唯一表达的meta基因。 空间domain以及为这些域检测到的相应 SVG 和meta基因提供了关于组织中基因表达空间梯度的全面图景。
我们来看看文章里面的分析结果
SpaGCN软件的介绍
SpaGCN 首先构建一个图来表示所有样本(基于测序的spot)的关系,同时考虑空间位置和组织学信息;接下来,SpaGCN 利用图卷积层聚合来自相邻spot的基因表达信息;然后,SpaGCN 使用聚合的基因表达矩阵使用无监督迭代聚类算法对spot进行聚类;每个cluster被视为一个空间domain,然后 SpaGCN 从中检测通过差异表达分析在域中丰富的 SVG。
当单个基因不能标记一个空间domain的表达模式时,SpaGCN会构建一个由多个SVG组合而成的meta基因来表示该域的基因表达。 由于斑点/细胞的表达谱受到其局部微环境的严重影响,SpaGCN 还提供了每个空间域内的子cluster检测选项。 还可以检测 SVG 以帮助理解每个子空间domain的功能。
接下来是软件的一些运用
应用于小鼠嗅球数据
K-means 只识别了 3 个主要空间域,只有很少的点被分配到了域 1 和 3。 Louvain 的方法识别了 5 个主要空间域。 然而,由于它没有考虑空间和组织学信息,域 2、3 和 4 的边界模糊,并且比 SpaGCN 有更多的异常值。 相比之下,SpaGCN 检测到的域与生物已知的 MOB 5 层结构更吻合。
然后对小鼠嗅球数据检测高变基因
all genes show strong specificity for the corresponding domain(用SpaGCN检测到的高变基因),当然作者也比较了SpatialDE and SPARK检测空间高变基因的结果,当然,SpaGCN最具有解释性。相比之下,SpaGCN 检测到的所有 SVG 都是特定于领域的,根据对层结构的了解,提供了合理的解释。 注意到,如果用户将domian 2和domain 4 组合为 SVG 检测中的目标域,则 SpaGCN 也可以检测到具有清晰但非domain特定空间模式的信息较少的 SVG,例如 PCP4。
在小鼠后脑数据中的应用(还是SpaGCN的结果更加合理)
同样的空间高变基因的检测比较,The Moran’s I values of SpaGCN detected SVGs are much higher than those detected by SPARK and SpatialDE (median of 0.50 for SpaGCN against 0.21 for SPARK and 0.16 for SpatialDE).
对 SPARK 和 SpatialDE 检测到的 SVG 进行仔细检查后发现,大多数 SVG 都存在先前在 MOB 数据集中观察到的两个问题之一:它们 (1) 仅在少数几个点中表达或在大多数点中高度表达,表明 SPARK 和 SpatialDE 的高误报率或 (2) 空间可变,但在多个相邻空间域中表达,使其难以解释。这两种方法的另一个限制是来自 SPARK 的 FDR 调整 p 值和来自 SpatialDE 的 q 值不提供信息。具有相似 p 值/q 值的基因不一定显示相似的空间模式,较小的 p 值/q 值并不能保证更好的空间模式(下图)。
SPARK 和 SpatialDE 的 p 值和 q 值分布高度偏向 0(下图)。
相比之下,SpaGCN 检测到的 SVG 在特定空间域中富集(下图),
它们的表达模式可转移到小鼠后脑中的相邻组织切片(下图)。
此外,SpaGCN 中实现的多域自适应过滤标准使其能够消除误报 SVG,并确保所有检测到的 SVG 具有清晰的空间表达模式。
为了说明适当过滤的重要性,我们以domain 1、5 和 8 为例。对于这些domain中的每一个,SpaGCN 都检测到在该区域中富含的单个 SVG(下图)。
PVALB 在域 1 中富集,TRiM62 在域 8 中富集。虽然域 1 和域 8 彼此相邻,但这两个 SVG 仍然可以很好地标记这些域。 NRGN 是 SpaGCN 针对域 5 和 7 检测到的 SVG。域 5 和 7 中 NRGN 的高表达也表明这两个域在神经解剖学上相似——均由皮层和海马的锥体层组成。皮层和海马体都是位于大脑曲面上的区域。此后脑组织切片具有域 5 中曲面的顶部和域 7 中曲面的底部。域 5 和域 7 在完整的 3D 重建中是连续的,由于方式人为分离该部分被切断。因此,除了 NRGN 之外,SpaGCN 还检测到许多其他 SVG,如 APP、ATP6V1G2、CALM2、CHN1、CLSTN1、ARPP21、CYP46A1、DCLK1、LINGO1 和 MARCKS,这并不奇怪,它们在两个域中都高度表达 5和 7。SpaGCN 中独特而强大的 SVG 检测程序可确保不会遗漏此类基因。
(重点)meta gene 的识别
SpaGCN 没有识别域 0 的任何 SVG。然而,我们推断由多个基因组合形成的meta gene可能比任何单个基因更好地揭示空间模式。
首先,通过降低过滤阈值,SpaGCN 识别出在结构域 0 下部高度表达的 KLK6。使用 KLK6 作为起始基因,SpaGCN 使用一种新方法找到了 KLK6、MBP 和 MBP 基因表达的对数线性组合。 ATP1B1,准确标记了空间域 0。在该元基因中,KLK6 和 MBP 被认为是阳性标记,因为它们在域 0 的某些点上高表达,而 ATP1B1 被认为是阴性标记,因为它主要在其他区域表达比域 0。以前的研究表明 KLK6 和 MBP 的表达仅限于少突胶质细胞,而 ATP1B1 主要在神经元和星形胶质细胞中表达。这与域 0 代表由少突胶质细胞主导且几乎没有神经元细胞体的白质的事实产生共鸣。因此,构成这个元基因的基因具有有意义的生物学解释。使用这种元基因检测程序,我们还检测了域 2、7、8 和 9 的元基因,并发现这些元基因可转移到相邻的组织切片(下图)。
一个spot的表达谱和生物学功能受其相邻点的严重影响。周围的spot可以触发响应路径或向该点发出信号以执行某些任务(其实就是我们经常谈到的临近通讯)。尽管 SpaGCN 检测到的一个空间域中的spot在空间上是一致的,并且具有相似的基因表达模式,但由于它们周围的spot不同,它们可能仍然具有不同的功能。例如,与位于空间域内部的spot相比,位于空间域边界附近的spot可能具有不同的功能。为了更多地了解不同邻域对spot的影响,我们进行了子域检测。例如,域 2 位于组织切片的中心并被多个其他空间域包围。因此,域 2 中的spot的相邻环境会发生变化。如下图所示,域 2 被分成 5 个子域,它们位于域 2 的中心或不同边界区域,这表明spot邻域的差异导致域内异质性。为每个子域检测到的 SVG 可以帮助我们了解每个子域内spot的基因表达变异性。
LIBD 人类背外侧前额叶皮层数据的应用(同样的套路)
空间高变基因的检测,Patterns of SVGs for other domains are not very clear
SVGs detected by SPARK lack domain specificity(下图)
SpatialDE detected 3,654 SVGs with 806 of them having q-values equal to 0, but these genes do not necessarily show better spatial pattern than genes with larger q-values
这两种方法检测到的基因缺乏区分表达中不同程度空间变异性的能力,因为它们的 p 值和 q 值分布高度偏向于 0
下图显示 SpaGCN 检测到的 SVG 的 Moran's I 值显着高于 SpatialDE 和 SPARK 检测到的值。
有些区域可以识别单个specific gene(下图)
但更合理的解释是空间高变的meta gene
在人原发性胰腺癌组织中的应用
上图shows that domain 2 detected by SpaGCN has a better correspondence to the cancer region than clusters reported in the original study。
空间高变基因的检测,SpaGCN的可解释性最好
在 MERFISH 小鼠下丘脑数据中的应用
Method,主要关注一下软件的算法,当然非常难,我们下一篇详细分享。
示例代码
安装
pip3 install SpaGCN
#Note: you need to make sure that the pip is for python3,or we should install SpaGCN by
python3 -m pip install SpaGCN
pip3 install SpaGCN
#If you do not have permission (when you get a permission denied error), you should install SpaGCN by
pip3 install --user SpaGCN
加载,Import python modules
import os,csv,re
import pandas as pd
import numpy as np
import scanpy as sc
import math
import SpaGCN as spg
from scipy.sparse import issparse
import random, torch
import warnings
warnings.filterwarnings("ignore")
import matplotlib.colors as clr
import matplotlib.pyplot as plt
import SpaGCN as spg
#In order to read in image data, we need to install some package. Here we recommend package "opencv"
#inatll opencv in python
#!pip3 install opencv-python
import cv2
读取数据
当前版本的 SpaGCN 需要三个输入数据:
- 基因表达矩阵(n by k):expression_matrix.h5;
- samplespositions.txt 的空间坐标;
- 组织学图像(可选):histology.tif,可以是 tif 或 png 或 jepg。
- 基因表达数据可以存储为 AnnData 对象。 AnnData 将数据矩阵 .X 与观察注释 .obs、变量 .var 和非结构化注释 .uns 一起存储。
"""
#Read original 10x_h5 data and save it to h5ad
from scanpy import read_10x_h5
adata = read_10x_h5("../tutorial/data/151673/expression_matrix.h5")
spatial=pd.read_csv("../tutorial/data/151673/positions.txt",sep=",",header=None,na_filter=False,index_col=0)
adata.obs["x1"]=spatial[1]
adata.obs["x2"]=spatial[2]
adata.obs["x3"]=spatial[3]
adata.obs["x4"]=spatial[4]
adata.obs["x5"]=spatial[5]
#Select captured samples
adata=adata[adata.obs["x1"]==1]
adata.var_names=[i.upper() for i in list(adata.var_names)]
adata.var["genename"]=adata.var.index.astype("str")
adata.write_h5ad("../tutorial/data/151673/sample_data.h5ad")
"""
#Read in gene expression and spatial location
adata=sc.read("../tutorial/data/151673/sample_data.h5ad")
#Read in hitology image
img=cv2.imread("../tutorial/data/151673/histology.tif")
Integrate gene expression and histology into a Graph
#Set coordinates
adata.obs["x_array"]=adata.obs["x2"]
adata.obs["y_array"]=adata.obs["x3"]
adata.obs["x_pixel"]=adata.obs["x4"]
adata.obs["y_pixel"]=adata.obs["x5"]
x_array=adata.obs["x_array"].tolist()
y_array=adata.obs["y_array"].tolist()
x_pixel=adata.obs["x_pixel"].tolist()
y_pixel=adata.obs["y_pixel"].tolist()
#Test coordinates on the image
img_new=img.copy()
for i in range(len(x_pixel)):
x=x_pixel[i]
y=y_pixel[i]
img_new[int(x-20):int(x+20), int(y-20):int(y+20),:]=0
cv2.imwrite('./sample_results/151673_map.jpg', img_new)
- “s”参数确定在计算每两个点之间的欧几里得距离时赋予组织学的权重。 's = 1' 表示组织学像素强度值与 (x,y) 坐标具有相同的尺度方差,而 's' 值越高表示尺度方差越大,因此,在计算欧几里得距离时,组织学的权重越高 .
- “b”参数确定提取颜色强度时每个点的面积。
#Calculate adjacent matrix
s=1
b=49
adj=spg.calculate_adj_matrix(x=x_pixel,y=y_pixel, x_pixel=x_pixel, y_pixel=y_pixel, image=img, beta=b, alpha=s, histology=True)
#If histlogy image is not available, SoaGCN can calculate the adjacent matrix using the fnction below
#adj=calculate_adj_matrix(x=x_pixel,y=y_pixel, histology=False)
np.savetxt('./data/151673/adj.csv', adj, delimiter=',')
Spatial domain detection using SpaGCN(空间区域检测)
adata=sc.read("./data/151673/sample_data.h5ad")
adj=np.loadtxt('./data/151673/adj.csv', delimiter=',')
adata.var_names_make_unique()
spg.prefilter_genes(adata,min_cells=3) # avoiding all genes are zeros
spg.prefilter_specialgenes(adata)
#Normalize and take log for UMI
sc.pp.normalize_per_cell(adata)
sc.pp.log1p(adata)
设置超参数
- p:社区贡献的总表达百分比。
- l:控制p的参数。
p=0.5
#Find the l value given p
l=spg.search_l(p, adj, start=0.01, end=1000, tol=0.01, max_run=100)
- n_clusters: Number of spatial domains wanted.
- res: Resolution in the initial Louvain's Clustering methods. If the number of clusters is known, we can use the spg.search_res() fnction to search for suitable resolution(optional)
#If the number of clusters known, we can use the spg.search_res() fnction to search for suitable resolution(optional)
#For this toy data, we set the number of clusters=7 since this tissue has 7 layers
n_clusters=7
#Set seed
r_seed=t_seed=n_seed=100
#Seaech for suitable resolution
res=spg.search_res(adata, adj, l, n_clusters, start=0.7, step=0.1, tol=5e-3, lr=0.05, max_epochs=20, r_seed=r_seed, t_seed=t_seed, n_seed=n_seed)
运行SpaGCN
clf=spg.SpaGCN()
clf.set_l(l)
#Set seed
random.seed(r_seed)
torch.manual_seed(t_seed)
np.random.seed(n_seed)
#Run
clf.train(adata,adj,init_spa=True,init="louvain",res=res, tol=5e-3, lr=0.05, max_epochs=200)
y_pred, prob=clf.predict()
adata.obs["pred"]= y_pred
adata.obs["pred"]=adata.obs["pred"].astype('category')
#Do cluster refinement(optional)
#shape="hexagon" for Visium data, "square" for ST data.
adj_2d=spg.calculate_adj_matrix(x=x_array,y=y_array, histology=False)
refined_pred=spg.refine(sample_id=adata.obs.index.tolist(), pred=adata.obs["pred"].tolist(), dis=adj_2d, shape="hexagon")
adata.obs["refined_pred"]=refined_pred
adata.obs["refined_pred"]=adata.obs["refined_pred"].astype('category')
#Save results
adata.write_h5ad("./sample_results/results.h5ad")
Plot spatial domains
adata=sc.read("./sample_results/results.h5ad")
#Set colors used
plot_color=["#F56867","#FEB915","#C798EE","#59BE86","#7495D3","#D1D1D1","#6D1A9C","#15821E","#3A84E6","#997273","#787878","#DB4C6C","#9E7A7A","#554236","#AF5F3C","#93796C","#F9BD3F","#DAB370","#877F6C","#268785"]
#Plot spatial domains
domains="pred"
num_celltype=len(adata.obs[domains].unique())
adata.uns[domains+"_colors"]=list(plot_color[:num_celltype])
ax=sc.pl.scatter(adata,alpha=1,x="y_pixel",y="x_pixel",color=domains,title=domains,color_map=plot_color,show=False,size=100000/adata.shape[0])
ax.set_aspect('equal', 'box')
ax.axes.invert_yaxis()
plt.savefig("./sample_results/pred.png", dpi=600)
plt.close()
#Plot refined spatial domains
domains="refined_pred"
num_celltype=len(adata.obs[domains].unique())
adata.uns[domains+"_colors"]=list(plot_color[:num_celltype])
ax=sc.pl.scatter(adata,alpha=1,x="y_pixel",y="x_pixel",color=domains,title=domains,color_map=plot_color,show=False,size=100000/adata.shape[0])
ax.set_aspect('equal', 'box')
ax.axes.invert_yaxis()
plt.savefig("./sample_results/refined_pred.png", dpi=600)
plt.close()
Identify SVGs
#Read in raw data
raw=sc.read("../tutorial/data/151673/sample_data.h5ad")
raw.var_names_make_unique()
raw.obs["pred"]=adata.obs["pred"].astype('category')
raw.obs["x_array"]=raw.obs["x2"]
raw.obs["y_array"]=raw.obs["x3"]
raw.obs["x_pixel"]=raw.obs["x4"]
raw.obs["y_pixel"]=raw.obs["x5"]
#Convert sparse matrix to non-sparse
raw.X=(raw.X.A if issparse(raw.X) else raw.X)
raw.raw=raw
sc.pp.log1p(raw)
- target:用于识别 SVG 的目标域。
- min_in_group_fraction:最小组内表达分数。
- min_in_out_group_ratio:最小值(组内表达分数)/(组外表达分数)。
- min_fold_change:最小(组内表达式)/(组外表达式)。
- r:检测一个点的相邻点的半径。
#Use domain 0 as an example
target=0
#Set filtering criterials
min_in_group_fraction=0.8
min_in_out_group_ratio=1
min_fold_change=1.5
#Search radius such that each spot in the target domain has approximately 10 neighbors on average
adj_2d=spg.calculate_adj_matrix(x=x_array, y=y_array, histology=False)
start, end= np.quantile(adj_2d[adj_2d!=0],q=0.001), np.quantile(adj_2d[adj_2d!=0],q=0.1)
r=spg.search_radius(target_cluster=target, cell_id=adata.obs.index.tolist(), x=x_array, y=y_array, pred=adata.obs["pred"].tolist(), start=start, end=end, num_min=10, num_max=14, max_run=100)
#Detect neighboring domains
nbr_domians=spg.find_neighbor_clusters(target_cluster=target,
cell_id=raw.obs.index.tolist(),
x=raw.obs["x_array"].tolist(),
y=raw.obs["y_array"].tolist(),
pred=raw.obs["pred"].tolist(),
radius=r,
ratio=1/2)
nbr_domians=nbr_domians[0:3]
de_genes_info=spg.rank_genes_groups(input_adata=raw,
target_cluster=target,
nbr_list=nbr_domians,
label_col="pred",
adj_nbr=True,
log=True)
#Filter genes
de_genes_info=de_genes_info[(de_genes_info["pvals_adj"]<0.05)]
filtered_info=de_genes_info
filtered_info=filtered_info[(filtered_info["pvals_adj"]<0.05) &
(filtered_info["in_out_group_ratio"]>min_in_out_group_ratio) &
(filtered_info["in_group_fraction"]>min_in_group_fraction) &
(filtered_info["fold_change"]>min_fold_change)]
filtered_info=filtered_info.sort_values(by="in_group_fraction", ascending=False)
filtered_info["target_dmain"]=target
filtered_info["neighbors"]=str(nbr_domians)
print("SVGs for domain ", str(target),":", filtered_info["genes"].tolist())
filtered_info
genes | in_group_fraction | out_group_fraction | in_out_group_ratio | in_group_mean_exp | out_group_mean_exp | fold_change | pvals_adj | target_dmain | neighbors | ||
---|---|---|---|---|---|---|---|---|---|---|---|
0 | CAMK2N1 | 1.000000 | 0.944964 | 1.058242 | 2.333675 | 1.578288 | 2.128434 | 1.656040e-11 | 0 | [3, 2] | |
2 | ENC1 | 0.998638 | 0.941848 | 1.060295 | 2.457791 | 1.696083 | 2.141931 | 1.552131e-03 | 0 | [3, 2] | |
4 | GPM6A | 0.997275 | 0.922118 | 1.081505 | 2.224006 | 1.561187 | 1.940255 | 8.602227e-03 | 0 | [3, 2] | |
6 | ARPP19 | 0.982289 | 0.853583 | 1.150784 | 1.889256 | 1.272106 | 1.853637 | 4.823349e-02 | 0 | [3, 2] | |
1 | HPCAL1 | 0.851499 | 0.465213 | 1.830342 | 1.141321 | 0.406338 | 2.085448 | 9.706465e-05 | 0 | [3, 2] |
#Plot refinedspatial domains
color_self = clr.LinearSegmentedColormap.from_list('pink_green', ['#3AB370',"#EAE7CC","#FD1593"], N=256)
for g in filtered_info["genes"].tolist():
raw.obs["exp"]=raw.X[:,raw.var.index==g]
ax=sc.pl.scatter(raw,alpha=1,x="y_pixel",y="x_pixel",color="exp",title=g,color_map=color_self,show=False,size=100000/raw.shape[0])
ax.set_aspect('equal', 'box')
ax.axes.invert_yaxis()
plt.savefig("./sample_results/"+g+".png", dpi=600)
plt.close()
最重要的部分, Identify Meta Gene
#Use domain 2 as an example
target=2
meta_name, meta_exp=spg.find_meta_gene(input_adata=raw,
pred=raw.obs["pred"].tolist(),
target_domain=target,
start_gene="GFAP",
mean_diff=0,
early_stop=True,
max_iter=3,
use_raw=False)
raw.obs["meta"]=meta_exp
#Plot meta gene
g="GFAP"
raw.obs["exp"]=raw.X[:,raw.var.index==g]
ax=sc.pl.scatter(raw,alpha=1,x="y_pixel",y="x_pixel",color="exp",title=g,color_map=color_self,show=False,size=100000/raw.shape[0])
ax.set_aspect('equal', 'box')
ax.axes.invert_yaxis()
plt.savefig("./sample_results/"+g+".png", dpi=600)
plt.close()
raw.obs["exp"]=raw.obs["meta"]
ax=sc.pl.scatter(raw,alpha=1,x="y_pixel",y="x_pixel",color="exp",title=meta_name,color_map=color_self,show=False,size=100000/raw.shape[0])
ax.set_aspect('equal', 'box')
ax.axes.invert_yaxis()
plt.savefig("./sample_results/meta_gene.png", dpi=600)
plt.close()
Multiple tissue sections analysis(联合分析)
读取数据
adata1=sc.read("./data/Mouse_brain/MA1.h5ad")
adata2=sc.read("./data/Mouse_brain/MP1.h5ad")
img1=cv2.imread("./data/Mouse_brain/MA1_histology.tif")
img2=cv2.imread("./data/Mouse_brain/MP1_histology.tif")
Extract color intensity
b=49
s=1
x_pixel1=adata1.obs["x4"].tolist()
y_pixel1=adata1.obs["x5"].tolist()
adata1.obs["color"]=spg.extract_color(x_pixel=x_pixel1, y_pixel=y_pixel1, image=img1, beta=b)
z_scale=np.max([np.std(x_pixel1), np.std(y_pixel1)])*s
adata1.obs["z"]=(adata1.obs["color"]-np.mean(adata1.obs["color"]))/np.std(adata1.obs["color"])*z_scale
x_pixel2=adata2.obs["x4"].tolist()
y_pixel2=adata2.obs["x5"].tolist()
adata2.obs["color"]=spg.extract_color(x_pixel=x_pixel2, y_pixel=y_pixel2, image=img2, beta=b)
z_scale=np.max([np.std(x_pixel2), np.std(y_pixel2)])*s
adata2.obs["z"]=(adata2.obs["color"]-np.mean(adata2.obs["color"]))/np.std(adata2.obs["color"])*z_scale
del img1, img2
Modify coordinates to combine 2 sections
from anndata import AnnData
adata1.obs["x_pixel"]=x_pixel1
adata1.obs["y_pixel"]=y_pixel1
adata2.obs["x_pixel"]=x_pixel2-np.min(x_pixel2)+np.min(x_pixel1)
adata2.obs["y_pixel"]=y_pixel2-np.min(y_pixel2)+np.max(y_pixel1)
adata1.var_names_make_unique()
adata2.var_names_make_unique()
adata_all=AnnData.concatenate(adata1, adata2,join='inner',batch_key="dataset_batch",batch_categories=["0","1"])
Integrate gene expression and histology into a Graph
X=np.array([adata_all.obs["x_pixel"], adata_all.obs["y_pixel"], adata_all.obs["z"]]).T.astype(np.float32)
adj=spg.pairwise_distance(X)
Spatial domain detection using SpaGCN
sc.pp.normalize_per_cell(adata_all, min_counts=0)
sc.pp.log1p(adata_all)
p=0.5
#Find the l value given p
l=spg.search_l(p, adj, start=0.01, end=1000, tol=0.01, max_run=100)
res=1.0
seed=100
random.seed(seed)
torch.manual_seed(seed)
np.random.seed(seed)
clf=spg.SpaGCN()
clf.set_l(l)
clf.train(adata_all,adj,init_spa=True,init="louvain",res=res, tol=5e-3, lr=0.05, max_epochs=200)
y_pred, prob=clf.predict()
adata_all.obs["pred"]= y_pred
adata_all.obs["pred"]=adata_all.obs["pred"].astype('category')
colors_use=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#bcbd22', '#17becf', '#aec7e8', '#ffbb78', '#98df8a', '#ff9896', '#bec1d4', '#bb7784', '#0000ff', '#111010', '#FFFF00', '#1f77b4', '#800080', '#959595',
'#7d87b9', '#bec1d4', '#d6bcc0', '#bb7784', '#8e063b', '#4a6fe3', '#8595e1', '#b5bbe3', '#e6afb9', '#e07b91', '#d33f6a', '#11c638', '#8dd593', '#c6dec7', '#ead3c6', '#f0b98d', '#ef9708', '#0fcfc0', '#9cded6', '#d5eae7', '#f3e1eb', '#f6c4e1', '#f79cd4']
num_celltype=len(adata_all.obs["pred"].unique())
adata_all.uns["pred_colors"]=list(colors_use[:num_celltype])
ax=sc.pl.scatter(adata_all,alpha=1,x="y_pixel",y="x_pixel",color="pred",show=False,size=150000/adata_all.shape[0])
ax.set_aspect('equal', 'box')
ax.axes.invert_yaxis()
plt.savefig("./sample_results/mouse_barin_muti_sections_domains.png", dpi=600)
plt.close()
非常棒的方法,大家一定要试一试
生活很好,有你更好