我正在尝试创建几张跨越宽纬度范围的地图。我正在 R 中通过
mapboxapi
使用 Mapbox 地图。我想知道如何正确执行此操作,以便准确放置地图和我放在上面的数据。我需要重新投影吗?
地图上的经度显然相当正确,但直布罗陀海峡应该位于纬度约 36 度处。
basemap <- layer_static_mapbox(location = c(-20,10,20,55),
# style_id = "streets-v12",
style_url = "mapbox://styles/mapbox/streets-v12",
username = "User",
access_token = "Token",
attribution = T,
logo = T)
当我添加数据时情况会变得更糟(在“EPSG:4326”中):
快速而肮脏的
borders
映射可以准确地定位数据和世界:
ggplot(data, aes(lon, lat)) +
borders(xlim = c(-10, 10), ylim = c(10, 55)) +
geom_hline(yintercept = 36, lty = 2, color = "cornflowerblue") +
geom_point()
您的问题源于与
location =
坐标如何转换有关的问题。来自有关 location
的文档:
虽然输入 sf 对象可以位于任意坐标参考系中,但如果提供长度为 4 的边界框向量,则它必须表示 WGS84 经度/纬度坐标,并且顺序为 c(xmin, ymin, xmax, ymax)
由于某种原因,无法正确解释使用
c(xmin, ymin, xmax, ymax)
选项。我怀疑由于“mapbox”数据的 CRS 是 WGS84 Pseudo-Mercator/EPSG:3857,因此某些内容未正确翻译。可能需要其他设置,但我无法确定如何使该选项发挥作用。
但是,这里有一个可以实现您想要的结果的代表。它涉及使用基于已投影到
mapbox
的 WGS84 Pseudo-Mercator/EPSG:3857 的坐标的 sf 对象。我稍微扩展了坐标以反映您的示例图像。我使用了 static_mapbox()
而不是 layer_static_mapbox()
,但这种方法无论如何都应该有效。
library(mapboxapi)
library(magick)
library(terra)
library(sf)
library(ggplot2)
library(tidyterra)
# Add API key (may be prompted to restart or to run readRenviron("~/.Renviron") )
mapboxapi::mb_access_token("pk.XXXX", install = TRUE, overwrite = TRUE)
readRenviron("~/.Renviron")
# Check API key is correct
Sys.getenv("MAPBOX_PUBLIC_TOKEN")
# "pk.XXXX"
# Create sf coordinates for basemap extent (slightly larger than your example)
# and project to WGS84 Pseudo-Mercator/EPSG:3857
map_ext <- as.polygons(ext(-20, 25, 10, 55), crs = "EPSG:4326") |>
st_as_sf() |>
st_transform(3857)
# Create static basemap using map_ext for extent
basemap <- static_mapbox(location = map_ext,
buffer_dist = 0,
style_url = "mapbox://styles/mapbox/streets-v12",
username = "mapbox",
attribution = TRUE,
logo = TRUE)
# Convert basemap to raw
img_raw <- image_data(basemap, channels = "rgb")
# Convert raw to a raster array
img_array <- as.integer(img_raw)
dim(img_array) <- c(image_info(basemap)$height, image_info(basemap)$width, 3)
# Create a SpatRaster object from array
r_base <- rast(img_array)
# Assign extent and CRS
ext(r_base) <- ext(map_ext)
crs(r_base) <- "EPSG:3857"
# Example point data (if not already, you will need to project your data to "EPSG:3857")
data <- data.frame(lon = seq(-15, 10, 1),
lat = seq(15, 50, length.out = 26)) |>
st_as_sf(coords = c("lon", "lat"), crs = 4326) |>
st_transform(3857)
ggplot() +
geom_spatraster_rgb(data = r_base) +
geom_sf(data = data) +
coord_sf(expand = FALSE)