Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

206 lines
6.3KB

  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. enter_name <- rlang::quo_name(rlang::enquo(enter))
  36. exit_name <- rlang::quo_name(rlang::enquo(exit))
  37. structure(
  38. list(
  39. transition_length = transition_length,
  40. state_length = state_length,
  41. ease_default = ease_default,
  42. ease_other = ease_other,
  43. enter = setNames(list(enter), enter_name),
  44. exit = setNames(list(exit), exit_name),
  45. text_family = text_family,
  46. text_size = text_size,
  47. title_family = title_family,
  48. title_size = title_size,
  49. ...
  50. ),
  51. class = "anim_opts"
  52. )
  53. }
  54. print.anim_opts <- function(ao) {
  55. aop <- ao
  56. # Replace ggproto (enter/exit functions) with their names
  57. aop$enter <- paste("ggproto:", names(ao$enter))
  58. aop$exit <- paste("ggproto:", names(ao$exit))
  59. str(aop)
  60. invisible(ao)
  61. }
  62. validate_anim_opts <- function(ao, quiet = FALSE, strict = getOption("tidyexplain.strict_dots", FALSE)) {
  63. if (!inherits(ao, "anim_opts")) {
  64. rlang::warn("Use `anim_options()` to set `anim_opts`")
  65. }
  66. stopifnot(is.ggproto(ao$enter[[1]]), is.ggproto(ao$exit[[1]]))
  67. extra_names <- setdiff(names(ao), names(formals(anim_options)))
  68. if (!quiet && length(extra_names)) {
  69. extra_names <- paste0(sprintf("`%s`", extra_names), collapse = ", ")
  70. msg <- paste("Unknown animation options will be ignored:", extra_names)
  71. if (isTrue(strict)) rlang::abort(msg) else rlang::warn(msg)
  72. }
  73. invisible(ao)
  74. }
  75. merge.anim_opts <- function(ao_new, ao_base = anim_options()) {
  76. ao_new <- remove_default_anim_opts(ao_new)
  77. utils::modifyList(ao_base, ao_new, TRUE)
  78. }
  79. remove_default_anim_opts <- function(ao) {
  80. ao_default <- anim_options()
  81. same_names <- purrr::map2_lgl(ao, ao_default, ~ identical(names(.x), names(.y)))
  82. same <- purrr::map2_lgl(ao, ao_default, ~ identical(.x, .y))
  83. same[["enter"]] <- same_names[["enter"]]
  84. same[["exit"]] <- same_names[["exit"]]
  85. ao[!same]
  86. }
  87. #' Animates a plot
  88. #'
  89. #' @param d a processed dataset
  90. #' @param title the title of the plot
  91. #' @param anim_opts Animation options generated with [anim_options()]. Overrides
  92. #' any options set in `...`.
  93. #' @return a `gganim` object
  94. #' @examples
  95. #' NULL
  96. animate_plot <- function(
  97. d,
  98. title = "",
  99. ...,
  100. anim_opts = anim_options(...)
  101. ) {
  102. ao <- validate_anim_opts(anim_opts)
  103. ease_opts <- if (!is.null(ao$ease_other)) {
  104. ao$ease_other$default <- ao$ease_default
  105. ao$ease_other
  106. } else list(default = ao$ease_default)
  107. ao_ease_aes <- do.call(ease_aes, ease_opts)
  108. static_plot(d, title, anim_opts = ao) +
  109. transition_states(.frame, ao$transition_length, ao$state_length) +
  110. ao$enter[[1]] +
  111. ao$exit[[1]] +
  112. ao_ease_aes
  113. }
  114. #' Prints the tiles for a processed dataset statically
  115. #'
  116. #' @inheritParams animate_plot
  117. #' @inheritDotParams anim_options
  118. #'
  119. #' @return a ggplot
  120. #'
  121. #' @examples
  122. #' NULL
  123. static_plot <- function(
  124. d,
  125. title = "",
  126. ...,
  127. anim_opts = anim_options(...)
  128. ) {
  129. ao <- validate_anim_opts(anim_opts)
  130. text_size <- get_text_size(ao$text_size, default = 5)
  131. title_size <- get_title_size(ao$title_size, default = 17)
  132. if (!".alpha" %in% names(d)) d <- d %>% mutate(.alpha = 1)
  133. if (!".textcolor" %in% names(d))
  134. d <- d %>% mutate(.textcolor = choose_text_color(.color))
  135. if (".id_long" %in% names(d)) {
  136. d <- d %>% mutate(.item_id = paste(.id_long, .col, sep = "-"))
  137. } else {
  138. # tidyr
  139. d <- d %>% mutate(.item_id = .id)
  140. }
  141. ggplot(d, aes(x = .x, y = .y, fill = .color, alpha = .alpha, group = .item_id)) +
  142. geom_tile(width = 0.9, height = 0.9) +
  143. coord_equal() +
  144. geom_text(data = d %>% filter(!is.na(.val)), aes(label = .val, color = .textcolor),
  145. family = ao$text_family, size = text_size) +
  146. scale_fill_identity() +
  147. scale_color_identity() +
  148. scale_alpha_identity() +
  149. labs(title = title) +
  150. theme_void() +
  151. theme(plot.title = element_text(family = ao$title_family, hjust = 0.5, size = title_size))
  152. }
  153. #' Set Default Text Sizes for Animation Plots
  154. #'
  155. #' Sets the default text sizes for the animated and static plots produced by
  156. #' this package during the current session.
  157. #'
  158. #' @param text_size Font size of value labels inside the data frame squares
  159. #' @param title_size Font size of the function call or plot title
  160. #' @export
  161. set_font_size <- function(text_size = NULL, title_size = NULL) {
  162. old <- list()
  163. if (!is.null(text_size)) old$text_size <- set_text_size(text_size)
  164. if (!is.null(title_size)) old$title_size <- set_title_size(title_size)
  165. invisible(old)
  166. }
  167. set_text_size <- function(size) {
  168. old <- plot_settings$text_size
  169. plot_settings$text_size <- size
  170. invisible(old)
  171. }
  172. set_title_size <- function(size) {
  173. old <- plot_settings$title_size
  174. plot_settings$title_size <- size
  175. invisible(old)
  176. }
  177. get_text_size <- function(x = NULL, default = 5) {
  178. if (!is.null(x)) return(x)
  179. plot_settings$text_size %||%
  180. getFromNamespace("theme_env", "ggplot2")$current$text$size %||%
  181. default
  182. }
  183. get_title_size <- function(x = NULL, default = 17) {
  184. if (!is.null(x)) return(x)
  185. plot_settings$title_size %||%
  186. getFromNamespace("theme_env", "ggplot2")$current$plot.title$size %||%
  187. default
  188. }