File: rbind-cbind.r

package info (click to toggle)
r-cran-gtable 0.3.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 392 kB
  • sloc: sh: 8; makefile: 5
file content (145 lines) | stat: -rw-r--r-- 4,456 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#' Row and column binding for gtables.
#'
#' These functions are the parallels of the `matrix`/`data.frame` row and
#' column bindings. As such they work in the same way, except they have to take
#' care of additional attributes within the gtables. Most importantly it needs
#' to take care of the sizing of the final gtable, as the different gtables
#' going in may have different widths or heights. By default it tries to
#' calculate the maximum width/height among the supplied gtables, but other
#' options exists. Further, the relative layering of the grobs in each gtable
#' can be modified or left as-is.
#'
#' @param ... gtables to combine (`x` and `y`)
#' @param size How should the widths (for rbind) and the heights (for cbind)
#'   be combined across the gtables: take values from `first`,
#'   or `last` gtable, or compute the `min` or `max` values.
#'   Defaults to `max`.
#' @param z A numeric vector indicating the relative z values of each gtable.
#'   The z values of each object in the resulting gtable will be modified
#'   to fit this order. If `NULL`, then the z values of obects within
#'   each gtable will not be modified.
#'
#' @return A gtable object
#'
#' @name bind
#'
#' @examples
#' library(grid)
#' a <- rectGrob(gp = gpar(fill = "red"))
#' b <- circleGrob()
#' c <- linesGrob()
#'
#' row <- matrix(list(a, b), nrow = 1)
#' col <- matrix(list(a, b), ncol = 1)
#' mat <- matrix(list(a, b, c, nullGrob()), nrow = 2)
#'
#' row_gt <- gtable_matrix("demo", row, unit(c(1, 1), "null"), unit(1, "null"))
#' col_gt <- gtable_matrix("demo", col, unit(1, "null"), unit(c(1, 1), "null"))
#' mat_gt <- gtable_matrix("demo", mat, unit(c(1, 1), "null"), unit(c(1, 1), "null"))
#'
#' # cbind
#' c_binded <- cbind(mat_gt, col_gt, size = "first")
#' plot(c_binded)
#'
#' # rbind
#' r_binded <- rbind(mat_gt, row_gt, size = "last")
#' plot(r_binded)
#'
#' # Dimensions must match along bind direction
#' try(cbind(mat_gt, row_gt))
#'
NULL

#' @rdname bind
#' @method rbind gtable
#' @export
rbind.gtable <- function(..., size = "max", z = NULL) {
  gtables <- list(...)
  if (!is.null(z)) {
    gtables <- z_arrange_gtables(gtables, z)
  }
  Reduce(function(x, y) rbind_gtable(x, y, size = size), gtables)
}

rbind_gtable <- function(x, y, size = "max") {
  if (length(x$widths) != length(y$widths)) stop("x and y must have the same number of columns", call. = FALSE)
  x_row <- length(x$heights)
  y_row <- length(y$heights)
  if (x_row == 0) return(y)
  if (y_row == 0) return(x)

  lay_x <- unclass(x$layout)
  lay_y <- unclass(y$layout)

  x$layout <- new_data_frame(list(
    t = c(lay_x$t, lay_y$t + x_row),
    l = c(lay_x$l, lay_y$l),
    b = c(lay_x$b, lay_y$b + x_row),
    r = c(lay_x$r, lay_y$r),
    z = c(lay_x$z, lay_y$z),
    clip = c(lay_x$clip, lay_y$clip),
    name = c(lay_x$name, lay_y$name)
  ))

  x$heights <- insert.unit(x$heights, y$heights)
  x$rownames <- c(x$rownames, y$rownames)

  size <- match.arg(size, c("first", "last", "max", "min"))
  x$widths <- switch(size,
    first = x$widths,
    last = y$widths,
    min = compare_unit(x$widths, y$widths, pmin),
    max = compare_unit(x$widths, y$widths, pmax)
  )

  x$grobs <- append(x$grobs, y$grobs)

  x
}

#' @rdname bind
#' @method cbind gtable
#' @export
cbind.gtable <- function(..., size = "max", z = NULL) {
  gtables <- list(...)
  if (!is.null(z)) {
    gtables <- z_arrange_gtables(gtables, z)
  }
  Reduce(function(x, y) cbind_gtable(x, y, size = size), gtables)
}

cbind_gtable <- function(x, y, size = "max") {
  if (length(x$heights) != length(y$heights)) stop("x and y must have the same number of rows", call. = FALSE)
  x_col <- length(x$widths)
  y_col <- length(y$widths)
  if (x_col == 0) return(y)
  if (y_col == 0) return(x)

  lay_x <- unclass(x$layout)
  lay_y <- unclass(y$layout)

  x$layout <- new_data_frame(list(
    t = c(lay_x$t, lay_y$t),
    l = c(lay_x$l, lay_y$l + x_col),
    b = c(lay_x$b, lay_y$b),
    r = c(lay_x$r, lay_y$r + x_col),
    z = c(lay_x$z, lay_y$z),
    clip = c(lay_x$clip, lay_y$clip),
    name = c(lay_x$name, lay_y$name)
  ))

  x$widths <- insert.unit(x$widths, y$widths)
  x$colnames <- c(x$colnames, y$colnames)

  size <- match.arg(size, c("first", "last", "max", "min"))
  x$heights <- switch(size,
    first = x$heights,
    last = y$heights,
    min = compare_unit(x$heights, y$heights, pmin),
    max = compare_unit(x$heights, y$heights, pmax)
  )

  x$grobs <- append(x$grobs, y$grobs)

  x
}