| 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 | 
 | 4 | #' its look. Right now it supports the following three properties: column width, | 
 | 5 | #' bold text and italic text. | 
 | 6 | #' | 
 | 7 | #' @param kable_input Output of `knitr::kable()` with `format` specified | 
| Hao Zhu | bf5bfe2 | 2017-06-21 14:37:41 -0400 | [diff] [blame] | 8 | #' @param column A numeric value indicating which column to be selected. When | 
 | 9 | #' you do the counting, ignore the extra header columns you added through | 
 | 10 | #' add_header_left. | 
| Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 11 | #' @param width A character string telling HTML & LaTeX how wide the column | 
 | 12 | #' needs to be, e.g. "10cm", "3in" or "30em". | 
 | 13 | #' @param bold A T/F value to control whether the text of the selected column | 
 | 14 | #' need to be bolded. | 
 | 15 | #' @param italic A T/F value to control whether the text of the selected column | 
 | 16 | #' need to be emphasized. | 
| Hao Zhu | 78e6122 | 2017-05-24 20:53:35 -0400 | [diff] [blame] | 17 | #' | 
 | 18 | #' @examples x <- knitr::kable(head(mtcars), "html") | 
 | 19 | #' column_spec(x, 1, width = "20em", bold = TRUE, italic = TRUE) | 
 | 20 | #' | 
| Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 21 | #' @export | 
| Hao Zhu | f13a35e | 2017-05-24 00:55:43 -0400 | [diff] [blame] | 22 | column_spec <- function(kable_input, column, | 
| Hao Zhu | 78e6122 | 2017-05-24 20:53:35 -0400 | [diff] [blame] | 23 |                         width = NULL, bold = FALSE, italic = FALSE) { | 
| Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 24 |   if (!is.numeric(column)) { | 
 | 25 |     stop("column must be a numeric value") | 
 | 26 |   } | 
 | 27 |   kable_format <- attr(kable_input, "format") | 
 | 28 |   if (!kable_format %in% c("html", "latex")) { | 
 | 29 |     message("Currently generic markdown table using pandoc is not supported.") | 
 | 30 |     return(kable_input) | 
 | 31 |   } | 
 | 32 |   if (kable_format == "html") { | 
 | 33 |     return(column_spec_html(kable_input, column, width, bold, italic)) | 
 | 34 |   } | 
 | 35 |   if (kable_format == "latex") { | 
 | 36 |     return(column_spec_latex(kable_input, column, width, bold, italic)) | 
 | 37 |   } | 
 | 38 | } | 
 | 39 |  | 
 | 40 | column_spec_html <- function(kable_input, column, width, bold, italic) { | 
 | 41 |   kable_attrs <- attributes(kable_input) | 
 | 42 |   kable_xml <- read_xml(as.character(kable_input), options = "COMPACT") | 
 | 43 |   kable_tbody <- xml_tpart(kable_xml, "tbody") | 
 | 44 |  | 
 | 45 |   group_header_rows <- attr(kable_input, "group_header_rows") | 
| Hao Zhu | 32f43f7 | 2017-06-20 18:24:54 -0400 | [diff] [blame] | 46 |   if (is.null(kable_attrs$column_adjust)) { | 
 | 47 |     all_contents_rows <- seq(1, length(xml_children(kable_tbody))) | 
 | 48 |     all_contents_array <- rep(column, length(all_contents_rows)) | 
 | 49 |   } else { | 
 | 50 |     column <- column + kable_attrs$column_adjust$count | 
 | 51 |     all_contents_array <- colSums(kable_attrs$column_adjust$matrix[1:column, ]) | 
 | 52 |     all_contents_rows <- which(all_contents_array != 0 & | 
 | 53 |                                  kable_attrs$column_adjust$matrix[column, ]) | 
 | 54 |   } | 
 | 55 |  | 
| Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 56 |   if (!is.null(group_header_rows)) { | 
 | 57 |     all_contents_rows <- all_contents_rows[!all_contents_rows %in% | 
 | 58 |                                              group_header_rows] | 
 | 59 |   } | 
 | 60 |  | 
 | 61 |   for (i in all_contents_rows) { | 
| Hao Zhu | 32f43f7 | 2017-06-20 18:24:54 -0400 | [diff] [blame] | 62 |     target_cell <- xml_child(xml_child(kable_tbody, i), all_contents_array[i]) | 
| Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 63 |     if (!is.null(width)) { | 
 | 64 |       xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), | 
 | 65 |                                               "width: ", width, "; ") | 
 | 66 |     } | 
 | 67 |     if (bold) { | 
 | 68 |       xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), | 
 | 69 |                                                "font-weight: bold;") | 
 | 70 |     } | 
 | 71 |     if (italic) { | 
 | 72 |       xml_attr(target_cell, "style") <- paste0(xml_attr(target_cell, "style"), | 
 | 73 |                                                "font-style: italic;") | 
 | 74 |     } | 
 | 75 |   } | 
 | 76 |   out <- structure(as.character(kable_xml), format = "html", | 
 | 77 |                    class = "knitr_kable") | 
 | 78 |   attributes(out) <- kable_attrs | 
 | 79 |   return(out) | 
 | 80 | } | 
 | 81 |  | 
 | 82 | column_spec_latex <- function(kable_input, column, width, bold, italic) { | 
 | 83 |   table_info <- magic_mirror(kable_input) | 
| Hao Zhu | f4b3529 | 2017-06-25 22:38:37 -1000 | [diff] [blame] | 84 |   if (!is.null(table_info$collapse_rows)) { | 
 | 85 |     message("Usually it is recommended to use column_spec before collapse_rows,", | 
 | 86 |             " especially in LaTeX, to get a desired result. ") | 
 | 87 |   } | 
| Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 88 |   align_collapse <- ifelse(table_info$booktabs, "", "\\|") | 
 | 89 |   kable_align_old <- paste(table_info$align_vector, collapse = align_collapse) | 
 | 90 |  | 
| Hao Zhu | 32f43f7 | 2017-06-20 18:24:54 -0400 | [diff] [blame] | 91 |   table_info$align_vector[column] <- latex_column_align_builder( | 
 | 92 |     table_info$align_vector[column], width, bold, italic) | 
| Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 93 |  | 
 | 94 |   kable_align_new <- paste(table_info$align_vector, collapse = align_collapse) | 
 | 95 |  | 
 | 96 |   out <- sub(kable_align_old, kable_align_new, as.character(kable_input), | 
 | 97 |              perl = T) | 
 | 98 |   out <- structure(out, format = "latex", class = "knitr_kable") | 
| Hao Zhu | f4b3529 | 2017-06-25 22:38:37 -1000 | [diff] [blame] | 99 |   if (!is.null(width)) { | 
 | 100 |     if (is.null(table_info$column_width)) { | 
 | 101 |       table_info$column_width <- list() | 
 | 102 |     } | 
 | 103 |     table_info$column_width[[paste0("column_", column)]] <- width | 
 | 104 |   } | 
| Hao Zhu | 32f43f7 | 2017-06-20 18:24:54 -0400 | [diff] [blame] | 105 |   attr(out, "kable_meta") <- table_info | 
| Hao Zhu | bff0191 | 2017-05-23 18:05:00 -0400 | [diff] [blame] | 106 |   return(out) | 
 | 107 | } | 
