My problem is somewhat related to Convert units from npc to native using grid in R .
I'm trying to figure out the location of certain plot elements start in a ggplot2 object (axes, main plot, etc). I found the following code:
rm(list = ls())
library(ggplot2)
library(grid)
library(gtable)
# a dummy plot
g <- ggplot(cars, aes(x = speed, y = dist)) +
geom_point()
g
# a layout of each element
obj <- ggplotGrob(g)
l <- gtable:::gtable_layout(obj)
grid:::grid.show.layout(l)

All the information I need must be in the layout object called l. However, the heights and widths of this objects are rather odd. They are often zero, even though there is something draw for the layout! I tweaked grid:::grid.show.layout to print the sizes of what it's drawing:
# aside from sprintf and cat a copy of grid:::grid.show.layout
foo <- function(l, newpage = TRUE, vp.ex = 0.8, bg = "light grey",
cell.border = "blue", cell.fill = "light blue", cell.label = TRUE,
label.col = "blue", unit.col = "red", vp = NULL, ...) {
if (!grid:::is.layout(l))
stop("'l' must be a layout")
if (newpage)
grid.newpage()
if (!is.null(vp))
pushViewport(vp)
grid.rect(gp = gpar(col = NULL, fill = bg))
vp.mid <- viewport(0.5, 0.5, vp.ex, vp.ex, layout = l)
pushViewport(vp.mid)
grid.rect(gp = gpar(fill = "white"))
gp.red <- gpar(col = unit.col)
objs <- matrix(list(), l$nrow, l$ncol)
unitType <- "cm"
for (i in 1L:l$nrow) for (j in 1L:l$ncol) {
h <- convertX(x = l$heights[i, top = FALSE], unitTo = unitType)
w <- convertY(x = l$widths[j, top = FALSE], unitTo = unitType)
s1 <- sprintf("s1: i = %d, j = %d, height = %s, width = %s\n", i, j, h, w)
cat(s1)
vp.inner <- viewport(layout.pos.row = i, layout.pos.col = j)
pushViewport(vp.inner)
# an attempt so save the drawn objects
objs[[i, j]] <- grid.rect(gp = gpar(col = cell.border, fill = cell.fill))
if (cell.label)
grid.text(paste0("(", i, ", ", j, ")"), gp = gpar(col = label.col))
if (j == 1)
grid.text(format(l$heights[i, top = FALSE], ...),
gp = gp.red, just = c("right", "centre"), x = unit(-0.05,
"inches"), y = unit(0.5, "npc"), rot = 0)
if (i == l$nrow)
grid.text(format(l$widths[j, top = FALSE], ...),
gp = gp.red, just = c("centre", "top"), x = unit(0.5,
"npc"), y = unit(-0.05, "inches"), rot = 0)
if (j == l$ncol)
grid.text(format(l$heights[i, top = FALSE], ...),
gp = gp.red, just = c("left", "centre"), x = unit(1,
"npc") + unit(0.05, "inches"), y = unit(0.5,
"npc"), rot = 0)
if (i == 1)
grid.text(format(l$widths[j, top = FALSE], ...),
gp = gp.red, just = c("centre", "bottom"), x = unit(0.5,
"npc"), y = unit(1, "npc") + unit(0.05, "inches"),
rot = 0)
popViewport()
}
popViewport()
if (!is.null(vp))
popViewport()
return(objs)
}
Running foo(l) prints:
s1: i = 1, j = 1, height = 0.193302891933029cm, width = 0.193302891933029cm
...
s1: i = 7, j = 5, height = 0cm, width = 0cm
...
s1: i = 12, j = 9, height = 0.193302891933029cm, width = 0.193302891933029cm
The weird thing is, stepping through the function withbrowser shows that i = 7, j = 5 prints the biggest rectangle in the center, yet the size is 0cm, 0cm! The original units (were 1null, 1null).
So my question is, How do I obtain the sizes/ coordinates of the rectangles in npc/ native units? I'm perfectly happy iterating through the entire structure, but I would like to convert the units of each rectangle into something sensible. Ideally, I obtain for each layout element the position of the four corners drawn by grid.rect in npc or native units of the device.
Any ideas?