You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
8.2KB

  1. ##' Output a desctable to the desired target format
  2. ##'
  3. ##' Output a simple or grouped desctable to a different formats.
  4. ##' Currently available formats are\itemize{
  5. ##' \item data.frame ("df")
  6. ##' \item pander ("pander")
  7. ##' \item datatable ("DT")
  8. ##' }
  9. ##'
  10. ##' All numerical values will be rounded to the digits argument.
  11. ##' If statistical tests are presents, p values below 1E-digits will be replaced with "< 1E-digits"
  12. ##' (eg. "< 0.01" for values below 0.01 when digits = 2)
  13. ##'
  14. ##' @title desc_output
  15. ##' @param desctable The desctable to output
  16. ##' @param target The desired target. One of "df", "pander", or "DT".
  17. ##' @param digits The number of digits to display. The p values will be simplified under 1E-digits
  18. ##' @param ... Other arguments to pass to \code{data.frame}, \code{pander::pander}, or \code{DT::datatable}
  19. ##' @return The output object (or corresponding side effect)
  20. ##' @export
  21. ##' @seealso \code{\link[DT]{datatable}}
  22. ##' @seealso \code{\link[pander]{pander}}
  23. ##' @family desc_table core functions
  24. desc_output <- function(desctable, target = c("df", "pander", "DT"), digits = 2, ...) {
  25. switch(which.desctable(desctable),
  26. simple = switch(target,
  27. df = output_df_simple(desctable, digits, ...),
  28. pander = output_pander_simple(desctable, digits, ...),
  29. DT = output_DT_simple(desctable, digits, ...),
  30. stop("target must be one of \"df\", \"pander\", or \"DT\"")),
  31. grouped = switch(target,
  32. df = output_df_grouped(desctable, digits, ...),
  33. pander = output_pander_grouped(desctable, digits, ...),
  34. DT = output_DT_grouped(desctable, digits, ...),
  35. stop("target must be one of \"df\", \"pander\", or \"DT\"")),
  36. stop("Unexpected input. `desc_output` must be used on the output of `desc_table` or `desc_table` and `desc_tests`"))
  37. }
  38. output_df_simple <- function(desctable, digits, ...) {
  39. # Fix variables
  40. variables <- gsub("\\*\\*(.*?)\\*\\*: \\*(.*?)\\*", "\u00A0\u00A0\u00A0\u00A0\\2", desctable$Variables)
  41. desctable$Variables <- NULL
  42. # Round to digits and set row names
  43. desctable %>%
  44. lapply(prettyNum, digits = digits) %>%
  45. lapply(gsub, pattern = "^NA$", replacement = "") %>%
  46. as.data.frame(check.names = F,
  47. stringsAsFactors = F,
  48. row.names = variables,
  49. ...)
  50. }
  51. output_df_grouped <- function(desctable, digits, ...) {
  52. # Fix variables
  53. variables <- gsub("\\*\\*(.*?)\\*\\*: \\*(.*?)\\*", "\u00A0\u00A0\u00A0\u00A0\\2", desctable$.vars[[1]]$Variables)
  54. # Add tests and round p values
  55. table <- Reduce(desctable$.stats, f = cbind)
  56. if (desctable %>% utils::hasName(".tests")) {
  57. tests <- desctable$.tests[[1]]
  58. tests$p[tests$p < 10^-digits] <- 10^-digits
  59. prettyNum(tests$p, digits = digits) %>%
  60. gsub(pattern = "^NA$", replacement = "") %>%
  61. gsub(pattern = "^(0.0*1)$", replacement = "< \\1") -> tests$p
  62. table <- cbind(table, tests)
  63. }
  64. # Build header
  65. indices <- cumsum(c(1, sapply(desctable$.stats, length)))
  66. indices <- indices[1:length(indices) - 1]
  67. nmtoreplace <- names(table)[indices]
  68. names(table)[indices] <- paste0(names(desctable)[1], " = ", desctable[[1]], " (N = ", sapply(desctable$data, nrow), ")\n", nmtoreplace)
  69. # Round to digits and set row names
  70. table %>%
  71. lapply(prettyNum, digits = digits) %>%
  72. lapply(gsub, pattern = "^NA$", replacement = "") %>%
  73. as.data.frame(check.names = F,
  74. stringsAsFactors = F,
  75. row.names = variables,
  76. ...)
  77. }
  78. output_pander_simple <- function(desctable, digits, ...) {
  79. # Fix variables
  80. variables <- gsub("\\*\\*(.*?)\\*\\*: \\*(.*?)\\*", "&nbsp;&nbsp;&nbsp;&nbsp;\\2", desctable$Variables)
  81. desctable$Variables <- NULL
  82. # Round to digits and set row names
  83. desctable %>%
  84. `row.names<-`(variables) %>%
  85. pander(digits = digits,
  86. justify = "left",
  87. missing = "" ,
  88. keep.line.breaks = T,
  89. split.tables = Inf,
  90. emphasize.rownames = F,
  91. ...)
  92. }
  93. output_pander_grouped <- function(desctable, digits, ...) {
  94. # Fix variables
  95. variables <- gsub("\\*\\*(.*?)\\*\\*: \\*(.*?)\\*", "&nbsp;&nbsp;&nbsp;&nbsp;\\2", desctable$.vars[[1]]$Variables)
  96. # Add tests and round p values
  97. table <- Reduce(desctable$.stats, f = cbind)
  98. if (desctable %>% utils::hasName(".tests")) {
  99. tests <- desctable$.tests[[1]]
  100. tests$p[tests$p < 10^-digits] <- 10^-digits
  101. prettyNum(tests$p, digits = digits) %>%
  102. gsub(pattern = "^NA$", replacement = "") %>%
  103. gsub(pattern = "^(0.0*1)$", replacement = "< \\1") -> tests$p
  104. table <- cbind(table, tests)
  105. }
  106. # Build header
  107. indices <- cumsum(c(1, sapply(desctable$.stats, length)))
  108. indices <- indices[1:length(indices) - 1]
  109. nmtoreplace <- names(table)[indices]
  110. names(table)[indices] <- paste0(names(desctable)[1], " = ", desctable[[1]], "</br>\n(N = ", sapply(desctable$data, nrow), ")</br>\n", nmtoreplace)
  111. # Round to digits and set row names
  112. table %>%
  113. `row.names<-`(variables) %>%
  114. pander(digits = digits,
  115. justify = "left",
  116. missing = "" ,
  117. keep.line.breaks = T,
  118. split.tables = Inf,
  119. emphasize.rownames = F,
  120. ...)
  121. }
  122. output_DT_simple <- function(desctable, digits, ...) {
  123. # Fix variables
  124. variables <- gsub("\\*\\*(.*?)\\*\\*: \\*(.*?)\\*", "&nbsp;&nbsp;&nbsp;&nbsp;\\2", desctable$Variables)
  125. variables <- gsub("\\*\\*(.*?)\\*\\*", "<b>\\1</b>", variables)
  126. desctable$Variables <- NULL
  127. # Round to digits and set row names
  128. desctable %>%
  129. sapply(function(x) !(is.integer(x) | is.character(x)), simplify = T) %>%
  130. which -> toRound
  131. DT::datatable(desctable,
  132. options = list(paging = F,
  133. info = F,
  134. search = list(),
  135. dom = "Brtip",
  136. fixedColumns = T,
  137. fixedHeader = T,
  138. buttons = c("copy", "excel")),
  139. rownames = variables,
  140. escape = F,
  141. style = "default",
  142. extensions = c("FixedHeader", "FixedColumns", "Buttons"),
  143. ...) %>%
  144. DT::formatRound(digits = digits, columns = toRound)
  145. }
  146. output_DT_grouped <- function(desctable, digits, ...) {
  147. # Fix variables
  148. variables <- gsub("\\*\\*(.*?)\\*\\*: \\*(.*?)\\*", "&nbsp;&nbsp;&nbsp;&nbsp;\\2", desctable$.vars[[1]]$Variables)
  149. variables <- gsub("\\*\\*(.*?)\\*\\*", "<b>\\1</b>", variables)
  150. # Add tests and round p values
  151. table <- Reduce(desctable$.stats, f = cbind)
  152. if (desctable %>% utils::hasName(".tests")) {
  153. tests <- desctable$.tests[[1]]
  154. tests$p[tests$p < 10^-digits] <- 10^-digits
  155. prettyNum(tests$p, digits = digits) %>%
  156. gsub(pattern = "^NA$", replacement = "") %>%
  157. gsub(pattern = "^(0.0*1)$", replacement = "< \\1") -> tests$p
  158. table <- cbind(table, tests)
  159. }
  160. # Build header
  161. header <- htmltools::tags$table(
  162. htmltools::tags$thead(
  163. htmltools::tags$tr(
  164. htmltools::tags$th(rowspan = 2, ""),
  165. mapply(htmltools::tags$th,
  166. colspan = sapply(desctable$.stats, length),
  167. paste0(names(desctable)[1], " = ", desctable[[1]], " (N = ", sapply(desctable$data, nrow) , ")"),
  168. SIMPLIFY = F)),
  169. htmltools::tags$tr(
  170. lapply(unlist(names(table)),htmltools::tags$th))),
  171. class = "display")
  172. # Round to digits and set row names
  173. table %>%
  174. sapply(function(x) !(is.integer(x) | is.character(x)), simplify = T) %>%
  175. which -> toRound
  176. DT::datatable(table,
  177. container = header,
  178. options = list(paging = F,
  179. info = F,
  180. search = list(),
  181. dom = "Brtip",
  182. fixedColumns = T,
  183. fixedHeader = T,
  184. buttons = c("copy", "excel")),
  185. rownames = variables,
  186. escape = F,
  187. style = "default",
  188. extensions = c("FixedHeader", "FixedColumns", "Buttons"),
  189. ...) %>%
  190. DT::formatRound(digits = digits, columns = toRound)
  191. }