1#' Add new rows in specified position. 2#' 3#' Insert new rows in a gtable and adjust the grob placement accordingly. If 4#' rows are added in the middle of a grob spanning multiple rows, the grob will 5#' continue to span them all. If a row is added above or below a grob, the grob 6#' will not span the new row(s). 7#' 8#' @param x a [gtable()] object 9#' @param heights a unit vector giving the heights of the new rows 10#' @param pos new row will be added below this position. Defaults to 11#' adding row on bottom. `0` adds on the top. 12#' 13#' @return A gtable with the new rows added. 14#' 15#' @family gtable manipulation 16#' 17#' @export 18#' 19#' @examples 20#' library(grid) 21#' rect <- rectGrob(gp = gpar(fill = "#00000080")) 22#' tab <- gtable(unit(rep(1, 3), "null"), unit(rep(1, 3), "null")) 23#' tab <- gtable_add_grob(tab, rect, t = 1, l = 1, r = 3) 24#' tab <- gtable_add_grob(tab, rect, t = 1, b = 3, l = 1) 25#' tab <- gtable_add_grob(tab, rect, t = 1, b = 3, l = 3) 26#' dim(tab) 27#' plot(tab) 28#' 29#' # Grobs will continue to span over new rows if added in the middle 30#' tab2 <- gtable_add_rows(tab, unit(1, "null"), 1) 31#' dim(tab2) 32#' plot(tab2) 33#' 34#' # But not when added to top (0) or bottom (-1, the default) 35#' tab3 <- gtable_add_rows(tab, unit(1, "null")) 36#' tab3 <- gtable_add_rows(tab3, unit(1, "null"), 0) 37#' dim(tab3) 38#' plot(tab3) 39#' 40gtable_add_rows <- function(x, heights, pos = -1) { 41 if (!is.gtable(x)) stop("x must be a gtable", call. = FALSE) 42 if (length(pos) != 1) stop("pos must be a scalar unit", call. = FALSE) 43 n <- length(heights) 44 45 pos <- neg_to_pos(pos, length(x$heights)) 46 47 # Shift existing rows down 48 x$heights <- insert.unit(x$heights, heights, pos) 49 layout <- unclass(x$layout) 50 layout$t <- ifelse(layout$t > pos, layout$t + n, layout$t) 51 layout$b <- ifelse(layout$b > pos, layout$b + n, layout$b) 52 x$layout <- new_data_frame(layout) 53 54 x 55} 56 57#' Add new columns in specified position. 58#' 59#' Insert new columns in a gtable and adjust the grob placement accordingly. If 60#' columns are added in the middle of a grob spanning multiple columns, the grob 61#' will continue to span them all. If a column is added to the left or right of 62#' a grob, the grob will not span the new column(s). 63#' 64#' @param x a [gtable()] object 65#' @param widths a unit vector giving the widths of the new columns 66#' @param pos new columns will be added to the right of this position. Defaults 67#' to adding col on right. `0` adds on the left. 68#' 69#' @return A gtable with the new columns added. 70#' 71#' @family gtable manipulation 72#' 73#' @export 74#' 75#' @examples 76#' library(grid) 77#' rect <- rectGrob(gp = gpar(fill = "#00000080")) 78#' tab <- gtable(unit(rep(1, 3), "null"), unit(rep(1, 3), "null")) 79#' tab <- gtable_add_grob(tab, rect, t = 1, l = 1, r = 3) 80#' tab <- gtable_add_grob(tab, rect, t = 1, b = 3, l = 1) 81#' tab <- gtable_add_grob(tab, rect, t = 1, b = 3, l = 3) 82#' dim(tab) 83#' plot(tab) 84#' 85#' # Grobs will continue to span over new rows if added in the middle 86#' tab2 <- gtable_add_cols(tab, unit(1, "null"), 1) 87#' dim(tab2) 88#' plot(tab2) 89#' 90#' # But not when added to left (0) or right (-1, the default) 91#' tab3 <- gtable_add_cols(tab, unit(1, "null")) 92#' tab3 <- gtable_add_cols(tab3, unit(1, "null"), 0) 93#' dim(tab3) 94#' plot(tab3) 95#' 96gtable_add_cols <- function(x, widths, pos = -1) { 97 if (!is.gtable(x)) stop("x must be a gtable", call. = FALSE) 98 if (length(pos) != 1) stop("pos must be a scalar unit", call. = FALSE) 99 n <- length(widths) 100 101 pos <- neg_to_pos(pos, length(x$widths)) 102 103 # Shift existing columns right 104 x$widths <- insert.unit(x$widths, widths, pos) 105 layout <- unclass(x$layout) 106 layout$l <- ifelse(layout$l > pos, layout$l + n, layout$l) 107 layout$r <- ifelse(layout$r > pos, layout$r + n, layout$r) 108 x$layout <- new_data_frame(layout) 109 x 110} 111