Я пытаюсь построить только часть карты мира, ограниченную квадратом с пределами долготы (-30, 90) и широты (30, 82). Когда я пытаюсь обрезать карту с помощью sf_crop, она не возвращает желаемый квадрат при построении с помощью ggplot, хотя я проверяю, что используемая карта мира имеет «нормальный» crs с указанием crs = 4326. Я знаю, что, вероятно, мог бы ввести ограничения карты с помощью coord_sf, но мне нужно альтернативное решение. Я был бы очень признателен за любую помощь.
Я попробовал следующий код, который создает описанную проблему:
lapply(c("rnaturalearthdata", "sf", "ggplot2","dplyr"), require, character.only = TRUE)
world <- ne_coastline(scale = "small", returnclass = "sf") %>%
st_transform(world, crs = 4326)
world_cropped <- st_crop(world, xmin = -30, xmax = 90, ymin = 30, ymax = 82)
ggplot() +
geom_sf(data = world, fill = NA, color = "black")
ggplot() +
geom_sf(data = world_cropped, fill = NA, color = "black")
Вторая обрезанная карта, не вырезал "квадрат", как я ожидал, странный результат
Выделил (от руки) квадрат карты, который примерно хочу показать
При работе с географическими координатами (WGS84/EPSG:4326) sf
по умолчанию использует операции со сферической геометрией через s2. Таким образом, ваша ограничивающая рамка, определяемая четырьмя углами, на самом деле не является прямоугольником; при проецировании на плоскость две ее стороны становятся дугами, которые следуют кратчайшими путями между двумя точками на сфере. Мы можем визуализировать это, добавив больше точек к «прямым» краям bbox с помощью st_segmentize()
:
library(rnaturalearth)
library(ggplot2)
library(sf)
world <- ne_coastline(scale = "small")
bb_wgs84 <-
st_bbox(c(xmin = -30, xmax = 90, ymin = 30, ymax = 82), crs = "WGS84") |>
st_as_sfc()
world_cropped <- st_crop(world, bb_wgs84)
ggplot() +
geom_sf(data = st_segmentize(bb_wgs84, 1000), fill = "lightgreen", alpha = .2) +
geom_sf(data = bb_wgs84, fill = NA, color = "darkgreen", linewidth = 1) +
geom_sf(data = world_cropped, fill = NA)
Вероятно, самый простой обходной путь — отключить s2 для операции обрезки, чтобы координаты обрабатывались как плоские координаты, что позволяет выполнить прямоугольную обрезку, которая вам, вероятно, нужна.
sf_use_s2(use_s2 = FALSE)
#> Spherical geometry (s2) switched off
world_cropped <- st_crop(world, xmin = -30, xmax = 90, ymin = 30, ymax = 82)
#> although coordinates are longitude/latitude, st_intersection assumes that they
#> are planar
#> Warning: attribute variables are assumed to be spatially constant throughout
#> all geometries
sf_use_s2(use_s2 = TRUE)
#> Spherical geometry (s2) switched on
ggplot() +
geom_sf(data = st_segmentize(bb_wgs84, 1000), fill = "lightgreen", alpha = .2) +
geom_sf(data = bb_wgs84, fill = NA, color = "darkgreen", linewidth = 1) +
geom_sf(data = world_cropped, fill = NA)
Created on 2024-07-09 with reprex v2.1.0
небольшой комментарий к части «две стороны становятся дугами, которые следуют кратчайшими путями между двумя точками на сфере», если можно, но не слишком придирчиво - технически все стороны обрезки следуют кратчайшими путями (большие круги). Просто меридианы уже представляют собой большие круги, а параллели почти никогда ими не являются (за заметным исключением экватора). Как будто нужно было еще одно подтверждение того, что гео странное...
@JindraLacko, ваши дополнения всегда приветствуются. В настоящее время мне сложно перефразировать это самому, чтобы не запутать, поэтому надеюсь, что ваш комментарий останется :). И вы также можете редактировать.
Спасибо! Решение с sf_use_s2(use_s2 = TRUE), предоставленное @margusl, сработало. Действительно хороший ответ, хорошо иллюстрирующий, как работает sf_crop.