| Hao Zhu | 32f43f7 | 2017-06-20 18:24:54 -0400 | [diff] [blame] | 108 |  | 
 | 109 | latex_column_align_builder <- function(x, width, bold, italic) { | 
 | 110 |   extra_align <- "" | 
 | 111 |   if (!is.null(width)) { | 
 | 112 |     extra_align <- switch(x, | 
| Hao Zhu | bf5bfe2 | 2017-06-21 14:37:41 -0400 | [diff] [blame] | 113 |                           "l" = "\\\\raggedright\\\\arraybackslash", | 
 | 114 |                           "c" = "\\\\centering\\\\arraybackslash", | 
 | 115 |                           "r" = "\\\\raggedleft\\\\arraybackslash") | 
| Hao Zhu | 32f43f7 | 2017-06-20 18:24:54 -0400 | [diff] [blame] | 116 |     x <- paste0("p\\{", width, "\\}") | 
 | 117 |   } | 
 | 118 |  | 
 | 119 |   if (bold | italic | extra_align != "") { | 
 | 120 |     latex_array_options <- c("\\\\bfseries", "\\\\em")[c(bold, italic)] | 
 | 121 |     latex_array_options <- c(latex_array_options, extra_align) | 
 | 122 |     latex_array_options <- paste0( | 
 | 123 |       "\\>\\{", paste(latex_array_options, collapse = ""), "\\}" | 
 | 124 |     ) | 
 | 125 |     x <- paste0(latex_array_options, x) | 
 | 126 |   } | 
 | 127 |  | 
 | 128 |   return(x) | 
 | 129 | } |