How do I combine grobs to create a closed shape using grid in R?

57 views Asked by At

I am currently writing a ggplot2 extension, and in the process I am trying to create a filled shape using grid, with certain sides being defined by function grobs. I am unsure how to take a tree of grobs and turn them into a closed shape in order to fill it.

I've looked through the R Graphics v3 book to no avail. Is this even possible in grid? Would it be possible in gridSVG or gridGeometry?

Here's a minimal example:

library(grid)
grid.newpage()
pushViewport(viewport(xscale=c(0, 2*pi), yscale=c(0,1.1), default.units = "native"))
bottom <- linesGrob(x=c(pi/4, (3/4)*pi), y=c(0.1, 0.1), default.units = "native")
top <- functionGrob(function(x) list(x=x, y=sin(x)),
             range=c(pi/4, 3*pi/4))
right <- linesGrob(x=c(3*pi/4, 3*pi/4), y=c(0.1, sin(pi/4)), default.units = "native")
left <- linesGrob(x=c(pi/4, pi/4), y=c(sin(pi/4), 0.1), default.units = "native")
all <- grobTree(bottom,right,top,left)

grid.fill(all, gp=gpar(fill=rgb(1,0,0)))             # The sine path is filled
grid.stroke(all, gp=gpar(lwd = 2, col=rgb(0,1,0)))   # The paths are stroked

It appears that grid.fill is being applied to each grob individually rather that to a closed shape defined by their combination. The shape I am attempting to draw is more complicated, and so cannot be filled simply by combining this functionGrob and a rectGrob, unfortunately.

1

There are 1 answers

0
ksdjnf On

Following Allan's comment, I tried making a big poly with xyListFromGrob (from gridGeometry) - the poly concatenation is hacky, but it works anyway, with some care taken to endpoints and grob directions.

library(grid)
library(gridGeometry)

grid.newpage()

pushViewport(viewport(xscale=c(0, 2*pi), yscale=c(0,1.1), default.units = "native"))

bottom <- linesGrob(x=c(pi/4, (3/4)*pi), y=c(0.1, 0.1), default.units = "native")
top <- functionGrob(function(x) list(x=x, y=sin(x)),
                    range=c(3*pi/4, pi/4))
right <- linesGrob(x=c(3*pi/4, 3*pi/4), y=c(sin(pi/4), 0.1), default.units = "native")
left <- linesGrob(x=c(pi/4, pi/4), y=c(0.1, sin(pi/4)), default.units = "native")

top_c <- xyListFromGrob(top, closed = FALSE)
bottom_c <- xyListFromGrob(bottom, closed = FALSE)
left_c <- xyListFromGrob(left, closed = FALSE)
right_c <- xyListFromGrob(right, closed = FALSE)

all_coords <- c()
all_coords$x <- c(left_c[[1]]$x, top_c[[1]]$x, right_c[[1]]$x)
all_coords$y <- c(left_c[[1]]$y, top_c[[1]]$y, right_c[[1]]$y)
all_poly <- xyListToPolygon(list(all_coords))

grid.draw(all_poly)
grid.fill(all_poly, gp=gpar(fill=rgb(1,1,0)))