如何使用 ggplot 将图表添加到空间地图?
How could I add a graph to a spatial map using ggplot?
我有一张加拿大地区的地图,是我使用 ggplot 和 sf 包创建的。在地图上的特定点,我想使用该位置的数据添加一条线,指向图表的标注。我知道如何在传单中弹出窗口,但这需要是一份在我打印出硬拷贝时可以使用的文档。我也可以在 Illustrator 中完成,但最好用它编码!
有什么想法吗?
这是一些示例代码
library(ggmap)
library(sf)
library(tidyverse)
# example point object
point.forMap = data.frame(lon=-111.19, lat=56.55, ID="1A3") %>%
st_as_sf(coords=c("lon", "lat")) %>%
st_set_crs(4326)
# Example data that I want to add as a graph
data.forGraph = data.frame(ID=rep("1A3", 30), xval=runif(30, min=5, max=20), yval=runif(30, min=0, max=20) )
# data for the background of the map
background_map = get_map(location=c(lon=-111.19, lat=56.5), zoom=8,maptype="satellite")
# plot the map
ggmap(background_map)+
geom_sf(data=point.forMap, inherit.aes = FALSE, size=8, color="red")
# plot the graph
ggplot(data=data.forGraph)+
geom_point(aes(x=xval, y=yval))
现在的问题是,如何让图表显示在地图上该点附近的某处? data.forGraph 和 point.forMap 都有一个 ID 列,我们可以在上面加入两个数据框,但我不确定从这里去哪里。
将图表添加到地图的一个选项是通过 annotation_custom
。在我看来,棘手的部分是获得正确的位置,这可能需要一些摆弄才能获得漂亮的情节。
但基本上你可以
- 将您的点坐标、图表边界框的坐标和图表本身放入
tibble
。
- 使用辅助函数为一个图表添加
annotation_custom
层,其中包括图表本身以及将图表连接到点的线段。
- 使用
purrr::pmap
遍历我们在步骤 1 中设置的 tibble
的行以将图表添加到地图
注意:我添加了第二点来说明添加多个图表的一般方法。
library(ggmap)
library(sf)
library(ggplot2)
library(dplyr)
library(purrr)
point_df <- data.frame(lon = c(-111.19, -110),
lat = c(56.55, 56),
ID = c("1A3", "1A4"))
point.forMap <- point_df %>%
st_as_sf(coords = c("lon", "lat")) %>%
st_set_crs(4326)
# Example data that I want to add as a graph
data.forGraph <- data.frame(ID = rep("1A3", 30), xval = runif(30, min = 5, max = 20), yval = runif(30, min = 0, max = 20))
# data for the background of the map
background_map <- get_map(location = c(lon = -111.19, lat = 56.5), zoom = 8, maptype = "satellite")
# plot the map
p1 <- ggmap(background_map) +
geom_sf(data = point.forMap, inherit.aes = FALSE, size = 8, color = "red")
#> Coordinate system already present. Adding new coordinate system, which will replace the existing one.
# Set up a tibble containing coordinates of points, bounding box of the charts and the charts
p2 <- tibble(
ID = c("1A3", "1A4"),
p = list(ggplot(data = data.forGraph) + geom_point(aes(x = xval, y = yval)),
ggplot(data = data.forGraph) + geom_point(aes(x = xval, y = yval)))
)
p2 <- left_join(p2, point_df, by = "ID") %>%
rename(x = lon, y = lat) %>%
mutate(xmin = x - 1, xmax = x - .2,
ymin = y + .25, ymax = y + .75) %>%
select(-ID)
# Helper function
add_chart <- function(p, x, y, xmin, xmax, ymin, ymax) {
list(
# Add chart
annotation_custom(
grob = ggplotGrob(p),
xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax
),
# Add segment
annotation_custom(
grob = grid::segmentsGrob(
y0 = unit(1, "npc"), y1 = unit(0, "npc"),
gp = grid::gpar(lwd = unit(1, "lines"), col = "white")
),
xmin = x, xmax = xmax, ymin = y, ymax = ymin
)
)
}
# Add charts to the map
p1 +
purrr::pmap(p2, add_chart)
我有一张加拿大地区的地图,是我使用 ggplot 和 sf 包创建的。在地图上的特定点,我想使用该位置的数据添加一条线,指向图表的标注。我知道如何在传单中弹出窗口,但这需要是一份在我打印出硬拷贝时可以使用的文档。我也可以在 Illustrator 中完成,但最好用它编码!
有什么想法吗?
这是一些示例代码
library(ggmap)
library(sf)
library(tidyverse)
# example point object
point.forMap = data.frame(lon=-111.19, lat=56.55, ID="1A3") %>%
st_as_sf(coords=c("lon", "lat")) %>%
st_set_crs(4326)
# Example data that I want to add as a graph
data.forGraph = data.frame(ID=rep("1A3", 30), xval=runif(30, min=5, max=20), yval=runif(30, min=0, max=20) )
# data for the background of the map
background_map = get_map(location=c(lon=-111.19, lat=56.5), zoom=8,maptype="satellite")
# plot the map
ggmap(background_map)+
geom_sf(data=point.forMap, inherit.aes = FALSE, size=8, color="red")
# plot the graph
ggplot(data=data.forGraph)+
geom_point(aes(x=xval, y=yval))
现在的问题是,如何让图表显示在地图上该点附近的某处? data.forGraph 和 point.forMap 都有一个 ID 列,我们可以在上面加入两个数据框,但我不确定从这里去哪里。
将图表添加到地图的一个选项是通过 annotation_custom
。在我看来,棘手的部分是获得正确的位置,这可能需要一些摆弄才能获得漂亮的情节。
但基本上你可以
- 将您的点坐标、图表边界框的坐标和图表本身放入
tibble
。 - 使用辅助函数为一个图表添加
annotation_custom
层,其中包括图表本身以及将图表连接到点的线段。 - 使用
purrr::pmap
遍历我们在步骤 1 中设置的tibble
的行以将图表添加到地图
注意:我添加了第二点来说明添加多个图表的一般方法。
library(ggmap)
library(sf)
library(ggplot2)
library(dplyr)
library(purrr)
point_df <- data.frame(lon = c(-111.19, -110),
lat = c(56.55, 56),
ID = c("1A3", "1A4"))
point.forMap <- point_df %>%
st_as_sf(coords = c("lon", "lat")) %>%
st_set_crs(4326)
# Example data that I want to add as a graph
data.forGraph <- data.frame(ID = rep("1A3", 30), xval = runif(30, min = 5, max = 20), yval = runif(30, min = 0, max = 20))
# data for the background of the map
background_map <- get_map(location = c(lon = -111.19, lat = 56.5), zoom = 8, maptype = "satellite")
# plot the map
p1 <- ggmap(background_map) +
geom_sf(data = point.forMap, inherit.aes = FALSE, size = 8, color = "red")
#> Coordinate system already present. Adding new coordinate system, which will replace the existing one.
# Set up a tibble containing coordinates of points, bounding box of the charts and the charts
p2 <- tibble(
ID = c("1A3", "1A4"),
p = list(ggplot(data = data.forGraph) + geom_point(aes(x = xval, y = yval)),
ggplot(data = data.forGraph) + geom_point(aes(x = xval, y = yval)))
)
p2 <- left_join(p2, point_df, by = "ID") %>%
rename(x = lon, y = lat) %>%
mutate(xmin = x - 1, xmax = x - .2,
ymin = y + .25, ymax = y + .75) %>%
select(-ID)
# Helper function
add_chart <- function(p, x, y, xmin, xmax, ymin, ymax) {
list(
# Add chart
annotation_custom(
grob = ggplotGrob(p),
xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax
),
# Add segment
annotation_custom(
grob = grid::segmentsGrob(
y0 = unit(1, "npc"), y1 = unit(0, "npc"),
gp = grid::gpar(lwd = unit(1, "lines"), col = "white")
),
xmin = x, xmax = xmax, ymin = y, ymax = ymin
)
)
}
# Add charts to the map
p1 +
purrr::pmap(p2, add_chart)