Нарисуйте SpatialPolygons с несколькими подполигонами и отверстиями с помощью ggplot2

Я хотел бы нарисовать SpatialPolygons из библиотеки sp с дырками в ggplot2. Благодаря другим вопросам о stackoverflow, я знаю, что это разрешено при работе с многоугольниками, написанными по часовой стрелке:
http://stackoverflow.com/questions/12047643/geom-polygon-with-multiple-hole/12051278#12051278
Действительно, при преобразовании SpatialPolygons с использованием broom::tidy (заменяя ggplot2::fortify), Полигоны отверстий сохраняются в направлении по часовой стрелке, чтобы их можно было рисовать как отверстия.
В ggplot2 способ рисования многоугольников с отверстиями заставляет их рисовать один раз с помощью fill, а в другой раз с помощью colour, иначе вы можете увидеть линии, пересекающие многоугольники. При работе с несколькими субполигонами, некоторые из которых имеют дыры, это сложнее, порядок точек объектов, определенный в broom::tidy, может не позволять заполнять полигоны (см. Изображение ниже).
У кого-нибудь из вас есть решение, от которого можно избавиться это поведение проблемы наполнения?

Вот воспроизводимый пример:

library(sp)
library(ggplot2)

# Create two polygons: second would be a hole inside the first
xy = cbind(
  x = c(13.4, 13.4, 13.6, 13.6, 13.4),
  y = c(48.9, 49, 49, 48.9, 48.9)
    )
hole.xy <- cbind(
  x = c(13.5, 13.5, 13.45, 13.45, 13.5),
  y = c(48.98, 48.92, 48.92, 48.98, 48.98)
  )

# Transform as SpatialPolygons with holes
xy.sp <- SpatialPolygons(list(
  Polygons(list(Polygon(xy),
                Polygon(hole.xy, hole = TRUE)), "1"),
  Polygons(list(Polygon(xy + 0.2),
                Polygon(xy + 0.35),
                Polygon(hole.xy + 0.2, hole = TRUE)), "2")
  ))

# Transform SpatialObject to be used by ggplot2
xy.sp.l <- broom::tidy(xy.sp)

ggplot(xy.sp.l) +
  geom_polygon(aes(x = long, y = lat, group = id, fill = id))

Проблема заполнения ggplot в SpatialPolygons с отверстиями
(источник: statnmap.com)


person Sébastien Rochette    schedule 23.05.2017    source источник
comment
Одно из решений могло бы включать разделение полигонов в вызове функции SpatialPolygons. например Два многоугольника с id = 2 становятся 2a и 2b. Возможно ли это, или вы ищете решение, начиная с xy.sp.l.   -  person Jeremy Voisey    schedule 29.05.2017


Ответы (3)


Может быть, самое время "перейти" к пакету sf. На самом деле работа с sf объектом в ggplot намного проще благодаря геометрии geom_sf:

library("sf")
library("rgeos")
sf_poly <- as(xy.sp, "sf")
sf::st_crs(sf_poly) <- 4326
sf_poly$id <- c(1,2)
ggplot(sf_poly) +
  geom_sf(aes(fill = as.factor(id)))

введите описание изображения здесь

person lbusett    schedule 29.05.2017
comment
Да, в самом деле. Ваш ответ решает поставленную здесь проблему простым способом. Думаю, это побудит людей, у которых есть эта проблема, перейти на sf ... Я лично ждал момента, когда sf будет достаточно стабильным с параметрами и именами функций. Однако это поднимает мою другую проблему - возможность рисовать полигоны заштрихованной области с помощью sf-объектов. Мне придется изменить мою функцию, чтобы разрешить это с помощью sf, а затем листовки с sf. Но это другой вопрос, в другой раз ... Спасибо. - person Sébastien Rochette; 30.05.2017
comment
Я принимаю этот ответ, чтобы люди перешли на sf. Но второй ответ присуждается, потому что это ответ на мой вопрос. - person Sébastien Rochette; 01.06.2017

Добавление строк показывает источник проблемы. Рисуется синий «многоугольник», нижний -> верхний -> дыра.

введите описание изображения здесь

Этот код (который не очень элегантен, извините) возвращает путь к начальной точке первого фрагмента, прежде чем перейти к 3-му.

 library(dplyr)
    extra <- xy.sp.l %>%
        filter(piece != 1) %>%
        group_by(id, group) %>%
        summarise(last_pt = max(order))


for (n in 1:nrow(extra)) {
    id_ex <- as.character(extra[n,"id"])
    x <- subset(xy.sp.l, id == id_ex & piece == 1 & order == 1)
    x$order <- as.numeric(extra[n,"last_pt"]) + 0.5
    xy.sp.l <- rbind(xy.sp.l,x)
}

xy.sp.l <- xy.sp.l[order(xy.sp.l$id, xy.sp.l$order),] 

введите описание изображения здесь

person Jeremy Voisey    schedule 29.05.2017
comment
Спасибо за Ваш ответ. Возвращение к одной точке первого многоугольника, кажется, решает проблему для любого нового суб-многоугольника или порядка многоугольника. Думаю, этот трюк можно использовать для любых полигонов библиотеки sp, которые будут построены в ggplot2. - person Sébastien Rochette; 30.05.2017
comment
Я считаю, что это так, поскольку это позволяет избежать проблемы создания дополнительных многоугольников (например, треугольника выше). - person Jeremy Voisey; 30.05.2017
comment
Я награждаю этот ответ, потому что он отвечает прямо на мой вопрос. Однако, чтобы побудить людей перейти на sf, я принимаю первый ответ. - person Sébastien Rochette; 01.06.2017

Это хороший вопрос, на который уже есть отличные ответы. Я также считаю, что люди должны научиться работать с sf объектами, поскольку это следующее поколение пространственного типа данных в R. Но я хочу поделиться, что в этом случае geom_spatial из пакета ggspatial может быть вариантом для построения пространственных полигонов.

library(sp)
library(ggplot2)
library(ggspatial)

ggplot() +
  geom_spatial(xy.sp, aes(fill = id))
# Ignoring argument 'mapping' in geom_spatial.SpatialPolygons
# Autodetect projection: assuming lat/lon (epsg 4326)

введите описание изображения здесь

person www    schedule 06.12.2017