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