前言
將網(wǎng)絡(luò)圖結(jié)構(gòu)與我們平常繪制的數(shù)據(jù)圖進(jìn)行對(duì)比概耻,我們可以發(fā)現(xiàn)寂汇,圖的布局就相當(dāng)于每個(gè)數(shù)據(jù)點(diǎn)的坐標(biāo)权逗,而節(jié)點(diǎn)就相當(dāng)于數(shù)據(jù)點(diǎn)美尸,邊就是連接數(shù)據(jù)點(diǎn)的幾何圖形冤议,可以是直線斟薇、曲線或帶箭頭的線等。
所以恕酸,不同的節(jié)點(diǎn)形狀和不同的邊形狀進(jìn)行組合堪滨,就繪制出了上節(jié)我們展示的各式各樣的圖形。
下面蕊温,我們要介紹節(jié)點(diǎn)與邊的相關(guān)操作袱箱,圖結(jié)構(gòu)如下
edges <- read.csv('~/Downloads/p53_signaling_pathway.csv')
colnames(edges) <- c("from", "to")
edges <- edges %>%
mutate(corr = sample(-1:1, size = n(), replace = TRUE))
nodes <- data.frame(
name = unique(union(edges$from, edges$to))
)
nodes$type <- sample(c("up", "down"), size = length(nodes$name), replace = TRUE)
g <- tbl_graph(nodes = nodes, edges = edges)
節(jié)點(diǎn)
節(jié)點(diǎn)就像是一個(gè)數(shù)據(jù)點(diǎn),我們也可以用 ggplot2
的方式來繪制所有的節(jié)點(diǎn)
ggraph(g, layout = 'kk') +
geom_point(aes(x, y)) +
theme_graph()
因?yàn)閷?duì)圖進(jìn)行布局時(shí)义矛,會(huì)返回一個(gè)數(shù)據(jù)框
> head(create_layout(g, layout = 'kk'))
x y name friends .ggraph.orig_index circular .ggraph.index
1 0.44575339 -2.14390304 MDM4 few 1 FALSE 1
2 -0.93225120 0.59792670 CHEK1 few 2 FALSE 2
3 -0.07559781 0.92801986 ATR few 3 FALSE 3
4 -0.62547450 0.89958214 CHEK2 few 4 FALSE 4
5 -1.14085626 0.24507223 ATM few 5 FALSE 5
6 2.63609895 -0.06153547 IGFBP3 few 6 FALSE 6
我們實(shí)際使用的是這個(gè)數(shù)據(jù)框來繪制的发笔,因此,我們可以在 aes()
中使用布局算法返回的數(shù)據(jù)框中的變量
雖然可以使用 ggplot2
所提供的幾何圖形凉翻,但是 ggraph
在 ggplot2
的基礎(chǔ)上定義了自己的幾何圖形 geom_node_*()
了讨,讓我們的代碼更加清晰、簡(jiǎn)潔。
ggraph
包含的節(jié)點(diǎn)幾何圖形有:
geom_node_point
將節(jié)點(diǎn)表示為點(diǎn)前计,其參數(shù)類似于 geom_point
ggraph(g, layout = 'kk') +
geom_node_point(aes(colour = type, shape = type), size = 4) +
theme_graph()
所有的 geom_node_*()
函數(shù)都有一個(gè)額外的參數(shù) filter
可以用于篩選節(jié)點(diǎn)
ggraph(g, layout = 'kk') +
geom_node_point(aes(filter = type == "down"),
shape = 23, size = 4,
colour = "blue", fill = "red") +
theme_graph()
-
geom_node_text
和geom_node_label
這兩個(gè)函數(shù)用于將節(jié)點(diǎn)繪制成純文本或帶矩形框的文本胞谭,可以類比于 geom_text
和 geom_label
,少了一個(gè) group
參數(shù)男杈,其他參數(shù)都一樣
ggraph(g, layout = 'stress') +
geom_node_text(aes(label = name, colour = type),
angle = 45, repel = TRUE) +
theme_graph()
ggraph(g, layout = 'stress') +
geom_node_label(aes(label = name, fill = type),
colour = "white", fontface = "bold",
repel = TRUE) +
theme_graph()
使用 repel
盡可能避免文本的重疊
geom_node_tile
在 treemap
布局中丈屹,可以繪制矩形樹狀圖。參數(shù)類似于 geom_tile()
我們先構(gòu)建一個(gè)樹結(jié)構(gòu)
flareGraph <- tbl_graph(flare$vertices, flare$edges) %>%
mutate(
class = map_bfs_chr(node_is_root(), .f = function(node, dist, path, ...) {
if (dist <= 1) {
return(shortName[node])
}
path$result[[nrow(path)]]
})
)
繪制矩形樹狀圖
ggraph(flareGraph, 'treemap', weight = size) +
geom_node_tile(aes(fill = class, filter = leaf, alpha = depth), colour = NA) +
geom_node_tile(aes(size = depth), colour = 'white') +
scale_alpha(range = c(1, 0.5), guide = 'none') +
scale_size(range = c(4, 0.2), guide = 'none')
在 partition
布局中伶棒,可以繪制冰柱圖
ggraph(flareGraph, 'partition') +
geom_node_tile(aes(y = -y, fill = class)) +
theme_graph()
在這里旺垒,我們?cè)O(shè)置了 y = -y
將冰柱圖倒置
geom_node_voronoi
維諾圖,將節(jié)點(diǎn)繪制成類似細(xì)胞一樣的形狀苞冯,根據(jù)節(jié)點(diǎn)將空間進(jìn)行分割袖牙,可以避免節(jié)點(diǎn)之間的重疊
ggraph(g, layout = 'stress') +
geom_node_voronoi(aes(fill = type, colour = type), alpha = 0.3) +
geom_node_point() +
geom_edge_link() +
theme_graph()
可以設(shè)置 max.radius
參數(shù)的值,讓節(jié)點(diǎn)形狀看起來更像細(xì)胞
ggraph(g, layout = 'stress') +
geom_node_voronoi(aes(fill = type, colour = type),
alpha = 0.3, max.radius = 1) +
geom_node_point() +
geom_edge_link() +
theme_graph()
geom_node_circle
繪制圓形節(jié)點(diǎn)舅锄,必須與 coord_fixed()
搭配使用才能繪制圓形鞭达。
ggraph(g, layout = 'stress') +
geom_node_circle(aes(fill = type,
colour = type, r = 0.2)) +
geom_edge_link() +
coord_fixed() +
theme_graph()
必須在 aes
中設(shè)置 r
的值
與 circlepack
布局搭配使用,可以繪制圓堆積圖.
ggraph(flareGraph, 'circlepack') +
geom_node_circle(aes(fill = factor(depth))) +
coord_fixed() +
theme_graph()
那為什么不用設(shè)置 r
的值呢皇忿?因?yàn)樵摬季址祷刂抵邪?r
> head(create_layout(flareGraph, 'circlepack'))
x y r circular leaf depth name size shortName class .ggraph.orig_index
1 0.000000 0.0000000 16.1255485 FALSE FALSE 0 flare 0 flare flare 252
2 -7.859692 9.2774060 3.6877643 FALSE FALSE 1 flare.animate 0 animate animate 224
3 -4.679497 3.6143179 2.8071727 FALSE FALSE 1 flare.data 0 data data 227
4 -2.911247 7.5871414 1.5413945 FALSE FALSE 1 flare.display 0 display display 228
5 -2.001902 1.5657652 0.5641896 FALSE FALSE 1 flare.flex 0 flex flex 229
6 -2.878393 -0.9334722 2.0842862 FALSE FALSE 1 flare.physics 0 physics physics 230
.ggraph.index
1 1
2 2
3 3
4 4
5 5
6 6
geom_node_arc_bar
根據(jù)內(nèi)外半徑弧線繪制圖形畴蹭,主要與圓形 partition
布局搭配,繪制 sunburst
圖
ggraph(flareGraph, 'partition', circular = TRUE, weight = size) +
geom_node_arc_bar(aes(fill = class)) +
coord_fixed() +
theme_graph()
geom_node_range
主要與 fabric
分布一起使用鳍烁,將節(jié)點(diǎn)作為水平線
ggraph(g, layout = 'fabric') +
geom_node_range(aes(color = type, linetype = type),
size = 0.8) +
geom_edge_span() +
theme_graph()
邊
我們可以將節(jié)點(diǎn)作為數(shù)據(jù)點(diǎn)叨襟,那邊就是 geom_segment()
了嗎?可以這么理解幔荒,但是 ggraph
提供了更多的內(nèi)容糊闽。
直線只是邊的其中一種表現(xiàn)形式,有時(shí)候甚至沒有繪制爹梁,而是以一種容量或位置的形式表現(xiàn)右犹,如 treemap
、circle packing
和 partition
布局姚垃。但大多數(shù)時(shí)候都是以某種線條的形式來表現(xiàn)的念链。
邊的幾何形狀都是用 geom_edge_*()
函數(shù)來設(shè)置的,幾乎每個(gè)幾何形狀都有三個(gè)不同水平的函數(shù)积糯,即 geom_edge_*0()
和 geom_edge_*2()
掂墓。
其中,常規(guī)版本看成,即不帶數(shù)字后綴的函數(shù)君编,會(huì)沿著邊將其分割為一系列的點(diǎn),并且每個(gè)點(diǎn)都有一個(gè)數(shù)字值 index
川慌,該值與點(diǎn)的位置相關(guān)吃嘿。例如 colour = stat(index)
會(huì)沿著邊的方向設(shè)置漸變顏色偿荷。
2
后綴的函數(shù)為長(zhǎng)邊模式,在邊的起始和終止節(jié)點(diǎn)插入節(jié)點(diǎn)參數(shù)唠椭,通常性能更低跳纳。只在需要的時(shí)候再用。0
后綴的函數(shù)是最高性能的版本贪嫂,會(huì)忽略掉很多設(shè)置寺庄,追求極致的性能,沒有 index
計(jì)算變量
通常這些函數(shù)都有一些共同的參數(shù)用于對(duì)邊進(jìn)行設(shè)置:
-
edge_colour
力崇,也可以使用colour
參數(shù)斗塘,會(huì)自動(dòng)進(jìn)行轉(zhuǎn)換 edge_width
edge_linetype
edge_alpha
filter
geom_edge_*()
和 geom_edge_*2()
函數(shù)的參數(shù)還可以設(shè)置邊的標(biāo)簽等:
start_cap
end_cap
label
label_pos
label_size
angle
hjust
vjust
family
fontface
lineheight
1. link
使用直線連接節(jié)點(diǎn)
ggraph(g, layout = 'stress') +
geom_edge_link0(aes(colour = factor(corr))) +
theme_graph()
使用 index
變量來繪制漸變色
ggraph(g, layout = 'stress') +
geom_edge_link(aes(colour = factor(corr), alpha = stat(index))) +
theme_graph()
使用節(jié)點(diǎn)的類型為邊上色,記住不能直接使用 type
亮靴,類型不同的節(jié)點(diǎn)之間的邊會(huì)有兩種顏色
ggraph(g, layout = 'stress') +
geom_edge_link2(aes(colour = node.type)) +
theme_graph()
2. fan
如果兩個(gè)節(jié)點(diǎn)之間的邊不只一條馍盟,那直接繪制直線的方式是不行的。對(duì)于存在平行邊的圖茧吊,可以使用 geom_edge_fan()
來繪制贞岭,不同的平行邊,會(huì)繪制成不同曲率的圓弧搓侄,而沒有平行邊的還是繪制成直線瞄桨。例如
gr <- create_notable('bull') %>%
convert(to_directed) %>%
bind_edges(data.frame(from = c(1, 2, 2, 3), to = c(2, 1, 3, 2))) %E>%
mutate(class = sample(letters[1:3], 9, TRUE)) %N>%
mutate(class = sample(c('x', 'y'), 5, TRUE))
ggraph(gr, 'stress') +
geom_edge_fan2(aes(colour = node.class)) +
theme_graph()
其他設(shè)置與 link
相同
上面的代碼中 %E>%
管道表示對(duì)邊數(shù)據(jù)框進(jìn)行操作,%N>%
表示對(duì)節(jié)點(diǎn)數(shù)據(jù)框進(jìn)行操作
3. parallel
與 fan
類似讶踪,將平行邊繪制成平行線
ggraph(gr, 'stress') +
geom_edge_parallel0(aes(colour = class)) +
theme_graph()
4. loops
如果圖存在自循環(huán)芯侥,正常使用上面的方法是不會(huì)顯示的,因?yàn)檫@種邊是沒有長(zhǎng)度的乳讥,可以使用 geom_edge_loop
ggraph(gr, 'stress') +
geom_edge_loop(aes(colour = stat(index))) +
geom_edge_fan(aes(colour = stat(index))) +
theme_graph()
自循環(huán)沒有 geom_edge_loop2()
函數(shù)
5. density
添加密度陰影
ggraph(g, layout = 'stress') +
geom_edge_density(aes(fill = factor(corr))) +
geom_edge_link(alpha = 0.25) +
theme_graph()
6. arcs
曲線邊柱查,通常與 linear
和 circular
布局一起使用。
ggraph(g, 'linear') +
geom_edge_arc2(aes(colour = node.type), strength = 0.6) +
theme_graph()
圓形布局
ggraph(g, 'linear', circular = TRUE) +
geom_edge_arc2(aes(colour = node.type), strength = 0.6) +
theme_graph()
7. elbow
用于繪制樹狀圖云石,用直角邊連接兩個(gè)節(jié)點(diǎn)
irisDen <- hclust(dist(iris[1:4], method = 'euclidean'), method = 'ward.D2') %>%
as_tbl_graph() %>%
mutate(class = sample(letters[1:3], n(), TRUE)) %>%
activate(edges) %>%
mutate(class = sample(letters[1:3], n(), TRUE))
ggraph(irisDen, 'dendrogram') +
geom_edge_elbow2(aes(colour = node.class)) +
theme_graph()
上面的代碼中唉工,activate()
函數(shù)用于激活邊或節(jié)點(diǎn)數(shù)據(jù)框,即 activate(edges)
表示后面的管道操作都是針對(duì)邊數(shù)據(jù)框來進(jìn)行的
圓形布局
ggraph(irisDen, 'dendrogram', circular = TRUE) +
geom_edge_elbow(aes(colour = stat(index))) +
coord_fixed() +
theme_graph()
8. diagonals
將邊繪制成對(duì)角貝塞爾曲線留晚,也是一種樹狀圖
ggraph(irisDen, 'dendrogram') +
geom_edge_diagonal0(aes(colour = class)) +
theme_graph()
9. bends
也是繪制樹狀圖酵紫,是 diagonals
的一種替代方案告嘲,相當(dāng)于二次貝塞爾曲線错维,圓角連接線
ggraph(irisDen, 'dendrogram') +
geom_edge_bend2(aes(colour = node.class)) +
theme_graph()
10. hive
該幾何圖形只能與 hive
布局一起使用,將邊繪制為貝塞爾曲線
g <- g %>%
mutate(friends = ifelse(
centrality_degree(mode = 'all') < 3, "few",
ifelse(centrality_degree(mode = 'all') > 3, "many", "medium")
))
ggraph(g, 'hive', axis = friends) +
geom_edge_hive(aes(colour = factor(corr))) +
geom_axis_hive(aes(colour = friends), size = 2, label = FALSE) +
coord_fixed() +
theme_graph()
11. span
將邊繪制為豎直線橄唬,用于連接水平線表示的節(jié)點(diǎn)赋焕,只能在 fabric
布局中使用
ggraph(g, 'fabric', sort.by = node_rank_fabric()) +
geom_node_range(aes(colour = type)) +
geom_edge_span(aes(colour = factor(corr)), end_shape = 'circle') +
scale_edge_colour_brewer(palette = "Set1") +
theme_graph()
12. point and tile
對(duì)于 matrix
布局,x
軸表示起始節(jié)點(diǎn)的位置仰楚,y
軸表示終止節(jié)點(diǎn)的位置隆判,表可以表示為對(duì)應(yīng)于 (x, y)
的圖形
對(duì)于下面的圖
gr <- create_notable('zachary') %>%
mutate(group = group_infomap()) %>%
morph(to_split, group) %>%
activate(edges) %>%
mutate(edge_group = as.character(.N()$group[1])) %>%
unmorph()
繪制不同形狀的點(diǎn)來表示邊
ggraph(gr, 'matrix', sort.by = node_rank_hclust()) +
geom_edge_point(aes(colour = edge_group, edge_shape = edge_group),
mirror = TRUE, edge_size = 3) +
scale_y_reverse() +
coord_fixed() +
theme_graph()
或者使用矩形來表示
ggraph(gr, 'matrix', sort.by = node_rank_hclust()) +
geom_edge_tile(aes(fill = edge_group),
mirror = TRUE, edge_size = 3) +
scale_y_reverse() +
coord_fixed() +
theme_graph()
邊樣式
1. strength
許多邊幾何圖形都有一個(gè) strength
參數(shù)犬庇,用于表示它們與直線的偏離程度,strength = 0
將會(huì)變成直線侨嘀,默認(rèn)樣式對(duì)應(yīng)于 strength = 1
臭挽。
例如
small_tree <- create_tree(10, 2)
ggraph(small_tree, 'dendrogram') +
geom_edge_elbow(strength = 0.75) +
theme_graph()
ggraph(small_tree, 'dendrogram') +
geom_edge_diagonal(strength = 0.5) +
theme_graph()
2. 邊的修飾
邊不僅僅只是一條線,它還可以添加標(biāo)簽和箭頭
2.1 箭頭
給邊添加箭頭的方式與 ggplot2
一樣咬腕,例如
ggraph(g, layout = 'graphopt') +
geom_edge_link(arrow = arrow(length = unit(4, 'mm'))) +
geom_node_point(size = 5) +
theme_graph()
但是這種不好看欢峰,箭頭的頂點(diǎn)都延伸到節(jié)點(diǎn)的中心了,所以涨共,我們需要設(shè)置邊與兩端節(jié)點(diǎn)之間的間隔
ggraph(g, layout = 'graphopt') +
geom_edge_link(arrow = arrow(length = unit(4, 'mm')),
end_cap = circle(3, 'mm')) +
geom_node_point(size = 5) +
theme_graph()
可以看到,箭頭已經(jīng)與節(jié)點(diǎn)分開了。
可以使用 circle()
磨澡、square()
指巡、ellipsis()
和 rectangle()
函數(shù)來設(shè)置不同類型的間隔
ggraph(g, layout = 'stress') +
geom_edge_arc(aes(colour = corr),
arrow = arrow(length = unit(4, 'mm')),
start_cap = square(3, 'mm'),
end_cap = circle(3, 'mm')) +
geom_node_point(aes(colour = type), size = 5) +
theme_graph()
對(duì)于純文本的節(jié)點(diǎn),可以計(jì)算標(biāo)簽的矩形范圍來控制間隔
ggraph(g, layout = 'graphopt') +
geom_edge_link(aes(colour = corr,
start_cap = label_rect(node1.name),
end_cap = label_rect(node2.name)),
arrow = arrow(length = unit(4, 'mm'))) +
geom_node_text(aes(label = name), size = 3) +
theme_graph()
2.2 標(biāo)簽
我們可以為邊添加標(biāo)簽
edges <- edges %>%
mutate(corr = sample(-1:1, size = n(), replace = TRUE),
type = ifelse(corr == -1, "Neg",
ifelse(corr == 0, "None", "Pos"))
)
g <- tbl_graph(nodes = nodes, edges = edges)
ggraph(g, layout = 'stress') +
geom_edge_link(aes(label = type,
end_cap = circle(2, 'mm')),
arrow = arrow(length = unit(4, 'mm'))) +
geom_node_point(aes(colour = type), size = 3) +
theme_graph()
讓標(biāo)簽沿著邊放置
ggraph(g, layout = 'stress') +
geom_edge_link(aes(label = type),
angle_calc = 'along',
label_dodge = unit(2.5, 'mm'),
end_cap = circle(2, 'mm'),
arrow = arrow(length = unit(4, 'mm'))) +
geom_node_point(aes(colour = type), size = 3) +
theme_graph()