Simple tweenr animations with ggplot2

Animations with tweenr

IN THIS POST WE ARE GOING TO CREATE TWO SIMPLE animated data visualizations using R ggplot2, animation, and tweenr packages.

See this post about tweenr for an introduction to tweenr, and more examples here and here.

Unlike those examples we are going to create visualizations using the data that ship with the tidyverse packages (mainly ggplot2). This will allow for easier replication.

A simple stripped down example.

Let’s start with a stripped down example. I actually tweeted this out starting here:

But let’s put it all in a single place.

#load libraries
library(tidyverse)
library(animation)
library(tweenr)
library(ggplot2)

myf<-function(i){
  df<-mtcars
  df$y<-mtcars[,i]
  df$yname<-as.factor(names(df)[i])
  return(df)
}

mylist<-lapply(seq(11,1),myf)
tween.df<-tween_states(mylist,tweenlength=1,statelength=2, ease=rep('cubic-in-out',11), nframes=121)

myplot<-function(i){  
g<-ggplot(data=filter(tween.df,i==.frame),aes(x=mpg,y=y))+geom_point(size=3)+theme_bw()+
  labs(y=filter(tween.df,i==.frame)$yname)
return(g)
}

oopt = ani.options(interval = 0.1)
saveGIF({for (i in 1:max(tween.df$.frame)) {
  g<-myplot(i)
  print(g)
  print(i)
  ani.pause()
}
},movie.name="mtcars tween.gif",ani.width = 840, ani.height =450)
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
## [1] 11
## [1] 12
## [1] 13
## [1] 14
## [1] 15
## [1] 16
## [1] 17
## [1] 18
## [1] 19
## [1] 20
## [1] 21
## [1] 22
## [1] 23
## [1] 24
## [1] 25
## [1] 26
## [1] 27
## [1] 28
## [1] 29
## [1] 30
## [1] 31
## [1] 32
## [1] 33
## [1] 34
## [1] 35
## [1] 36
## [1] 37
## [1] 38
## [1] 39
## [1] 40
## [1] 41
## [1] 42
## [1] 43
## [1] 44
## [1] 45
## [1] 46
## [1] 47
## [1] 48
## [1] 49
## [1] 50
## [1] 51
## [1] 52
## [1] 53
## [1] 54
## [1] 55
## [1] 56
## [1] 57
## [1] 58
## [1] 59
## [1] 60
## [1] 61
## [1] 62
## [1] 63
## [1] 64
## [1] 65
## [1] 66
## [1] 67
## [1] 68
## [1] 69
## [1] 70
## [1] 71
## [1] 72
## [1] 73
## [1] 74
## [1] 75
## [1] 76
## [1] 77
## [1] 78
## [1] 79
## [1] 80
## [1] 81
## [1] 82
## [1] 83
## [1] 84
## [1] 85
## [1] 86
## [1] 87
## [1] 88
## [1] 89
## [1] 90
## [1] 91
## [1] 92
## [1] 93
## [1] 94
## [1] 95
## [1] 96
## [1] 97
## [1] 98
## [1] 99
## [1] 100
## [1] 101
## [1] 102
## [1] 103
## [1] 104
## [1] 105
## [1] 106
## [1] 107
## [1] 108
## [1] 109
## [1] 110
## [1] 111
## [1] 112
## [1] 113
## [1] 114
## [1] 115
## [1] 116
## [1] 117
## [1] 118
## [1] 119
## [1] 120
## [1] 121
## [1] 122
## [1] 123
## [1] 124
## [1] 125
## [1] 126
## [1] 127
## [1] 128
## Warning: running command 'C:\WINDOWS\system32\cmd.exe /c convert --version'
## had status 4
## Warning in find_magic(): ImageMagick not installed yet!
## Warning in im.convert(img.files, output = path.expand(movie.name), convert
## = convert, : Please install ImageMagick first or put its bin path into the
## system PATH variable
## [1] FALSE

Running this creates:

mtcars gif

In this example, we loop through the mtcars data and plot successive scatterplots showing the relationship between mpg and other variables in the dataset.

We first create a simple function to create a dataset for each frame in our animation. Then we use tweenr to interpolate between frames to create a smooth animation. I’ve also found it convenient to create a plot function and insert that in the loop.

Animated map

We can make another example using a map. I’m going to use the txhousing dataset that comes with ggplot2.

These data, from the Real Estate Center at Texas A&M University provide some basic stats on trends in Texas housing markets. Modifying example 4 in this post we can create a simple map of median sales prices by city in June 2015:

library(maps)
data(us.cities) # from the package maps
data(txhousing) # from the package ggplot2

# Preprocessing
tx.cities <- subset(us.cities, country.etc == "TX" & pop >= 100000)
tx.cities$city <- unlist(strsplit(tx.cities$name, " TX"))
txhousing.2015 <- subset(txhousing, year == 2015 & month == 6 &
                             city %in% tx.cities$city)
temp <- tx.cities[tx.cities$city %in% txhousing.2015$city, c("pop", "lat", "long")]
temp <- temp[rep(seq_len(nrow(temp)), each = 6), ]
txhousing.2015.geo <- cbind(txhousing.2015, temp)

ggplot(txhousing.2015.geo, aes(x = long, y = lat,  colour = median/1000)) +
  borders("county", "texas", colour = "grey70") + 
  geom_point(size=3,alpha=0.82) + 
  ggtitle("Housing market for populous cities in Texas (Jun 2015)") +
  scale_colour_continuous(name  = "Median price ($, Ths)") +
  labs(caption="test caption")

Now we can use tweenr to interpolate between points.

For the animation we’ll just plot an outline of the state of Texas and then have a dot for each city move around the map. In a future exercise we could combine the map with a time series line or bar chart to show trends in metro data. As that would be more complicated we’ll do that at a later time. Right now, let’s just make the map and animate following the same approach as above.

city.list<-unique(txhousing.2015.geo$city)

myf<-function(c){
  df<-subset(merge(txhousing.2015,tx.cities),city==city.list[c])
  df$city<-factor(df$city)
  df %>% map_if(is.character, as.factor) %>% as_data_frame -> df
  return(df)
}

myplot<-function(indata){  
  g<-
  ggplot(data=indata, aes(x = long, y = lat,  label=city)) +
  borders("county", "texas", colour = "grey70") + 
  geom_point(data=indata,size=3,alpha=0.82) + 
  geom_text(data=indata,vjust=0,nudge_y=.5)+
  ggtitle("Texas Metros") +
  labs(caption="@lenkiefer",subtitle=" These metros are moving!")+
  theme(plot.caption=element_text(hjust=0))
  return(g)
}

mylist<-lapply(c(seq(1,18),1),myf)
tween.df<-tween_states(mylist,tweenlength=1,statelength=2, ease=rep('cubic-in-out',20), nframes=210)
tween.df$country.etc<-as.character(tween.df$country.etc)

oopt = ani.options(interval = 0.1)
saveGIF({for (i in 1:max(tween.df$.frame)) {
  g<-myplot(tween.df[i,])
  print(g)
  print(i)
  ani.pause()
}
},movie.name="TX map tween.gif",ani.width = 600, ani.height =600)

TX metros move!

Extend the example

That’s enough for now, but perhaps in future we can extend these examples.

 Share!