YOU HAVE SPOKEN and we will go with ticks out, at least 54% of the time.
In a graph, should axis ticks face in or out?
— Leonard Kiefer (@lenkiefer) February 5, 2017
To celebrate, let’s make an animated gif where the axis expands over time. We’ll use data we used in our mortgage rate post.
Let’s start by loading the data and plotting a static graph (with ticks out of course).
####################
#### Load Data ####
####################
library(readxl)
library(tidyverse)
## -- Attaching packages -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- tidyverse 1.2.1 --
## v ggplot2 2.2.1 v purrr 0.2.4
## v tibble 1.4.2 v dplyr 0.7.4
## v tidyr 0.8.0 v stringr 1.3.0
## v readr 1.1.1 v forcats 0.3.0
## -- Conflicts ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
library(data.table)
## Warning: package 'data.table' was built under R version 3.6.0
##
## Attaching package: 'data.table'
## The following objects are masked from 'package:dplyr':
##
## between, first, last
## The following object is masked from 'package:purrr':
##
## transpose
library(extrafont)
## Registering fonts with R
#for mor on these data see http://lenkiefer.com/2016/12/08/10-ways-to-visualize-rates
dt<- read_excel('data/rates.xlsx',sheet= 'rates')
dt$date<-as.Date(dt$date, format="%m/%d/%Y")
dt<-data.table(dt)
dt$year<-year(dt$date) # create year variable
###########################################
####### Functions for better axis ########
###########################################
################################
# for use with continuous axis
################################
base_breaks_x <- function(x){
b <- pretty(x)
d <- data.frame(y=-Inf, yend=-Inf, x=min(b), xend=max(b))
list(geom_segment(data=d, aes(x=x, y=y, xend=xend, yend=yend), inherit.aes=FALSE),
scale_x_continuous(breaks=b))
}
################################
# for use with date axis
################################
base_breaks_x_date <- function(x,dd,dd.format="default"){
#b <- pretty(x)
b<- c(min(x),max(x))
b2<- c(min(dd),max(dd))
if (dd.format != "default") {b2<-as.character(b2,format=dd.format)}
d <- data.frame(y=-Inf, yend=-Inf, x=min(x), xend=max(x))
list(geom_segment(data=d, aes(x=x, y=y, xend=xend, yend=yend),
inherit.aes=FALSE),
scale_x_continuous(breaks=b,labels=b2))
}
################################
# for use on y axis
################################
base_breaks_y <- function(x){
b <- pretty(x)
d <- data.frame(x=-Inf, xend=-Inf, y=min(b), yend=max(b))
list(geom_segment(data=d, aes(x=x, y=y, xend=xend, yend=yend), inherit.aes=FALSE),
scale_y_continuous(breaks=b))
}
#####################
#### Make Graph ####
#####################
ggplot(data=dt, aes(x=as.numeric(date),y=rate30,label=rate30))+
geom_line()+theme_bw()+
#scale_x_date(date_breaks="1 month", date_labels="%b-%y")+
#scale_y_continuous(limits=c(3,4.4),breaks=seq(3,4.4,.1))+
labs(x="", y="",
title="30-year Fixed Mortgage Rate (%)",
subtitle="weekly average rates",
caption="@lenkiefer Source: Freddie Mac Primary Mortgage Market Survey")+
theme(plot.title=element_text(size=18),
plot.caption=element_text(hjust=0))+
theme(panel.border = element_blank(),
panel.grid.major = element_blank(),
text=element_text(family="Palatino Linotype"),
panel.grid.minor = element_blank(),
axis.ticks.length=unit(0.25,"cm") ) +
### Use our sweet axis functions:
base_breaks_x_date(as.numeric(dt$date),dt$date) +
base_breaks_y(dt$rate30)
Make an animation
Let’s have some fun and make an animated version.
For smooth animations we’ll use tweenr. See my earlier post about tweenr for an introduction to tweenr, and more examples here and here.
We’ll have the axes expand as the data evolve.
library(tweenr)
myf<-function(dd,dmin=as.Date("2014-12-31"),
#Variable subt contains annotations in the subtitle frame
subt="Nothing",
keepdots="No"){
DT2<-copy(dt)
#set max to last value
DT2[date>dd,rate30:=dt[date==dd]$rate30]
DT2[date>dd,date:=dd]
#set min to first value
DT2[date<=dmin,rate30:=dt[date==dmin]$rate30]
DT2[date<=dmin,date:=dmin]
DT2[,subt:=label_wrap_gen(100)(subt)]
DT2$subt<-factor(DT2$subt)
DT2$keepdots<-factor(keepdots)
as.data.frame(DT2[, list(date,rate30,subt,keepdots)])}
tf <- tween_states(
list(myf(as.Date("2016-11-03"),as.Date("2015-12-31"),subt="rates fell throughout most of 2016 up to the U.S. general election..."),
myf(as.Date("2017-02-02"),as.Date("2015-12-31"),subt="...rising rapidly after the election...."),
myf(as.Date("2017-02-02"),as.Date("2012-12-27"),subt="...having declined after the Taper Talk in 2013...."),
myf(as.Date("2017-02-02"),as.Date("1971-04-02"),subt="...and after over 30 years of general decline."),
myf(as.Date("2015-12-31"),as.Date("2012-12-27"),subt="...rates entered 2016 above 4%, but..."),myf(as.Date("2016-11-03"),as.Date("2015-12-31"),subt="rates fell throughout most of 2016 up to the U.S. general election...")
),tweenlength= 3, statelength=1, ease=rep('cubic-in-out',2),nframes=110)
tf<-data.table(tf)
oopt = ani.options(interval = 0.15)
saveGIF({for (i in 1:max(tf$.frame)) {
dt3<-tf[.frame==i]
g<-
ggplot(data=dt3, aes(x=as.numeric(date),y=rate30,label=rate30))+
geom_line()+theme_bw()+
#scale_x_date(date_breaks="1 month", date_labels="%b-%y")+
#scale_y_continuous(limits=c(3,4.4),breaks=seq(3,4.4,.1))+
labs(x="", y="",
title="30-year Fixed Mortgage Rate (%)",
subtitle=tf[.frame==i,]$subt,
caption="@lenkiefer Source: Freddie Mac Primary Mortgage Market Survey")+
theme(plot.title=element_text(size=18),
plot.caption=element_text(hjust=0))+
theme(panel.border = element_blank(),
panel.grid.major = element_blank(),
text=element_text(family="Palatino Linotype"),
panel.grid.minor = element_blank(),
axis.ticks.length=unit(0.25,"cm") ) +
### Use our sweet axis functions:
base_breaks_x_date(as.numeric(dt3$date),dt3$date) +
base_breaks_y(dt3$rate30)
print(g)
ani.pause()
print(i)
}
},movie.name="rate_02_06_annotate.gif",ani.width = 500, ani.height = 350)