单细胞分析之细胞交互-1:CellphoneDB


常用的细胞通讯软件:

  • CellphoneDB:是公开的人工校正的,储存受体、配体以及两种相互作用的数据库。此外,还考虑了结构组成,能够描述异构复合物。(配体-受体+多聚体)
  • iTALK:通过平均表达量方式,筛选高表达的胚体和受体,根据结果作圈图。(配体-受体)
  • CellChat:CellChat将细胞的基因表达数据作为输入,并结合配体受体及其辅助因子的相互作用来模拟细胞间通讯。(配体-受体+多聚体+辅因子)
  • NicheNet // NicheNet多样本分析 // 目标基因的配体和靶基因活性预测:通过将相互作用细胞的表达数据与信号和基因调控网络的先验知识相结合来预测相互作用细胞之间的配体-靶标联系的方法。( 配体-受体+信号通路)
    附:NicheNet使用的常见问题汇总

其它细胞互作软件还包括CelltalkerSingleCellSignalRscTensorSoptSC(这几个也是基于配体-受体相互作用)


1. CellPhoneDB介绍

Nature protocol原文

CellPhoneDB是包含配体、受体及其相互作用的数据库,可以对细胞间的通讯分子进行全面、系统的分析,研究不同细胞类型之间的相互交流及通讯网络。

CellPhoneDB 是目前使用最广泛的细胞通讯分析软件,CellPhoneDB的配体-受体数据库集成于UniProt、Ensembl、PDB、IUPHAR等,共存储978种蛋白质:其中501种是分泌蛋白,而585种是膜蛋白,这些蛋白质参与1,396种相互作用。CellPhoneDB数据库还考虑了配体和受体的亚基结构,准确地表示了异聚体复合物,有466个是异聚体,对于准确研究多亚基复合物介导的细胞通讯很关键。CellPhoneDB有474种相互作用涉及分泌蛋白,而490种相互作用涉及膜蛋白,总共有250个涉及整合素的相互作用。
数据库链接:https://www.cellphonedb.org/ppi-resources
目前支持的物种:人(也可通过人和鼠的同源基因比对应用于鼠)

2. CellPhoneDB原理

参考:https://www.cellphonedb.org/explore-sc-rna-seq

  1. CellphoneDB基于一种细胞类型的受体和另一种细胞类型的配体的表达,得出两种细胞群之间丰富的受体-配体相互作用。对于细胞群所表达的基因,计算表达该基因的细胞百分比和基因表达平均值。若该基因只在该群中10%及以下的细胞中表达(默认值为0.1),则被移除。
  2. 将所有细胞的簇标签随机排列1000次(可选值),并确定簇中受体平均表达水平和相互作用簇中配体平均表达水平的平均值。对于两种细胞类型之间每对比较中的每一个受体-配体对,这产生了一个零分布(null distribution,亦称伯努利分布、两点分布,指的是对于随机变量X有, 参数为p(0<p<1),如果它分别以概率p和1-p取1和0为值。EX= p,DX=p(1-p)。伯努利试验成功的次数服从伯努利分布,参数p是试验成功的概率)。
  3. 通过计算等于或高于实际平均值的平均值的比例,可以得到了一个P值,表示给定受体-配体复合物细胞类型特异性的可能性。换句话说,如果观察到的平均值在前5%,则相互作用的P值为0.05。
  4. 根据两种细胞类型中富集到的显著的受体-配体对的数量,对细胞类型之间高度特异性的相互作用进行排序,以便手动筛选出生物学相关的相互作用关系。

3. CellPhoneDB下载和使用

3.1 CellPhoneDB下载和主要功能介绍
  • 安装:
    CellPhoneDB软件仓库地址:https://github.com/Teichlab/cellphonedb
    PIP安装:pip install cellphonedb(python版本需要python>3.5)
    CellPhoneDB安装完成后,可以在终端测试是否成功。

  • CellPhoneDB主要分成method、plot、query和database4个模块。

我们主要进行分析的是method(分析模块)和plot模块(画图模块)。
query是进行数据查询的模块,查询基因有哪些互作结果(get_interaction_gene结果为数据库涉及到的基因,find_interactions_by_element可以找到特定基因的受体配体作用数据对)。
database是输入数据库,一般默认可以不输入,直接使用即可。

  • 四个重要的函数:
  • 核心可选参数:

