我正在try 向我的一些数字添加底图.从网上阅读来看,basemaps套餐似乎是最好的 Select ,但我一直未能让它发挥作用,并且遇到了几个问题.

这是该图的原始代码,运行得非常好:

ggplot() +
  geom_raster(subset(results, !is.na(var)), mapping = aes(long, lat, fill = var), interpolate = TRUE) +
  coord_sf(datum = "ESRI:102001") +
  scale_fill_gradientn('Variance', colours = colors) + #limits = c(0, 1)) +
  geom_sf(data = lg.parks, fill = NA, color = "black") + 
  geom_sf(data = canada, fill = NA, color = "black") + 
  annotation_scale(location = "bl", width_hint = 0.5) +
  annotation_north_arrow(location = "bl", which_north = "true", 
                         pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
                         style = north_arrow_fancy_orienteering) +
  theme_void() +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        axis.title.x=element_blank(),
        axis.title.y=element_blank())

这是我现在的身材:

a map of canada with a legend reading 'variance', which shows values from 0 to 0.2

我想在此图中添加底图.

当我try 添加行basemap_gglayer(ext = ext(canada)) + 时,它返回错误

Error in st_transform.sfc(st_as_sfc(st_bbox(x)), crs = crs_webmerc) : 
  cannot transform sfc object with missing crs

我似乎可以通过指定ext = st_bbox(canada)来解决这个问题.然而,如果我try 用线basemap_gglayer(ext = st_bbox(canada))绘制我的图形,我会得到另一个错误:

Error in `scale_fill_gradientn()`:
! Discrete values supplied to continuous scale.
ℹ Example values: "#91DED8", "#91DED8", "#91DED8", "#91DED8", and "#91DED8"

所以这不起作用.我try 将底图保存为单独的格栅,然后使用tidyterra包中的geom_spatraster函数绘制它.

bm <- basemaps::basemap_raster(ext = st_bbox(canada))
bm <- as(bm, "SpatRaster")

ggplot() +
  geom_spatraster(data = bm) +
  geom_raster(subset(results, !is.na(var)), mapping = aes(long, lat, fill = var), interpolate = TRUE) +
  coord_sf(datum = "ESRI:102001") +
  scale_fill_gradientn('Variance', colours = colors) + #limits = c(0, 1)) +
  geom_sf(data = lg.parks, fill = NA, color = "black") + 
  geom_sf(data = canada, fill = NA, color = "black") + 
  annotation_scale(location = "bl", width_hint = 0.5) +
  annotation_north_arrow(location = "bl", which_north = "true", 
                         pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
                         style = north_arrow_fancy_orienteering) +
  theme_void() +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        axis.title.x=element_blank(),
        axis.title.y=element_blank())

这是输出:

a dark blue map of canada with park shapefiles on top of it

这真的不是我想让它做的,哈哈.如果我只绘制基层,它看起来像这样:

map of canada in white with surrounding ocean in various shades of teal

理想情况下,我的最终身材看起来是这样的,我的原始身材只是分层在上面.

我的默认设置为basemaps::set_defaults(map_service = "esri", map_type = "world_terrain_base"),因为我想避免需要API密钥的Google/Stadia map .我正在Linux ubuntu v 22.04.4上运行R 4.3.3.

编辑:以下是我的results个 pyramid 的样子和 pyramid 的格栅:

> head(results)
     lat     long  park ecozone        var    mean_res      mean       cv
1 69.425 -125.025 FALSE     ARC 0.02040808 -0.15004042 0.2764668 0.682502
2 72.125 -124.125  TRUE     ARC 0.03036255 -0.07685251 0.1612495 1.433145
3 73.025 -123.675  TRUE     ARC 0.02992938 -0.07491194 0.1648732 1.381233
4 73.025 -123.225  TRUE     ARC 0.02981253 -0.07340767 0.1551282 1.444258
5 72.575 -122.775  TRUE     ARC 0.02772352 -0.06835325 0.1393356 1.590863
6 72.125 -122.325  TRUE     ARC 0.02867879 -0.05654028 0.1109921 1.988154

> results.rast
class       : SpatRaster 
dimensions  : 91, 196, 1  (nrow, ncol, nlyr)
resolution  : 0.45, 0.45  (x, y)
extent      : -141, -52.8, 42.2, 83.15  (xmin, xmax, ymin, ymax)
coord. ref. : WGS 84 / Pseudo-Mercator (EPSG:3857) 
source(s)   : memory
name        :      var 
min value   : 0.000000 
max value   : 0.177362 

我在下面生成了一些可复制的代码:

library(ggplot2)
library(rgeoboundaries) #for canada shapefile
library(basemaps)
library(tidyterra)
library(terra) #for crop + mask functions

#canada shapefile
canada <- geoboundaries("Canada")

basemaps::set_defaults(map_service = "esri", map_type = "world_terrain_base")

#generate a raster
x <- raster(ncol=50, nrow=50, xmn=-141, xmx=-52, ymn=41, ymx=83)
y <- crop(x, canada)
values(y) <- 1:ncell(y)
y <- mask(y, canada)
z <- as.data.frame(y, xy = TRUE) #convert to dataframe for ggplot

ggplot() +
  #basemap_gglayer(ext = st_bbox(canada)) + 
