Draw SpatialPolygons with multiple subpolygons and holes using ggplot2

Could be a good time to "go over" to the sf package. Working with sf object is in fact much easier in ggplot, thanks to the geom_sf geometry:

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)))

enter image description here


Adding lines shows the source of the problem. The blue "polygon" is being drawn, lower -> upper -> hole.

enter image description here

This code (which is not very elegant, sorry) makes the path go back to the starting point of the first piece before proceeding to 3rd.

 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),] 

enter image description here


This post is a good question and already received great answers. I also believe people should learn how to work with sf objects as it is the next generation of the spatial data type in R. But I want to share that in this case geom_spatial from the ggspatial package could be an option to plot the SpatialPolygons.

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)

enter image description here