自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

三種可視化方法,手把手教你用R繪制地圖網(wǎng)絡(luò)圖!

大數(shù)據(jù) 數(shù)據(jù)可視化
不知道如何在地圖上可視化網(wǎng)絡(luò)圖?下面這篇博客將使用R中的igraph、ggplot2或ggraph包來(lái)介紹三種在地圖上可視化網(wǎng)絡(luò)圖的方法。在對(duì)地理位置以及位置的連接關(guān)系進(jìn)行可視化時(shí),還可以在圖中展示一些屬性。

大數(shù)據(jù)文摘出品

 

 

編譯:睡不著的iris、陳同學(xué)、YYY

 

 

不知道如何在地圖上可視化網(wǎng)絡(luò)圖?下面這篇博客將使用R中的igraph、ggplot2或ggraph包來(lái)介紹三種在地圖上可視化網(wǎng)絡(luò)圖的方法。在對(duì)地理位置以及位置的連接關(guān)系進(jìn)行可視化時(shí),還可以在圖中展示一些屬性。

當(dāng)我們對(duì)節(jié)點(diǎn)(nodes)為地理位置的網(wǎng)絡(luò)圖進(jìn)行可視化時(shí),比較有效的做法是將這些節(jié)點(diǎn)繪制在地圖上并畫(huà)出它們之間的連接關(guān)系,因?yàn)檫@樣我們可以直接看到網(wǎng)絡(luò)圖中節(jié)點(diǎn)的地理分布及其連接關(guān)系。

但這與傳統(tǒng)的網(wǎng)絡(luò)圖是不同的。在傳統(tǒng)的網(wǎng)絡(luò)圖中,節(jié)點(diǎn)的分布取決于使用何種布局算法(layout algorithm),有一些算法可能會(huì)使緊密聯(lián)系的那些節(jié)點(diǎn)聚成集群。

下面將介紹三種可視化的方法。

 準(zhǔn)備工作

首先,我們需要加載下面的庫(kù):

library(assertthat)
library(dplyr)
library(purrr)
library(igraph)
library(ggplot2)
library(ggraph)
library(ggmap)

現(xiàn)在,讓我們加載一些樣本節(jié)點(diǎn)。我隨機(jī)選取了幾個(gè)國(guó)家的地理坐標(biāo)。

country_coords_txt <- "
1 3.00000 28.00000 Algeria
2 54.00000 24.00000 UAE
3 139.75309 35.68536 Japan
4 45.00000 25.00000 'Saudi Arabia'
5 9.00000 34.00000 Tunisia
6 5.75000 52.50000 Netherlands
7 103.80000 1.36667 Singapore
8 124.10000 -8.36667 Korea
9 -2.69531 54.75844 UK
10 34.91155 39.05901 Turkey
11 -113.64258 60.10867 Canada
12 77.00000 20.00000 India
13 25.00000 46.00000 Romania
14 135.00000 -25.00000 Australia
15 10.00000 62.00000 Norway"

# nodes come from the above table and contain geo-coordinates for some
# randomly picked countries
nodes <- read.delim(text = country_coords_txt, header = FALSE,
quote = "'", sep = "",
ccol.names = c('id', 'lon', 'lat', 'name'))

我們選取了15個(gè)國(guó)家作為網(wǎng)絡(luò)圖的節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)的信息包括國(guó)名、地理坐標(biāo)(經(jīng)度和緯度)和一個(gè)ID?,F(xiàn)在,我將隨機(jī)生成這些節(jié)點(diǎn)之間的連接關(guān)系:

set.seed(123)  # set random generator state for the same output

N_EDGES_PER_NODE_MIN <- 1
N_EDGES_PER_NODE_MAX <- 4
N_CATEGORIES <- 4


# edges: create random connections between countries (nodes)
edges <- map_dfr(nodes$id, function(id) {
n <- floor(runif(1, N_EDGES_PER_NODE_MIN, N_EDGES_PER_NODE_MAX+1))
to <- sample(1:max(nodes$id), n, replace = FALSE)
to <- to[to != id]
categories <- sample(1:N_CATEGORIES, length(to), replace = TRUE)
weights <- runif(length(to))
data_frame(from = id, toto = to, weight = weights, category = categories)
})

