Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

245 lines
9.2KB

  1. #' Animation Options
  2. #'
  3. #' Helper function to set animation and plotting options to be passed to
  4. #' [animate_plot()] and [static_plot()].
  5. #'
  6. #' @param color_header Color of the header row.
  7. #' @param color_other Color of the cells that are not highlighted otherwise.
  8. #' @param color_missing Color of the missing cells.
  9. #' @param color_fun A function that generates the colors for the highlighted
  10. #' cells, default is [scales::brewer_pal()] Set1.
  11. #' @param text_color Color of the text of the cells, default is a black or
  12. #' white, based on the background color of the cell.
  13. #' @param text_family Font family for the plot text, default is "Fira Mono". Use
  14. #' [set_font_size()] to set global default font sizes.
  15. #' @param title_family Font family for the plot title, default is "Fira Mono".
  16. #' Use [set_font_size()] to set global default font sizes.
  17. #' @param text_size Font size of the plot text, default is 5.
  18. #' @param title_size Font size of the plot title, default is 17.
  19. #' @param cell_width Width of a cell, default is 1.
  20. #' @param cell_height Height of a cell, default is 1.
  21. #' @param ease_default Default aes easing function. See [tweenr::display_ease()]
  22. #' for more options. The tidyexplain default value is `sine-in-out`.
  23. #' @param ease_other Additional aes easing options, specified as a named list.
  24. #' List entries are named with the aesthetic to which the easeing should be
  25. #' applied, consistent with [gganimate::ease_aes()]. E.g. `list(color =
  26. #' "sine")`.
  27. #' @param enter Enter fading function applied to objects in the animation. See
  28. #' [gganimate::enter_exit] for a complete list of options. The tidyexplain
  29. #' default is [gganimate::enter_fade()].
  30. #' @param exit Exit fading function applied to objects in the animation. See
  31. #' [gganimate::enter_exit] for a complete list of options. The tidyexplain
  32. #' default is [gganimate::exit_fade()].
  33. #' @inheritParams gganimate::transition_states
  34. #' @export
  35. anim_options <- function(
  36. transition_length = NULL,
  37. state_length = NULL,
  38. ease_default = NULL,
  39. ease_other = NULL,
  40. enter = NULL,
  41. exit = NULL,
  42. text_family = NULL,
  43. title_family = NULL,
  44. text_size = NULL,
  45. title_size = NULL,
  46. color_header = NULL,
  47. color_other = NULL,
  48. color_missing = NULL,
  49. color_fun = NULL,
  50. text_color = NULL,
  51. cell_width = NULL,
  52. cell_height = NULL,
  53. ...
  54. ){
  55. enter_name <- if (!missing(enter)) rlang::quo_name(rlang::enquo(enter))
  56. exit_name <- if (!missing(exit)) rlang::quo_name(rlang::enquo(exit))
  57. ao <- list(
  58. transition_length = transition_length,
  59. state_length = state_length,
  60. ease_default = ease_default,
  61. ease_other = ease_other,
  62. enter = if (!is.null(enter)) setNames(list(enter), enter_name),
  63. exit = if (!is.null(exit)) setNames(list(exit), exit_name),
  64. text_family = text_family,
  65. text_size = text_size,
  66. title_family = title_family,
  67. title_size = title_size,
  68. color_header = color_header,
  69. color_other = color_other,
  70. color_missing = color_missing,
  71. color_fun = color_fun,
  72. text_color = text_color,
  73. cell_width = cell_width,
  74. cell_height = cell_height,
  75. ...
  76. )
  77. ao <- purrr::compact(ao)
  78. structure(ao, class = "anim_opts")
  79. }
  80. # Global Animation Options Setters and Getters ----------------------------
  81. #' @describeIn anim_options Set default animation options for the current session.
  82. #' @param anim_opts An [anim_options()] options list.
  83. #' @export
  84. set_anim_options <- function(anim_opts = anim_options()) {
  85. stopifnot(is.anim_opts(anim_opts))
  86. ao_old <- plot_settings$anim_opts
  87. plot_settings$anim_opts <- merge(anim_opts, plot_settings$anim_opts)
  88. invisible(ao_old)
  89. }
  90. get_anim_opt <- function(anim_opt = NULL) {
  91. if (is.null(anim_opt)) return(plot_settings$anim_opts)
  92. if (anim_opt %in% c("text_size", "title_size")) rlang::abort(
  93. "Use get_text_size() or get_title_size()"
  94. )
  95. plot_settings$anim_opts[[anim_opt]] %||% plot_settings$default[[anim_opt]]
  96. }
  97. # Animation Options Methods -----------------------------------------------
  98. #' @export
  99. print.anim_opts <- function(x) {
  100. # Replace ggproto (enter/exit functions) with their names
  101. if ("enter" %in% names(x)) x$enter <- paste("ggproto:", names(x$enter))
  102. if ("exit" %in% names(x)) x$exit <- paste("ggproto:", names(x$exit))
  103. anim_opts <- capture.output(str(x, no.list = TRUE))
  104. cat(
  105. paste0("<anim_options: ", length(x), " options>"),
  106. anim_opts, sep = "\n"
  107. )
  108. }
  109. #' @export
  110. is.anim_opts <- function(ao) inherits(ao, "anim_opts")
  111. # Fill, Validate, Merge Animation Options ---------------------------------
  112. # Fills in default animation options
  113. fill_anim_opts <- function(ao) {
  114. ao$transition_length <- ao$transition_length %||% get_anim_opt("transition_length")
  115. ao$state_length <- ao$state_length %||% get_anim_opt("state_length")
  116. ao$ease_default <- ao$ease_default %||% get_anim_opt("ease_default")
  117. ao$ease_other <- ao$ease_other %||% get_anim_opt("ease_other")
  118. ao$enter <- ao$enter %||% get_anim_opt("enter")
  119. ao$exit <- ao$exit %||% get_anim_opt("exit")
  120. ao$text_family <- ao$text_family %||% get_anim_opt("text_family")
  121. ao$title_family <- ao$title_family %||% get_anim_opt("title_family")
  122. ao$color_header <- ao$color_header %||% get_anim_opt("color_header")
  123. ao$color_other <- ao$color_other %||% get_anim_opt("color_other")
  124. ao$color_missing <- ao$color_missing %||% get_anim_opt("color_missing")
  125. ao$color_fun <- ao$color_fun %||% get_anim_opt("color_fun")
  126. ao$text_color <- ao$text_color %||% get_anim_opt("text_color")
  127. ao$cell_width <- ao$cell_width %||% get_anim_opt("cell_width")
  128. ao$cell_height <- ao$cell_height %||% get_anim_opt("cell_height")
  129. ao
  130. }
  131. validate_anim_opts <- function(ao, quiet = FALSE, strict = getOption("tidyexplain.strict_dots", FALSE)) {
  132. if (!inherits(ao, "anim_opts")) {
  133. rlang::warn("Use `anim_options()` to set `anim_opts`")
  134. }
  135. ao <- fill_anim_opts(ao)
  136. stopifnot(is.ggproto(ao$enter[[1]]), is.ggproto(ao$exit[[1]]))
  137. extra_names <- setdiff(names(ao), names(formals(anim_options)))
  138. if (!quiet && length(extra_names)) {
  139. extra_names <- paste0(sprintf("`%s`", extra_names), collapse = ", ")
  140. msg <- paste("Unknown animation options will be ignored:", extra_names)
  141. if (isTRUE(strict)) rlang::abort(msg) else rlang::warn(msg)
  142. }
  143. invisible(ao)
  144. }
  145. merge.anim_opts <- function(ao_new, ao_base = anim_options()) {
  146. ao_new <- purrr::discard(ao_new, is.null)
  147. ao_base <- purrr::discard(ao_base, is.null)
  148. unique_base <- setdiff(names(ao_base), names(ao_new))
  149. ao <- append(ao_new, ao_base[unique_base])
  150. ao <- ao[names(formals(anim_options))]
  151. ao <- purrr::discard(ao, is.null)
  152. class(ao) <- "anim_opts"
  153. ao
  154. }
  155. # Default Animation Options for Verb Families -----------------------------
  156. default_anim_opts <- function(family, ao_custom = NULL) {
  157. family_options <- c("join", "set", "gather", "spread")
  158. family <- match.arg(family, family_options, several.ok = FALSE)
  159. ao_default <- switch(
  160. family,
  161. "gather" = anim_options(enter = enter_fade(), exit = exit_fade(),
  162. ease_default = "sine-in-out",
  163. ease_other = list(y = "cubic-out", x = "cubic-in")),
  164. "spread" = anim_options(enter = enter_fade(), exit = exit_fade(),
  165. ease_default = "sine-in-out",
  166. ease_other = list(y = "cubic-out", x = "cubic-in")),
  167. anim_options()
  168. )
  169. if (is.null(ao_custom)) {
  170. # User set globals override defaults
  171. ao_custom <- get_anim_opt()
  172. } else {
  173. # Opts from function call override user-set globals
  174. ao_custom <- merge(ao_custom, get_anim_opt())
  175. }
  176. # function > user-set global > default (> global default)
  177. if (!is.null(ao_custom)) merge(ao_custom, ao_default) else ao_default
  178. }
  179. # Font Size Setters and Getters -------------------------------------------
  180. #' Set Default Text Sizes for Animation Plots
  181. #'
  182. #' Sets the default text sizes for the animated and static plots produced by
  183. #' this package during the current session.
  184. #'
  185. #' @param text_size Font size of value labels inside the data frame squares
  186. #' @param title_size Font size of the function call or plot title
  187. #' @export
  188. set_font_size <- function(text_size = NULL, title_size = NULL) {
  189. old <- list()
  190. if (!is.null(text_size)) old$text_size <- set_text_size(text_size)
  191. if (!is.null(title_size)) old$title_size <- set_title_size(title_size)
  192. invisible(old)
  193. }
  194. #' @describeIn set_font_size Get current global font sizes
  195. #' @export
  196. get_font_size <- function() {
  197. list("text_size" = get_text_size(), "title_size" = get_title_size())
  198. }
  199. set_text_size <- function(size) {
  200. old <- plot_settings$text_size
  201. set_anim_options(anim_options(text_size = size))
  202. invisible(old)
  203. }
  204. set_title_size <- function(size) {
  205. old <- plot_settings$title_size
  206. set_anim_options(anim_options(title_size = size))
  207. invisible(old)
  208. }
  209. get_text_size <- function(x = NULL) {
  210. if (!is.null(x)) return(x)
  211. plot_settings$anim_opts$text_size %||%
  212. getFromNamespace("theme_void", "ggplot2")()$text$size %||%
  213. plot_settings$default$text_size
  214. }
  215. get_title_size <- function(x = NULL) {
  216. if (!is.null(x)) return(x)
  217. plot_settings$anim_opts$title_size %||%
  218. getFromNamespace("theme_void", "ggplot2")()$plot.title$size %||%
  219. plot_settings$default$title_size
  220. }