r-lib / gtable

The layout packages that powers ggplot2
https://gtable.r-lib.org
Other
87 stars 18 forks source link

Spanning grobs remain even when a middle cell is dropped #32

Closed wch closed 5 years ago

wch commented 12 years ago

This appears to be the expected behavior, but the expected behavior can lead to problems when using grobs with a fixed size.

Here are some examples of grobs with non-fixed size -- it looks OK:

# Create a 3x3 gtable
gt <- gtable(name = "test",
  heights=unit(c(1,1,1), "cm"), widths=unit(c(1,1,1), "cm") )

# Add some grobs
gt <- gtable_add_grob(gt, rectGrob(gp = gpar(fill="red",   alpha=0.25)),
        1, 1, 1, 3, clip = FALSE)
gt <- gtable_add_grob(gt, rectGrob(gp = gpar(fill="blue",  alpha=0.25)),
        1, 1, 3, 1, clip = FALSE)
gt <- gtable_add_grob(gt, rectGrob(gp = gpar(fill="black", alpha=0.25)),
        1, 1, 3, 3, clip = FALSE)

# Draw it
grid.newpage()
grid.draw(gt)

# Drop the middle row and middle col
# All grobs remain (but are smaller)
grid.newpage()
grid.draw(gt[c(1,3), c(1,3)])

# Drop the middle row and last col
# Two of the grobs are removed
grid.newpage()
grid.draw(gt[c(1,3), c(1,2)])

So far, so good. But what happens if the grobs have a fixed dimension?

# Create a 3x3 gtable
gt <- gtable(name = "test",
  heights=unit(c(1,1,1), "cm"), widths=unit(c(1,1,1), "cm") )

# Add grobs with fixed dimensions
gt <- gtable_add_grob(gt, rectGrob(width=unit(3, "cm"),
        gp = gpar(fill="red",   alpha=0.25)), 1, 1, 1, 3, clip = FALSE)
gt <- gtable_add_grob(gt, rectGrob(height=unit(3, "cm"),
        gp = gpar(fill="blue",  alpha=0.25)), 1, 1, 3, 1, clip = FALSE)
gt <- gtable_add_grob(gt, rectGrob(width=unit(3, "cm"), height=unit(3, "cm"),
        gp = gpar(fill="black", alpha=0.25)), 1, 1, 3, 3, clip = FALSE)

# Draw it - looks the same as before
grid.newpage()
grid.draw(gt)

# Drop the middle row and middle col
# All grobs remain and are moved, but they are the same size
# and look wrong now
grid.newpage()
grid.draw(gt[c(1,3), c(1,3)])

It might be better to drop spanning grobs when any cell in the span is dropped. The fix is simple (I already have the code) but I'd like to get feedback first.

wch commented 12 years ago

This is the change to [.gtable that will implement the new behavior:

-  keep <- x$layout$t %in% rows & x$layout$b %in% rows & 
-          x$layout$l %in% cols & x$layout$r %in% cols
+  # Figure out which grobs to keep or drop
+  keep <- logical(nrow(x$layout))
+  for (k in seq_len(nrow(x$layout))) {
+    # Keep a grob only if we're keeping all the rows from top:bottom
+    # and all the cols from left:right
+    keep[k] <- all(x$layout$t[k]:x$layout$b[k] %in% rows) &&
+               all(x$layout$l[k]:x$layout$r[k] %in% cols)
+  }