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.

180 lines
5.4KB

  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 text_family Font family for the plot text
  7. #' @param title_family Font family for the plot title
  8. #' @param text_size Font size of the plot text
  9. #' @param title_size Font size of the plot title
  10. #' @param ease_default Default aes easing function. See [tweenr::display_ease()]
  11. #' for more options.
  12. #' @param ease_other Additional aes easing options, specified as a named list.
  13. #' List entries are named with the aesthetic to which the easeing should be
  14. #' applied, consistent with [gganimate::ease_aes()].
  15. #' E.g. `list(color = "sine")`.
  16. #' @param enter Enter fading function applied to objects in the animation. See
  17. #' [gganimate::enter_exit] for a complete list of options.
  18. #' @param exit Exit fading function applied to objects in the animation. See
  19. #' [gganimate::enter_exit] for a complete list of options.
  20. #' @inheritParams gganimate::transition_states
  21. #' @export
  22. anim_options <- function(
  23. transition_length = 2,
  24. state_length = 1,
  25. ease_default = "sine-in-out",
  26. ease_other = NULL,
  27. enter = enter_fade(),
  28. exit = exit_fade(),
  29. text_family = "Fira Sans",
  30. title_family = "Fira Mono",
  31. text_size = NULL,
  32. title_size = NULL,
  33. ...
  34. ){
  35. structure(
  36. list(
  37. transition_length = transition_length,
  38. state_length = state_length,
  39. ease_default = ease_default,
  40. ease_other = ease_other,
  41. enter = enter,
  42. exit = exit,
  43. text_family = text_family,
  44. text_size = text_size,
  45. title_family = title_family,
  46. title_size = title_size,
  47. ...
  48. ),
  49. class = "anim_opts"
  50. )
  51. }
  52. validate_anim_opts <- function(ao, quiet = FALSE, strict = getOption("tidyexplain.strict_dots", FALSE)) {
  53. if (!inherits(ao, "anim_opts")) {
  54. rlang::warn("Use `anim_options()` to set `anim_opts`")
  55. }
  56. extra_names <- setdiff(names(ao), names(formals(anim_options)))
  57. if (!quiet && length(extra_names)) {
  58. extra_names <- paste0(sprintf("`%s`", extra_names), collapse = ", ")
  59. msg <- paste("Unknown animation options will be ignored:", extra_names)
  60. if (isTrue(strict)) rlang::abort(msg) else rlang::warn(msg)
  61. }
  62. invisible(ao)
  63. }
  64. #' Animates a plot
  65. #'
  66. #' @param d a processed dataset
  67. #' @param title the title of the plot
  68. #' @param anim_opts Animation options generated with [anim_options()]. Overrides
  69. #' any options set in `...`.
  70. #' @return a `gganim` object
  71. #' @examples
  72. #' NULL
  73. animate_plot <- function(
  74. d,
  75. title = "",
  76. ...,
  77. anim_opts = anim_options(...)
  78. ) {
  79. ao <- validate_anim_opts(anim_opts)
  80. ease_opts <- if (!is.null(ao$ease_other)) {
  81. ao$ease_other$default <- ao$ease_default
  82. ao$ease_other
  83. } else list(default = ao$ease_default)
  84. ao_ease_aes <- do.call(ease_aes, ease_opts)
  85. static_plot(d, title, anim_opts = ao) +
  86. transition_states(.frame, ao$transition_length, ao$state_length) +
  87. ao$enter +
  88. ao$exit +
  89. ao_ease_aes
  90. }
  91. #' Prints the tiles for a processed dataset statically
  92. #'
  93. #' @inheritParams animate_plot
  94. #' @inheritDotParams anim_options
  95. #'
  96. #' @return a ggplot
  97. #'
  98. #' @examples
  99. #' NULL
  100. static_plot <- function(
  101. d,
  102. title = "",
  103. ...,
  104. anim_opts = anim_options(...)
  105. ) {
  106. ao <- validate_anim_opts(anim_opts)
  107. text_size <- get_text_size(ao$text_size, default = 5)
  108. title_size <- get_title_size(ao$title_size, default = 17)
  109. if (!".alpha" %in% names(d)) d <- d %>% mutate(.alpha = 1)
  110. if (!".textcolor" %in% names(d))
  111. d <- d %>% mutate(.textcolor = choose_text_color(.color))
  112. if (".id_long" %in% names(d)) {
  113. d <- d %>% mutate(.item_id = paste(.id_long, .col, sep = "-"))
  114. } else {
  115. # tidyr
  116. d <- d %>% mutate(.item_id = .id)
  117. }
  118. ggplot(d, aes(x = .x, y = .y, fill = .color, alpha = .alpha, group = .item_id)) +
  119. geom_tile(width = 0.9, height = 0.9) +
  120. coord_equal() +
  121. geom_text(data = d %>% filter(!is.na(.val)), aes(label = .val, color = .textcolor),
  122. family = ao$text_family, size = text_size) +
  123. scale_fill_identity() +
  124. scale_color_identity() +
  125. scale_alpha_identity() +
  126. labs(title = title) +
  127. theme_void() +
  128. theme(plot.title = element_text(family = ao$title_family, hjust = 0.5, size = title_size))
  129. }
  130. #' Set Default Text Sizes for Animation Plots
  131. #'
  132. #' Sets the default text sizes for the animated and static plots produced by
  133. #' this package during the current session.
  134. #'
  135. #' @param text_size Font size of value labels inside the data frame squares
  136. #' @param title_size Font size of the function call or plot title
  137. #' @export
  138. set_font_size <- function(text_size = NULL, title_size = NULL) {
  139. old <- list()
  140. if (!is.null(text_size)) old$text_size <- set_text_size(text_size)
  141. if (!is.null(title_size)) old$title_size <- set_title_size(title_size)
  142. invisible(old)
  143. }
  144. set_text_size <- function(size) {
  145. old <- plot_settings$text_size
  146. plot_settings$text_size <- size
  147. invisible(old)
  148. }
  149. set_title_size <- function(size) {
  150. old <- plot_settings$title_size
  151. plot_settings$title_size <- size
  152. invisible(old)
  153. }
  154. get_text_size <- function(x = NULL, default = 5) {
  155. if (!is.null(x)) return(x)
  156. plot_settings$text_size %||%
  157. getFromNamespace("theme_env", "ggplot2")$current$text$size %||%
  158. default
  159. }
  160. get_title_size <- function(x = NULL, default = 17) {
  161. if (!is.null(x)) return(x)
  162. plot_settings$title_size %||%
  163. getFromNamespace("theme_env", "ggplot2")$current$plot.title$size %||%
  164. default
  165. }