每次有正事的時候就想逃避寫個簡書,假裝自己沒有干不正經(jīng)的事。(明明我還有一些數(shù)據(jù)需要分析呢,但是毫無分析的動力。)好的,今天我們來介紹一個很酷炫的圖:弧形圖(Arc Diagram)。
什么是弧形圖(Arc Diagram)
弧形圖顧名思義,是由弧形組成的。粗暴一點,直接上圖讓大家來看一下什么是弧形圖。

可以看到上圖中有很多個節(jié)點,不同的節(jié)點之間用弧形進行連接。沒錯,弧形圖就是一種可以用來表示關(guān)聯(lián),展示多個節(jié)點之間關(guān)系的一種圖。
這種關(guān)聯(lián)可能有多種情況,最常見的可以用于展現(xiàn)相關(guān)性結(jié)果,還可以用于展現(xiàn)不同字詞共同出現(xiàn)的頻率等等(比如上面這張圖就分析了雨果的名作《悲慘世界》中的人物出現(xiàn)情況)。
通過線的粗細(xì)、顏色以及節(jié)點的各種屬性,你可以在圖中展現(xiàn)關(guān)聯(lián)各種特性,比如可以用線的粗細(xì)表示共現(xiàn)的頻率,用節(jié)點大小表示該詞匯出現(xiàn)的頻率。
你可能會疑惑,我們已經(jīng)有很多種展現(xiàn)關(guān)聯(lián)的方式,比如最簡單的網(wǎng)絡(luò)圖或者和弦圖(好像我都沒有講過,糟糕,我以后慢慢補)。為什么要用弧形圖呢?其實,這幾種展現(xiàn)網(wǎng)絡(luò)關(guān)系的圖各自特點,下面我們來看一個非常有意思的例子,以展現(xiàn)弧形圖的優(yōu)勢(例子來源:data-to-viz網(wǎng)站)。
首先來介紹一下繪圖的數(shù)據(jù)。在學(xué)術(shù)圈,不同實驗室之間可能會有一些長期合作的關(guān)系,因此某些作者可能常常會出現(xiàn)在同一篇文章里。比如有一些老板之間可能是師徒,或者是從同一個實驗室里出來,所以會經(jīng)常合作。
而這次例子的數(shù)據(jù)就是收集了許多文章和作者,通過不同的網(wǎng)絡(luò)圖來展示作者之間的關(guān)聯(lián):如果兩個作者出現(xiàn)在同一篇文章里,那么就會用線將他們連接起來。
我們先來看一下最基礎(chǔ)的網(wǎng)絡(luò)圖的效果。可以看到出現(xiàn)了多個模塊,體現(xiàn)出了一些人之間的關(guān)系可能更為親密。但是一旦關(guān)系復(fù)雜起來,比如最大的那個模塊,似乎很難清楚地標(biāo)注每一個節(jié)點是誰。即便標(biāo)注出來了,也不便于你快速找到你關(guān)注的目標(biāo)。

那么有沒有什么方法可以顯示所有人的姓名呢?和弦圖怎么樣?
雖然和弦圖能夠表示所有人的姓名,但是與網(wǎng)絡(luò)圖比起來,似乎人與人之間的關(guān)系沒有那么直觀了,感覺這些線有點雜亂無章。

那么我們再來看看弧形圖的效果,可以發(fā)現(xiàn)弧形圖不僅能夠很好地展現(xiàn)每一個人的姓名,也可以看到一些人之間存在緊密的關(guān)聯(lián),一些人之間的關(guān)聯(lián)很少或者根本沒有關(guān)聯(lián)。

當(dāng)然,如果你對節(jié)點不進行調(diào)整,那么就有可能出現(xiàn)下圖這種可怕的情況。

