Skip to content

Instantly share code, notes, and snippets.

@ikashnitsky
Last active December 12, 2019 20:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ikashnitsky/64ce22c6de6fdd5e1aac87fafe073453 to your computer and use it in GitHub Desktop.
Save ikashnitsky/64ce22c6de6fdd5e1aac87fafe073453 to your computer and use it in GitHub Desktop.
Generate snowfall -- every snowflake scaled to a country population size ^1/3
#===============================================================================
# 2019-12-12 -- twitter
# Generate snowfall -- every snowflake scaled to a country population size ^1/3
# Ilya Kashnitsky, ilya.kashnitsky@gmail.com
#===============================================================================
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")
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment