| geom_tile(width = 0.9, height = 0.9) + | geom_tile(width = 0.9, height = 0.9) + | ||||
| coord_equal() + | coord_equal() + | ||||
| geom_text(data = d %>% filter(!is.na(val)), aes(label = val), color = "white", | geom_text(data = d %>% filter(!is.na(val)), aes(label = val), color = "white", | ||||
| family = text_family, size = 20, fontface = "bold") + | |||||
| family = text_family, size = 12, fontface = "bold") + | |||||
| scale_fill_identity() + | scale_fill_identity() + | ||||
| scale_alpha_identity() + | scale_alpha_identity() + | ||||
| labs(title = title) + | labs(title = title) + | ||||
| theme_void() + | theme_void() + | ||||
| theme(plot.title = element_text(family = title_family, hjust = 0.5, size = 30)) | |||||
| theme(plot.title = element_text(family = title_family, hjust = 0.5, size = 24)) | |||||
| } | } |
| message = FALSE, | message = FALSE, | ||||
| cache = TRUE | cache = TRUE | ||||
| ) | ) | ||||
| library(tidyAnimatedVerbs) | |||||
| ``` | ``` | ||||
| [gganimate]: https://github.com/thomasp85/gganimate#README | [gganimate]: https://github.com/thomasp85/gganimate#README | ||||
| Currently, the animations cover the [dplyr two-table verbs][dplyr-two-table] and I'd like to expand the animations to include more verbs from the tidyverse. | Currently, the animations cover the [dplyr two-table verbs][dplyr-two-table] and I'd like to expand the animations to include more verbs from the tidyverse. | ||||
| [Suggestions are welcome!](https://github.com/gadenbuie/tidy-animated-verbs/issues) | [Suggestions are welcome!](https://github.com/gadenbuie/tidy-animated-verbs/issues) | ||||
| ## Installing | |||||
| The library can be installed with | |||||
| ```{r, echo=T,eval=F} | |||||
| # install.package("devtools") | |||||
| devtools::install_github("gadenbuie/tidy-animated-verbs") | |||||
| ``` | |||||
| ## Mutating Joins | ## Mutating Joins | ||||
| ```{r intial-dfs} | |||||
| source("R/00_base_join.R") | |||||
| df_names <- data_frame( | |||||
| .x = c(1.5, 4.5), .y = 0.25, | |||||
| value = c("x", "y"), | |||||
| size = 12, | |||||
| color = "black" | |||||
| ```{r intial-dfs, echo=T} | |||||
| library(tidyAnimatedVerbs) | |||||
| x <- data_frame( | |||||
| id = 1:3, | |||||
| x = paste0("x", 1:3) | |||||
| ) | ) | ||||
| g <- plot_data(initial_join_dfs) + | |||||
| geom_text(data = df_names, family = "Fira Mono", size = 24) | |||||
| y <- data_frame( | |||||
| id = (1:4)[-3], | |||||
| y = paste0("y", (1:4)[-3]) | |||||
| ) | |||||
| save_static_plot(g, "original-dfs") | |||||
| animate_full_join(x, y, by = c("id"), export = "first") | |||||
| ``` | ``` | ||||
| <img src="images/static/png/original-dfs.png" width="480px" /> | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| x | x | ||||
| > All rows from `x` where there are matching values in `y`, and all columns from `x` and `y`. | > All rows from `x` where there are matching values in `y`, and all columns from `x` and `y`. | ||||
| ```{r inner-join} | |||||
| source("R/inner_join.R") | |||||
| ```{r inner-join, echo=T} | |||||
| animate_inner_join(x, y, by = "id") | |||||
| ``` | ``` | ||||
|  | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| inner_join(x, y, by = "id") | inner_join(x, y, by = "id") | ||||
| > All rows from `x`, and all columns from `x` and `y`. Rows in `x` with no match in `y` will have `NA` values in the new columns. | > All rows from `x`, and all columns from `x` and `y`. Rows in `x` with no match in `y` will have `NA` values in the new columns. | ||||
| ```{r left-join} | |||||
| source("R/left_join.R") | |||||
| ```{r left-join, echo=T} | |||||
| animate_inner_join(x, y, by = "id") | |||||
| ``` | ``` | ||||
|  | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| left_join(x, y, by = "id") | left_join(x, y, by = "id") | ||||
| > ... If there are multiple matches between `x` and `y`, all combinations of the matches are returned. | > ... If there are multiple matches between `x` and `y`, all combinations of the matches are returned. | ||||
| ```{r left-join-extra} | ```{r left-join-extra} | ||||
| source("R/left_join_extra.R") | |||||
| # Not yet working | |||||
| # source("R/left_join_extra.R") | |||||
| y_extra <- bind_rows(y, data_frame(id = 2, y = "y5")) | |||||
| ``` | ``` | ||||
|  |  | ||||
| > All rows from y, and all columns from `x` and `y`. Rows in `y` with no match in `x` will have `NA` values in the new columns. | > All rows from y, and all columns from `x` and `y`. Rows in `y` with no match in `x` will have `NA` values in the new columns. | ||||
| ```{r right-join} | |||||
| source("R/right_join.R") | |||||
| ```{r right-join, echo = T} | |||||
| animate_right_join(x, y, by = "id") | |||||
| ``` | ``` | ||||
|  | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| right_join(x, y, by = "id") | right_join(x, y, by = "id") | ||||
| > All rows and all columns from both `x` and `y`. Where there are not matching values, returns `NA` for the one missing. | > All rows and all columns from both `x` and `y`. Where there are not matching values, returns `NA` for the one missing. | ||||
| ```{r full-join} | |||||
| source("R/full_join.R") | |||||
| ```{r full-join, echo=T} | |||||
| animate_full_join(x, y, by = "id") | |||||
| ``` | ``` | ||||
|  | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| full_join(x, y, by = "id") | full_join(x, y, by = "id") | ||||
| > All rows from `x` where there are matching values in `y`, keeping just columns from `x`. | > All rows from `x` where there are matching values in `y`, keeping just columns from `x`. | ||||
| ```{r semi-join} | |||||
| source("R/semi_join.R") | |||||
| ```{r semi-join, echo=T} | |||||
| animate_semi_join(x, y, by = "id") | |||||
| ``` | ``` | ||||
|  | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| semi_join(x, y, by = "id") | semi_join(x, y, by = "id") | ||||
| > All rows from `x` where there are not matching values in `y`, keeping just columns from `x`. | > All rows from `x` where there are not matching values in `y`, keeping just columns from `x`. | ||||
| ```{r anti-join} | ```{r anti-join} | ||||
| source("R/anti_join.R") | |||||
| animate_anti_join(x, y, by = "id") | |||||
| ``` | ``` | ||||
|  | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| anti_join(x, y, by = "id") | anti_join(x, y, by = "id") | ||||
| ## Set Operations | ## Set Operations | ||||
| ```{r intial-dfs-so} | |||||
| source("R/00_base_set.R") | |||||
| df_names <- data_frame( | |||||
| .x = c(2.5, 5.5), .y = 0.25, | |||||
| value = c("x", "y"), | |||||
| size = 12, | |||||
| color = "black" | |||||
| ) | |||||
| ```{r intial-dfs-so, echo=T} | |||||
| g <- plot_data_set(initial_set_dfs, "", NULL, NULL) + | |||||
| geom_text(data = df_names, family = "Fira Mono", size = 24) | |||||
| x <- tibble::tribble( | |||||
| ~x, ~y, | |||||
| "1", "a", | |||||
| "1", "b", | |||||
| "2", "a" | |||||
| ) | |||||
| save_static_plot(g, "original-dfs-set-ops") | |||||
| ``` | |||||
| y <- tibble::tribble( | |||||
| ~x, ~y, | |||||
| "1", "a", | |||||
| "2", "b" | |||||
| ) | |||||
| ```{r remove-set-ops-ids} | |||||
| x <- x %>% select(-id) | |||||
| y <- y %>% select(-id) | |||||
| animate_union(x, y, export = "first") | |||||
| ``` | ``` | ||||
| <img src="images/static/png/original-dfs-set-ops.png" width="480px" /> | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| x | x | ||||
| > All unique rows from `x` and `y`. | > All unique rows from `x` and `y`. | ||||
| ```{r union} | |||||
| source("R/union.R") | |||||
| <<remove-set-ops-ids>> | |||||
| ```{r union, export=T} | |||||
| animate_union(x, y) | |||||
| ``` | ``` | ||||
|  | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| union(x, y) | union(x, y) | ||||
| ``` | ``` | ||||
|  | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| animate_union(y, x) | |||||
| union(y, x) | union(y, x) | ||||
| ``` | ``` | ||||
| > All rows from `x` and `y`, keeping duplicates. | > All rows from `x` and `y`, keeping duplicates. | ||||
| ```{r union-all} | |||||
| source("R/union_all.R") | |||||
| <<remove-set-ops-ids>> | |||||
| ```{r union-all, echo=T} | |||||
| animate_union_all(x, y) | |||||
| ``` | ``` | ||||
|  | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| > Common rows in both `x` and `y`, keeping just unique rows. | > Common rows in both `x` and `y`, keeping just unique rows. | ||||
| ```{r intersect} | |||||
| source("R/intersect.R") | |||||
| <<remove-set-ops-ids>> | |||||
| ```{r intersect, echo=T} | |||||
| animate_intersect(x, y) | |||||
| ``` | ``` | ||||
|  | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| intersect(x, y) | intersect(x, y) | ||||
| > All rows from `x` which are not also rows in `y`, keeping just unique rows. | > All rows from `x` which are not also rows in `y`, keeping just unique rows. | ||||
| ```{r setdiff} | |||||
| source("R/setdiff.R") | |||||
| <<remove-set-ops-ids>> | |||||
| ```{r setdiff, echo=T} | |||||
| animate_setdiff(x, y) | |||||
| ``` | ``` | ||||
|  | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| setdiff(x, y) | setdiff(x, y) | ||||
| ``` | ``` | ||||
|  | |||||
| ```{r echo=TRUE} | ```{r echo=TRUE} | ||||
| animate_setdiff(y, x) | |||||
| setdiff(y, x) | setdiff(y, x) | ||||
| ``` | ``` | ||||
| [Suggestions are | [Suggestions are | ||||
| welcome\!](https://github.com/gadenbuie/tidy-animated-verbs/issues) | welcome\!](https://github.com/gadenbuie/tidy-animated-verbs/issues) | ||||
| ## Installing | |||||
| The library can be installed with | |||||
| ``` r | |||||
| # install.package("devtools") | |||||
| devtools::install_github("gadenbuie/tidy-animated-verbs") | |||||
| ``` | |||||
| ## Mutating Joins | ## Mutating Joins | ||||
| <img src="images/static/png/original-dfs.png" width="480px" /> | |||||
| ``` r | |||||
| library(tidyAnimatedVerbs) | |||||
| x <- data_frame( | |||||
| id = 1:3, | |||||
| x = paste0("x", 1:3) | |||||
| ) | |||||
| y <- data_frame( | |||||
| id = (1:4)[-3], | |||||
| y = paste0("y", (1:4)[-3]) | |||||
| ) | |||||
| animate_full_join(x, y, by = c("id"), export = "first") | |||||
| ``` | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| x | x | ||||
| > All rows from `x` where there are matching values in `y`, and all | > All rows from `x` where there are matching values in `y`, and all | ||||
| > columns from `x` and `y`. | > columns from `x` and `y`. | ||||
|  | |||||
| ``` r | |||||
| animate_inner_join(x, y, by = "id") | |||||
| ``` | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| inner_join(x, y, by = "id") | inner_join(x, y, by = "id") | ||||
| > All rows from `x`, and all columns from `x` and `y`. Rows in `x` with | > All rows from `x`, and all columns from `x` and `y`. Rows in `x` with | ||||
| > no match in `y` will have `NA` values in the new columns. | > no match in `y` will have `NA` values in the new columns. | ||||
|  | |||||
| ``` r | |||||
| animate_inner_join(x, y, by = "id") | |||||
| ``` | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| left_join(x, y, by = "id") | left_join(x, y, by = "id") | ||||
| > All rows from y, and all columns from `x` and `y`. Rows in `y` with no | > All rows from y, and all columns from `x` and `y`. Rows in `y` with no | ||||
| > match in `x` will have `NA` values in the new columns. | > match in `x` will have `NA` values in the new columns. | ||||
|  | |||||
| ``` r | |||||
| animate_right_join(x, y, by = "id") | |||||
| ``` | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| right_join(x, y, by = "id") | right_join(x, y, by = "id") | ||||
| > All rows and all columns from both `x` and `y`. Where there are not | > All rows and all columns from both `x` and `y`. Where there are not | ||||
| > matching values, returns `NA` for the one missing. | > matching values, returns `NA` for the one missing. | ||||
|  | |||||
| ``` r | |||||
| animate_full_join(x, y, by = "id") | |||||
| ``` | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| full_join(x, y, by = "id") | full_join(x, y, by = "id") | ||||
| > All rows from `x` where there are matching values in `y`, keeping just | > All rows from `x` where there are matching values in `y`, keeping just | ||||
| > columns from `x`. | > columns from `x`. | ||||
|  | |||||
| ``` r | |||||
| animate_semi_join(x, y, by = "id") | |||||
| ``` | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| semi_join(x, y, by = "id") | semi_join(x, y, by = "id") | ||||
| > All rows from `x` where there are not matching values in `y`, keeping | > All rows from `x` where there are not matching values in `y`, keeping | ||||
| > just columns from `x`. | > just columns from `x`. | ||||
|  | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| anti_join(x, y, by = "id") | anti_join(x, y, by = "id") | ||||
| ## Set Operations | ## Set Operations | ||||
| <img src="images/static/png/original-dfs-set-ops.png" width="480px" /> | |||||
| ``` r | |||||
| x <- tibble::tribble( | |||||
| ~x, ~y, | |||||
| "1", "a", | |||||
| "1", "b", | |||||
| "2", "a" | |||||
| ) | |||||
| y <- tibble::tribble( | |||||
| ~x, ~y, | |||||
| "1", "a", | |||||
| "2", "b" | |||||
| ) | |||||
| animate_union(x, y, export = "first") | |||||
| ``` | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| x | x | ||||
| > All unique rows from `x` and `y`. | > All unique rows from `x` and `y`. | ||||
|  | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| union(x, y) | union(x, y) | ||||
| #> 4 1 a | #> 4 1 a | ||||
| ``` | ``` | ||||
|  | |||||
| ``` r | |||||
| animate_union(y, x) | |||||
| ``` | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| union(y, x) | union(y, x) | ||||
| #> # A tibble: 4 x 2 | #> # A tibble: 4 x 2 | ||||
| #> x y | #> x y | ||||
| > All rows from `x` and `y`, keeping duplicates. | > All rows from `x` and `y`, keeping duplicates. | ||||
|  | |||||
| ``` r | |||||
| animate_union_all(x, y) | |||||
| ``` | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| union_all(x, y) | union_all(x, y) | ||||
| > Common rows in both `x` and `y`, keeping just unique rows. | > Common rows in both `x` and `y`, keeping just unique rows. | ||||
|  | |||||
| ``` r | |||||
| animate_intersect(x, y) | |||||
| ``` | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| intersect(x, y) | intersect(x, y) | ||||
| > All rows from `x` which are not also rows in `y`, keeping just unique | > All rows from `x` which are not also rows in `y`, keeping just unique | ||||
| > rows. | > rows. | ||||
|  | |||||
| ``` r | |||||
| animate_setdiff(x, y) | |||||
| ``` | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| setdiff(x, y) | setdiff(x, y) | ||||
| #> 2 2 a | #> 2 2 a | ||||
| ``` | ``` | ||||
|  | |||||
| ``` r | |||||
| animate_setdiff(y, x) | |||||
| ``` | |||||
| <!-- --> | |||||
| ``` r | ``` r | ||||
| setdiff(y, x) | setdiff(y, x) | ||||
| #> # A tibble: 1 x 2 | #> # A tibble: 1 x 2 | ||||
| #> x y | #> x y |
| library(tidyAnimatedVerbs) | |||||
| library(here) | |||||
| check_and_create <- function(ff) { | |||||
| if (!dir.exists(ff)) dir.create(ff, recursive = T) | |||||
| } | |||||
| x <- data_frame( | |||||
| id = 1:3, | |||||
| x = paste0("x", 1:3) | |||||
| ) | |||||
| y <- data_frame( | |||||
| id = (1:4)[-3], | |||||
| y = paste0("y", (1:4)[-3]) | |||||
| ) | |||||
| check_and_create(here("images", "static", "png")) | |||||
| joins <- c(full_join = animate_full_join, | |||||
| inner_join = animate_inner_join, | |||||
| left_join = animate_left_join, | |||||
| right_join = animate_right_join, | |||||
| semi_join = animate_right_join) | |||||
| a <- sapply(1:length(joins), function(i) { | |||||
| nam <- names(joins)[i] | |||||
| nam <- str_replace(nam, "_", "-") | |||||
| width <- 7 | |||||
| height <- 7 | |||||
| gif_ <- joins[[i]](x, y, by = "id") | |||||
| first_ <- joins[[i]](x, y, by = "id", export = "first") | |||||
| last_ <- joins[[i]](x, y, by = "id", export = "last") | |||||
| save_animation(gif_, here("images", paste0(nam, ".gif"))) | |||||
| ggsave(here("images", "static", "png", paste0(nam, "-first.png")), first_, | |||||
| height = height, width = width) | |||||
| ggsave(here("images", "static", "svg", paste0(nam, "-first.svg")), first_, | |||||
| height = height, width = width) | |||||
| ggsave(here("images", "static", "png", paste0(nam, "-last.png")), last_, | |||||
| height = height, width = width) | |||||
| ggsave(here("images", "static", "svg", paste0(nam, "-last.svg")), last_, | |||||
| height = height, width = width) | |||||
| }) | |||||
| # instr_extra <- instr %>% slice(c(1, 1:n())) | |||||
| # animate_left_join(singer, instr_extra, by = c("name", "band")) # <- NOT WORKING | |||||
| x <- tibble::tribble( | |||||
| ~x, ~y, | |||||
| "1", "a", | |||||
| "1", "b", | |||||
| "2", "a" | |||||
| ) | |||||
| y <- tibble::tribble( | |||||
| ~x, ~y, | |||||
| "1", "a", | |||||
| "2", "b" | |||||
| ) | |||||
| sets <- c(union = animate_union, | |||||
| union_all = animate_union_all, | |||||
| intersect = animate_intersect, | |||||
| setdiff = animate_setdiff) | |||||
| a <- sapply(1:length(sets), function(i) { | |||||
| nam <- names(sets)[i] | |||||
| nam <- str_replace(nam, "_", "-") | |||||
| width <- 7 | |||||
| height <- 7 | |||||
| gif_ <- sets[[i]](x, y, by = "id") | |||||
| first_ <- sets[[i]](x, y, by = "id", export = "first") | |||||
| last_ <- sets[[i]](x, y, by = "id", export = "last") | |||||
| save_animation(gif_, here("images", paste0(nam, ".gif"))) | |||||
| ggsave(here("images", "static", "png", paste0(nam, "-first.png")), first_, | |||||
| height = height, width = width) | |||||
| ggsave(here("images", "static", "svg", paste0(nam, "-first.svg")), first_, | |||||
| height = height, width = width) | |||||
| ggsave(here("images", "static", "png", paste0(nam, "-last.png")), last_, | |||||
| height = height, width = width) | |||||
| ggsave(here("images", "static", "svg", paste0(nam, "-last.svg")), last_, | |||||
| height = height, width = width) | |||||
| }) |