不過如果能夠?qū)?jié)點的順序進行一些調(diào)整,和弦圖就能很好地體現(xiàn)出各個節(jié)點之間的關(guān)聯(lián),同時還能允許展現(xiàn)出每個節(jié)點的標(biāo)注。而當(dāng)節(jié)點較多的時候,在網(wǎng)絡(luò)圖中其實很難做到這一點,即便做到這一點,也讓人覺得眼花繚亂。而和弦圖雖然也能展現(xiàn)出節(jié)點信息,但是由于是一個環(huán)狀,所以也可讀性也不如弧形圖。
那么弧形圖要如何繪制呢?
怎么做弧形圖
1)需要什么格式的數(shù)據(jù)
我們還是用上面例子中的數(shù)據(jù),代碼來源還是參考上面提到的data-to-viz網(wǎng)站。
具體需要兩部分的數(shù)據(jù),一部分是具體的貢獻(xiàn)情況connect表,另一個是各個作者的共現(xiàn)數(shù)目coauth表。
library(tidyverse)
dataUU <- read.table("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/13_AdjacencyUndirectedUnweighted.csv", header=TRUE)
#將dataUU轉(zhuǎn)化成所需的格式
connect <- dataUU %>%
gather(key="to", value="value", -1) %>% #將matrix變成三列,一列from,一列to,一列共現(xiàn)文獻(xiàn)數(shù)
mutate(to = gsub("\\.", " ",to)) %>% #將to這一列中姓名.去掉變成空格
na.omit() #剔除NA
head(connect)#第一列的數(shù)字是剔除NA之前的行號
from to value
89 RF Murphy A Bateman 1
184 M Ardisson A Besnard 1
234 Y Holtz A Besnard 1
237 A Armero A Breil 1
276 FC Baurens A Breil 1
326 S Bocs A Breil 1
# 計算每個作者的共現(xiàn)條數(shù)
c( as.character(connect$from), as.character(connect$to)) %>%
as.tibble() %>% #將數(shù)據(jù)的type轉(zhuǎn)變?yōu)閠bl_df,tibble可以理解成是一種加強版的數(shù)據(jù)框
group_by(value) %>% #按照value進行分組
summarize(n=n()) -> coauth
colnames(coauth) <- c("name", "n")#修改列名
head(coauth)
# A tibble: 6 x 2
value n
<chr> <int>
1 A Armero 6
2 A Bateman 5
3 A Besnard 6
4 A Breil 6
5 A Cenci 4
6 A Chifolleau 1
library(igraph)
mygraph <- graph_from_data_frame( connect, vertices = coauth, directed = FALSE )
理論上使用上述數(shù)據(jù)就可以作圖了(具體代碼參見下一小節(jié)),但是我們可以看一下做出來的效果。

沒錯效果非常糟糕,這就是我們?yōu)槭裁匆獙?jié)點進行調(diào)整的原因,那么我們要如何對節(jié)點進行調(diào)整呢?我們可以使用igraph包中的walktrap.community函數(shù)。這是一個用來進行社區(qū)劃分的函數(shù)。
當(dāng)然,igraph包中還提供了許多其他劃分函數(shù)比如fastgreedy.community,spinglass.community,edge.betweenness.community,leading.eigenvector.community等(不過我還沒有仔細(xì)研究過具體的區(qū)別)。
那么我們來調(diào)整一下數(shù)據(jù):
# 鑒定社區(qū)
com <- walktrap.community(mygraph)
#重新整理數(shù)據(jù)
coauth <- coauth %>%
mutate( grp = com$membership) %>%
arrange(grp) %>%
mutate(name=factor(name, name))
# 保留排名前15的社區(qū)
coauth <- coauth %>%
filter(grp<16)
# 只保留排名前15的社區(qū)涉及的作者
connect <- connect %>%
filter(from %in% coauth$name) %>%
filter(to %in% coauth$name)
mygraph <- graph_from_data_frame( connect, vertices = coauth, directed = FALSE )
2)如何作圖
接著,我們將使用ggraph函數(shù)進行畫圖。
library(RColorBrewer)
library(ggraph)
mycolor<-colorRampPalette(brewer.pal(9, "Paired"))
ggraph(mygraph, layout="linear") +
geom_edge_arc(edge_colour="black", edge_alpha=0.2, edge_width=0.3, fold=TRUE) +
geom_node_point(aes(size=n, color=as.factor(grp), fill=grp), alpha=0.5) +
scale_size_continuous(range=c(0.5,8)) +
scale_color_manual(values=mycolor(15)) +
geom_node_text(aes(label=name), angle=65, hjust=1, nudge_y = -1.1, size=2.3) +
theme_void() +
theme(
legend.position="none",
plot.margin=unit(c(0,0,0.4,0), "null"),
panel.spacing=unit(c(0,0,3.4,0), "null")
) +
expand_limits(x = c(-1.2, 1.2), y = c(-5.6, 1.2))

今天的分享就到這里啦。
往期R數(shù)據(jù)可視化分享
R數(shù)據(jù)可視化17:?;鶊D
R數(shù)據(jù)可視化16:啞鈴圖
R數(shù)據(jù)可視化15:傾斜圖 Slope Graph
R數(shù)據(jù)可視化14:生存曲線圖
R數(shù)據(jù)可視化13:瀑布圖/突變圖譜
R數(shù)據(jù)可視化12: 曼哈頓圖
R數(shù)據(jù)可視化11: 相關(guān)性圖
R數(shù)據(jù)可視化10: 蜜蜂圖 Beeswarm
R數(shù)據(jù)可視化9: 棒棒糖圖 Lollipop Chart
R數(shù)據(jù)可視化8: 金字塔圖和偏差圖
R數(shù)據(jù)可視化7: 氣泡圖 Bubble Plot
R數(shù)據(jù)可視化6: 面積圖 Area Chart
R數(shù)據(jù)可視化5: 熱圖 Heatmap
R數(shù)據(jù)可視化4: PCA和PCoA圖
R數(shù)據(jù)可視化3: 直方/條形圖
R數(shù)據(jù)可視化2: 箱形圖 Boxplot
R數(shù)據(jù)可視化1: 火山圖