Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 1 | #' Specify the look of the selected column |
| 2 | #' |
| 3 | #' @description This function allows users to select a column and then specify |
Hao Zhu | e7c8f70 | 2017-10-10 13:22:59 -0400 | [diff] [blame] | 4 | #' its look. |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 5 | #' |
| 6 | #' @param kable_input Output of `knitr::kable()` with `format` specified |
Hao Zhu | 322de08 | 2017-09-11 19:25:29 -0400 | [diff] [blame] | 7 | #' @param column A numeric value or vector indicating which column(s) to be selected. |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 8 | #' @param width A character string telling HTML & LaTeX how wide the column |
| 9 | #' needs to be, e.g. "10cm", "3in" or "30em". |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 10 | #' @param bold T/F value or vector to control whether the text of the selected |
| 11 | #' column need to be bolded. |
| 12 | #' @param italic T/F value or vector to control whether the text of the |
| 13 | #' selected column need to be emphasized. |
| 14 | #' @param monospace T/F value or vector to control whether the text of the |
| 15 | #' selected column need to be monospaced (verbatim) |
| 16 | #' @param underline T/F value or vector to control whether the text of the |
| 17 | #' selected row need to be underlined |
| 18 | #' @param strikeout T/F value or vector to control whether the text of the |
| 19 | #' selected row need to be striked out. |
| 20 | #' @param color A character string or vector for column text color. Here please |
| 21 | #' pay attention to the differences in color codes between HTML and LaTeX. |
| 22 | #' @param background A character string or vector for column background color. Here please |
Hao Zhu | 53e240f | 2017-09-04 20:04:29 -0400 | [diff] [blame] | 23 | #' pay attention to the differences in color codes between HTML and LaTeX. |
| 24 | #' @param border_left A logical variable indicating whether there should be a |
| 25 | #' border line on the left of the selected column. In HTML, you can also pass |
| 26 | #' in a character string for the CSS of the border line |
| 27 | #' @param border_right A logical variable indicating whether there should be a |
| 28 | #' border line on the right of the selected column. In HTML, you can also pass |
| 29 | #' in a character string for the CSS of the border line |
Hao Zhu | 6107f37 | 2018-05-21 00:23:26 -0400 | [diff] [blame] | 30 | #' @param width_min Only for HTML table. Normal column width will automatically |
| 31 | #' collapse when the window cannot hold enough contents. With this `width_min`, |
Hao Zhu | b1caa27 | 2018-04-14 14:19:46 -0400 | [diff] [blame] | 32 | #' you can set up a column with a width that won't collapse even when the |
| 33 | #' window is not wide enough. |
Hao Zhu | 6107f37 | 2018-05-21 00:23:26 -0400 | [diff] [blame] | 34 | #' @param width_max Only for HTML table. `width_max` defines the maximum width |
Hao Zhu | b1caa27 | 2018-04-14 14:19:46 -0400 | [diff] [blame] | 35 | #' of table columns. |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 36 | #' @param extra_css A vector of extra css text to be passed into the cells of |
| 37 | #' the column. |
Hao Zhu | 907ddfe | 2018-04-23 15:19:09 -0400 | [diff] [blame] | 38 | #' @param include_thead T/F. A HTML only feature to contoll whether the |
| 39 | #' header row will be manipulated. Default is `FALSE`. |
Duncan Murdoch | 8bc9622 | 2019-04-29 12:46:39 -0400 | [diff] [blame] | 40 | #' @param latex_column_spec Only for LaTeX tables. Code to replace the column |
| 41 | #' specification. If not `NULL`, will override all other arguments. |
Hao Zhu | 2b739ac | 2020-08-15 01:38:51 -0400 | [diff] [blame] | 42 | #' @param latex_valign vertical alignment. Only works when you specified column |
| 43 | #' width. Choose among `p`, `m`, `b`. |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 44 | #' @param link A vector of strings for url links. |
| 45 | #' @param new_tab T/F for whether to open up the new link in new tab |
| 46 | #' @param tooltip A vector of strings to be displayed as tooltip. |
| 47 | #' Obviously, this feature is only available in HTML. Read the package |
| 48 | #' vignette to see how to use bootstrap tooltip css to improve the loading |
| 49 | #' speed and look. |
| 50 | #' @param popover Similar with tooltip but can hold more contents. The best way |
| 51 | #' to build a popover is through `spec_popover()`. If you only provide a text |
| 52 | #' string, it will be used as content. Note that You have to enable this |
| 53 | #' bootstrap module manually. Read the package vignette to see how. |
Duncan Murdoch | 8bc9622 | 2019-04-29 12:46:39 -0400 | [diff] [blame] | 54 | #' |
| 55 | #' @details Use `latex_column_spec` in a LaTeX table to change or |
| 56 | #' customize the column specification. Because of the way it is handled |
| 57 | #' internally, any backslashes must be escaped. |
Hao Zhu | 78e6122 | 2017-05-24 20:53:35 -0400 | [diff] [blame] | 58 | #' |
| 59 | #' @examples x <- knitr::kable(head(mtcars), "html") |
Hao Zhu | 4840bc9 | 2017-09-15 15:55:05 -0400 | [diff] [blame] | 60 | #' column_spec(x, 1:2, width = "20em", bold = TRUE, italic = TRUE) |
Duncan Murdoch | 8bc9622 | 2019-04-29 12:46:39 -0400 | [diff] [blame] | 61 | #' x <- knitr::kable(head(mtcars), "latex", booktabs = TRUE) |
| 62 | #' column_spec(x, 1, latex_column_spec = ">{\\\\color{red}}c") |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 63 | #' @export |
Hao Zhu | 322de08 | 2017-09-11 19:25:29 -0400 | [diff] [blame] | 64 | column_spec <- function(kable_input, column, |
Hao Zhu | 8f20299 | 2017-07-15 02:20:18 -0400 | [diff] [blame] | 65 | width = NULL, bold = FALSE, italic = FALSE, |
Hao Zhu | ef0c830 | 2018-01-12 13:30:20 -0500 | [diff] [blame] | 66 | monospace = FALSE, underline = FALSE, strikeout = FALSE, |
| 67 | color = NULL, background = NULL, |
Hao Zhu | b1de967 | 2018-01-08 16:29:24 -0500 | [diff] [blame] | 68 | border_left = FALSE, border_right = FALSE, |
Hao Zhu | b1caa27 | 2018-04-14 14:19:46 -0400 | [diff] [blame] | 69 | width_min = NULL, width_max = NULL, |
Duncan Murdoch | 8bc9622 | 2019-04-29 12:46:39 -0400 | [diff] [blame] | 70 | extra_css = NULL, include_thead = FALSE, |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 71 | latex_column_spec = NULL, latex_valign = 'p', |
| 72 | link = NULL, new_tab = TRUE, |
| 73 | tooltip = NULL, popover = NULL) { |
Hao Zhu | 322de08 | 2017-09-11 19:25:29 -0400 | [diff] [blame] | 74 | if (!is.numeric(column)) { |
| 75 | stop("column must be numeric. ") |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 76 | } |
| 77 | kable_format <- attr(kable_input, "format") |
| 78 | if (!kable_format %in% c("html", "latex")) { |
Hao Zhu | 401ebd8 | 2018-01-14 17:10:20 -0500 | [diff] [blame] | 79 | warning("Please specify format in kable. kableExtra can customize either ", |
| 80 | "HTML or LaTeX outputs. See https://haozhu233.github.io/kableExtra/ ", |
| 81 | "for details.") |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 82 | return(kable_input) |
| 83 | } |
| 84 | if (kable_format == "html") { |
Hao Zhu | 322de08 | 2017-09-11 19:25:29 -0400 | [diff] [blame] | 85 | return(column_spec_html(kable_input, column, width, |
Hao Zhu | 669bcd2 | 2017-08-19 14:53:40 -0400 | [diff] [blame] | 86 | bold, italic, monospace, |
Hao Zhu | ef0c830 | 2018-01-12 13:30:20 -0500 | [diff] [blame] | 87 | underline, strikeout, |
Hao Zhu | ec7ab92 | 2017-08-19 22:56:44 -0400 | [diff] [blame] | 88 | color, background, |
Hao Zhu | b1caa27 | 2018-04-14 14:19:46 -0400 | [diff] [blame] | 89 | border_left, border_right, |
| 90 | width_min, width_max, |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 91 | extra_css, include_thead, |
| 92 | link, new_tab, tooltip, popover)) |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 93 | } |
| 94 | if (kable_format == "latex") { |
Hao Zhu | 322de08 | 2017-09-11 19:25:29 -0400 | [diff] [blame] | 95 | return(column_spec_latex(kable_input, column, width, |
Hao Zhu | 669bcd2 | 2017-08-19 14:53:40 -0400 | [diff] [blame] | 96 | bold, italic, monospace, |
Hao Zhu | ef0c830 | 2018-01-12 13:30:20 -0500 | [diff] [blame] | 97 | underline, strikeout, |
Hao Zhu | ec7ab92 | 2017-08-19 22:56:44 -0400 | [diff] [blame] | 98 | color, background, |
Duncan Murdoch | 8bc9622 | 2019-04-29 12:46:39 -0400 | [diff] [blame] | 99 | border_left, border_right, |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 100 | latex_column_spec, latex_valign, include_thead, |
| 101 | link)) |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 102 | } |
| 103 | } |
| 104 | |
Hao Zhu | 322de08 | 2017-09-11 19:25:29 -0400 | [diff] [blame] | 105 | column_spec_html <- function(kable_input, column, width, |
Hao Zhu | 669bcd2 | 2017-08-19 14:53:40 -0400 | [diff] [blame] | 106 | bold, italic, monospace, |
Hao Zhu | ef0c830 | 2018-01-12 13:30:20 -0500 | [diff] [blame] | 107 | underline, strikeout, |
Hao Zhu | ec7ab92 | 2017-08-19 22:56:44 -0400 | [diff] [blame] | 108 | color, background, |
Hao Zhu | b1caa27 | 2018-04-14 14:19:46 -0400 | [diff] [blame] | 109 | border_left, border_right, |
| 110 | width_min, width_max, |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 111 | extra_css, include_thead, |
| 112 | link, new_tab, tooltip, popover) { |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 113 | kable_attrs <- attributes(kable_input) |
Hao Zhu | 558c72f | 2017-07-24 15:12:00 -0400 | [diff] [blame] | 114 | kable_xml <- read_kable_as_xml(kable_input) |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 115 | kable_tbody <- xml_tpart(kable_xml, "tbody") |
| 116 | |
| 117 | group_header_rows <- attr(kable_input, "group_header_rows") |
Hao Zhu | 9b43f62 | 2017-09-11 19:00:08 -0400 | [diff] [blame] | 118 | all_contents_rows <- seq(1, length(xml_children(kable_tbody))) |
Hao Zhu | 32f43f7 | 2017-06-20 18:24:54 -0400 | [diff] [blame] | 119 | |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 120 | if (!is.null(group_header_rows)) { |
| 121 | all_contents_rows <- all_contents_rows[!all_contents_rows %in% |
| 122 | group_header_rows] |
| 123 | } |
| 124 | |
Hao Zhu | ec7ab92 | 2017-08-19 22:56:44 -0400 | [diff] [blame] | 125 | # Border css |
| 126 | border_l_css <- "1px solid" |
| 127 | border_r_css <- "1px solid" |
| 128 | if (is.character(border_left)) { |
| 129 | border_l_css <- border_left |
| 130 | border_left <- T |
| 131 | } |
| 132 | if (is.character(border_right)) { |
| 133 | border_r_css <- border_right |
| 134 | border_right <- T |
| 135 | } |
| 136 | |
Hao Zhu | 907ddfe | 2018-04-23 15:19:09 -0400 | [diff] [blame] | 137 | if (include_thead) { |
| 138 | kable_thead <- xml_tpart(kable_xml, "thead") |
| 139 | nrow_thead <- length(xml_children(kable_thead)) |
| 140 | for (j in column) { |
| 141 | target_cell <- xml_child(xml_child(kable_thead, nrow_thead), j) |
| 142 | column_spec_html_cell( |
| 143 | target_cell, width, width_min, width_max, |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 144 | bold[1], italic[1], monospace[1], underline[1], strikeout[1], |
| 145 | color[1], background[1], border_left, border_right, |
Hao Zhu | 907ddfe | 2018-04-23 15:19:09 -0400 | [diff] [blame] | 146 | border_l_css, border_r_css, |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 147 | extra_css[1], link[1], new_tab[1], tooltip[1], popover[1] |
| 148 | ) |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | nrows <- length(all_contents_rows) |
| 153 | off <- 0 |
| 154 | |
| 155 | bold <- ensure_len_html(bold, nrows, "bold") |
| 156 | italic <- ensure_len_html(italic, nrows, "italic") |
| 157 | monospace <- ensure_len_html(monospace, nrows, "monospace") |
| 158 | underline <- ensure_len_html(underline, nrows, "underline") |
| 159 | strikeout <- ensure_len_html(strikeout, nrows, "strikeout") |
| 160 | color <- ensure_len_html(color, nrows, "color") |
| 161 | background <- ensure_len_html(background, nrows,"background") |
| 162 | link <- ensure_len_html(link, nrows, "link") |
| 163 | new_tab <- ensure_len_html(new_tab, nrows, "new_tab") |
| 164 | tooltip <- ensure_len_html(tooltip, nrows, "tooltip") |
| 165 | popover <- ensure_len_html(popover, nrows, "popover") |
| 166 | |
| 167 | for (i in all_contents_rows) { |
| 168 | for (j in column) { |
| 169 | target_cell <- xml_child(xml_child(kable_tbody, i), j) |
| 170 | column_spec_html_cell( |
| 171 | target_cell, width, width_min, width_max, |
| 172 | bold[i], italic[i], monospace[i], underline[i], strikeout[i], |
| 173 | color[i], background[i], border_left, border_right, |
| 174 | border_l_css, border_r_css, |
| 175 | extra_css, |
| 176 | link[i], new_tab[i], tooltip[i], popover[i] |
Hao Zhu | 907ddfe | 2018-04-23 15:19:09 -0400 | [diff] [blame] | 177 | ) |
| 178 | } |
| 179 | } |
Hao Zhu | 6a14e88 | 2017-10-31 17:04:12 -0400 | [diff] [blame] | 180 | |
Hao Zhu | f2dfd14 | 2017-07-24 14:43:28 -0400 | [diff] [blame] | 181 | out <- as_kable_xml(kable_xml) |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 182 | attributes(out) <- kable_attrs |
Hao Zhu | f210083 | 2018-01-11 16:20:29 -0500 | [diff] [blame] | 183 | if (!"kableExtra" %in% class(out)) class(out) <- c("kableExtra", class(out)) |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 184 | return(out) |
| 185 | } |
| 186 | |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 187 | ensure_len_html <- function(x, l, name) { |
| 188 | if (is.null(x)) return(NULL) |
| 189 | if (length(x) == 1) return(rep(x, l)) |
| 190 | if (length(x) == l) return(x) |
| 191 | warning("The number of provided values in ", name, " does not equal to the ", |
| 192 | "number of rows. ") |
| 193 | return(rep(x, ceiling(l / length(x)))[seq(1, l)]) |
| 194 | } |
| 195 | |
Hao Zhu | 907ddfe | 2018-04-23 15:19:09 -0400 | [diff] [blame] | 196 | column_spec_html_cell <- function(target_cell, width, width_min, width_max, |
| 197 | bold, italic, monospace, underline, strikeout, |
| 198 | color, background, |
| 199 | border_left, border_right, |
| 200 | border_l_css, border_r_css, |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 201 | extra_css, |
| 202 | link, new_tab, tooltip, popover) { |
Hao Zhu | 517453c | 2018-05-13 13:07:18 -0400 | [diff] [blame] | 203 | if (is.na(xml_attr(target_cell, "style"))) { |
| 204 | xml_attr(target_cell, "style") <- "" |
| 205 | } |
Hao Zhu | 907ddfe | 2018-04-23 15:19:09 -0400 | [diff] [blame] | 206 | if (!is.null(width)) { |
| 207 | xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), |
| 208 | "width: ", width, "; ") |
| 209 | } |
| 210 | if (!is.null(width_min)) { |
| 211 | xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), |
| 212 | "min-width: ", width_min, "; ") |
| 213 | } |
| 214 | if (!is.null(width_max)) { |
| 215 | xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), |
| 216 | "max-width: ", width_max, "; ") |
| 217 | } |
| 218 | if (bold) { |
| 219 | xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), |
| 220 | "font-weight: bold;") |
| 221 | } |
| 222 | if (italic) { |
| 223 | xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), |
| 224 | "font-style: italic;") |
| 225 | } |
| 226 | if (monospace) { |
| 227 | xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), |
| 228 | "font-family: monospace;") |
| 229 | } |
| 230 | if (underline) { |
| 231 | xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), |
| 232 | "text-decoration: underline;") |
| 233 | } |
| 234 | if (strikeout) { |
| 235 | xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), |
| 236 | "text-decoration: line-through;") |
| 237 | } |
| 238 | if (!is.null(color)) { |
| 239 | xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), |
Hao Zhu | 72917f9 | 2019-03-15 18:41:42 -0400 | [diff] [blame] | 240 | "color: ", html_color(color), |
| 241 | " !important;") |
Hao Zhu | 907ddfe | 2018-04-23 15:19:09 -0400 | [diff] [blame] | 242 | } |
| 243 | if (!is.null(background)) { |
| 244 | xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), |
| 245 | "background-color: ", |
Hao Zhu | 72917f9 | 2019-03-15 18:41:42 -0400 | [diff] [blame] | 246 | html_color(background), |
| 247 | " !important;") |
Hao Zhu | 907ddfe | 2018-04-23 15:19:09 -0400 | [diff] [blame] | 248 | } |
| 249 | if (border_left) { |
| 250 | xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), |
| 251 | "border-left:", border_l_css, ";") |
| 252 | } |
| 253 | if (border_right) { |
| 254 | xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), |
| 255 | "border-right:", border_r_css, ";") |
| 256 | } |
| 257 | if (!is.null(extra_css)) { |
| 258 | xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), |
| 259 | extra_css) |
| 260 | } |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 261 | |
| 262 | # favor popover over tooltip |
| 263 | if (!is.null(popover)) { |
| 264 | if (class(popover) != "ke_popover") popover <- spec_popover(popover) |
| 265 | popover_list <- attr(popover, 'list') |
| 266 | for (p in names(popover_list)) { |
| 267 | xml_attr(target_cell, p) <- popover_list[p] |
| 268 | } |
| 269 | } else if (!is.null(tooltip)) { |
| 270 | if (class(tooltip) != "ke_tooltip") tooltip <- spec_tooltip(tooltip) |
| 271 | tooltip_list <- attr(tooltip, 'list') |
| 272 | for (t in names(tooltip_list)) { |
| 273 | xml_attr(target_cell, t) <- tooltip_list[t] |
| 274 | } |
| 275 | } |
| 276 | # if (!is.null(popover)) { |
| 277 | # if (class(popover) != "ke_popover") popover <- spec_popover(popover) |
| 278 | # popover_list <- attr(popover, 'list') |
| 279 | # span_node <- xml2::read_xml(paste0( |
| 280 | # '<span>', xml_text(target_cell), '</span>' |
| 281 | # )) |
| 282 | # for (p in names(popover_list)) { |
| 283 | # xml_attr(span_node, p) <- popover_list[p] |
| 284 | # } |
| 285 | # xml_add_child(target_cell, span_node) |
| 286 | # xml_text(target_cell) <- "" |
| 287 | # } else if (!is.null(tooltip)) { |
| 288 | # if (class(tooltip) != "ke_tooltip") tooltip <- spec_tooltip(tooltip) |
| 289 | # tooltip_list <- attr(tooltip, 'list') |
| 290 | # span_node <- xml2::read_xml(paste0( |
| 291 | # '<span>', xml_text(target_cell), '</span>' |
| 292 | # )) |
| 293 | # for (t in names(tooltip_list)) { |
| 294 | # xml_attr(span_node, t) <- tooltip_list[t] |
| 295 | # } |
| 296 | # xml_add_child(target_cell, span_node) |
| 297 | # xml_text(target_cell) <- "" |
| 298 | # } |
| 299 | |
| 300 | if (!is.null(link)) { |
| 301 | href_node <- xml2::read_xml(paste0( |
| 302 | '<a href="', link, '">', xml_text(target_cell), '</a>' |
| 303 | )) |
| 304 | if (!is.null(color)) { |
| 305 | xml_attr(href_node, "style") <- paste0("color: ", html_color(color), |
| 306 | " !important;") |
| 307 | } |
| 308 | xml_add_child(target_cell, href_node) |
| 309 | xml_text(target_cell) <- "" |
| 310 | } |
Hao Zhu | 907ddfe | 2018-04-23 15:19:09 -0400 | [diff] [blame] | 311 | } |
| 312 | |
Hao Zhu | 322de08 | 2017-09-11 19:25:29 -0400 | [diff] [blame] | 313 | column_spec_latex <- function(kable_input, column, width, |
Hao Zhu | a73601b | 2017-08-19 15:31:51 -0400 | [diff] [blame] | 314 | bold, italic, monospace, |
Hao Zhu | ef0c830 | 2018-01-12 13:30:20 -0500 | [diff] [blame] | 315 | underline, strikeout, |
Hao Zhu | ec7ab92 | 2017-08-19 22:56:44 -0400 | [diff] [blame] | 316 | color, background, |
Duncan Murdoch | 8bc9622 | 2019-04-29 12:46:39 -0400 | [diff] [blame] | 317 | border_left, border_right, |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 318 | latex_column_spec, latex_valign, include_thead, |
| 319 | link) { |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 320 | table_info <- magic_mirror(kable_input) |
Hao Zhu | f4b3529 | 2017-06-25 22:38:37 -1000 | [diff] [blame] | 321 | if (!is.null(table_info$collapse_rows)) { |
| 322 | message("Usually it is recommended to use column_spec before collapse_rows,", |
| 323 | " especially in LaTeX, to get a desired result. ") |
| 324 | } |
Hao Zhu | 67764aa | 2019-03-15 11:57:50 -0400 | [diff] [blame] | 325 | align_collapse <- ifelse(table_info$booktabs | !is.null(table_info$xtable), |
| 326 | "", "\\|") |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 327 | kable_align_old <- paste(table_info$align_vector, collapse = align_collapse) |
| 328 | |
Hao Zhu | 322de08 | 2017-09-11 19:25:29 -0400 | [diff] [blame] | 329 | table_info$align_vector[column] <- unlist(lapply( |
| 330 | table_info$align_vector_origin[column], |
Hao Zhu | 6ea2afd | 2017-09-11 18:30:49 -0400 | [diff] [blame] | 331 | function(x) { |
| 332 | latex_column_align_builder( |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 333 | x, width, border_left, border_right, latex_column_spec, latex_valign) |
Hao Zhu | 6ea2afd | 2017-09-11 18:30:49 -0400 | [diff] [blame] | 334 | } |
| 335 | )) |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 336 | |
| 337 | kable_align_new <- paste(table_info$align_vector, collapse = align_collapse) |
| 338 | |
Duncan Murdoch | 6eb2950 | 2018-12-16 20:21:00 -0500 | [diff] [blame] | 339 | out <- sub(paste0("\\{", kable_align_old, "\\}"), |
| 340 | paste0("\\{", kable_align_new, "\\}"), |
Hao Zhu | 3fc0e88 | 2018-04-03 16:06:41 -0400 | [diff] [blame] | 341 | solve_enc(kable_input), |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 342 | perl = T) |
Hao Zhu | ae80df4 | 2018-04-12 15:45:11 -0400 | [diff] [blame] | 343 | |
| 344 | if (!is.null(width)) { |
| 345 | fix_newline <- replace_makecell_with_newline(out, table_info, column) |
| 346 | out <- fix_newline[[1]] |
| 347 | table_info <- fix_newline[[2]] |
| 348 | } |
| 349 | |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 350 | if (table_info$duplicated_rows) { |
| 351 | dup_fx_out <- fix_duplicated_rows_latex(out, table_info) |
| 352 | out <- dup_fx_out[[1]] |
| 353 | table_info <- dup_fx_out[[2]] |
| 354 | } |
| 355 | |
| 356 | nrows <- length(table_info$contents) |
| 357 | off <- table_info$position_offset |
| 358 | |
| 359 | bold <- ensure_len_latex(bold, nrows, off, include_thead, FALSE, "bold") |
| 360 | italic <- ensure_len_latex(italic, nrows, off, include_thead, FALSE, "italic") |
| 361 | monospace <- ensure_len_latex(monospace, nrows, off, include_thead, FALSE, |
| 362 | "monospace") |
| 363 | underline <- ensure_len_latex(underline, nrows, off, include_thead, FALSE, |
| 364 | "underline") |
| 365 | strikeout <- ensure_len_latex(strikeout, nrows, off, include_thead, FALSE, |
| 366 | "strikeout") |
| 367 | color <- ensure_len_latex(color, nrows, off, include_thead, "black", "color") |
| 368 | background <- ensure_len_latex(background, nrows, off, include_thead, "white", |
| 369 | "background") |
| 370 | link <- ensure_len_latex(link, nrows, off, include_thead, "#", "link") |
| 371 | |
| 372 | if (include_thead) { |
| 373 | rows <- seq(1, nrows) |
| 374 | } else { |
| 375 | rows <- seq(1 + off, nrows) |
| 376 | } |
| 377 | |
| 378 | for (i in rows) { |
| 379 | target_row <- table_info$contents[i] |
| 380 | new_row <- latex_cell_builder( |
| 381 | target_row, column, table_info, |
| 382 | bold[i], italic[i], monospace[i], underline[i], |
| 383 | strikeout[i], color[i], background[i], link[i] |
| 384 | # font_size, angle |
| 385 | ) |
| 386 | temp_sub <- ifelse(i == 1 & (table_info$tabular == "longtable" | |
| 387 | !is.null(table_info$repeat_header_latex)), |
| 388 | gsub, sub) |
| 389 | out <- temp_sub(target_row, new_row, out, perl = T) |
| 390 | table_info$contents[i] <- new_row |
| 391 | } |
| 392 | |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 393 | out <- structure(out, format = "latex", class = "knitr_kable") |
Hao Zhu | f4b3529 | 2017-06-25 22:38:37 -1000 | [diff] [blame] | 394 | if (!is.null(width)) { |
| 395 | if (is.null(table_info$column_width)) { |
| 396 | table_info$column_width <- list() |
| 397 | } |
Hao Zhu | 322de08 | 2017-09-11 19:25:29 -0400 | [diff] [blame] | 398 | for (i in column) { |
Hao Zhu | 9b43f62 | 2017-09-11 19:00:08 -0400 | [diff] [blame] | 399 | table_info$column_width[[paste0("column_", i)]] <- width |
| 400 | } |
Hao Zhu | f4b3529 | 2017-06-25 22:38:37 -1000 | [diff] [blame] | 401 | } |
Hao Zhu | 32f43f7 | 2017-06-20 18:24:54 -0400 | [diff] [blame] | 402 | attr(out, "kable_meta") <- table_info |
Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 403 | return(out) |
| 404 | } |
Hao Zhu | 32f43f7 | 2017-06-20 18:24:54 -0400 | [diff] [blame] | 405 | |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 406 | ensure_len_latex <- function(x, l, off, include_thead, def, name) { |
| 407 | if (is.null(x)) return(NULL) |
| 408 | if (length(x) == 1) return(rep(x, l)) |
| 409 | if (include_thead) { |
| 410 | if (length(x) == l) return(x) |
| 411 | warning("The number of provided values in ", name, " does not equal to the ", |
| 412 | "number of rows. ") |
| 413 | return(rep(x, ceiling(l / length(x)))[seq(1, l)]) |
| 414 | } else { |
| 415 | l_ = l - off |
| 416 | if (length(x) == l_) return(c(def, x)) |
| 417 | warning("The number of provided values in ", name, " does not equal to the ", |
| 418 | "number of rows. ") |
| 419 | return(c(def, rep(x, ceiling(l_ / length(x)))[seq(1, l_)])) |
| 420 | } |
| 421 | } |
| 422 | |
| 423 | latex_column_align_builder <- function(x, width, |
Duncan Murdoch | 8bc9622 | 2019-04-29 12:46:39 -0400 | [diff] [blame] | 424 | border_left, border_right, |
Hao Zhu | 2b739ac | 2020-08-15 01:38:51 -0400 | [diff] [blame] | 425 | latex_column_spec, latex_valign) { |
Hao Zhu | 32f43f7 | 2017-06-20 18:24:54 -0400 | [diff] [blame] | 426 | extra_align <- "" |
| 427 | if (!is.null(width)) { |
| 428 | extra_align <- switch(x, |
Hao Zhu | bf5bfe2 | 2017-06-21 14:37:41 -0400 | [diff] [blame] | 429 | "l" = "\\\\raggedright\\\\arraybackslash", |
| 430 | "c" = "\\\\centering\\\\arraybackslash", |
| 431 | "r" = "\\\\raggedleft\\\\arraybackslash") |
Hao Zhu | 2b739ac | 2020-08-15 01:38:51 -0400 | [diff] [blame] | 432 | x <- paste0(latex_valign, "\\{", width, "\\}") |
Hao Zhu | 32f43f7 | 2017-06-20 18:24:54 -0400 | [diff] [blame] | 433 | } |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 434 | # if (!is.null(color)) { |
| 435 | # color <- paste0("\\\\leavevmode\\\\color", latex_color(color)) |
| 436 | # } |
| 437 | # |
| 438 | # if (!is.null(background)) { |
| 439 | # background <- paste0("\\\\columncolor", latex_color(background)) |
| 440 | # } |
| 441 | # |
| 442 | # latex_array_options <- c("\\\\bfseries", "\\\\em", "\\\\ttfamily", |
| 443 | # "\\\\underline", "\\\\sout")[ |
| 444 | # c(bold, italic, monospace, underline, strikeout)] |
| 445 | # latex_array_options <- c(latex_array_options, extra_align, |
| 446 | # color, background) |
| 447 | # latex_array_options <- paste0( |
| 448 | # "\\>\\{", paste(latex_array_options, collapse = ""), "\\}" |
| 449 | # ) |
| 450 | # x <- paste0(latex_array_options, x) |
Hao Zhu | ec7ab92 | 2017-08-19 22:56:44 -0400 | [diff] [blame] | 451 | if (border_left) { |
Hao Zhu | b49bddf | 2018-01-12 15:25:23 -0500 | [diff] [blame] | 452 | x <- paste0("\\|", x) |
Hao Zhu | ec7ab92 | 2017-08-19 22:56:44 -0400 | [diff] [blame] | 453 | } |
| 454 | if (border_right) { |
Hao Zhu | b49bddf | 2018-01-12 15:25:23 -0500 | [diff] [blame] | 455 | x <- paste0(x, "\\|") |
Hao Zhu | ec7ab92 | 2017-08-19 22:56:44 -0400 | [diff] [blame] | 456 | } |
Duncan Murdoch | 8bc9622 | 2019-04-29 12:46:39 -0400 | [diff] [blame] | 457 | if (!is.null(latex_column_spec)) |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 458 | x <- latex_column_spec |
Hao Zhu | a73601b | 2017-08-19 15:31:51 -0400 | [diff] [blame] | 459 | |
Hao Zhu | 32f43f7 | 2017-06-20 18:24:54 -0400 | [diff] [blame] | 460 | return(x) |
| 461 | } |
Hao Zhu | ae80df4 | 2018-04-12 15:45:11 -0400 | [diff] [blame] | 462 | |
| 463 | replace_makecell_with_newline <- function(kable_input, table_info, column) { |
| 464 | if (!str_detect(kable_input, "makecell")) return(list(kable_input, table_info)) |
| 465 | contents_table <- data.frame(sapply(table_info$contents, |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 466 | function(x) {str_split(x, " \\& ")[[1]]}), |
| 467 | stringsAsFactors = F) |
Hao Zhu | ae80df4 | 2018-04-12 15:45:11 -0400 | [diff] [blame] | 468 | names(contents_table) <- paste0("x", 1:table_info$nrow) |
| 469 | rows_check_makecell <- str_detect(contents_table[column, ], "makecell") |
| 470 | if (sum(rows_check_makecell) == 0) return(list(kable_input, table_info)) |
| 471 | rows_to_replace <- which(rows_check_makecell) |
| 472 | |
| 473 | for (i in column) { |
| 474 | target_column <- contents_table[i, ] |
| 475 | for (j in which(str_detect(target_column, "\\\\\\\\makecell"))) { |
| 476 | contents_table[i, j] <- str_replace( |
| 477 | contents_table[i, j], "\\\\\\\\makecell\\\\\\[.\\\\\\]\\\\\\{", "") |
| 478 | contents_table[i, j] <- str_replace( |
Hao Zhu | 9ac3e38 | 2018-04-12 18:56:32 -0400 | [diff] [blame] | 479 | contents_table[i, j], "\\\\\\}$", "") |
Hao Zhu | ae80df4 | 2018-04-12 15:45:11 -0400 | [diff] [blame] | 480 | contents_table[i, j] <- str_replace_all( |
| 481 | contents_table[i, j], "\\\\\\\\\\\\\\\\", "\\\\\\\\newline " |
| 482 | ) |
| 483 | } |
| 484 | } |
| 485 | |
| 486 | new_contents <- unlist(lapply(contents_table, paste, collapse = " & ")) |
| 487 | for (i in rows_to_replace) { |
| 488 | kable_input <- sub(table_info$contents[i], new_contents[i], kable_input, |
| 489 | perl = T) |
| 490 | table_info$contents[i] <- new_contents[i] |
| 491 | } |
| 492 | |
| 493 | return(list(kable_input, table_info)) |
| 494 | } |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 495 | |
| 496 | latex_cell_builder <- function(target_row, column, table_info, |
| 497 | bold, italic, monospace, |
| 498 | underline, strikeout, |
| 499 | color, background, link |
| 500 | # font_size, angle |
| 501 | ) { |
| 502 | new_row <- latex_row_cells(target_row)[[1]] |
| 503 | if (bold) { |
| 504 | new_row[column] <- paste0("\\\\textbf\\{", new_row[column], "\\}") |
| 505 | } |
| 506 | if (italic) { |
| 507 | new_row[column] <- paste0("\\\\em\\{", new_row[column], "\\}") |
| 508 | } |
| 509 | if (monospace) { |
| 510 | new_row[column] <- paste0("\\\\ttfamily\\{", new_row[column], "\\}") |
| 511 | } |
| 512 | if (underline) { |
| 513 | new_row[column] <- paste0("\\\\underline\\{", new_row[column], "\\}") |
| 514 | } |
| 515 | if (strikeout) { |
| 516 | new_row[column] <- paste0("\\\\sout\\{", new_row[column], "\\}") |
| 517 | } |
| 518 | if (!is.null(color)) { |
Hao Zhu | c79d854 | 2020-08-18 03:19:21 -0400 | [diff] [blame^] | 519 | clean_columns <- unlist(lapply(new_row[column], clear_color_latex)) |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 520 | new_row[column] <- paste0("\\\\textcolor", latex_color(color), "\\{", |
Hao Zhu | c79d854 | 2020-08-18 03:19:21 -0400 | [diff] [blame^] | 521 | clean_columns, "\\}") |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 522 | } |
| 523 | # if (!is.null(font_size)) { |
| 524 | # new_row[column] <- paste0("\\\\begingroup\\\\fontsize\\{", font_size, "\\}\\{", |
| 525 | # as.numeric(font_size) + 2, |
| 526 | # "\\}\\\\selectfont ", new_row[column], "\\\\endgroup") |
| 527 | # } |
| 528 | # if (!is.null(angle)) { |
| 529 | # new_row[column] <- paste0("\\\\rotatebox\\{", angle, "\\}\\{", |
| 530 | # new_row[column], "\\}") |
| 531 | # } |
| 532 | if (!is.null(background)) { |
Hao Zhu | c79d854 | 2020-08-18 03:19:21 -0400 | [diff] [blame^] | 533 | clean_columns <- unlist(lapply(new_row[column], clear_color_latex, TRUE)) |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 534 | new_row[column] <- paste0("\\\\cellcolor", latex_color(background), "\\{", |
Hao Zhu | c79d854 | 2020-08-18 03:19:21 -0400 | [diff] [blame^] | 535 | clean_columns, "\\}") |
Hao Zhu | 33b865f | 2020-08-18 02:10:43 -0400 | [diff] [blame] | 536 | } |
| 537 | |
| 538 | if (!is.null(link)) { |
| 539 | new_row[column] <- paste0("\\\\href\\{", escape_latex(link), "\\}\\{", |
| 540 | new_row[column], "\\}") |
| 541 | } |
| 542 | |
| 543 | new_row <- paste(new_row, collapse = " & ") |
| 544 | |
| 545 | return(new_row) |
| 546 | } |