R 數(shù)據(jù)可視化 —— igraph 布局與繪圖

前言

圖是一種抽象的數(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ù)值宝与。

圖的可視化通常由三個步驟組成:

  1. 找到節(jié)點(diǎn)在二維或三維空間上合適的排列方式焚廊,這一步可能是最重要的。好的布局往往能夠解釋一些有趣的現(xiàn)象习劫,如對稱性咆瘟、密集連接區(qū)域。


從上面的圖可以看出诽里,第一個隨機(jī)布局搞疗,完全看不出什么有價值的信息,而從第二和第三幅可以看出存在某些對稱性

  1. 將節(jié)點(diǎn)和邊的重要屬性映射到圖像上

  2. 安排好節(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è)置不同的顏色屬性掂名,就不再一一列舉了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市哟沫,隨后出現(xiàn)的幾起案子饺蔑,更是在濱河造成了極大的恐慌,老刑警劉巖嗜诀,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猾警,死亡現(xiàn)場離奇詭異孔祸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)发皿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門崔慧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人穴墅,你說我怎么就攤上這事惶室。” “怎么了封救?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捣作。 經(jīng)常有香客問我誉结,道長,這世上最難降的妖魔是什么券躁? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任惩坑,我火速辦了婚禮,結(jié)果婚禮上也拜,老公的妹妹穿的比我還像新娘以舒。我一直安慰自己,他們只是感情好慢哈,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布蔓钟。 她就那樣靜靜地躺著,像睡著了一般卵贱。 火紅的嫁衣襯著肌膚如雪滥沫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天键俱,我揣著相機(jī)與錄音兰绣,去河邊找鬼。 笑死编振,一個胖子當(dāng)著我的面吹牛缀辩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播踪央,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼臀玄,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了畅蹂?” 一聲冷哼從身側(cè)響起镐牺,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎魁莉,沒想到半個月后睬涧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體募胃,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年畦浓,在試婚紗的時候發(fā)現(xiàn)自己被綠了痹束。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡讶请,死狀恐怖祷嘶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情夺溢,我是刑警寧澤论巍,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站风响,受9級特大地震影響嘉汰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜状勤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一鞋怀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧持搜,春花似錦密似、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贫导,卻和暖如春废累,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背脱盲。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工邑滨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人钱反。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓掖看,卻偏偏與公主長得像,于是被迫代替她去往敵國和親面哥。 傳聞我的和親對象是個殘疾皇子哎壳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容