blob: 19c9169b208287c9afe27b71b6881af47bd9cd08 [file] [log] [blame]
Hao Zhu8f417202017-05-20 16:37:14 -04001#' Add indentations to row headers
Hao Zhubd95bb22017-05-22 16:08:49 -04002#'
3#' @param kable_input Output of `knitr::kable()` with `format` specified
4#' @param positions A vector of numeric row numbers for the rows that need to
5#' be indented.
Hao Zhu9410a272020-08-03 01:11:47 -04006#' @param level_of_indent a numeric value for the indent level. Default is 1.
Hao Zhu8f46db82020-08-18 21:48:23 -04007#' @param all_cols T/F whether to apply indentation to all columns
Damian Thomasf36f9602021-04-28 09:59:51 -04008#' @param target_cols A vector of numeric column positions. Default is 1.
Hao Zhubd95bb22017-05-22 16:08:49 -04009#'
Hao Zhu9399dcc2020-08-26 17:27:38 -040010#' @examples
11#' \dontrun{
12#' x <- knitr::kable(head(mtcars), "html")
Hao Zhu78e61222017-05-24 20:53:35 -040013#' # Add indentations to the 2nd & 4th row
Samia67d70572020-07-06 00:54:13 -040014#' add_indent(x, c(2, 4), level_of_indent = 1)
Hao Zhu9399dcc2020-08-26 17:27:38 -040015#' }
Hao Zhu78e61222017-05-24 20:53:35 -040016#'
Hao Zhu8f417202017-05-20 16:37:14 -040017#' @export
Hao Zhu9410a272020-08-03 01:11:47 -040018add_indent <- function(kable_input, positions,
Damian Thomasf36f9602021-04-28 09:59:51 -040019 level_of_indent = 1, all_cols = FALSE,
20 target_cols = 1) {
Samia106ad582020-07-15 14:19:09 -040021
Hao Zhud972e7f2017-05-22 13:27:15 -040022 if (!is.numeric(positions)) {
23 stop("Positions can only take numeric row numbers (excluding header rows).")
24 }
Hao Zhu8f417202017-05-20 16:37:14 -040025 kable_format <- attr(kable_input, "format")
26 if (!kable_format %in% c("html", "latex")) {
Hao Zhu401ebd82018-01-14 17:10:20 -050027 warning("Please specify format in kable. kableExtra can customize either ",
28 "HTML or LaTeX outputs. See https://haozhu233.github.io/kableExtra/ ",
29 "for details.")
Hao Zhu8f417202017-05-20 16:37:14 -040030 return(kable_input)
31 }
32 if (kable_format == "html") {
Damian Thomasf36f9602021-04-28 09:59:51 -040033 return(add_indent_html(kable_input, positions, level_of_indent, all_cols, target_cols))
Hao Zhu8f417202017-05-20 16:37:14 -040034 }
35 if (kable_format == "latex") {
Damian Thomasf36f9602021-04-28 09:59:51 -040036 return(add_indent_latex(kable_input, positions, level_of_indent, all_cols, target_cols))
Hao Zhu8f417202017-05-20 16:37:14 -040037 }
38}
39
Hao Zhu62cdde52017-05-20 22:16:03 -040040# Add indentation for LaTeX
Hao Zhu9410a272020-08-03 01:11:47 -040041add_indent_latex <- function(kable_input, positions,
Damian Thomasf36f9602021-04-28 09:59:51 -040042 level_of_indent = 1, all_cols = FALSE,
43 target_cols = 1) {
Hao Zhud972e7f2017-05-22 13:27:15 -040044 table_info <- magic_mirror(kable_input)
Hao Zhu3fc0e882018-04-03 16:06:41 -040045 out <- solve_enc(kable_input)
Samia67d70572020-07-06 00:54:13 -040046 level_of_indent<-as.numeric(level_of_indent)
Hao Zhu064990d2017-10-17 18:08:42 -040047
48 if (table_info$duplicated_rows) {
49 dup_fx_out <- fix_duplicated_rows_latex(out, table_info)
50 out <- dup_fx_out[[1]]
51 table_info <- dup_fx_out[[2]]
52 }
Hao Zhu8f417202017-05-20 16:37:14 -040053
Hao Zhu37dbe3f2018-05-14 11:16:06 -040054 max_position <- table_info$nrow - table_info$position_offset
Leo83f05132018-05-10 14:12:16 +080055
56 if (max(positions) > max_position) {
Hao Zhu8f417202017-05-20 16:37:14 -040057 stop("There aren't that many rows in the table. Check positions in ",
58 "add_indent_latex.")
59 }
60
Hao Zhu37dbe3f2018-05-14 11:16:06 -040061 for (i in positions + table_info$position_offset) {
Leo83f05132018-05-10 14:12:16 +080062 rowtext <- table_info$contents[i]
Damian Thomasf36f9602021-04-28 09:59:51 -040063 new_rowtext <- unlist(latex_row_cells(rowtext))
Hao Zhu9410a272020-08-03 01:11:47 -040064 if (all_cols) {
Hao Zhu9410a272020-08-03 01:11:47 -040065 new_rowtext <- lapply(new_rowtext, function(x) {
66 paste0("\\\\hspace\\{", level_of_indent ,"em\\}", x)
67 })
68 new_rowtext <- paste(unlist(new_rowtext), collapse = " & ")
69 } else {
Damian Thomasf36f9602021-04-28 09:59:51 -040070 if (all(target_cols %in% seq_along(new_rowtext))) {
71 new_rowtext[target_cols] <- latex_indent_unit(new_rowtext[target_cols], level_of_indent)
72 } else {
73 stop("There aren't that many columns in the row. Check target_cols in ",
74 "add_indent_latex.")
75 }
Hao Zhu9410a272020-08-03 01:11:47 -040076 }
Damian Thomasf36f9602021-04-28 09:59:51 -040077 new_rowtext <- paste(unlist(new_rowtext), collapse = " & ")
Hao Zhu93282122021-05-25 15:50:13 -040078 out <- sub(paste0(rowtext, "(\\\\\\\\\\*?(\\[.*\\])?\n)"),
79 paste0(new_rowtext, "\\1"),
80 out, perl = TRUE)
Hao Zhu9410a272020-08-03 01:11:47 -040081 table_info$contents[i] <- new_rowtext
Hao Zhu8f417202017-05-20 16:37:14 -040082 }
Hao Zhu2ce42b92017-06-15 17:15:33 -040083 out <- structure(out, format = "latex", class = "knitr_kable")
Hao Zhu32f43f72017-06-20 18:24:54 -040084 attr(out, "kable_meta") <- table_info
Hao Zhu8f417202017-05-20 16:37:14 -040085 return(out)
Samia6c4b24f2020-07-06 00:46:41 -040086
87
Hao Zhu8f417202017-05-20 16:37:14 -040088}
89
Hao Zhu9410a272020-08-03 01:11:47 -040090latex_indent_unit <- function(rowtext, level_of_indent) {
91 paste0("\\\\hspace\\{", level_of_indent ,"em\\}", rowtext)
Hao Zhu8f417202017-05-20 16:37:14 -040092}
Hao Zhu62cdde52017-05-20 22:16:03 -040093
Samia6c4b24f2020-07-06 00:46:41 -040094
95
Hao Zhu62cdde52017-05-20 22:16:03 -040096# Add indentation for HTML
Hao Zhu9410a272020-08-03 01:11:47 -040097add_indent_html <- function(kable_input, positions,
Damian Thomasf36f9602021-04-28 09:59:51 -040098 level_of_indent = 1, all_cols = FALSE,
99 target_cols = 1) {
Hao Zhu62cdde52017-05-20 22:16:03 -0400100 kable_attrs <- attributes(kable_input)
101
Hao Zhu9410a272020-08-03 01:11:47 -0400102 kable_xml <- kable_as_xml(kable_input)
Hao Zhu62cdde52017-05-20 22:16:03 -0400103 kable_tbody <- xml_tpart(kable_xml, "tbody")
104
105 group_header_rows <- attr(kable_input, "group_header_rows")
106 if (!is.null(group_header_rows)) {
107 positions <- positions_corrector(positions, group_header_rows,
108 length(xml_children(kable_tbody)))
109 }
Alan Butlerc81c1fe2018-01-30 11:16:18 -0700110
Hao Zhu62cdde52017-05-20 22:16:03 -0400111 for (i in positions) {
Hao Zhu9410a272020-08-03 01:11:47 -0400112 row_to_edit = xml_children(kable_tbody)[[i]]
113 if (all_cols) {
114 target_cols = 1:xml2::xml_length(row_to_edit)
Hao Zhu9410a272020-08-03 01:11:47 -0400115 }
116
117 for (j in target_cols) {
Hao Zhu9410a272020-08-03 01:11:47 -0400118 node_to_edit <- xml_child(row_to_edit, j)
119 if (!xml_has_attr(node_to_edit, "indentlevel")) {
Hao Zhu594057b2021-01-19 00:50:50 -0500120 xml_attr(node_to_edit, "style") <- paste0(
Hao Zhu9410a272020-08-03 01:11:47 -0400121 xml_attr(node_to_edit, "style"), "padding-left: ",paste0(level_of_indent*2,"em;")
122 )
123 xml_attr(node_to_edit, "indentlevel") <- 1
124 } else {
125 indentLevel <- as.numeric(xml_attr(node_to_edit, "indentlevel"))
126 xml_attr(node_to_edit, "style") <- sub(
127 paste0("padding-left: ", indentLevel * 2, "em;"),
128 paste0("padding-left: ", (indentLevel + 1) * 2, "em;"),
129 xml_attr(node_to_edit, "style")
130 )
131 xml_attr(node_to_edit, "indentlevel") <- indentLevel + 1
132 }
Hao Zhu62cdde52017-05-20 22:16:03 -0400133 }
134 }
Hao Zhuf2dfd142017-07-24 14:43:28 -0400135 out <- as_kable_xml(kable_xml)
Hao Zhu62cdde52017-05-20 22:16:03 -0400136 attributes(out) <- kable_attrs
Hao Zhuf2100832018-01-11 16:20:29 -0500137 if (!"kableExtra" %in% class(out)) class(out) <- c("kableExtra", class(out))
Hao Zhu62cdde52017-05-20 22:16:03 -0400138 return(out)
139}