Другое

Исправление обрезанного полигона в R Maps: заполнение всей области графика

Узнайте, почему фон вашей карты R ggplot2 показывает округлые формы вместо заполнения всей области графика. Узнайте, как исправить проблемы расширения coord_sf с помощью параметра expand = FALSE.

Почему мой обрезанный многоугольник не заполняет всю область графика после проецирования в R?

Я работаю с визуализацией геопространственных данных в R, используя пакеты sf, rnaturalearth и ggplot2. Раньше мой код корректно работал для создания карт с плоским фоном, который заполнял всю область графика. Однако с другими данными, но при той же структуре кода, теперь я вижу проблему, где фоновая карта имеет округлую форму вместо того, чтобы заполнять всю область.

Мой код для создания базовой карты:

r
library(rnaturalearth)
library(sf)

countries <- ne_countries(scale = "medium", returnclass = "sf") %>% st_transform("ESRI:54030")

Затем я обрезаю это с помощью ограничивающего прямоугольника (bounding box), чтобы соответствовать области моих данных, что приводит к созданию нового объекта с CRS EPSG:3035:

r
st_crs(countries_cropped)
# Система координат:
#   Ввод пользователя: EPSG:3035

Мой код ggplot2 для визуализации:

r
library(ggplot2)

ggplot() + 
  geom_sf(data = countries_cropped, fill = "gray70", color = "gray60", size = 0.2) + 
  geom_sf(data = grid_ids %>% filter(!is.na(source_class)), aes(fill = source_class), color = NA) +
  coord_sf(crs = st_crs(3035))

Раньше этот код создавал карту с плоским, квадратным фоном, который заполнял всю область графика. Теперь, с другими данными, но при том же подходе, фоновая карта отображается с округлой формой, и мои ячейки сетки следуют этой кривой границе вместо того, чтобы сохранять квадратную компоновку.

Мои данные проецируются корректно (подтверждается тем, что мои красные квадраты остаются квадратами в правильном положении без искажений). Единственная проблема - это форма фоновой карты во второй версии.

Что может вызывать эту разницу в отображении обрезанного многоугольника после проецирования, и как я могу убедиться, что фон заполняет всю область графика в виде плоского, квадратного shape?

Проблема с вашим обрезанным полигоном, который не заполняет всю область графика после проекции, вероятно, связана с поведением расширения по умолчанию coord_sf() и тем, как он обрабатывает экстент графика. Когда вы используете coord_sf() без указания expand = FALSE, ggplot2 автоматически добавляет отступы вокруг экстента данных, что может создавать закругленные формы или пробелы в области графика. Добавление expand = FALSE должно решить эту проблему, заставив график использовать полный экстент ваших данных.


Содержание


Понимание поведения расширения coord_sf

Функция coord_sf() в ggplot2 имеет параметр expand, который контролирует, сколько отступов добавляется вокруг экстента данных. По умолчанию этот параметр установлен в TRUE, что означает, что ggplot2 добавит некоторый отступ, чтобы убедиться, что точки данных у краев не обрезаются.

Согласно официальной документации ggplot2, аргумент expand будет повторен до длины 4 при необходимости. Альтернативно, он может быть именованным логическим вектором для управления одним направлением, например expand = c(bottom = FALSE).

Когда вы работаете с обрезанными полигонами, имеющими неправильные границы, это расширение по умолчанию может создавать вид закругленных форм или пробелов в области графика, поскольку система координат пытается accommodate весь экстент, сохраняя правильные соотношения сторон.

Почему обрезанные полигоны выглядят закругленными

Закругленный вид, который вы видите, вероятно, вызван комбинацией:

  1. Расширение по умолчанию в coord_sf: Как упоминалось в нескольких источниках, поведение по умолчанию добавляет отступы вокруг вашего экстента данных.

  2. Артефакты преобразования CRS: Когда вы преобразуете свои данные из одной CRS в другую (например, из WGS84 в EPSG:3035), геометрическое представление изменяется. Это может создавать визуальные искажения на краях вашей обрезанной области.

  3. Соображения соотношения сторон графика: ggplot2 пытается поддерживать правильные соотношения сторон для географических данных, что иногда может приводить к неожиданным визуальным результатам при работе с обрезанными или неправильными экстентами.

Проблема на GitHub #4029 специально упоминает, что “ggplot последовательно не будет заполнять один полигон, если они обрезаны параметрами xlim, ylim в coord_sf. Однако он будет рисовать контур”. Это соответствует описанию вашей проблемы.


Решения для заполнения всей области графика

Основное решение: Используйте expand = FALSE

Наиболее прямое решение - добавить expand = FALSE в вызов вашей функции coord_sf():

r
ggplot() + 
  geom_sf(data = countries_cropped, fill = "gray70", color = "gray60", size = 0.2) + 
  geom_sf(data = grid_ids %>% filter(!is.na(source_class)), aes(fill = source_class), color = NA) +
  coord_sf(crs = st_crs(3035), expand = FALSE)

