Исправление обрезанного полигона в R Maps: заполнение всей области графика
Узнайте, почему фон вашей карты R ggplot2 показывает округлые формы вместо заполнения всей области графика. Узнайте, как исправить проблемы расширения coord_sf с помощью параметра expand = FALSE.
Почему мой обрезанный многоугольник не заполняет всю область графика после проецирования в R?
Я работаю с визуализацией геопространственных данных в R, используя пакеты sf, rnaturalearth и ggplot2. Раньше мой код корректно работал для создания карт с плоским фоном, который заполнял всю область графика. Однако с другими данными, но при той же структуре кода, теперь я вижу проблему, где фоновая карта имеет округлую форму вместо того, чтобы заполнять всю область.
Мой код для создания базовой карты:
library(rnaturalearth)
library(sf)
countries <- ne_countries(scale = "medium", returnclass = "sf") %>% st_transform("ESRI:54030")
Затем я обрезаю это с помощью ограничивающего прямоугольника (bounding box), чтобы соответствовать области моих данных, что приводит к созданию нового объекта с CRS EPSG:3035:
st_crs(countries_cropped)
# Система координат:
# Ввод пользователя: EPSG:3035
Мой код ggplot2 для визуализации:
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
Функция coord_sf() в ggplot2 имеет параметр expand, который контролирует, сколько отступов добавляется вокруг экстента данных. По умолчанию этот параметр установлен в TRUE, что означает, что ggplot2 добавит некоторый отступ, чтобы убедиться, что точки данных у краев не обрезаются.
Согласно официальной документации ggplot2, аргумент expand будет повторен до длины 4 при необходимости. Альтернативно, он может быть именованным логическим вектором для управления одним направлением, например expand = c(bottom = FALSE).
Когда вы работаете с обрезанными полигонами, имеющими неправильные границы, это расширение по умолчанию может создавать вид закругленных форм или пробелов в области графика, поскольку система координат пытается accommodate весь экстент, сохраняя правильные соотношения сторон.
Почему обрезанные полигоны выглядят закругленными
Закругленный вид, который вы видите, вероятно, вызван комбинацией:
-
Расширение по умолчанию в coord_sf: Как упоминалось в нескольких источниках, поведение по умолчанию добавляет отступы вокруг вашего экстента данных.
-
Артефакты преобразования CRS: Когда вы преобразуете свои данные из одной CRS в другую (например, из WGS84 в EPSG:3035), геометрическое представление изменяется. Это может создавать визуальные искажения на краях вашей обрезанной области.
-
Соображения соотношения сторон графика: ggplot2 пытается поддерживать правильные соотношения сторон для географических данных, что иногда может приводить к неожиданным визуальным результатам при работе с обрезанными или неправильными экстентами.
Проблема на GitHub #4029 специально упоминает, что “ggplot последовательно не будет заполнять один полигон, если они обрезаны параметрами xlim, ylim в coord_sf. Однако он будет рисовать контур”. Это соответствует описанию вашей проблемы.
Решения для заполнения всей области графика
Основное решение: Используйте expand = FALSE
Наиболее прямое решение - добавить expand = FALSE в вызов вашей функции 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-bloggers и WZB Data Science Blog, этот параметр “удаляет пробелы” и гарантирует, что формы заполнят всю область графика без отступов.
Альтернативное решение: Обрезайте данные перед построением графика
Другой подход - обрезать ваши данные на уровне данных, а не полагаться на экстент графика для обработки обрезки. Это дает вам больше контроля над конечным результатом:
# Определите вашу ограничивающую рамку
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)
Дополнительные шаги по устранению неполадок
Проверьте операцию обрезки
Убедитесь, что ваша операция обрезки работает как ожидалось, проверив результат:
# Проверьте результат обрезки
plot(st_geometry(countries_cropped))
# Проверьте ограничивающую рамку
st_bbox(countries_cropped)
Проверьте согласованность CRS
Убедитесь, что все ваши слои имеют согласованную CRS:
# Проверьте 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() для прямого изменения ваших данных:
# Создайте ограничивающую рамку
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)
Полный рабочий пример
Вот полный пример, который должен работать для вашего случая использования:
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() # Опционально: удаляет оси и сетку для более чистой карты
Заключение
Основные выводы для решения проблемы заполнения полигонов:
- Всегда используйте
expand = FALSEвcoord_sf()при работе с обрезанными полигонами, чтобы они заполняли всю область графика - Обрезайте данные на уровне данных с помощью
stCrop()вместо того, чтобы полагаться на пределы графика для лучшего контроля - Проверяйте согласованность CRS во всех ваших слоях для избежания артефактов проекции
- Проверяйте результат операции обрезки, чтобы он соответствовал вашим ожиданиям
Реализовав expand = FALSE в вызове вашей функции coord_sf(), вы должны увидеть, что ваша фоновая карта заполняет всю область графика в виде плоской квадратной формы, а не отображается с закругленными краями. Этот параметр специально решает проблему поведения отступов, которая вызывала визуальную проблему в ваших графиках.
Источники
- Документация ggplot2 coord_sf - параметр expand
- R-bloggers - Увеличение масштаба карт с помощью sf и ggplot2
- WZB Data Science Blog - Увеличение масштаба карт с помощью sf и ggplot2
- Проблема на GitHub #4029 - ggplot geom_sf не заполняет полигоны
- r-spatial.org - Рисование красивых карт с ggplot2 и sf
- GIS StackExchange - Только часть shapefile отображена