geom_raster(subset(z, !is.na(layer)), mapping = aes(x, y, fill = layer), interpolate = TRUE) +
  coord_sf(datum = "ESRI:102001") +
  geom_sf(data = canada, fill = NA, color = "black") + 
  theme_void()

我不确定这是包裹的问题,还是我这边的问题.或者也许有更好的方法来获取底图!欢迎任何建议

编辑:请注意,我原始代码中的results.rast格栅是从results rame创建的,而不是相反(正如我在可复制代码中所做的那样)-但是,我认为它应该以同样的方式工作.我正在使用的rame是在很多很多步骤前从网格创建的(因此,如果问题来自这些原始网格,我将不得不重新运行几个月的工作..此时我宁愿放弃底图)

推荐答案

您的方法存在一些问题:

  • ESRI basemap_raster()数据的默认CRS为EPSG:3857,但geoboundaries()数据的CRS为EPSG:4326;
  • 对于具有RB值的SpatRaster,您使用geom_spatraster()而不是geom_spatraster_rgb();
  • 您的x对象没有CRS,这通常不是空间对象的好做法,并且x不会扩展到您的canada对象的全部范围(小问题,但会导致 map 难看;)
  • 您正在使用basemap_raster().这特定于raster包,如果未加载raster包,可能会导致问题.例如,如果您在用basemap_raster()创建的Ruby SpatRaster上try 类似terra::project()的内容,而不加载raster包,它会映射删除Ruby值.您应该使用basemap_terra()

以下repex通过为所有数据设置一致的CRS、扩展x的范围并使用正确的绘图功能来解决所有这些问题.请注意,您没有提供colorslg.parks对象的副本,因此这些对象已被替换或省略.

Edit responding to updated question and comments 处理空间数据时的一个常见错误是将CRS错误地分配给错误的坐标值-在这种情况下,将EPSG:3857分配给WGS 84/EPSG:4326值.为了避免投影问题,了解您从哪里开始非常重要.

Load packages and create data:

library(rgeoboundaries) # For Canada shapefile
library(basemaps)
library(tidyterra)
library(sf) # For sf objects, e.g. st_transform()
library(terra)
library(ggplot2)
library(ggspatial)

# Canada shapefile, project to match default basemap_raster crs
canada <- geoboundaries("Canada") %>%
  st_transform(3857)

# Basemap
set_defaults(map_service = "esri", map_type = "world_terrain_base")
bm <- basemap_terra(ext = st_bbox(canada)) %>%
  as("SpatRaster")

# Get extent of Canada sf for min/max values of example x raster
st_bbox(canada)
#      xmin      ymin      xmax      ymax 
# -15696344   5113338  -5857561  17955343 

# Generate an example raster using canada min/max values
x <- rast(ncols = 50, nrows = 50, nlyrs = 1, 
          xmin = -15696344, xmax = -5857561, 
          ymin = 5113338, ymax = 17955343, 
          names = c("rast_val"), 
          crs = "EPSG:3857") %>%
  init("cell")

y <- crop(x, canada)
values(y) <- 1:ncell(y)
y <- mask(y, canada)
z <- as.data.frame(y, xy = TRUE) # Convert to dataframe for ggplot

Plot data:

ggplot() +
  geom_spatraster_rgb(data = bm) +
  geom_raster(subset(z, !is.na(rast_val)),
              mapping = aes(x, y, fill = rast_val, alpha = 0.5),
              interpolate = TRUE) +
  geom_sf(data = canada, fill = NA, color = "black") +
  scale_fill_gradientn("Variance", colours = terrain.colors(5)) +
  # geom_sf(data = lg.parks, fill = NA, color = "black") + 
  annotation_scale(location = "bl", 
                   width_hint = 0.5,
                   pad_x = unit(0.18, "in")) +
  annotation_north_arrow(location = "bl",
                         which_north = "true", 
                         pad_x = unit(0.2, "in"), 
                         pad_y = unit(4, "in"),
                         style = north_arrow_fancy_orienteering) +
  guides(alpha = "none") +
  coord_sf(datum = "ESRI:102001") +
  theme_void()

将出现以下警告:

map 上的比例尺差异超过10%,比例尺可能不准确

结果:

result

R相关问答推荐

使用sensemakr和fixest feols模型(R)

R形式的一维数字线/箱形图样式图表

如何删除多个.CSV文件的行

如何对数据集进行逆向工程?

如何在所有绘图中保持条件值的 colored颜色 相同?

在ggplot2中更改小提琴情节的顺序

R:从geom_ol()中删除轮廓并导出为pdf

在R函数中使用加号

函数可以跨多个列搜索多个字符串并创建二进制输出变量

R中的类别比较

观察器中的inaliateLater的位置

创建在文本字符串中发现两个不同关键字的实例的数据框

有没有办法将不等长的列表转换为R中的数据帧

为R中的16组参数生成10000个样本的有效方法是什么?

如何预测原始数据集并将值添加到原始数据集中

如何在R中创建条形图,使条形图在y轴上围绕0.5而不是0构建条形图?

禁用时,SelecizeInput将变得不透明

使用列名和r中的前缀 Select 列的CREATE函数

如何修复geom_rect中的层错误?

如何修改Rust中的R字符串并将其赋给新的R变量,并使用extendr保留原始R字符串