edges <- edges %>% mutate(category = as.factor(category))

這里每條邊均通過(guò)from列和to列里的節(jié)點(diǎn)ID來(lái)確定節(jié)點(diǎn)之間的連接關(guān)系。此外,我們生成隨機(jī)連接關(guān)系的類型和強(qiáng)度。這些屬性通常用于圖表分析,之后也可以被可視化。

這樣我們的節(jié)點(diǎn)和邊就充分表現(xiàn)了圖的內(nèi)容?,F(xiàn)在我們可以用igraph庫(kù)生成一個(gè)圖結(jié)構(gòu)g,這對(duì)于以后快速計(jì)算每個(gè)節(jié)點(diǎn)的等級(jí)或其他屬性尤為必要。

g <- graph_from_data_frame(edges, directed = FALSE, vertices = nodes)

我們現(xiàn)在創(chuàng)建一些數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)將用于我們將要生成的所有的圖。首先,我們創(chuàng)建一個(gè)數(shù)據(jù)框來(lái)繪制邊。這個(gè)數(shù)據(jù)框?qū)⑴cedges數(shù)據(jù)框類似,但是有額外四列數(shù)據(jù)來(lái)定義每條邊的開(kāi)始點(diǎn)和結(jié)束點(diǎn)(x, y 和 xend, yend):

edges_for_plot <- edges %>%
inner_join(nodes %>% select(id, lon, lat), by = c('from' = 'id')) %>%
rename(x = lon, y = lat) %>%
inner_join(nodes %>% select(id, lon, lat), by = c('to' = 'id')) %>%
rename(xend = lon, yend = lat)

assert_that(nrow(edges_for_plot) == nrow(edges))

現(xiàn)在我們給每個(gè)節(jié)點(diǎn)賦予一個(gè)權(quán)重,并使用等級(jí)作為指標(biāo)。在地圖上這個(gè)指標(biāo)表現(xiàn)為節(jié)點(diǎn)的大小。

nodes$weight = degree(g)

現(xiàn)在我們定義一個(gè)通用的ggplot2 的主題(在ggplot中設(shè)置及美化圖形的一個(gè)工具)來(lái)展示地圖 (無(wú)坐標(biāo)軸和網(wǎng)格線):

maptheme <- theme(panel.grid = element_blank()) +
theme(axis.text = element_blank()) +
theme(axis.ticks = element_blank()) +
theme(axis.title = element_blank()) +
theme(legend.position = "bottom") +
theme(panel.grid = element_blank()) +
theme(panel.background = element_rect(fill = "#596673")) +
theme(plot.margin = unit(c(0, 0, 0.5, 0), 'cm'))

所有的圖將會(huì)應(yīng)用同一個(gè)主題,并使用相同的世界地圖作為“背景”(用map_data(‘world’)實(shí)現(xiàn)),采取同一個(gè)固定比例的坐標(biāo)系來(lái)限定經(jīng)度和緯度。

country_shapes <- geom_polygon(aes(x = long, y = lat, groupgroup = group),
data = map_data('world'),
fill = "#CECECE", color = "#515151",
size = 0.15)
mapcoords <- coord_fixed(xlim = c(-150, 180), ylim = c(-55, 80))

圖1:僅ggplot2

讓我們從ggplot2開(kāi)始入門(mén)吧!

除了世界地圖(country_shapes)中的國(guó)家多邊形以外,我們還需創(chuàng)建三個(gè)幾何對(duì)象:使用geom_point將節(jié)點(diǎn)繪制為點(diǎn),使用geom_text為節(jié)點(diǎn)添加標(biāo)簽;使用geom_curve將節(jié)點(diǎn)之間的邊繪制成曲線。

在圖中,我們需要為每個(gè)幾何對(duì)象定義圖形屬性映射(aesthetic mappings,也稱為美學(xué)映射,用以“描述數(shù)據(jù)中的變量如何映射到視覺(jué)屬性”)。

圖形屬性映射鏈接:http://ggplot2.tidyverse.org/reference/aes.html

