Animating Plots
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
TLDR
There are many instances where it may be useful to animate graphical representations of data, perhaps to add an additional dimension to a plot. The below example builds a cumulative map of car accidents in the UK using some of the functionality of the gganimate
package.
Making Moving Plots with gganimate
Graphics made using the ggplot2
package are already extremely customisable. They can be further enhanced using some of the extensions that have been developed. These include providing access to new themes, as well as entirely new functionality.
gganimate
allows for the animation of existing ggplot graphics. Once installed, we can load both packages (ggplot2
is included as part of the tidyverse
):
library(gganimate); library(tidyverse)
The example uses a car accident dataset that I found on Kaggle. Here are the first few rows of the variables that we’re interested in:
head(Accidents_Dec2015 %>% dplyr::select(Date, Longitude, Latitude, Number_of_Casualties, Accident_Severity)) ## Date Longitude Latitude Number_of_Casualties Accident_Severity ## 1 2015-12-01 -0.155880 51.48959 1 Slight ## 2 2015-12-01 -0.200271 51.49262 1 Slight ## 3 2015-12-03 -0.210643 51.49997 2 Slight ## 4 2015-12-03 -0.156754 51.49293 1 Slight ## 5 2015-12-03 -0.159124 51.50205 1 Slight ## 6 2015-12-04 -0.197452 51.49104 1 Slight
We can plot the coordinates using a map of the UK included in ggplot2
.
UK_coords <- ggplot2::map_data(map = 'world', region = 'UK')
Before animating we need to create a ggplot that we will work from.
accidents_plot <- ggplot(data = UK_coords)+ geom_polygon(mapping = aes(x = long, y = lat, group = group), col = 'black', fill = NA)+ theme_void(base_size = 12, base_family = 'Bahnschrift')+ geom_point(data = Accidents_Dec2015, mapping = aes(x = Longitude, y = Latitude, col = as.factor(Accident_Severity), alpha = as.factor(Accident_Severity), size = Number_of_Casualties, group = seq_len(length.out = nrow(Accidents_Dec2015))))+ theme(legend.position = 'right')+ scale_size_continuous(breaks = c(1, 3, 9))+ scale_color_manual(values = c('firebrick', 'forestgreen', 'steelblue'))+ scale_alpha_manual(values = c(0.4, 0.2, 0.1), guide = 'none')+ guides(col = guide_legend(title = element_blank(), ncol = 1), size = guide_legend(title = element_text('Casualties', size = 10), ncol = 1, alpha = 0.4)) accidents_plot
We can now add some functions from gganimate
, which will describe how and saving as a new variable:
library(gganimate) accidents_plot <- accidents_plot + transition_time(time = Date)+ enter_grow()+ shadow_mark()+ ggtitle(label = 'UK Car Accidents in December 2015', subtitle = 'Date : {frame_time}')+ labs(caption = 'Data from Kaggle: https://www.kaggle.com/silicon99/dft-accident-data/data | @Domenic_DF')
transition_time()
requires specification of a time variable that the plot will display sequentially. As shown above, this animation will transition through values of Date
. There are many more options that allow for animation across different data types in different ways.
shadow_mark()
has been added to keep accidents from previous dates. Again, there are various methods of showing data from previous states.
enter_grow()
means that when new data first appear on the plot, they will emerge by growing into their final size.
Some of these additional options are detailed here.
In this case, transition_length
and state_length
describe the relative amount of time spent displaying the current state, and transitioning to the next state.
Regardless of the transition function selected, the best way to create the moving plot is to use the animate
function:
animate(plot = accidents_plot, fps = 20, duration = 30, end_pause = 100)
The animate()
function requires us to specify the plot (to be animated), but includes many additional arguments not all of which are detailed above.
fps
is the frames per second, duration
is the length of the animation (in seconds), and end_pause
is the length of time that the final frame is held for (in number of frames.)
Final Animation
I tried a few alternatives here. In this case each state has quite a few points and so I wanted it to be held for a reasonable amount of time. The trade-off here is the number of frames (and associated processing time and file size). The below allocates approximately 1
second per day and results in a total of 600 frames for the animation. On my (ageing) laptop this required approximately 4 minutes to render.
Thoughts on the Animation
What does the animation tell us that the stationary plot doesn’t?
The final frame is pretty much identical, but the transitions will show when the accidents occurred. From viewing the animation there doesn’t appear to be a clear time when accidents were more frequent. We can check this with an additional plot:
Accidents_Dec2015 %>% dplyr::select(Date, Number_of_Casualties, Accident_Severity) %>% ggplot(mapping = aes(x = Date))+ geom_bar(stat = 'count', fill = 'grey80')+ facet_wrap(facets = ~ Accident_Severity, scales = 'free')+ theme_ddf_light()+ coord_flip()+ theme(axis.title = element_blank())
What isn’t shown in the data is the number of cars that were on the road at the time, so it could be that there were a higher proportion of accidents between the 24
th and 31
st December - but that will have to remain speculation for now.
One tip that I picked up from the package developer was the need to group data in the geom to avoid new points travelling from the location of other points. Given the context of the plot, that could have been interpreted as the same vehicles having accidents all over the UK. I’m glad that I was able to avoid this ambiguity in the plot.
In conclusion, I think the animated plot looks cool, but it is perhaps a little gimmicky for this particular application. The same information is contained in the two static plots in this post. However, I hope this has content serves as a helpful introduction to how the gganimate
package can automate animated graphics.
Additional Resources
This example is certainly not exhaustive and there are many additional tweaks available to further customise an animation. I have personally found the below resources to be particularly helpful.
- The official beginner’s guide to
gganimate
. - A tutorial from the ISU Graphics Group.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.