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