| .Rproj.user | |||||
| README_cache | |||||
| .DS_Store |
| # Animated dplyr joins with gganimate | |||||
| # * Garrick Aden-Buie | |||||
| # * garrickadenbuie.com | |||||
| # * MIT License: https://opensource.org/licenses/MIT | |||||
| # Note: I used Fira Sans and Fira Mono fonts. | |||||
| # Use search and replace to use a different font if Fira is not available. | |||||
| library(tidyverse) | |||||
| library(gganimate) | |||||
| if (!getOption("tidy_verb_anim.font_registered", FALSE)) { | |||||
| source(here::here("R", "01_register-fonts.R")) | |||||
| } | |||||
| if (!getOption("tidy_verb_anim.functions_loaded", FALSE)) { | |||||
| source(here::here("R", "02_functions.R")) | |||||
| } | |||||
| if (!dir.exists(here::here("images"))) dir.create(here::here("images")) | |||||
| # Data ---- | |||||
| x <- data_frame( | |||||
| id = 1:3, | |||||
| x = paste0("x", 1:3) | |||||
| ) | |||||
| y <- data_frame( | |||||
| id = (1:4)[-3], | |||||
| y = paste0("y", (1:4)[-3]) | |||||
| ) | |||||
| initial_dfs <- proc_data(x, "x") %>% | |||||
| bind_rows(mutate(proc_data(y, "y"), .x = .x + 3)) %>% | |||||
| mutate(frame = 1) |
| sysfonts::font_add_google("Fira Sans") | |||||
| sysfonts::font_add_google("Fira Mono") | |||||
| showtext::showtext_auto() | |||||
| options(tidy_verb_anim.font_registered = TRUE) |
| proc_data <- function(x, .id = "x") { | |||||
| colors <- scales::brewer_pal(type = "qual", "Set1")(max(x$id)) | |||||
| x %>% | |||||
| mutate(.y = -row_number()) %>% | |||||
| tidyr::gather("label", "value", -.y) %>% | |||||
| mutate(value = as.character(value)) %>% | |||||
| group_by(.y) %>% | |||||
| mutate( | |||||
| .x = 1:n(), | |||||
| .id = .id, | |||||
| color = ifelse(label == "id", value, max(x$id) + 1), | |||||
| color = colors[as.integer(color)], | |||||
| color = ifelse(is.na(color), "#d0d0d0", color), | |||||
| color = ifelse(is.na(value), "#ffffff", color) | |||||
| ) | |||||
| } | |||||
| plot_data <- function(x, title = "") { | |||||
| ggplot(x) + | |||||
| aes(.x, .y, fill = color, label = value) + | |||||
| geom_tile(color = "white", size = 3) + | |||||
| geom_text(aes(x = .x), hjust = 0.5, size = 12, family = "Fira Sans", color = "white") + | |||||
| scale_fill_identity() + | |||||
| coord_equal() + | |||||
| ggtitle(title) + | |||||
| theme_void() + | |||||
| theme(plot.title = element_text(family = "Fira Mono", hjust = 0.5, size = 24)) + | |||||
| guides(fill = FALSE) | |||||
| } | |||||
| animate_plot <- function(x) { | |||||
| x + | |||||
| transition_states(frame, transition_length = 2, state_length = 1) + | |||||
| enter_fade() + | |||||
| exit_fade() + | |||||
| ease_aes("sine-in-out") | |||||
| } | |||||
| options(tidy_verb_anim.functions_loaded = TRUE) |
| source(here::here("R/00_base.R")) | |||||
| step2 <- initial_dfs %>% | |||||
| filter(.id == "x" | value %in% paste(1:2)) %>% | |||||
| mutate( | |||||
| frame = 2, | |||||
| .x = ifelse(.id == "y", 1, .x), | |||||
| .x = .x + 1 | |||||
| ) | |||||
| step3 <- step2 %>% | |||||
| filter(grepl("3", value)) %>% | |||||
| ungroup() %>% | |||||
| mutate(frame = 3, .y = -1) | |||||
| aj <- initial_dfs %>% | |||||
| mutate(removed = .id == "y", removed = as.integer(removed)) %>% | |||||
| bind_rows(step2, step3) %>% | |||||
| mutate(removed = ifelse(is.na(removed), 0, removed)) %>% | |||||
| arrange(removed, .y, .x, desc(frame)) %>% #View() | |||||
| mutate(alpha = case_when( | |||||
| grepl("3", value) ~ 1, | |||||
| frame == 2 & label == "id" ~ 0.25, | |||||
| frame == 2 ~ 0.65, | |||||
| TRUE ~ 1 | |||||
| )) %>% | |||||
| { | |||||
| plot_data(., "anti_join(x, y)") + | |||||
| aes(alpha = alpha) + | |||||
| scale_alpha_identity() | |||||
| } %>% | |||||
| animate_plot() | |||||
| aj <- animate(aj) | |||||
| anim_save(here::here("images", "anti-join.gif"), aj) |
| source(here::here("R/00_base.R")) | |||||
| joined_df <- full_join(x, y, "id") %>% | |||||
| proc_data("x") %>% | |||||
| mutate(.id = ifelse(value %in% c("4", "y4"), "y", .id)) %>% | |||||
| mutate(frame = 2, .x = .x + 1) | |||||
| extra_blocks <- inner_join(x, y, "id") %>% | |||||
| select(id) %>% | |||||
| proc_data("y") %>% | |||||
| mutate(frame = 2, .x = .x + 1) | |||||
| fj <- initial_dfs %>% | |||||
| bind_rows(joined_df, extra_blocks) %>% | |||||
| plot_data("full_join(x, y)") + | |||||
| transition_states(frame, transition_length = 2, state_length = 1) + | |||||
| enter_appear() + | |||||
| exit_disappear(early = TRUE) + | |||||
| ease_aes("sine-in-out") | |||||
| fj <- animate(fj) | |||||
| anim_save(here::here("images", "full-join.gif"), fj) |
| source(here::here("R/00_base.R")) | |||||
| joined_df <- inner_join(x, y, "id") | |||||
| joined_df <- bind_rows( | |||||
| proc_data(joined_df, "x"), | |||||
| proc_data(joined_df, "y") | |||||
| ) %>% | |||||
| filter(!(label == "x" & .id == "y") & !(label == "y" & .id == "x")) %>% | |||||
| mutate(frame = 2, .x = .x + 1) | |||||
| ij <- initial_dfs %>% | |||||
| bind_rows(joined_df) %>% | |||||
| mutate(removed = value %in% c("3", "4", "x3", "y4"), | |||||
| removed = as.integer(removed)) %>% | |||||
| arrange(desc(frame), removed) %>% | |||||
| plot_data("inner_join(x, y)") %>% | |||||
| animate_plot() | |||||
| ij <- animate(ij) | |||||
| anim_save(here::here("images", "inner-join.gif"), ij) |
| source(here::here("R/00_base.R")) | |||||
| joined_dfs <- left_join(x, y, "id") %>% | |||||
| proc_data("x") %>% | |||||
| mutate(frame = 2, .x = .x + 1) | |||||
| extra_blocks <- inner_join(x, y, "id") %>% | |||||
| select(id) %>% | |||||
| proc_data("y") %>% | |||||
| mutate(frame = 2, .x = .x + 1) | |||||
| lj <- initial_dfs %>% | |||||
| bind_rows(joined_dfs) %>% | |||||
| bind_rows(extra_blocks) %>% | |||||
| mutate(color = ifelse(is.na(value), "#ffffff", color)) %>% | |||||
| plot_data("left_join(x, y)") %>% | |||||
| animate_plot() | |||||
| lj <- animate(lj) | |||||
| anim_save(here::here("images", "left-join.gif"), lj) |
| source(here::here("R/00_base.R")) | |||||
| joined_dfs <- right_join(x, y, "id") %>% | |||||
| proc_data("y") %>% | |||||
| mutate(frame = 2, .x = .x + 1) | |||||
| extra_blocks <- inner_join(x, y, "id") %>% | |||||
| select(id) %>% | |||||
| proc_data("x") %>% | |||||
| mutate(frame = 2, .x = .x + 1) | |||||
| rj <- initial_dfs %>% | |||||
| bind_rows(joined_dfs, extra_blocks) %>% | |||||
| arrange(desc(.id), frame, desc(label), value) %>% | |||||
| plot_data("right_join(x, y)") %>% | |||||
| animate_plot() | |||||
| rj <- animate(rj) | |||||
| anim_save(here::here("images", "right-join.gif"), rj) |
| source(here::here("R/00_base.R")) | |||||
| joined_df <- semi_join(x, y, "id") %>% | |||||
| proc_data("x") %>% | |||||
| mutate(frame = 2, .x = .x + 1) | |||||
| extra_blocks <- inner_join(x, y, "id") %>% | |||||
| select(id) %>% | |||||
| proc_data("y") %>% | |||||
| mutate(frame = 2) | |||||
| sj <- initial_dfs %>% | |||||
| bind_rows(joined_df, extra_blocks) %>% | |||||
| plot_data("semi_join(x, y)") %>% | |||||
| animate_plot() | |||||
| sj <- animate(sj) | |||||
| anim_save(here::here("images", "semi-join.gif"), sj) |
| --- | |||||
| output: github_document | |||||
| --- | |||||
| <!-- README.md is generated from README.Rmd. Please edit that file --> | |||||
| ```{r setup, include = FALSE} | |||||
| knitr::opts_chunk$set( | |||||
| collapse = TRUE, | |||||
| comment = "#>", | |||||
| echo = FALSE, | |||||
| warning = FALSE, | |||||
| message = FALSE, | |||||
| cache = TRUE | |||||
| ) | |||||
| ``` | |||||
| # Tidy Animated Verbs | |||||
| Garrick Aden-Buie -- [@grrrck](https://twitter.com/grrrck) -- [garrickadenbuie.com](https://www.garrickadenbuie.com) | |||||
| ## Mutate Joins | |||||
| ```{r intial-dfs} | |||||
| source("R/00_base.R") | |||||
| df_names <- data_frame( | |||||
| .x = c(1.5, 4.5), .y = 0.25, | |||||
| value = c("x", "y"), | |||||
| size = 12, | |||||
| color = "black" | |||||
| ) | |||||
| g <- plot_data(initial_dfs) + | |||||
| geom_text(data = df_names, family = "Fira Mono", size = 24) | |||||
| ggsave(g, file = here::here("images/original-dfs.png")) | |||||
| ``` | |||||
| <img src="images/original-dfs.png" style="max-width: 480px" /> | |||||
| ```{r echo=TRUE} | |||||
| x | |||||
| y | |||||
| ``` | |||||
| ### Inner Join | |||||
| ```{r inner-join} | |||||
| source("R/inner_join.R") | |||||
| ``` | |||||
|  | |||||
| ```{r echo=TRUE} | |||||
| inner_join(x, y, by = "id") | |||||
| ``` | |||||
| ### Left Join | |||||
| ```{r left-join} | |||||
| source("R/left_join.R") | |||||
| ``` | |||||
|  | |||||
| ```{r echo=TRUE} | |||||
| left_join(x, y, by = "id") | |||||
| ``` | |||||
| ### Right Join | |||||
| ```{r right-join} | |||||
| source("R/right_join.R") | |||||
| ``` | |||||
|  | |||||
| ```{r echo=TRUE} | |||||
| right_join(x, y, by = "id") | |||||
| ``` | |||||
| ### Full Join | |||||
| ```{r full-join} | |||||
| source("R/full_join.R") | |||||
| ``` | |||||
|  | |||||
| ```{r echo=TRUE} | |||||
| full_join(x, y, by = "id") | |||||
| ``` | |||||
| ## Filtering Joins | |||||
| ### Semi Join | |||||
| ```{r semi-join} | |||||
| source("R/semi_join.R") | |||||
| ``` | |||||
|  | |||||
| ```{r echo=TRUE} | |||||
| semi_join(x, y, by = "id") | |||||
| ``` | |||||
| ### Anti Join | |||||
| ```{r anti-join} | |||||
| source("R/anti_join.R") | |||||
| ``` | |||||
|  | |||||
| ```{r echo=TRUE} | |||||
| anti_join(x, y, by = "id") | |||||
| ``` |
| <!-- README.md is generated from README.Rmd. Please edit that file --> | |||||
| # Tidy Animated Verbs | |||||
| Garrick Aden-Buie – [@grrrck](https://twitter.com/grrrck) – | |||||
| [garrickadenbuie.com](https://www.garrickadenbuie.com) | |||||
| ## Mutate Joins | |||||
| <img src="images/original-dfs.png" style="max-width: 480px" /> | |||||
| ``` r | |||||
| x | |||||
| #> # A tibble: 3 x 2 | |||||
| #> id x | |||||
| #> <int> <chr> | |||||
| #> 1 1 x1 | |||||
| #> 2 2 x2 | |||||
| #> 3 3 x3 | |||||
| y | |||||
| #> # A tibble: 3 x 2 | |||||
| #> id y | |||||
| #> <int> <chr> | |||||
| #> 1 1 y1 | |||||
| #> 2 2 y2 | |||||
| #> 3 4 y4 | |||||
| ``` | |||||
| ### Inner Join | |||||
|  | |||||
| ``` r | |||||
| inner_join(x, y, by = "id") | |||||
| #> # A tibble: 2 x 3 | |||||
| #> id x y | |||||
| #> <int> <chr> <chr> | |||||
| #> 1 1 x1 y1 | |||||
| #> 2 2 x2 y2 | |||||
| ``` | |||||
| ### Left Join | |||||
|  | |||||
| ``` r | |||||
| left_join(x, y, by = "id") | |||||
| #> # A tibble: 3 x 3 | |||||
| #> id x y | |||||
| #> <int> <chr> <chr> | |||||
| #> 1 1 x1 y1 | |||||
| #> 2 2 x2 y2 | |||||
| #> 3 3 x3 <NA> | |||||
| ``` | |||||
| ### Right Join | |||||
|  | |||||
| ``` r | |||||
| right_join(x, y, by = "id") | |||||
| #> # A tibble: 3 x 3 | |||||
| #> id x y | |||||
| #> <int> <chr> <chr> | |||||
| #> 1 1 x1 y1 | |||||
| #> 2 2 x2 y2 | |||||
| #> 3 4 <NA> y4 | |||||
| ``` | |||||
| ### Full Join | |||||
|  | |||||
| ``` r | |||||
| full_join(x, y, by = "id") | |||||
| #> # A tibble: 4 x 3 | |||||
| #> id x y | |||||
| #> <int> <chr> <chr> | |||||
| #> 1 1 x1 y1 | |||||
| #> 2 2 x2 y2 | |||||
| #> 3 3 x3 <NA> | |||||
| #> 4 4 <NA> y4 | |||||
| ``` | |||||
| ## Filtering Joins | |||||
| ### Semi Join | |||||
|  | |||||
| ``` r | |||||
| semi_join(x, y, by = "id") | |||||
| #> # A tibble: 2 x 2 | |||||
| #> id x | |||||
| #> <int> <chr> | |||||
| #> 1 1 x1 | |||||
| #> 2 2 x2 | |||||
| ``` | |||||
| ### Anti Join | |||||
|  | |||||
| ``` r | |||||
| anti_join(x, y, by = "id") | |||||
| #> # A tibble: 1 x 2 | |||||
| #> id x | |||||
| #> <int> <chr> | |||||
| #> 1 3 x3 | |||||
| ``` |
| install.packages("tidyverse") | |||||
| install.packages("rmarkdown") | |||||
| install.packages("here") | |||||
| install.packages(c("sysfonts", "jsonlite", "curl", "showtext")) | |||||
| install.packages("devtools") | |||||
| devtools::install_github("thomasp85/gganimate") |
| r-2018-0815 |
| Version: 1.0 | |||||
| RestoreWorkspace: No | |||||
| SaveWorkspace: No | |||||
| AlwaysSaveHistory: Default | |||||
| EnableCodeIndexing: Yes | |||||
| UseSpacesForTab: Yes | |||||
| NumSpacesForTab: 2 | |||||
| Encoding: UTF-8 | |||||
| RnwWeave: Sweave | |||||
| LaTeX: pdfLaTeX | |||||
| AutoAppendNewline: Yes | |||||
| StripTrailingWhitespace: Yes | |||||
| BuildType: Package | |||||
| PackageUseDevtools: Yes | |||||
| PackageInstallArgs: --no-multiarch --with-keep.source | |||||
| PackageRoxygenize: rd,collate,namespace |