Last active
December 12, 2019 20:07
-
-
Save ikashnitsky/64ce22c6de6fdd5e1aac87fafe073453 to your computer and use it in GitHub Desktop.
Generate snowfall -- every snowflake scaled to a country population size ^1/3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#=============================================================================== | |
# 2019-12-12 -- twitter | |
# Generate snowfall -- every snowflake scaled to a country population size ^1/3 | |
# Ilya Kashnitsky, [email protected] | |
#=============================================================================== | |
library(tidyverse) | |
library(magrittr) | |
library(gganimate) | |
# helper function to ensure the snowflakes don't disappear ---------------- | |
# function for one snowflake | |
loop_single <- function(value){ | |
if(value %>% is_less_than(0)){value <- 1} | |
if(value %>% is_greater_than(1)){value <- 0} | |
return(value) | |
} | |
# vectorize | |
loop_multiple <- function(values){ | |
values %>% map_dbl(loop_single) | |
} | |
# create a larger dataframe with frames for snowflake movement ------------ | |
# function to create smooth frames for snowflake falling | |
fun_framing <- function(df, n_frames = 100, wind = 0){ | |
# frames vector | |
frames <- seq(1, n_frames) | |
# empty list | |
out <- list() | |
# place the init df in the first element | |
out[[1]] <- df | |
# length of the df | |
len <- nrow(df) | |
for (i in seq_along(frames)) { | |
# calculate x shift, unique for each snowflake | |
x_shift <- runif(len, -.5, .5) %>% add(wind) | |
dfi <- out[[i]] %>% | |
mutate( | |
x = x %>% | |
add(x_shift %>% multiply_by(size/1e3)) %>% | |
loop_multiple(), | |
y = y %>% | |
subtract(size/1e3) %>% | |
loop_multiple() | |
) | |
out[[i+1]] <- dfi | |
} | |
# bind list | |
out <- out %>% | |
bind_rows(.id = "frame") %>% | |
mutate(frame = frame %>% as.numeric) | |
return(out) | |
} | |
# calculate dataset ------------------------------------------------------- | |
# get countries' population size | |
library(wpp2019) | |
data(pop) | |
set.seed(911) | |
df <- pop %>% | |
filter( | |
country_code %>% paste %>% map_dbl(nchar) %>% equals(3), | |
country_code %>% paste %>% str_sub(1,1) %>% equals(9) %>% not | |
) %>% | |
transmute(id = country_code, name, pop = `2020`) %>% | |
# calculate size as scaled log(pop) | |
mutate( | |
size = pop %>% raise_to_power(1/3) %>% scales::rescale(to = c(1, 12)) | |
) %>% | |
# add random starting coordinates | |
mutate( | |
x = runif(178), | |
y = runif(178), | |
angle = runif(178) %>% scales::rescale(to = c(0, 60)) | |
) | |
# generate movement frames | |
set.seed(911) | |
# generate df for animation | |
df_anim <- df %>% fun_framing(n_frames = 3e2, wind = -1) | |
save(df_anim, file = "1912-animated-snow/df_anim.rda") | |
load("1912-animated-snow/df_anim.rda") | |
# plot/animate ------------------------------------------------------------ | |
library(ggimage) | |
svg_path <- "https://gist.githubusercontent.com/ikashnitsky/64ce22c6de6fdd5e1aac87fafe073453/raw/46c9908277330228515b57b7dafd532298ac5e18/snow-white.svg" | |
p <- df_anim %>% | |
ggplot(aes(x, y, size = I(size / 150))) + | |
geom_image(image = svg_path)+ | |
coord_cartesian(c(0, 1), c(0, 1), expand = FALSE)+ | |
theme_void()+ | |
theme( | |
panel.background = element_rect(fill = "black"), | |
plot.background = element_rect(fill = "black") | |
) | |
# add transition | |
ani <- p + | |
transition_time(frame)+ | |
ease_aes('linear')+ | |
enter_fade()+ | |
exit_fade() | |
# define the number of data points | |
nfr <- df_anim %>% pull(frame) %>% unique() %>% length() | |
# animate | |
animate( | |
ani, | |
nframes = nfr, fps = 30, | |
# device = "svg", renderer = magick_renderer(loop = TRUE), | |
width = 500, height = 500 | |
) | |
# save the output | |
anim_save("animated-snowflakes.gif") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment