0

I have two polygons whose outlines I would like to merge in ggplot2. How do I do that?

Currently I manage to merge the polygons visually, but my solution does not work for outlines:

tmp <- structure(list(y.min = c(68, 72), y.max = c(72, 73), x.min = c(-160, 
-130), x.max = c(-120, -120), ID = structure(1:2, .Label = c("a", 
"b"), class = "factor")), .Names = c("y.min", "y.max", "x.min", 
"x.max", "ID"), row.names = 1:2, class = "data.frame")

## Object tmp contains limits for the polygons I want to merge

## Transform them ready for ggplot2:

pols <- lapply(1:nrow(tmp), function(i){
  data.frame(ID = tmp$ID[i], y = c(tmp$y.max[i], tmp$y.max[i], tmp$y.min[i],
tmp$y.min[i]), x = c(tmp$x.min[i], tmp$x.max[i], tmp$x.max[i], tmp$x.min[i]))
})
pols <- do.call(rbind, pols)

## I can use the ID as a group argument to plot the polygons. 
## I get rid of the outlines by using NA as color:

library(ggplot2)

ggplot(data = pols, aes(x = x, y = y)) + geom_point() +
geom_polygon(aes(group = ID), alpha = 0.3, color = NA)

enter image description here

## I however would like to merge these polygons and only plot the outlines without filling: 

ggplot(data = pols, aes(x = x, y = y)) + geom_point() + 
geom_polygon(aes(group = ID), alpha = 0, color = "black") + 
annotate("segment", x = -130, y = 71, xend = -125, yend = 71.8,
arrow = arrow(length = unit(0.5, "cm"))) + 
annotate("text", x = -130, y = 70.8, label = "I want to get rid of this line")

enter image description here

Mikko
  • 7,530
  • 8
  • 55
  • 92
  • This is a spatial data problem - ggplot isn't really related. I think the `rgdal` or `spatstat` packages might be able to help. There are at least strongly related (if not duplicate) questions [such as this](http://stackoverflow.com/q/21327677/903061) [and this](http://stackoverflow.com/q/15201875/903061), the only realy difference being that your source data isn't geographic. – Gregor Thomas Nov 19 '15 at 17:31
  • @Gregor: I would like to find a way of doing this without loading extra packages if possible. I am aware that this problem could be solved using the spatial packages, but those feel like heavy weapons to use for such a small issue. One would have to convert the data to a spatial object and back to a `data.frame`. There is the `chull` function in R base, but that calculates only convex hulls, not polygons as in the example. There must be a mathematical way of defining the outlines for such polygons. I could not come up with one and that is why I am asking. – Mikko Nov 19 '15 at 18:06
  • One solution would be to sort the points in the figure clockwise and use `geom_path`, but how do I tell R to sort the points clockwise? – Mikko Nov 19 '15 at 18:14
  • Well, that's once again something the spatial packages already handle. If you're determined to reinvent the wheel I agree that sorting the points clockwise would be a good start. If you don't want to load other packages, I'd recommend looking at their code to see how they solve the problem before re-implementing it yourself. – Gregor Thomas Nov 19 '15 at 18:30
  • It also depends on how general your code needs to be. You might be able to find and take shortcuts all your constituent polygons are convex and if their areas don't overlap - only their edges. For clockwise ordering of a convex polygon, pick a point in the interior and calculate the angle each border point makes with a vertical or horizontal line passing through the interior point, then order by angle. This won't work with non-convex polygons. – Gregor Thomas Nov 19 '15 at 18:34
  • If two convex polygons share exactly one vertex, then you can insert the points from one in the ordering of the other - though you'll need to make sure you're doing it on the correct side... and it won't work if the areas overlap. If areas do overlap, you'll need to find the intersection points of the edges first. – Gregor Thomas Nov 19 '15 at 18:36
  • @Gregor I think you were right that this was a job for a spatial package. At least I could not find another solution. Anyways, I do not think that this question is a direct duplicate of the previous questions (I did my research and did not find solution from previous questions). I hope the solution below helps somebody having a similar problem. – Mikko Nov 20 '15 at 10:00

1 Answers1

0

Here is one way of doing it. This is easiest to do with a spatial package as @Gregor points out in the comments. I used spatstat:

library(spatstat)

polys <- lapply(1:nrow(tmp), function(i) {
  owin(c(tmp$x.min[i], tmp$x.max[i]), c(tmp$y.min[i], tmp$y.max[i]))
})

merged.poly <- union.owin(polys[[1]], polys[[2]])
merged.poly <- data.frame(x = merged.poly$bdry[[1]]$x, y = merged.poly$bdry[[1]]$y)

ggplot() + geom_polygon(data = merged.poly, aes(x = x, y = y),
color = "black", alpha = 0) + geom_point(data = pols, aes(x = x, y = y))

enter image description here

Mikko
  • 7,530
  • 8
  • 55
  • 92