對(duì)于節(jié)點(diǎn),我們將它們的地理坐標(biāo)映射到圖中的x和y位置,并且由其權(quán)重所決定節(jié)點(diǎn)的大小(aes(x = lon,y = lat,size = weight))。對(duì)于邊,我們傳遞edges_for_plot數(shù)據(jù)框架并使用x, y 和 xend, yend 作為曲線的起點(diǎn)和終點(diǎn)。

此外,每條邊的顏色都取決于它的類別(category),而它的“尺寸”(指它的線寬)取決于邊的權(quán)重(一會(huì)兒我們會(huì)發(fā)現(xiàn)后面這一條沒(méi)有實(shí)現(xiàn))。

請(qǐng)注意,幾何對(duì)象的順序非常重要,因?yàn)樗鼪Q定了哪個(gè)對(duì)象先被繪制,并可能會(huì)被隨后在下一個(gè)幾何對(duì)象層中繪制的對(duì)象所遮擋。因此,我們首先繪制邊,然后節(jié)點(diǎn),***才是頂部的標(biāo)簽:

ggplot(nodes) + country_shapes +
geom_curve(aes(xx = x, yy = y, xendxend = xend, yendyend = yend, # draw edges as arcs
color = category, size = weight),
data = edges_for_plot, curvature = 0.33,
alpha = 0.5) +
scale_size_continuous(guide = FALSE, range = c(0.25, 2)) + # scale for edge widths
geom_point(aes(x = lon, y = lat, size = weight), # draw nodes
shape = 21, fill = 'white',
color = 'black', stroke = 0.5) +
scale_size_continuous(guide = FALSE, range = c(1, 6)) + # scale for node size
geom_text(aes(x = lon, y = lat, label = name), # draw text labels
hjust = 0, nudge_x = 1, nudge_y = 4,
size = 3, color = "white", fontface = "bold") +
mapcoords + maptheme

這時(shí)候代碼界面中的控制臺(tái)中會(huì)顯示一條警告,提示“已顯示‘尺寸’標(biāo)度,添加其他的標(biāo)度‘尺寸‘將替換現(xiàn)有的標(biāo)度?!边@是因?yàn)槲覀儍纱问褂昧恕俺叽纭钡膱D形屬性及其標(biāo)度,一次用于節(jié)點(diǎn)大小,一次用于曲線的寬度。

比較麻煩的是,我們不能在同一個(gè)圖形屬性上定義兩種不同的標(biāo)度,即使這個(gè)圖形屬性要用于不同的幾何對(duì)象(比如在我們這個(gè)例子里:“尺寸”這個(gè)圖形屬性被同時(shí)用于節(jié)點(diǎn)的大小和邊的線寬)。據(jù)我所知在ggplot2中控制線寬只能通過(guò)“size“來(lái)實(shí)現(xiàn)。

使用ggplot2,我們只需決定要調(diào)整哪一個(gè)幾何對(duì)象的大小。此處,我選擇使用靜態(tài)節(jié)點(diǎn)大小和動(dòng)態(tài)線寬:

ggplot(nodes) + country_shapes +
geom_curve(aes(xx = x, yy = y, xendxend = xend, yendyend = yend, # draw edges as arcs
color = category, size = weight),
data = edges_for_plot, curvature = 0.33,
alpha = 0.5) +
scale_size_continuous(guide = FALSE, range = c(0.25, 2)) + # scale for edge widths
geom_point(aes(x = lon, y = lat), # draw nodes
shape = 21, size = 3, fill = 'white',
color = 'black', stroke = 0.5) +
geom_text(aes(x = lon, y = lat, label = name), # draw text labels
hjust = 0, nudge_x = 1, nudge_y = 4,
size = 3, color = "white", fontface = "bold") +
mapcoords + maptheme

圖2:ggplot2+ggraph

幸運(yùn)的是,ggplot2有一個(gè)名為ggraph的擴(kuò)展包,里面包含專門(mén)用于繪制網(wǎng)絡(luò)圖的幾何對(duì)象和圖形屬性。這樣我們就可以對(duì)節(jié)點(diǎn)和邊使用不同的標(biāo)度了。默認(rèn)情況下,ggraph將根據(jù)你指定的布局算法放置節(jié)點(diǎn)。但是我們還可以使用地理坐標(biāo)作為節(jié)點(diǎn)位置來(lái)自定義布局:

