blob: 47a02f0792eae5401f7419756da04e19b247c55f [file] [log] [blame]
Hao Zhu62cdde52017-05-20 22:16:03 -04001#' Put a few rows of a table into one category
2#'
Hao Zhubd95bb22017-05-22 16:08:49 -04003#' @description Group a few rows in a table together under a label.
4#'
5#' @param kable_input Output of `knitr::kable()` with `format` specified
6#' @param group_label A character string for the name of the group
7#' @param start_row A numeric value that tells the function in which row the
8#' group starts. Note that the counting excludes header rows and other group
9#' labeling rows
10#' @param end_row A numeric value that tells the function in which row the group
11#' ends.
12#' @param label_row_css A character string for any customized css used for the
13#' labeling row. By default, the labeling row will have a solid black line
14#' underneath. Only useful for HTML documents.
15#' @param latex_gap_space A character value telling LaTeX how large the gap
16#' between the previous row and the group labeling row. Only useful for LaTeX
17#' documents.
Hao Zhuac7e70f2017-08-02 00:18:36 -040018#' @param escape A T/F value showing whether special characters should be
19#' escaped.
Hao Zhubd95bb22017-05-22 16:08:49 -040020#'
Hao Zhu78e61222017-05-24 20:53:35 -040021#' @examples x <- knitr::kable(head(mtcars), "html")
22#' # Put Row 2 to Row 5 into a Group and label it as "Group A"
23#' group_rows(x, "Group A", 2, 5)
24#'
Hao Zhu62cdde52017-05-20 22:16:03 -040025#' @export
Hao Zhud972e7f2017-05-22 13:27:15 -040026group_rows <- function(kable_input, group_label, start_row, end_row,
27 label_row_css = "border-bottom: 1px solid;",
Hao Zhuac7e70f2017-08-02 00:18:36 -040028 latex_gap_space = "0.5em",
29 escape = TRUE) {
Hao Zhud972e7f2017-05-22 13:27:15 -040030 if (!is.numeric(c(start_row, end_row))) {
31 stop("Start_row and end_row must be numeric position of rows (excluding",
32 "header rows and other group-title rows). ")
33 }
Hao Zhu62cdde52017-05-20 22:16:03 -040034 kable_format <- attr(kable_input, "format")
35 if (!kable_format %in% c("html", "latex")) {
36 message("Currently generic markdown table using pandoc is not supported.")
37 return(kable_input)
38 }
39 if (kable_format == "html") {
Hao Zhud972e7f2017-05-22 13:27:15 -040040 return(group_rows_html(kable_input, group_label, start_row, end_row,
Hao Zhuac7e70f2017-08-02 00:18:36 -040041 label_row_css, escape))
Hao Zhu62cdde52017-05-20 22:16:03 -040042 }
43 if (kable_format == "latex") {
Hao Zhud972e7f2017-05-22 13:27:15 -040044 return(group_rows_latex(kable_input, group_label, start_row, end_row,
Hao Zhuac7e70f2017-08-02 00:18:36 -040045 latex_gap_space, escape))
Hao Zhu62cdde52017-05-20 22:16:03 -040046 }
47}
48
Hao Zhud972e7f2017-05-22 13:27:15 -040049group_rows_html <- function(kable_input, group_label, start_row, end_row,
Hao Zhuac7e70f2017-08-02 00:18:36 -040050 label_row_css, escape) {
Hao Zhu62cdde52017-05-20 22:16:03 -040051 kable_attrs <- attributes(kable_input)
Hao Zhu558c72f2017-07-24 15:12:00 -040052 kable_xml <- read_kable_as_xml(kable_input)
Hao Zhu62cdde52017-05-20 22:16:03 -040053 kable_tbody <- xml_tpart(kable_xml, "tbody")
54
Hao Zhuac7e70f2017-08-02 00:18:36 -040055 if (escape) {
56 group_label <- escape_html(group_label)
57 }
58
Hao Zhu62cdde52017-05-20 22:16:03 -040059 group_header_rows <- attr(kable_input, "group_header_rows")
60 group_seq <- seq(start_row, end_row)
61 if (!is.null(group_header_rows)) {
62 group_seq <- positions_corrector(group_seq, group_header_rows,
63 length(xml_children(kable_tbody)))
64 }
65
66 # Insert a group header row
67 starting_node <- xml_child(kable_tbody, group_seq[1])
68 kable_ncol <- length(xml_children(starting_node))
69 group_header_row_text <- paste0(
Hao Zhud972e7f2017-05-22 13:27:15 -040070 '<tr groupLength="', length(group_seq), '"><td colspan="', kable_ncol,
71 '" style="', label_row_css, '"><strong>', group_label,
72 "</strong></td></tr>"
Hao Zhu62cdde52017-05-20 22:16:03 -040073 )
74 group_header_row <- read_xml(group_header_row_text, options = "COMPACT")
75 xml_add_sibling(starting_node, group_header_row, .where = "before")
76
77 # add indentations to items
Hao Zhuf2dfd142017-07-24 14:43:28 -040078 out <- as_kable_xml(kable_xml)
Hao Zhu62cdde52017-05-20 22:16:03 -040079 attributes(out) <- kable_attrs
80 attr(out, "group_header_rows") <- c(attr(out, "group_header_rows"), group_seq[1])
81 out <- add_indent(out, positions = seq(start_row, end_row))
82 return(out)
83}
Hao Zhud972e7f2017-05-22 13:27:15 -040084
Hao Zhufc14c9b2017-05-22 14:03:22 -040085group_rows_latex <- function(kable_input, group_label, start_row, end_row,
Hao Zhuac7e70f2017-08-02 00:18:36 -040086 gap_space, escape) {
Hao Zhud972e7f2017-05-22 13:27:15 -040087 table_info <- magic_mirror(kable_input)
88 out <- kable_input
89
Hao Zhuac7e70f2017-08-02 00:18:36 -040090 if (escape) {
91 group_label <- escape_latex(group_label)
92 group_label <- gsub("\\\\", "\\\\\\\\", group_label)
93 }
94
Hao Zhud972e7f2017-05-22 13:27:15 -040095 # Add group label
96 rowtext <- table_info$contents[start_row + 1]
97 if (table_info$booktabs) {
98 new_rowtext <- paste0(
99 "\\\\addlinespace[", gap_space, "]\n",
100 "\\\\multicolumn{", table_info$ncol, "}{l}{\\\\textbf{", group_label,
101 "}}\\\\\\\\\n",
102 rowtext
103 )
Hao Zhud972e7f2017-05-22 13:27:15 -0400104 } else {
105 rowtext <- paste0("\\\\hline\n", rowtext)
106 new_rowtext <- paste0(
107 "\\\\hline\n\\\\multicolumn{", table_info$ncol, "}{l}{\\\\textbf{",
108 group_label, "}}\\\\\\\\\n", rowtext
109 )
110 }
111 out <- sub(rowtext, new_rowtext, out)
Hao Zhu8f202992017-07-15 02:20:18 -0400112 out <- gsub("\\\\addlinespace\n", "", out)
Hao Zhu32f43f72017-06-20 18:24:54 -0400113 table_info$group_rows_used <- TRUE
114 attr(out, "kable_meta") <- table_info
Hao Zhud972e7f2017-05-22 13:27:15 -0400115 out <- add_indent(out, seq(start_row, end_row))
116 return(out)
117}