前言
圖是一種抽象的數(shù)學(xué)結(jié)構(gòu)宿崭,不同對象之間通過線條連接起來释牺,而對象在圖中并沒有固定的位置表示,不同的放置位置顯示出的效果通常是不一樣的微服。
選擇一種優(yōu)秀的布局方式趾疚,可以讓圖形呈現(xiàn)出更好的效果,而 igraph
的工作方式是通過一類 node-edge
的算法來進(jìn)行布局的以蕴。
算法會將節(jié)點(diǎn)作為二維或三維空間上的點(diǎn)糙麦,使用直線或曲線來連接兩個相鄰的節(jié)點(diǎn)。對于有向圖來說丛肮,帶箭頭的線表示連接方向赡磅。在邊兩端的節(jié)點(diǎn)可以由不同的幾何圖形來表示,而一些重要的節(jié)點(diǎn)或邊的屬性可以用來設(shè)置圖形參數(shù)值宝与。
圖的可視化通常由三個步驟組成:
-
找到節(jié)點(diǎn)在二維或三維空間上合適的排列方式焚廊,這一步可能是最重要的。好的布局往往能夠解釋一些有趣的現(xiàn)象习劫,如對稱性咆瘟、密集連接區(qū)域。
從上面的圖可以看出诽里,第一個隨機(jī)布局搞疗,完全看不出什么有價值的信息,而從第二和第三幅可以看出存在某些對稱性
將節(jié)點(diǎn)和邊的重要屬性映射到圖像上
安排好節(jié)點(diǎn)與邊的繪制順序
布局
布局算法用于尋找合適的排列方式须肆,但是找到優(yōu)秀的排列確實(shí)不容易匿乃,因此,大部分的算法都是通過間接測量來評估布局的好壞豌汇。而且是一種啟發(fā)式的方法來求解幢炸,所以并不是每次都能找到最優(yōu)解。
大部分的布局算法只適用于較小的圖拒贱,較大的圖需要一些特殊技術(shù)來處理宛徊。
igraph
中所有布局算法都是 layout_*()
形式佛嬉,每個布局算法都會返回一個 layout
實(shí)例,類似列表型的對象闸天,包含了每個節(jié)點(diǎn)在圖中的 x暖呕、y
坐標(biāo)。
布局函數(shù)
布局是通過 plot()
函數(shù)的 layout
參數(shù)來控制的苞氮,例如
我們隨機(jī)生成一張圖
g <- sample_gnm(n = 15, m = 25)
plot(g)
隨機(jī)布局
plot(g, layout = layout_randomly)
圓形布局
plot(g, layout = layout_in_circle)
力導(dǎo)向布局湾揽,最常用的是 Fruchterman-Reingold
算法
plot(g, layout = layout_with_fr)
另一種比較常用的力導(dǎo)向算法 Kamada Kawai
plot(g, layout = layout_with_kk)
設(shè)置樹狀圖
par(mfrow=c(1, 3))
tree <- make_tree(20, 3)
plot(tree, layout=layout_as_tree)
# 自底向上
plot(tree, layout=layout_as_tree(tree, flip.y=FALSE))
# 圓形排列
plot(tree, layout=layout_as_tree(tree, circular=TRUE))
設(shè)置根節(jié)點(diǎn)
par(mfrow = c(1, 2))
tree2 <- make_tree(10, 3) + make_tree(10, 2)
plot(tree2, layout = layout_as_tree)
plot(tree2, layout =
layout_as_tree(
tree2, root = c(1, 11),
rootlevel = c(2, 1)
)
)
傳遞位置矩陣
g <- sample_gnm(n = 15, m = 25)
l <- cbind(1:vcount(g), c(1, vcount(g):2))
plot(g, layout = l)
繪制圖形
我們在前面的介紹中,都只用了 plot()
函數(shù)來繪制圖形笼吟,所有的一切圖形屬性都是默認(rèn)的库物,默認(rèn)的顏色、大小贷帮、布局等戚揭。在我們設(shè)置了邊和節(jié)點(diǎn)的顏色屬性之后,圖片才顯示出了不同的顏色撵枢。
在這里民晒,我們將介紹如何來調(diào)整節(jié)點(diǎn)和邊的圖形屬性,igraph
的繪制參數(shù)包括
我們以 KEEE
數(shù)據(jù)庫中的 ErbB
信號通路中的 EGF-ERBB2-RAS-ERK
信號通路為例锄禽。
利用 KEGG
官網(wǎng)提供的 API
接口镀虐,處理并獲取通路的圖結(jié)構(gòu),然后將其轉(zhuǎn)換為基因 symbol
邊列表沟绪,代碼如下
library(rvest)
library(tidyverse)
# 解析 ErbB signaling pathway 網(wǎng)絡(luò)結(jié)構(gòu)
kmgl <- read_html('http://rest.kegg.jp/get/hsa04012/kgml')
# 獲取所有基因的 entry id
node <- kmgl %>% html_elements(xpath = '//entry[@type="gene"]') %>%
html_attrs() %>%
lapply(function (x) c(x['id'], x['name'])) %>%
do.call(rbind, .) %>%
as.data.frame()
# 獲取所有 entry 之間的互作關(guān)系
edge <- kmgl %>% html_elements(xpath = '//relation') %>%
html_attrs() %>%
lapply(function (x) c(x['entry1'], x['entry2'])) %>%
do.call(rbind, .) %>%
as.data.frame()
# 將 entry id 轉(zhuǎn)換為 KEGG gene ID
net <- inner_join(node, edge, by = c('id' = 'entry1')) %>%
inner_join(node, by = c('entry2' = 'id')) %>%
dplyr::select(name.x, name.y) %>%
dplyr::rename(source = name.x, target = name.y)
# 將多對一轉(zhuǎn)換為多個一對一
edges_list <- list()
for (i in seq_along(net[,1])) {
gids <- str_split(gsub("hsa:", '', net[i,]), ' ')
s <- data.frame('source' = gids[[1]])
t <- data.frame('target' = gids[[2]])
edges_list[[i]] <- crossing(s, t)
}
# 合并為邊列表
all_edges <- do.call(rbind, edges_list)
# EGF-ERBB2-RAS-ERK signaling pathway genes
sub_path <- c(
1950, 2064, 1956, 2885,
6654, 6655, 3265, 3845,
4893, 369, 673, 5894, 5604,
5605, 5594, 5595
)
path_id <- all_edges %>%
filter(source %in% sub_path & target %in% sub_path)
# 將 ENTREZID 轉(zhuǎn)換為 SYMBOL
library(org.Hs.eg.db)
s <- select(org.Hs.eg.db, keys = path_id$source, columns = 'SYMBOL', 'ENTREZID')
t <- select(org.Hs.eg.db, keys = path_id$target, columns = 'SYMBOL', 'ENTREZID')
# 獲取最終的 SYMBOL 邊結(jié)構(gòu)
sub_path <- tibble(
source = s$SYMBOL,
target = t$SYMBOL
) %>%
distinct()
# 設(shè)置基因的類型刮便,是否癌基因或抑癌基因
genes <- unique(union(sub_path$source, sub_path$target))
gtype <- rep("other", length(genes))
gtype[grep("(RAS)|(RAF)", genes)] <- "proto-oncogene"
gene_type <- data.frame(
genes = genes,
type = gtype
)
# 獲取突變信息
mut <- read_delim('~/Downloads/luad_broad/data_mutations_mskcc.txt', delim = '\t') %>%
dplyr::select(Hugo_Symbol, Variant_Classification) %>%
filter(Hugo_Symbol %in% genes)
# 每個基因的突變頻數(shù),即突變類型
mut_cnt <- group_by(mut, Hugo_Symbol) %>%
summarise(mut_count = n())
mut_info <- distinct(mut) %>%
group_by(Hugo_Symbol) %>%
summarise(mut_class = n()) %>%
left_join(mut_cnt)
# 將基因的所有信息整合在一起
node_attr <- left_join(gene_type, mut_info, by = c("genes" = "Hugo_Symbol")) %>%
replace_na(list(mut_class = 0, mut_count = 0))
獲取代碼:https://github.com/dxsbiocc/learn/blob/main/R/data_process/get_hsa04012_kgml.R
突變數(shù)據(jù):https://github.com/dxsbiocc/learn/blob/main/data/mutation/data_mutations_mskcc.txt
為了方便绽慈,我們并沒有考慮通路中基因或蛋白復(fù)合物的情況恨旱。
創(chuàng)建圖
g <- graph_from_data_frame(d = sub_path, vertices = node_attr)
plot(g, layout = layout_with_fr)
有兩種方法來設(shè)置節(jié)點(diǎn)和邊的圖形屬性,第一種就是在 plot()
函數(shù)中傳遞對應(yīng)的參數(shù)
例如坝疼,設(shè)置邊的箭頭大小和曲率
plot(g, layout = layout_as_tree,
edge.arrow.size=.4,
edge.curved=.1
)
plot(g, layout = layout.circle,
edge.arrow.size=.2,
edge.color="#1f78b4",
vertex.color="#33a02c",
vertex.frame.color="#fb9a99",
vertex.label.color="#ff7f00"
)
第二種方法搜贤,將圖形屬性添加到 igraph
對象中。
例如钝凶,我們想根據(jù)基因的類型設(shè)置不同的顏色仪芒,根據(jù)基因突變頻率設(shè)置節(jié)點(diǎn)的大小
# 設(shè)置基因的顏色
V(g)$color <- if_else(V(g)$type == "other", "#80b1d3", "#fb8072")
# 設(shè)置基因的大小
V(g)$size <- log10(V(g)$mut_count + 1) * 10
# 不顯示基因名
V(g)$label <- NA
# 假設(shè)我們有基因之間的相關(guān)性,用于設(shè)置邊的寬度
E(g)$width <- abs(rnorm(n = ecount(g)))
# 設(shè)置箭頭大小和邊的顏色
E(g)$arrow.size <- .2
E(g)$edge.color <- "gray80"
# 設(shè)置布局
graph_attr(g, "layout") <- layout_with_lgl
plot(g)
可以在 plot
中覆蓋圖形屬性參數(shù)的值
plot(g, edge.color="orange", vertex.color="gray50")
添加圖例
legend(x=-1.5, y=-1.1, c("other","proto-oncogene"), pch=21,
col="#777777", pt.bg=c("#80b1d3", "#fb8072"),
pt.cex=2, cex=.8, bty="n", ncol=1)
我們可以只顯示節(jié)點(diǎn)的文本耕陷,而不添加形狀
plot(g, vertex.shape="none",
vertex.label.font=2,
vertex.label.color="gray40",
vertex.label.cex=.7,
edge.color="gray85",
edge.arrow.size = .2
)
為基因之間的調(diào)控與被調(diào)控關(guān)系設(shè)置不同的顏色
graph_attr(g, "layout") <- layout_with_lgl
V(g)$color <- if_else(V(g)$type == "other", "#80b1d3", "#fb8072")
edge.start <- ends(g, es=E(g), names=F)[,1]
edge.col <- V(g)$color[edge.start]
plot(g, edge.color=edge.col, edge.curved=.1, edge.arrow.size = .3)
根據(jù)基因的度來設(shè)置基因的大小
deg <- degree(g, mode="all")
V(g)$size <- deg * 6
plot(g, edge.color=edge.col,
edge.curved=.1, edge.arrow.size = .3)
大家可以根據(jù)需求自己設(shè)置不同的顏色屬性掂名,就不再一一列舉了