node_pos <- nodes %>%
select(lon, lat) %>%
rename(x = lon, y = lat) # node positions must be called x, y
lay <- create_layout(g, 'manual',
node.positions = node_pos)
assert_that(nrow(lay) == nrow(nodes))

# add node degree for scaling the node sizes
lay$weight <- degree(g)

我們使用先前定義的布局lay和拓展包ggraph中的幾何對(duì)象geom_edge_arc及geom_node_point來(lái)作圖:

ggraph(lay) + country_shapes +
geom_edge_arc(aes(color = category, edge_width = weight, # draw edges as arcs
circular = FALSE),
data = edges_for_plot, curvature = 0.33,
alpha = 0.5) +
scale_edge_width_continuous(range = c(0.5, 2), # scale for edge widths
guide = FALSE) +
geom_node_point(aes(size = weight), shape = 21, # draw nodes
fill = "white", color = "black",
stroke = 0.5) +
scale_size_continuous(range = c(1, 6), guide = FALSE) + # scale for node sizes
geom_node_text(aes(label = name), repel = TRUE, size = 3,
color = "white", fontface = "bold") +
mapcoords + maptheme

邊的寬度可以通過(guò)edge_width的圖形屬性及其標(biāo)度函數(shù)scale_edge_width進(jìn)行控制。節(jié)點(diǎn)則沿用之前的size來(lái)控制大小。另一個(gè)不錯(cuò)的功能是,geom_node_text可以通過(guò)repel = TRUE 來(lái)分布節(jié)點(diǎn)標(biāo)簽,這樣它們就不會(huì)互相遮擋太多。

請(qǐng)注意,圖的邊與之前ggplot2的圖采用了不同的繪制方式。由于ggraph采用了不同的布局算法,連接關(guān)系仍然相同,只是布局變了。例如,加拿大和日本之間的綠松石色邊線已經(jīng)從最北部轉(zhuǎn)移至南部,并穿過(guò)了非洲中心。

圖3:拙劣的方法(疊加數(shù)個(gè)ggplot2“plot grobs”)

我不想隱瞞另一個(gè)可能被認(rèn)為是拙劣的方法:通過(guò)將它們標(biāo)注為“grobs”(graphical objects的簡(jiǎn)稱),你可以疊加幾個(gè)單***建的圖(透明背景)。這可能不是圖形對(duì)象標(biāo)注功能本來(lái)的目的,但總之,當(dāng)你真的需要克服上面圖1中所描述的ggplot2圖形屬性限制時(shí),它隨時(shí)可以派上用場(chǎng)。

圖形對(duì)象標(biāo)注鏈接:http://ggplot2.tidyverse.org/reference/annotation_custom.html

如上所述,我們將制作獨(dú)立的圖并“堆疊”它們。***個(gè)圖就是之前以世界地圖為“背景”的圖。第二個(gè)圖是一個(gè)只顯示邊的疊加層。***,第三個(gè)疊加層圖僅顯示帶有節(jié)點(diǎn)及其標(biāo)簽的點(diǎn)。這樣設(shè)置后,我們便可以分別控制邊線的線寬和節(jié)點(diǎn)的大小,因?yàn)樗鼈兪窃趫D中各自單獨(dú)生成。

這兩次疊加需要有一個(gè)透明的背景,所以我們用一個(gè)主題來(lái)定義它:

theme_transp_overlay <- theme(
panel.background = element_rect(fill = "transparent", color = NA),
plot.background = element_rect(fill = "transparent", color = NA)
)

底圖或“背景”圖制作十分方便,且僅顯示地圖:

p_base <- ggplot() + country_shapes + mapcoords + maptheme

現(xiàn)在,我們創(chuàng)建***個(gè)疊加層的邊,線寬的大小由邊的權(quán)重所決定:

p_edges <- ggplot(edges_for_plot) +

geom_curve(aes(xx = x, yy = y, xendxend = xend, yendyend = yend, # draw edges as arcs
color = category, size = weight),
curvature = 0.33, alpha = 0.5) +
scale_size_continuous(guide = FALSE, range = c(0.5, 2)) + # scale for edge widths
mapcoords + maptheme + theme_transp_overlay +
theme(legend.position = c(0.5, -0.1),
legend.direction = "horizontal")