Как отмечено в нескольких источниках, включая R-bloggers и WZB Data Science Blog, этот параметр “удаляет пробелы” и гарантирует, что формы заполнят всю область графика без отступов.

Альтернативное решение: Обрезайте данные перед построением графика

Другой подход - обрезать ваши данные на уровне данных, а не полагаться на экстент графика для обработки обрезки. Это дает вам больше контроля над конечным результатом:

r
# Определите вашу ограничивающую рамку
crop_bbox <- st_bbox(c(xmin = min_x, xmax = max_x, ymin = min_y, ymax = max_y), 
                     crs = st_crs(countries_cropped))

# Обрежьте данные перед построением графика
countries_cropped <- st_crop(countries, crop_bbox)

# Затем постройте график без ограничений coord_sf
ggplot() + 
  geom_sf(data = countries_cropped, fill = "gray70", color = "gray60", size = 0.2) + 
  geom_sf(data = grid_ids %>% filter(!is.na(source_class)), aes(fill = source_class), color = NA) +
  coord_sf(crs = st_crs(3035), expand = FALSE)

Дополнительные шаги по устранению неполадок

Проверьте операцию обрезки

Убедитесь, что ваша операция обрезки работает как ожидалось, проверив результат:

r
# Проверьте результат обрезки
plot(st_geometry(countries_cropped))

# Проверьте ограничивающую рамку
st_bbox(countries_cropped)

Проверьте согласованность CRS

Убедитесь, что все ваши слои имеют согласованную CRS:

r
# Проверьте CRS всех данных
st_crs(countries_cropped)
st_crs(grid_ids)

# Если они различаются, преобразуйте их для соответствия
grid_ids <- st_transform(grid_ids, st_crs(countries_cropped))

Рассмотрите возможность использования st_crop вместо xlim/ylim

Вместо использования xlim и ylim в coord_sf, рассмотрите возможность использования st_crop() для прямого изменения ваших данных:

r
# Создайте ограничивающую рамку
bbox <- st_bbox(c(xmin = 2500000, xmax = 7500000, ymin = 1400000, ymax = 6400000), 
                crs = st_crs(3035))

# Обрежьте данные
countries_cropped <- st_crop(countries, bbox)

# Постройте график без ограничений координат
ggplot() + 
  geom_sf(data = countries_cropped, fill = "gray70", color = "gray60", size = 0.2) + 
  geom_sf(data = grid_ids %>% filter(!is.na(source_class)), aes(fill = source_class), color = NA) +
  coord_sf(crs = st_crs(3035), expand = FALSE)

Полный рабочий пример

Вот полный пример, который должен работать для вашего случая использования:

r
library(rnaturalearth)
library(sf)
library(ggplot2)

# Загрузите и преобразуйте данные мира
countries <- ne_countries(scale = "medium", returnclass = "sf") %>% 
  st_transform("ESRI:54030")

# Определите ограничивающую рамку для обрезки (примерные значения - настройте под свои нужды)
crop_bbox <- st_bbox(c(xmin = -2000000, xmax = 6000000, ymin = 1000000, ymax = 7000000), 
                     crs = "ESRI:54030")

# Обрежьте данные
countries_cropped <- st_crop(countries, crop_bbox)

# Проверьте CRS
st_crs(countries_cropped)  # Должен быть EPSG:3035

# Создайте график с expand = FALSE
ggplot() + 
  geom_sf(data = countries_cropped, fill = "gray70", color = "gray60", size = 0.2) + 
  geom_sf(data = grid_ids %>% filter(!is.na(source_class)), aes(fill = source_class), color = NA) +
  coord_sf(crs = st_crs(countries_cropped), expand = FALSE) +
  theme_void()  # Опционально: удаляет оси и сетку для более чистой карты

Заключение

Основные выводы для решения проблемы заполнения полигонов:

  1. Всегда используйте expand = FALSE в coord_sf() при работе с обрезанными полигонами, чтобы они заполняли всю область графика
  2. Обрезайте данные на уровне данных с помощью stCrop() вместо того, чтобы полагаться на пределы графика для лучшего контроля
  3. Проверяйте согласованность CRS во всех ваших слоях для избежания артефактов проекции
  4. Проверяйте результат операции обрезки, чтобы он соответствовал вашим ожиданиям

Реализовав expand = FALSE в вызове вашей функции coord_sf(), вы должны увидеть, что ваша фоновая карта заполняет всю область графика в виде плоской квадратной формы, а не отображается с закругленными краями. Этот параметр специально решает проблему поведения отступов, которая вызывала визуальную проблему в ваших графиках.


Источники

  1. Документация ggplot2 coord_sf - параметр expand
  2. R-bloggers - Увеличение масштаба карт с помощью sf и ggplot2
  3. WZB Data Science Blog - Увеличение масштаба карт с помощью sf и ggplot2
  4. Проблема на GitHub #4029 - ggplot geom_sf не заполняет полигоны
  5. r-spatial.org - Рисование красивых карт с ggplot2 и sf
  6. GIS StackExchange - Только часть shapefile отображена
Авторы
Проверено модерацией
Модерация