blob: cb64a8edad5ad653608a322e3064cbc3c6f81398 [file] [log] [blame]
Hao Zhu3166f062017-06-26 07:51:46 -10001#' Collapse repeated rows to multirow cell
Hao Zhu2a87e8e2017-06-14 15:49:33 -04002#'
Hao Zhu8a160b12017-06-26 13:41:35 -10003#' @description Collapse same values in columns into multirow cells. This
4#' feature does similar things with `group_rows`. However, unlike `group_rows`,
5#' it analyzes existing columns, finds out rows that can be grouped together,
6#' and make them multirow cells. Note that if you want to use `column_spec` to
7#' specify column styles, you should use `column_spec` before `collapse_rows`.
8#'
9#' @param kable_input Output of `knitr::kable()` with `format` specified
Hao Zhu5e2528e2020-08-03 09:16:34 -040010#' @param columns A numeric value or vector indicating in which column(s) rows
Jakob Richteraebd8292018-10-31 16:27:29 +010011#' need to be collapsed.
Kirill Müller64938ec2022-05-26 20:08:56 +020012#' @param valign Select from "top", "middle" (default), "bottom". The reason why
Hao Zhuec169362018-05-21 01:05:29 -040013#' "top" is not default is that the multirow package on CRAN win-builder is
14#' not up to date.
Kirill Müller64938ec2022-05-26 20:08:56 +020015#' Only used when `row_group_label_position` is `identity`.
Hao Zhu12b0ade2018-01-13 16:19:58 -050016#' @param latex_hline Option controlling the behavior of adding hlines to table.
Hao Zhud0f7c8a2020-08-20 01:17:23 -040017#' Choose from `full`, `major`, `none`, `custom` and `linespace`.
georgeguieaeb0cd2018-03-30 17:39:46 -050018#' @param custom_latex_hline Numeric column positions whose collapsed rows will
19#' be separated by hlines.
20#' @param row_group_label_position Option controlling positions of row group
Kirill Müller64938ec2022-05-26 20:08:56 +020021#' labels. Choose from `identity`, `stack`, or `first` -- the latter behaves
22#' like `identity` when `row_group_label_position` is `top` but without using
23#' the multirow package.
georgeguieaeb0cd2018-03-30 17:39:46 -050024#' @param row_group_label_fonts A list of arguments that can be supplied to
25#' group_rows function to format the row group label when
Kirill Müller64938ec2022-05-26 20:08:56 +020026#' `row_group_label_position` is `stack`.
georgeguieaeb0cd2018-03-30 17:39:46 -050027#' @param headers_to_remove Numeric column positions where headers should be
28#' removed when they are stacked.
Hao Zhuc9858942020-08-11 21:41:09 -040029#' @param target If multiple columns are selected to do collapsing and a target
30#' column is specified, this target column will be used to collapse other
31#' columns based on the groups of this target column.
32#' @param col_names T/F. A LaTeX specific option. If you set `col.names` be
33#' `NULL` in your `kable` call, you need to set this option false to let
34#' everything work properly.
Hao Zhu71b30f22020-08-12 22:47:13 -040035#' @param longtable_clean_cut T/F with default T. Multirow cell sometimes are
36#' displayed incorrectly around pagebreak. This option forces groups to cut
37#' before the end of a page. If you have a group that is longer than 1 page,
38#' you need to turn off this option.
Hao Zhu8a160b12017-06-26 13:41:35 -100039#'
Hao Zhu9399dcc2020-08-26 17:27:38 -040040#' @examples
41#' \dontrun{
42#' dt <- data.frame(a = c(1, 1, 2, 2), b = c("a", "a", "a", "b"))
Hao Zhu5a7689e2017-06-26 15:37:24 -100043#' x <- knitr::kable(dt, "html")
44#' collapse_rows(x)
Hao Zhu9399dcc2020-08-26 17:27:38 -040045#' }
Hao Zhu5a7689e2017-06-26 15:37:24 -100046#'
Hao Zhuf4b35292017-06-25 22:38:37 -100047#' @export
Hao Zhu12b0ade2018-01-13 16:19:58 -050048collapse_rows <- function(kable_input, columns = NULL,
Hao Zhuec169362018-05-21 01:05:29 -040049 valign = c("middle", "top", "bottom"),
Hao Zhud0f7c8a2020-08-20 01:17:23 -040050 latex_hline = c("full", "major", "none", "custom",
51 "linespace"),
Kirill Müller64938ec2022-05-26 20:08:56 +020052 row_group_label_position = c("identity", "stack", "first"),
georgeguieaeb0cd2018-03-30 17:39:46 -050053 custom_latex_hline = NULL,
54 row_group_label_fonts = NULL,
Hao Zhu5e2528e2020-08-03 09:16:34 -040055 headers_to_remove = NULL,
Hao Zhuc9858942020-08-11 21:41:09 -040056 target = NULL,
Hao Zhu71b30f22020-08-12 22:47:13 -040057 col_names = TRUE,
58 longtable_clean_cut = TRUE) {
Hao Zhu2a87e8e2017-06-14 15:49:33 -040059 kable_format <- attr(kable_input, "format")
60 if (!kable_format %in% c("html", "latex")) {
Hao Zhu401ebd82018-01-14 17:10:20 -050061 warning("Please specify format in kable. kableExtra can customize either ",
62 "HTML or LaTeX outputs. See https://haozhu233.github.io/kableExtra/ ",
63 "for details.")
Hao Zhu2a87e8e2017-06-14 15:49:33 -040064 return(kable_input)
65 }
Hao Zhu33b865f2020-08-18 02:10:43 -040066 valign <- match.arg(valign)
Hao Zhu5e2528e2020-08-03 09:16:34 -040067 if (!is.null(target)) {
68 if (length(target) > 1 && is.integer(target)) {
69 stop("target can only be a length 1 integer")
70 }
71 }
Hao Zhu2a87e8e2017-06-14 15:49:33 -040072 if (kable_format == "html") {
Hao Zhu5e2528e2020-08-03 09:16:34 -040073 return(collapse_rows_html(kable_input, columns, valign, target))
Hao Zhu2a87e8e2017-06-14 15:49:33 -040074 }
75 if (kable_format == "latex") {
Hao Zhu33b865f2020-08-18 02:10:43 -040076 latex_hline <- match.arg(latex_hline)
georgeguieaeb0cd2018-03-30 17:39:46 -050077 row_group_label_position <- match.arg(row_group_label_position,
Kirill Müller64938ec2022-05-26 20:08:56 +020078 c("identity", "stack", "first"))
Hao Zhu5dd3e282018-05-20 18:39:48 -040079 return(collapse_rows_latex(kable_input, columns, latex_hline, valign,
georgeguieaeb0cd2018-03-30 17:39:46 -050080 row_group_label_position, row_group_label_fonts, custom_latex_hline,
Hao Zhu71b30f22020-08-12 22:47:13 -040081 headers_to_remove, target, col_names, longtable_clean_cut))
Hao Zhu2a87e8e2017-06-14 15:49:33 -040082 }
83}
84
Hao Zhu5e2528e2020-08-03 09:16:34 -040085collapse_rows_html <- function(kable_input, columns, valign, target) {
Hao Zhu2a87e8e2017-06-14 15:49:33 -040086 kable_attrs <- attributes(kable_input)
Hao Zhu5e2528e2020-08-03 09:16:34 -040087 kable_xml <- kable_as_xml(kable_input)
Hao Zhu2a87e8e2017-06-14 15:49:33 -040088 kable_tbody <- xml_tpart(kable_xml, "tbody")
89
90 kable_dt <- rvest::html_table(xml2::read_html(as.character(kable_input)))[[1]]
Hao Zhua6af5c02021-03-11 22:28:25 -050091 kable_dt <- as.data.frame(kable_dt)
Hao Zhuf4b35292017-06-25 22:38:37 -100092 if (is.null(columns)) {
93 columns <- seq(1, ncol(kable_dt))
94 }
Hao Zhu5e2528e2020-08-03 09:16:34 -040095 if (!is.null(target)) {
96 if (!target %in% columns) {
97 stop("target has to be within the range of columns")
98 }
99 }
Hao Zhu23456762018-03-26 12:30:10 -0400100 if (!is.null(kable_attrs$header_above)) {
101 kable_dt_col_names <- unlist(kable_dt[kable_attrs$header_above, ])
102 kable_dt <- kable_dt[-(1:kable_attrs$header_above),]
103 names(kable_dt) <- kable_dt_col_names
104 }
Hao Zhu5e2528e2020-08-03 09:16:34 -0400105 collapse_matrix <- collapse_row_matrix(kable_dt, columns, target = target)
Hao Zhu2a87e8e2017-06-14 15:49:33 -0400106
107 for (i in 1:nrow(collapse_matrix)) {
108 matrix_row <- collapse_matrix[i, ]
Hao Zhu38cdcdb2017-06-27 09:08:30 -1000109 names(matrix_row) <- names(collapse_matrix)
Hao Zhu3166f062017-06-26 07:51:46 -1000110 target_row <- xml_child(kable_tbody, i)
111 row_node_rm_count <- 0
112 for (j in 1:length(matrix_row)) {
113 collapsing_col <- as.numeric(sub("x", "", names(matrix_row)[j])) -
114 row_node_rm_count
115 target_cell <- xml_child(target_row, collapsing_col)
116 if (matrix_row[j] == 0) {
117 xml_remove(target_cell)
118 row_node_rm_count <- row_node_rm_count + 1
119 } else if (matrix_row[j] != 1) {
120 xml_attr(target_cell, "rowspan") <- matrix_row[j]
121 xml_attr(target_cell, "style") <- paste0(
122 xml_attr(target_cell, "style"),
Hao Zhu5dd3e282018-05-20 18:39:48 -0400123 "vertical-align: ", valign, " !important;")
Hao Zhu2a87e8e2017-06-14 15:49:33 -0400124 }
125 }
126 }
127
Hao Zhuf2dfd142017-07-24 14:43:28 -0400128 out <- as_kable_xml(kable_xml)
Hao Zhufdff6f42020-08-09 14:38:10 -0400129 kable_attrs$collapse_matrix <- collapse_matrix
Hao Zhu2a87e8e2017-06-14 15:49:33 -0400130 attributes(out) <- kable_attrs
Hao Zhuf2100832018-01-11 16:20:29 -0500131 if (!"kableExtra" %in% class(out)) class(out) <- c("kableExtra", class(out))
Hao Zhu2a87e8e2017-06-14 15:49:33 -0400132 return(out)
133}
134
Hao Zhu5e2528e2020-08-03 09:16:34 -0400135split_factor <- function(x) {
136 group_idx <- seq(1, length(x))
137 return(factor(unlist(lapply(group_idx, function(i) {rep(i, x[i])}))))
138}
139
140collapse_row_matrix <- function(kable_dt, columns, html = T, target = NULL) {
Hao Zhuf4b35292017-06-25 22:38:37 -1000141 if (html) {
142 column_block <- function(x) c(x, rep(0, x - 1))
143 } else {
144 column_block <- function(x) c(rep(0, x - 1), x)
145 }
146 mapping_matrix <- list()
Hao Zhu5e2528e2020-08-03 09:16:34 -0400147 if (is.null(target)) {
148 for (i in columns) {
149 mapping_matrix[[paste0("x", i)]] <- unlist(lapply(
150 rle(kable_dt[, i])$lengths, column_block))
151 }
152 } else {
153 target_group = split_factor(rle(kable_dt[, target])$lengths)
154 for (i in columns) {
155 column_split = split(kable_dt[, i], target_group)
156 mapping_matrix[[paste0("x", i)]] <- unlist(lapply(
157 column_split, function(sp) {
158 lapply(rle(sp)$length, column_block)
159 }))
160 }
Hao Zhuf4b35292017-06-25 22:38:37 -1000161 }
Hao Zhu5e2528e2020-08-03 09:16:34 -0400162
Hao Zhuf4b35292017-06-25 22:38:37 -1000163 mapping_matrix <- data.frame(mapping_matrix)
164 return(mapping_matrix)
165}
166
Hao Zhu5dd3e282018-05-20 18:39:48 -0400167collapse_rows_latex <- function(kable_input, columns, latex_hline, valign,
georgeguieaeb0cd2018-03-30 17:39:46 -0500168 row_group_label_position, row_group_label_fonts,
Hao Zhuc9858942020-08-11 21:41:09 -0400169 custom_latex_hline, headers_to_remove, target,
Hao Zhu71b30f22020-08-12 22:47:13 -0400170 col_names, longtable_clean_cut) {
Hao Zhuf4b35292017-06-25 22:38:37 -1000171 table_info <- magic_mirror(kable_input)
Hao Zhuc33b1f42020-10-05 23:16:57 -0400172 if (table_info$nrow <= 2) return(kable_input)
Hao Zhu3fc0e882018-04-03 16:06:41 -0400173 out <- solve_enc(kable_input)
Hao Zhu876bcb02020-08-12 23:02:51 -0400174 out <- gsub("\\\\addlinespace\n", "", out)
Hao Zhu064990d2017-10-17 18:08:42 -0400175
Hao Zhu5dd3e282018-05-20 18:39:48 -0400176 valign <- switch(
177 valign,
178 top = "\\[t\\]",
179 middle = "",
180 bottom = "\\[b\\]"
181 )
182
Hao Zhuf4b35292017-06-25 22:38:37 -1000183 if (is.null(columns)) {
184 columns <- seq(1, table_info$ncol)
185 }
Hao Zhu064990d2017-10-17 18:08:42 -0400186
Hao Zhuf4b35292017-06-25 22:38:37 -1000187 contents <- table_info$contents
Hao Zhuc9858942020-08-11 21:41:09 -0400188 kable_dt <- kable_dt_latex(contents, col_names)
georgeguieaeb0cd2018-03-30 17:39:46 -0500189
Hao Zhuaa424412020-08-03 09:21:46 -0400190 collapse_matrix_rev <- collapse_row_matrix(kable_dt, columns, html = TRUE,
191 target)
192 collapse_matrix <- collapse_row_matrix(kable_dt, columns, html = FALSE,
193 target)
Hao Zhuf4b35292017-06-25 22:38:37 -1000194
195 new_kable_dt <- kable_dt
Jakob Richteraebd8292018-10-31 16:27:29 +0100196 for (j in seq_along(columns)) {
Hao Zhuf4b35292017-06-25 22:38:37 -1000197 column_align <- table_info$align_vector_origin[columns[j]]
198 column_width <- ifelse(
199 is.null(table_info$column_width[[paste0("column_", columns[j])]]),
Hao Zhu4e34cd82020-08-19 01:54:23 -0400200 "\\*", table_info$column_width[paste0("column_", columns[j])])
Hao Zhuf4b35292017-06-25 22:38:37 -1000201 for (i in seq(1:nrow(collapse_matrix))) {
georgeguieaeb0cd2018-03-30 17:39:46 -0500202 if(row_group_label_position == 'stack'){
Jakob Richteraebd8292018-10-31 16:27:29 +0100203 if(columns[j] < ncol(collapse_matrix) || collapse_matrix_rev[i, j] == 0){
204 new_kable_dt[i, columns[j]] <- ''
georgeguieaeb0cd2018-03-30 17:39:46 -0500205 }
Kirill Müller64938ec2022-05-26 20:08:56 +0200206 } else if(row_group_label_position == 'first'){
207 if(columns[j] <= ncol(collapse_matrix) && collapse_matrix_rev[i, j] == 0){
208 new_kable_dt[i, columns[j]] <- ''
209 }
georgeguieaeb0cd2018-03-30 17:39:46 -0500210 } else {
Jakob Richteraebd8292018-10-31 16:27:29 +0100211 new_kable_dt[i, columns[j]] <- collapse_new_dt_item(
212 kable_dt[i, columns[j]], collapse_matrix[i, j], column_width,
Hao Zhu5dd3e282018-05-20 18:39:48 -0400213 align = column_align, valign = valign
georgeguieaeb0cd2018-03-30 17:39:46 -0500214 )
215 }
Hao Zhuf4b35292017-06-25 22:38:37 -1000216 }
217 }
Hao Zhu654c91f2017-07-03 14:03:34 -0400218
219 midrule_matrix <- collapse_row_matrix(kable_dt, seq(1, table_info$ncol),
Hao Zhuaa424412020-08-03 09:21:46 -0400220 html = FALSE, target)
Hao Zhu654c91f2017-07-03 14:03:34 -0400221 midrule_matrix[setdiff(seq(1, table_info$ncol), columns)] <- 1
222
223 ex_bottom <- length(contents) - 1
224 contents[2:ex_bottom] <- paste0(contents[2:ex_bottom], "\\\\\\\\")
225 if (!table_info$booktabs) {
226 contents[2:ex_bottom] <- paste0(contents[2:ex_bottom], "\n\\\\hline")
227 }
Hao Zhu01b15b82018-01-12 17:48:21 -0500228
229 new_contents <- c()
georgeguieaeb0cd2018-03-30 17:39:46 -0500230 if(row_group_label_position == 'stack'){
231 if(is.null(headers_to_remove)) headers_to_remove <- head(columns, -1)
232 table_info$colnames[headers_to_remove] <- ''
233 new_header <- paste(table_info$colnames, collapse = ' & ')
234 out <- sub(contents[1], new_header, out)
235 table_info$contents[1] <- new_header
236 }
237 if(latex_hline == 'custom' & is.null(custom_latex_hline)){
238 if(row_group_label_position == 'stack'){
239 custom_latex_hline = 1:2
240 } else {
241 custom_latex_hline = 1
242 }
243 }
Hao Zhud0f7c8a2020-08-20 01:17:23 -0400244
245 if (table_info$tabular == "longtable" & longtable_clean_cut) {
246 if (max(collapse_matrix) > 50) {
247 warning("It seems that you have a group larger than 50 rows and span ",
248 "over a page. You probably want to set longtable_clean_cut to ",
249 "be FALSE.")
250 }
251 pagebreak_hint <- "\\\\pagebreak[0]"
252 nopagebreak <- "\\\\nopagebreak"
253 # out <- gsub("\\\\\\\\($|\n)", "\\\\\\\\\\\\nopagebreak\\1", out)
254 # out <- gsub("(\\\\cmidrule[{][^}]*[}])", "\\1\\\\pagebreak[0]", out)
255 } else {
256 pagebreak_hint <- ""
257 nopagebreak <- ""
258 }
259
Hao Zhuf4b35292017-06-25 22:38:37 -1000260 for (i in seq(1:nrow(collapse_matrix))) {
261 new_contents[i] <- paste0(new_kable_dt[i, ], collapse = " & ")
Hao Zhu12b0ade2018-01-13 16:19:58 -0500262 table_info$contents[i + 1] <- new_contents[i]
Hao Zhu654c91f2017-07-03 14:03:34 -0400263 if (i != nrow(collapse_matrix)) {
Hao Zhu12b0ade2018-01-13 16:19:58 -0500264 row_midrule <- switch(
265 latex_hline,
266 "none" = "",
Hao Zhud0f7c8a2020-08-20 01:17:23 -0400267 "full" = paste0(
Hao Zhu71b30f22020-08-12 22:47:13 -0400268 midline_groups(which(as.numeric(midrule_matrix[i, ]) > 0),
269 table_info$booktabs),
Hao Zhud0f7c8a2020-08-20 01:17:23 -0400270 ifelse(
271 sum(as.numeric(midrule_matrix[i, ]) > 0) == ncol(midrule_matrix),
272 pagebreak_hint, nopagebreak
273 )
Hao Zhu71b30f22020-08-12 22:47:13 -0400274 ),
Hao Zhu12b0ade2018-01-13 16:19:58 -0500275 "major" = ifelse(
276 sum(as.numeric(midrule_matrix[i, ]) > 0) == ncol(midrule_matrix),
Hao Zhud0f7c8a2020-08-20 01:17:23 -0400277 paste0(midline_groups(which(as.numeric(midrule_matrix[i, ]) > 0),
278 table_info$booktabs), pagebreak_hint),
279 nopagebreak
georgeguieaeb0cd2018-03-30 17:39:46 -0500280 ),
281 "custom" = ifelse(
282 sum(as.numeric(midrule_matrix[i, custom_latex_hline])) > 0,
283 midline_groups(which(as.numeric(midrule_matrix[i, ]) > 0),
284 table_info$booktabs),
285 ""
Hao Zhu876bcb02020-08-12 23:02:51 -0400286 ),
287 "linespace"= ifelse(
288 sum(as.numeric(midrule_matrix[i, ]) > 0) == ncol(midrule_matrix),
Hao Zhud0f7c8a2020-08-20 01:17:23 -0400289 "\\\\addlinespace",
Hao Zhu876bcb02020-08-12 23:02:51 -0400290 ""
291 )
Hao Zhu12b0ade2018-01-13 16:19:58 -0500292 )
Hao Zhu654c91f2017-07-03 14:03:34 -0400293 new_contents[i] <- paste0(new_contents[i], "\\\\\\\\\n", row_midrule)
294 }
Hao Zhub3f26ae2020-08-04 00:36:52 -0400295 out <- sub(contents[i + 1], new_contents[i], out, perl=TRUE)
Hao Zhuf4b35292017-06-25 22:38:37 -1000296 }
Hao Zhuf4b35292017-06-25 22:38:37 -1000297 out <- structure(out, format = "latex", class = "knitr_kable")
298 table_info$collapse_rows <- TRUE
Hao Zhuebdb3c22020-08-12 08:27:38 -0400299 table_info$collapse_matrix <- collapse_matrix
Hao Zhuf4b35292017-06-25 22:38:37 -1000300 attr(out, "kable_meta") <- table_info
georgeguieaeb0cd2018-03-30 17:39:46 -0500301 if(row_group_label_position == 'stack'){
302 group_row_index_list <- collapse_rows_index(kable_dt, head(columns, -1))
303 out <- collapse_rows_latex_stack(out, group_row_index_list, row_group_label_fonts)
304 }
Hao Zhuf4b35292017-06-25 22:38:37 -1000305 return(out)
306}
307
Hao Zhuc9858942020-08-11 21:41:09 -0400308kable_dt_latex <- function(x, col_names) {
309 if (col_names) {
310 x <- x[-1]
311 }
312 data.frame(do.call(rbind, str_split(x, " & ")), stringsAsFactors = FALSE)
Hao Zhuf4b35292017-06-25 22:38:37 -1000313}
314
Hao Zhu5dd3e282018-05-20 18:39:48 -0400315collapse_new_dt_item <- function(x, span, width = NULL, align, valign) {
Hao Zhuf4b35292017-06-25 22:38:37 -1000316 if (span == 0) return("")
317 if (span == 1) return(x)
318 out <- paste0(
Hao Zhu5dd3e282018-05-20 18:39:48 -0400319 "\\\\multirow", valign, "\\{", -span, "\\}\\{",
Hao Zhuf4b35292017-06-25 22:38:37 -1000320 ifelse(is.null(width), "\\*", width),
321 "\\}\\{",
322 switch(align,
323 "l" = "\\\\raggedright\\\\arraybackslash ",
324 "c" = "\\\\centering\\\\arraybackslash ",
325 "r" = "\\\\raggedleft\\\\arraybackslash "),
326 x, "\\}"
327 )
328 return(out)
Hao Zhu2a87e8e2017-06-14 15:49:33 -0400329}
Hao Zhu654c91f2017-07-03 14:03:34 -0400330
331midline_groups <- function(x, booktabs = T) {
332 diffs <- c(1, diff(x))
333 start_indexes <- c(1, which(diffs > 1))
Hao Zhu12b0ade2018-01-13 16:19:58 -0500334 end_indexes <- c(start_indexes - 1, length(x))
Hao Zhu654c91f2017-07-03 14:03:34 -0400335 ranges <- paste0(x[start_indexes], "-", x[end_indexes])
336 if (booktabs) {
337 out <- paste0("\\\\cmidrule{", ranges, "}")
338 } else {
339 out <- paste0("\\\\cline{", ranges, "}")
340 }
341 out <- paste0(out, collapse = "\n")
342 return(out)
343}
georgeguieaeb0cd2018-03-30 17:39:46 -0500344
Hao Zhu876bcb02020-08-12 23:02:51 -0400345linespace_groups <- function(x) {
346 diffs <- c(1, diff(x))
347 start_indexes <- c(1, which(diffs > 1))
348 end_indexes <- c(start_indexes - 1, length(x))
349 ranges <- paste0(x[start_indexes], "-", x[end_indexes])
350 out <- paste0("\\\\addlinespace")
351 out <- paste0(out, collapse = "\n")
352 return(out)
353}
354
georgeguieaeb0cd2018-03-30 17:39:46 -0500355
356collapse_rows_index <- function(kable_dt, columns) {
357 format_to_row_index <- function(x){
358 x = rle(x)
359 out = x$lengths
360 names(out) = x$values
361 out
362 }
363 group_rows_index_list <- lapply(columns, function(x) {
364 format_to_row_index(kable_dt[, x])
365 })
366 return(group_rows_index_list)
367}
368
369
370collapse_rows_latex_stack <- function(kable_input, group_row_index_list,
371 row_group_label_fonts){
372 merge_lists <- function(default_list, updated_list){
373 for(x in names(updated_list)){
374 default_list[[x]] <- updated_list[[x]]
375 }
376 return(default_list)
377 }
378 default_font_list <- list(
379 list(bold = T, italic = F),
380 list(bold = F, italic = T),
381 list(bold = F, italic = F)
382 )
383 n_default_fonts = length(default_font_list)
384 n_supplied_fonts = length(row_group_label_fonts)
385 group_row_font_list <- list()
386 out <- kable_input
387 for(i in 1:length(group_row_index_list)){
388 if(i > n_default_fonts){
389 group_row_args <- default_font_list[[n_default_fonts]]
390 } else {
391 group_row_args <- default_font_list[[i]]
392 }
393 if(i <= n_supplied_fonts){
394 group_row_args <- merge_lists(group_row_args, row_group_label_fonts[[i]])
395 }
396 group_row_args <- merge_lists(
Hao Zhu718fa3f2020-08-19 08:23:28 -0400397 list(kable_input = out, index = group_row_index_list[[i]], escape = FALSE),
georgeguieaeb0cd2018-03-30 17:39:46 -0500398 group_row_args)
399 out <- do.call(group_rows, group_row_args)
400 }
401 return(out)
402}