??

第二個(gè)疊加層顯示節(jié)點(diǎn)和標(biāo)簽:

p_nodes <- ggplot(nodes) +
geom_point(aes(x = lon, y = lat, size = weight),
shape = 21, fill = "white", color = "black", # draw nodes
stroke = 0.5) +
scale_size_continuous(guide = FALSE, range = c(1, 6)) + # scale for node size
geom_text(aes(x = lon, y = lat, label = name), # draw text labels
hjust = 0, nudge_x = 1, nudge_y = 4,
size = 3, color = "white", fontface = "bold") +
mapcoords + maptheme + theme_transp_overlay

??

***,我們使用圖形對(duì)象標(biāo)注組合疊加層。請(qǐng)注意,準(zhǔn)確定位圖形對(duì)象的工作十分繁瑣。我發(fā)現(xiàn)使用ymin可以做得很好,但似乎必須手動(dòng)調(diào)整參數(shù)。

p <- p_base +
annotation_custom(ggplotGrob(p_edges), ymin = -74) +
annotation_custom(ggplotGrob(p_nodes), ymin = -74)

print(p)


正如前面所述,這是一個(gè)拙劣的解決方案,應(yīng)謹(jǐn)慎使用。但在有些情況下,它還是有用的。例如,當(dāng)你需要在線圖中使用不同標(biāo)度的點(diǎn)尺寸和線寬時(shí),或者需要在單個(gè)繪圖中使用不同的色彩標(biāo)度時(shí),可以考慮采用這種方法。

總而言之,基于地圖的網(wǎng)絡(luò)圖對(duì)于顯示節(jié)點(diǎn)之間的地理尺度上的連接關(guān)系十分有用。缺點(diǎn)是,當(dāng)有很多地理位置接近的點(diǎn)和許多重疊的連接時(shí),它會(huì)看起來(lái)非?;靵y。在僅顯示地圖的某些細(xì)節(jié),或者對(duì)邊的定位點(diǎn)添加一些抖動(dòng)時(shí),這種方法可能會(huì)很有用。

完整的R腳本可參閱github上的gist。

相關(guān)報(bào)道:??https://www.r-bloggers.com/three-ways-of-visualizing-a-graph-on-a-map/??

【本文是51CTO專欄機(jī)構(gòu)大數(shù)據(jù)文摘的原創(chuàng)譯文,微信公眾號(hào)“大數(shù)據(jù)文摘( id: BigDataDigest)”】

     ?大數(shù)據(jù)文摘二維碼?

??戳這里,看該作者更多好文??

責(zé)任編輯:趙寧寧 來(lái)源: 51CTO專欄
相關(guān)推薦

2020-12-17 09:40:01

Matplotlib數(shù)據(jù)可視化命令

2022-07-24 21:43:48

數(shù)據(jù)可視化大數(shù)據(jù)

2021-08-26 09:00:48

PyechartsPython可視化

2021-01-27 21:55:13

代碼參數(shù)值ECharts

2021-01-21 09:10:29

ECharts柱狀圖大數(shù)據(jù)

2021-07-14 09:00:36

Python數(shù)據(jù)Python基礎(chǔ)

2009-08-27 18:10:58

PHP繪制3D圖形

2021-08-09 13:31:25

PythonExcel代碼

2022-10-19 14:30:59

2021-06-05 23:51:21

ECharts氣泡圖散點(diǎn)圖

2021-01-30 10:37:18

ScrapyGerapy網(wǎng)絡(luò)爬蟲(chóng)

2011-03-28 16:14:38

jQuery

2021-02-04 09:00:57

SQLDjango原生

2021-02-06 14:55:05

大數(shù)據(jù)pandas數(shù)據(jù)分析

2022-08-04 10:39:23

Jenkins集成CD

2020-12-14 08:05:28

Javascript隨機(jī)canvas

2009-04-22 09:17:19

LINQSQL基礎(chǔ)

2021-05-10 06:48:11

Python騰訊招聘

2021-01-08 10:32:24

Charts折線圖數(shù)據(jù)可視化

2021-02-02 13:31:35

Pycharm系統(tǒng)技巧Python
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)