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