Dan Chaltiel | 075db09 | 2020-08-03 22:18:33 +0200 | [diff] [blame] | 1 | #' Remove columns |
| 2 | #' |
| 3 | #' @param kable_input Output of [knitr::kable()] with format specified |
Hao Zhu | fdff6f4 | 2020-08-09 14:38:10 -0400 | [diff] [blame] | 4 | #' @param columns A numeric value or vector indicating in which column(s) rows |
| 5 | #' need to be removed |
Dan Chaltiel | 075db09 | 2020-08-03 22:18:33 +0200 | [diff] [blame] | 6 | #' |
| 7 | #' @export |
| 8 | #' |
| 9 | #' @examples |
Hao Zhu | 9399dcc | 2020-08-26 17:27:38 -0400 | [diff] [blame] | 10 | #' \dontrun{ |
Hao Zhu | fdff6f4 | 2020-08-09 14:38:10 -0400 | [diff] [blame] | 11 | #' remove_column(kable(mtcars), 1) |
Hao Zhu | 9399dcc | 2020-08-26 17:27:38 -0400 | [diff] [blame] | 12 | #' } |
Dan Chaltiel | 9e83d8f | 2020-08-03 22:46:35 +0200 | [diff] [blame] | 13 | remove_column <- function (kable_input, columns) { |
Hao Zhu | fdff6f4 | 2020-08-09 14:38:10 -0400 | [diff] [blame] | 14 | if (is.null(columns)) return(kable_input) |
Dan Chaltiel | 075db09 | 2020-08-03 22:18:33 +0200 | [diff] [blame] | 15 | kable_format <- attr(kable_input, "format") |
| 16 | if (!kable_format %in% c("html", "latex")) { |
Hao Zhu | fdff6f4 | 2020-08-09 14:38:10 -0400 | [diff] [blame] | 17 | warning("Please specify format in kable. kableExtra can customize", |
| 18 | " either HTML or LaTeX outputs. See ", |
| 19 | "https://haozhu233.github.io/kableExtra/ for details.") |
Dan Chaltiel | 075db09 | 2020-08-03 22:18:33 +0200 | [diff] [blame] | 20 | return(kable_input) |
| 21 | } |
Hao Zhu | fdff6f4 | 2020-08-09 14:38:10 -0400 | [diff] [blame] | 22 | |
| 23 | columns <- sort(unique(columns)) |
Dan Chaltiel | 075db09 | 2020-08-03 22:18:33 +0200 | [diff] [blame] | 24 | if (kable_format == "html") { |
| 25 | return(remove_column_html(kable_input, columns)) |
| 26 | } else if (kable_format == "latex") { |
| 27 | stop("Removing columns was not implemented for latex kables yet") |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | remove_column_html <- function (kable_input, columns) { |
| 32 | kable_attrs <- attributes(kable_input) |
| 33 | kable_xml <- kable_as_xml(kable_input) |
| 34 | kable_tbody <- xml_tpart(kable_xml, "tbody") |
| 35 | kable_thead <- xml_tpart(kable_xml, "thead") |
Hao Zhu | fdff6f4 | 2020-08-09 14:38:10 -0400 | [diff] [blame] | 36 | |
| 37 | group_header_rows <- attr(kable_input, "group_header_rows") |
| 38 | all_contents_rows <- seq(1, length(xml_children(kable_tbody))) |
| 39 | |
| 40 | if (!is.null(group_header_rows)) { |
| 41 | warning("It's recommended to use remove_column after add_header_above.", |
| 42 | "Right now some column span numbers might not be correct. ") |
| 43 | all_contents_rows <- all_contents_rows[!all_contents_rows %in% |
| 44 | group_header_rows] |
| 45 | } |
| 46 | |
| 47 | collapse_matrix <- attr(kable_input, "collapse_matrix") |
| 48 | collapse_columns <- NULL |
| 49 | if (!is.null(collapse_matrix)) { |
| 50 | collapse_columns <- sort(as.numeric(sub("x", "", |
| 51 | names(collapse_matrix)))) |
| 52 | collapse_columns_origin <- collapse_columns |
| 53 | } |
| 54 | |
| 55 | while (length(columns) > 0) { |
| 56 | xml2::xml_remove(xml2::xml_child( |
| 57 | xml2::xml_child(kable_thead, xml2::xml_length(kable_thead)), |
| 58 | columns[1])) |
| 59 | if (length(collapse_columns) != 0 && collapse_columns[1] <= columns[1]){ |
| 60 | if (columns[1] %in% collapse_columns) { |
| 61 | column_span <- collapse_matrix[[paste0('x', columns[1])]] |
| 62 | non_skip_rows <- column_span != 0 |
| 63 | collapse_columns <- collapse_columns[ |
| 64 | collapse_columns != columns[1] |
| 65 | ] - 1 |
| 66 | } else { |
| 67 | non_skip_rows <- rep(TRUE, length(all_contents_rows)) |
| 68 | } |
| 69 | prior_col <- which(collapse_columns_origin < columns[1]) |
| 70 | for (i in all_contents_rows[non_skip_rows]) { |
| 71 | if (length(prior_col) == 0) { |
| 72 | pos_adj <- 0 |
| 73 | } else { |
| 74 | pos_adj <- sum(collapse_matrix[i, prior_col] == 0) |
| 75 | } |
| 76 | target_cell <- xml2::xml_child( |
| 77 | xml2::xml_child(kable_tbody, i), |
| 78 | columns[1] - pos_adj) |
| 79 | xml2::xml_remove(target_cell) |
| 80 | } |
| 81 | } else { |
| 82 | for (i in all_contents_rows) { |
| 83 | target_cell <- xml2::xml_child( |
| 84 | xml2::xml_child(kable_tbody, i), |
| 85 | columns[1]) |
| 86 | xml2::xml_remove(target_cell) |
Dan Chaltiel | c0d3029 | 2020-08-04 00:17:24 +0200 | [diff] [blame] | 87 | } |
| 88 | } |
Hao Zhu | fdff6f4 | 2020-08-09 14:38:10 -0400 | [diff] [blame] | 89 | # not very efficient but for finite task it's probably okay |
| 90 | columns <- (columns - 1)[-1] |
Dan Chaltiel | c0d3029 | 2020-08-04 00:17:24 +0200 | [diff] [blame] | 91 | } |
Dan Chaltiel | 075db09 | 2020-08-03 22:18:33 +0200 | [diff] [blame] | 92 | out <- as_kable_xml(kable_xml) |
| 93 | attributes(out) <- kable_attrs |
Hao Zhu | fdff6f4 | 2020-08-09 14:38:10 -0400 | [diff] [blame] | 94 | if (!"kableExtra" %in% class(out)) |
Dan Chaltiel | 075db09 | 2020-08-03 22:18:33 +0200 | [diff] [blame] | 95 | class(out) <- c("kableExtra", class(out)) |
Hao Zhu | fdff6f4 | 2020-08-09 14:38:10 -0400 | [diff] [blame] | 96 | |
Dan Chaltiel | 075db09 | 2020-08-03 22:18:33 +0200 | [diff] [blame] | 97 | return(out) |
| 98 | } |