示例:

#(1)设置迭代和线程的数量
cellphonedb method statistical_analysis yourmetafile.txt yourcountsfile.txt --iterations=10 --threads=2
#(2)子项目文件夹
cellphonedb method analysis yourmetafile.txt yourcountsfile.txt --project-name=new_project
# (3)设置输出路径
mkdir custom_folder
cellphonedb method statistical_analysis yourmetafile.txt yourcountsfile.txt --output-path=custom_folder
#(4) 二次抽样
cellphonedb method analysis yourmetafile.txt yourcountsfile.txt --subsampling --subsampling-log false --subsampling-num-cells 3000
3.2 数据准备:注释好的pbmc3k(数据下载和准备见monocle
pbmc3k <- readRDS("pbmc.rds")

由于细胞类型已经注释好,接下来准备cellphonedb的文件:表达谱文件cellphonedb_count.txt和细胞分组注释文件cellphonedb_meta.txt。

write.table(as.matrix(pbmc3k@assays$RNA@data), 'cellphonedb_count.txt', sep='\t', quote=F)
meta_data <- cbind(rownames(pbmc3k@meta.data), pbmc3k@meta.data[,'cell_type', drop=F])  
meta_data <- as.matrix(meta_data)
meta_data[is.na(meta_data)] = "Unkown" #  细胞类型中不能有NA

write.table(meta_data, 'cellphonedb_meta.txt', sep='\t', quote=F, row.names=F)
3.3 终端运行cellphonedb:

安装好cellphonedb并加入环境变量后,使用终端运行如下代码:

cellphonedb method statistical_analysis  cellphonedb_meta.txt  cellphonedb_count.txt      --counts-data=gene_name
#如果我们count的基因是基因名格式,需要添加参数--counts-data=gene_name,如果行名为ensemble名称的话,可以不添加这个参数,使用默认值即可。

终端运行完上述代码,在工作目录下会得到一个out文件夹,里面有四个txt:

deconvoluted.txt:基因在亚群中的平均表达量
mean.txt:每对受体-配体的平均表达量
pvalues.txt:每对受体-配体的p值
significant_means.txt:每对受体-配体显著性结果的平均表达量值

#cellphonedb 自己的绘图
cellphonedb plot dot_plot 
cellphonedb plot heatmap_plot cellphonedb_meta.txt 

tree out 
#使用tree来查看cellphonedb生成的out文件夹下的文件。如果没有tree,可以使用brew install tree。
out
├── count_network.txt  ## 绘制网络图文件。注意这个文件是在cellphonedb plot中生成的,所以上面两个plot不要漏掉了。
├── deconvoluted.txt
├── heatmap_count.pdf
├── heatmap_log_count.pdf
├── interaction_count.txt
├── means.txt ## 绘制点图文件
├── plot.pdf
├── pvalues.txt ## 绘制点图文件 
└── significant_means.txt

得到3个图:

  1. plot.pdf
    CellPhoneDB气泡图:每一列为两个细胞亚群(如:B|DC T),每一行为一对受体配体名称(如:CD2_CD58),颜色代表两个亚群这两个基因的平均表达量高低,越红表示表达越高,气泡大小代表P值的-log10值,气泡越大,说明其越具显著性。
  1. heatmap_count.pdf和heatmap_log_count.pdf
    CellPhoneDB Heatmap:下面左图和右图其实都是对interaction_count.txt结果的展示,左图为亚群之间相互作用受体配体数目的热图,右图为将这个数目取了log10。

上述文件和图形的解读可以参考官网:https://www.cellphonedb.org/documentation

3.4 使用R对结果进行可视化(主要是网络图和点图)
pbmc='/practice/cellphonedb/out/' #outs下的文件放在这里了
library(psych)
library(qgraph)
library(igraph)
library(tidyverse)
netf<- "count_network.txt"
mynet <- read.delim(paste0(pbmc,"count_network.txt"), check.names = FALSE) #读取数据
table(mynet$count)
mynet %>% filter(count>0) -> mynet  # 过滤count为0的数据(有零会报错)
head(mynet)
net<- graph_from_data_frame(mynet) #构建net对象
plot(net)

为了给这个网络图的边点mapping上不同的属性我们引入一串颜色

allcolour=c("#DC143C","#0000FF","#20B2AA","#FFA500","#9370DB",
            "#98FB98","#F08080","#1E90FF","#7CFC00","#FFFF00",
            "#808000","#FF00FF","#FA8072","#7B68EE","#9400D3",
            "#800080","#A0522D","#D2B48C","#D2691E","#87CEEB",
            "#40E0D0","#5F9EA0","#FF1493",
            "#FFE4B5","#8A2BE2","#228B22","#E9967A","#4682B4",
            "#32CD32","#F0E68C","#FFFFE0","#EE82EE","#FF6347",
            "#6A5ACD","#9932CC","#8B008B","#8B4513","#DEB887")

karate_groups <- cluster_optimal(net) #统计每个端点的和
coords <- layout_in_circle(net, order =
                             order(membership(karate_groups)))  # 设置网络布局

E(net)$width  <- E(net)$count/10  #根据count值设置边的宽 
plot(net, edge.arrow.size=.1, 
     edge.curved=0,
     vertex.color=allcolour,
     vertex.frame.color="#555555",
     vertex.label.color="black",
     layout = coords,
     vertex.label.cex=.7) 

但是边的颜色和点的颜色还是对应不上,我们来修改一番边的属性。

net2 <- net  # 复制一份备用

for (i in 1: length(unique(mynet$SOURCE)) ){ #配置发出端的颜色
        E(net)[map(unique(mynet$SOURCE),function(x) {
                get.edge.ids(net,vp = c(unique(mynet$SOURCE)[i],x))
        })%>% unlist()]$color <- allcolour[i]
}  # 这波操作谁有更好的解决方案? 

plot(net, edge.arrow.size=.1, 
     edge.curved=0,
     vertex.color=allcolour,
     vertex.frame.color="#555555",
     vertex.label.color="black",
     layout = coords,
     vertex.label.cex=.7) 

我们观察到由于箭头是双向的,所以两个细胞类型之间的线条会被后来画上去的覆盖掉,这里我们把线条做成曲线:

plot(net, edge.arrow.size=.1,  #箭头大小设置为0.1
     edge.curved=0.2, # 只是调了曲率这个参数
     vertex.color=allcolour,
     vertex.frame.color="#555555", #圆圈颜色
     vertex.label.color="black", #标签颜色
     layout = coords, #网络布局位点
     vertex.label.cex=.7#标签大小) 

接下来,我们来绘制第二组类型贝壳一样的网络图。

dev.off()
length(unique(mynet$SOURCE)) # 查看需要绘制多少张图,以方便布局
par(mfrow=c(2,5), mar=c(.3,.3,.3,.3))

for (i in 1: length(unique(mynet$SOURCE)) ){
  net1<-net2
  E(net1)[map(unique(mynet$SOURCE),function(x) {
    get.edge.ids(net,vp = c(unique(mynet$SOURCE)[i],x))
  })%>% unlist()]$color <- allcolour[i]
  
  plot(net1, edge.arrow.size=.1, 
       edge.curved=0.4,
       vertex.color=allcolour,
       vertex.frame.color="#555555",
       vertex.label.color="black",
       layout = coords,
       vertex.label.cex=1) 
  
}

但是,细胞间通讯的频数(count)并没有绘制在图上,略显不足,这就补上吧。

dev.off()
length(unique(mynet$SOURCE))
par(mfrow=c(2,5), mar=c(.3,.3,.3,.3))

for (i in 1: length(unique(mynet$SOURCE)) ){
        net1<-net2
        
        E(net1)$count <- ""
        E(net1)[map(unique(mynet$SOURCE),function(x) {
                get.edge.ids(net,vp = c(unique(mynet$SOURCE)[i],x))
        })%>% unlist()]$count  <- E(net2)[map(unique(mynet$SOURCE),function(x) {
                get.edge.ids(net,vp = c(unique(mynet$SOURCE)[i],x))
        })%>% unlist()]$count  # 故技重施
        
        E(net1)[map(unique(mynet$SOURCE),function(x) {
                get.edge.ids(net,vp = c(unique(mynet$SOURCE)[i],x))
        })%>% unlist()]$color <- allcolour[i]
        
        plot(net1, edge.arrow.size=.1, 
             edge.curved=0.4,
             edge.label = E(net1)$count, # 绘制边的权重
             vertex.color=allcolour,
             vertex.frame.color="#555555",
             vertex.label.color="black",
             layout = coords,
             vertex.label.cex=1
        ) 
        
}

找两条边验证一下对应关系。

mynet %>% filter(SOURCE  == 'B',TARGET == 'DC')
  SOURCE TARGET count
1      B     DC    13

 mynet %>% filter(SOURCE  == 'Memory CD4 T',TARGET == 'B')
        SOURCE TARGET count
1 Memory CD4 T      B    15

用ggplot2 绘制点图,关键是把两张表合并到一起。

mypvals <- read.delim(paste0(pbmc,"pvalues.txt"), check.names = FALSE)
mymeans <- read.delim(paste0(pbmc,"means.txt"), check.names = FALSE)



# 这些基因list很有意思啊,建议保存
chemokines <- grep("^CXC|CCL|CCR|CX3|XCL|XCR", mymeans$interacting_pair,value = T)
chemokines <- grep("^CXC|CCL|CCR|CX3|XCL|XCR", mymeans$interacting_pair,value = T)
th1 <- grep("IL2|IL12|IL18|IL27|IFNG|IL10|TNF$|TNF |LTA|LTB|STAT1|CCR5|CXCR3|IL12RB1|IFNGR1|TBX21|STAT4", 
            mymeans$interacting_pair,value = T)
th2 <- grep("IL4|IL5|IL25|IL10|IL13|AREG|STAT6|GATA3|IL4R", 
            mymeans$interacting_pair,value = T)
th17 <- grep("IL21|IL22|IL24|IL26|IL17A|IL17A|IL17F|IL17RA|IL10|RORC|RORA|STAT3|CCR4|CCR6|IL23RA|TGFB", 
             mymeans$interacting_pair,value = T)
treg <- grep("IL35|IL10|FOXP3|IL2RA|TGFB", mymeans$interacting_pair,value = T)
costimulatory <- grep("CD86|CD80|CD48|LILRB2|LILRB4|TNF|CD2|ICAM|SLAM|LT[AB]|NECTIN2|CD40|CD70|CD27|CD28|CD58|TSLP|PVR|CD44|CD55|CD[1-9]", 
                      mymeans$interacting_pair,value = T)
coinhibitory <- grep("SIRP|CD47|ICOS|TIGIT|CTLA4|PDCD1|CD274|LAG3|HAVCR|VSIR", 
                     mymeans$interacting_pair,value = T)
niche <- grep("CSF", mymeans$interacting_pair,value = T)


mymeans %>% dplyr::filter(interacting_pair %in% costimulatory)%>%
        dplyr::select("interacting_pair",starts_with("NK"),ends_with("NK"))  %>%  
        reshape2::melt() -> meansdf

colnames(meansdf)<- c("interacting_pair","CC","means")

mypvals %>% dplyr::filter(interacting_pair %in% costimulatory)%>%
        dplyr::select("interacting_pair",starts_with("NK"),ends_with("NK"))%>%  
        reshape2::melt()-> pvalsdf

colnames(pvalsdf)<- c("interacting_pair","CC","pvals")
pvalsdf$joinlab<- paste0(pvalsdf$interacting_pair,"_",pvalsdf$CC)
meansdf$joinlab<- paste0(meansdf$interacting_pair,"_",meansdf$CC)
pldf <- merge(pvalsdf,meansdf,by = "joinlab")

summary((filter(pldf,means >1))$means)

pldf%>% filter(means >1) %>% 
        ggplot(aes(CC.x,interacting_pair.x) )+ 
        geom_point(aes(color=means,size=-log10(pvals+0.0001)) ) +
        scale_size_continuous(range = c(1,3))+
        scale_color_gradient2(high="red",mid = "yellow",low ="darkblue",midpoint = 25  )+ theme_bw()+ 
        theme(axis.text.x = element_text(angle = -45,hjust = -0.1,vjust = 0.8)) 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,601评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,367评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,249评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,539评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,967评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,929评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,098评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,825评论 0 207
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,609评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,796评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,282评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,603评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,277评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,159评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,959评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,079评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,874评论 2 277

推荐阅读更多精彩内容