Data tables are Viz too

THOUGH 2016 IS NOT OVER YET I want to get a jump on my 2017 resolution: make better tables.

I’ve been re-reading this paper on the Rudiments of Numeracy by A. S. C. Ehrenberg published in the Journal of the Royal Statistical Society in 1977. Though the paper is nearly 40 years old, it still offers some valuable insights.

This little post makes a simple table displaying monthly averages for 30-year fixed mortgage rates. I use the htmlTable package for R to make the table.

Data

The data I’m going to use are estimates of weekly U.S. average 30-year fixed mortgage rates from the Primary Mortgage Market Survey from Freddie Mac. These data can be easily downloaded from the St. Louis Fred database here.

I have the data saved in a simple text file with a column for data, the mortgage rate, and helper columns week, month, and year, where week is the week number starting with the first week of the year.

Code for table

Now we’ll load the data, do some data manipulations and make our table. We’re going to add some additional styling to the table.

# load libraries
library(tidyverse,quietly=T)
library(xtable,quietly=T)
library(data.table,quietly=T)
library(htmlTable,quietly=T)

# load data on weekly mortgage rates:
pmms30yr <- fread("data/pmms30yr.txt")
pmms30yr$date<-as.Date(pmms30yr$date, format="%m/%d/%Y")

# create month name variable "mname"
pmms30yr[,mname:=as.character(date,format="%b")]

#Compute averages by year/month
pm<-pmms30yr[,list(rate=round(mean(rate,na.rm=T),2)),by=c("year","mname")]

# "spread" rates over month in a wide data frame and coerce to data.frame
pms<-data.frame(spread(pm,mname,rate))

# drop year column
pms2 <- pms[,-1]

# use the first column (year) as rownames 
rownames(pms2) <- pms[,1]

# reorder the columns to by month (Jan, Feb, etc) instead of alphabetically (Apr, Aug, etc.)
pms2<-pms2[,unique(pmms30yr[year>1971]$mname)]

# Compute annual averages
pm.a<-pmms30yr[,list(Avg=round(mean(rate,na.rm=T),2)),by=c("year")]

# Add annual averages to data
pm3<-cbind(pms2,pm.a[,2,with=F])
pm3<-format(pm3,digits=3)

# Apply conditiional formatting to 2016 December and Annual averages to reflect fact that
# data is incomplete for those dates

my.format<-function(x){paste0("<span style='color:darkgray; font-style:italic'>",x,"*</span>")}

# overwrite values with styling using <span> and CSS
pm3[47,12:13]<-lapply(pm3[47,12:13],my.format)

#replace 

#create htmlTable

htmlTable(
  caption= # use CSS styling for title
    "<span style='text-align: left; font-size:x-large; font-weight:bold'>30-year Fixed Mortgage Rates in Percentage Points</span>",pm3, 
  # right align numbers
  align="right",
  # apply zebra striping
  col.rgroup = c("none", "#F7F7F7"),
  # group columns by quarter
  cgroup = c("1st Quarter", "2nd Quarter","3rd Quarter","4th Quarter","Annual"),
  n.cgroup = c(3,3,3,3,1),
  # increase spacing for table
  css.cell = "padding-left: .5em; padding-right: .1em;",
  # group data by decade
  tspanner=c("1970s","1980s","1990s","2000s","2010s"),
  n.tspanner=c(9,rep(10,3),8),
  # add a footnote
  tfoot="Source: Primary Mortgage Market Survey, Average of weekly rates\nData through 12/27/2016, <span style='color:darkgray; font-style:italic'>*based on year-to-date values</span>"
          )
30-year Fixed Mortgage Rates in Percentage Points
1st Quarter  2nd Quarter  3rd Quarter  4th Quarter  Annual
Jan Feb Mar   Apr May Jun   Jul Aug Sep   Oct Nov Dec   Avg
1970s
1971 NA NA NA   7.31 7.42 7.53   7.60 7.70 7.69   7.63 7.55 7.48   7.54
1972 7.44 7.32 7.30   7.29 7.37 7.37   7.40 7.40 7.42   7.42 7.43 7.44   7.38
1973 7.44 7.44 7.46   7.54 7.65 7.73   8.05 8.50 8.81   8.77 8.58 8.54   8.04
1974 8.54 8.46 8.41   8.58 8.97 9.09   9.28 9.59 9.96   9.98 9.79 9.62   9.19
1975 9.43 9.11 8.90   8.82 8.91 8.89   8.89 8.94 9.13   9.22 9.14 9.10   9.05
1976 9.02 8.81 8.75   8.73 8.77 8.85   8.93 9.00 8.98   8.93 8.81 8.79   8.87
1977 8.72 8.67 8.69   8.75 8.83 8.86   8.94 8.94 8.90   8.92 8.92 8.96   8.85
1978 9.02 9.14 9.20   9.36 9.57 9.71   9.74 9.79 9.76   9.86 10.11 10.35   9.64
1979 10.39 10.41 10.43   10.50 10.69 11.04   11.09 11.09 11.30   11.64 12.83 12.90   11.20
1980s
1980 12.88 13.04 15.28   16.33 14.26 12.71   12.19 12.56 13.20   13.79 14.21 14.79   13.74
1981 14.90 15.13 15.40   15.58 16.40 16.70   16.83 17.29 18.16   18.45 17.82 16.95   16.64
1982 17.48 17.60 17.16   16.89 16.68 16.70   16.82 16.27 15.43   14.61 13.82 13.62   16.04
1983 13.25 13.04 12.80   12.78 12.63 12.87   13.42 13.81 13.73   13.54 13.44 13.42   13.24
1984 13.37 13.23 13.39   13.65 13.94 14.42   14.67 14.47 14.35   14.13 13.64 13.18   13.88
1985 13.07 12.92 13.17   13.20 12.91 12.21   12.03 12.19 12.19   12.13 11.78 11.26   12.43
1986 10.89 10.71 10.08   9.94 10.14 10.68   10.51 10.20 10.01   9.97 9.70 9.31   10.19
1987 9.20 9.08 9.04   9.83 10.60 10.54   10.28 10.33 10.89   11.26 10.65 10.64   10.21
1988 10.38 9.89 9.93   10.20 10.46 10.46   10.43 10.60 10.48   10.30 10.27 10.61   10.34
1989 10.73 10.64 11.03   11.05 10.77 10.20   9.88 9.98 10.13   9.95 9.77 9.74   10.32
1990s
1990 9.89 10.20 10.27   10.37 10.48 10.16   10.04 10.10 10.18   10.18 10.01 9.67   10.13
1991 9.64 9.37 9.50   9.49 9.47 9.62   9.57 9.24 9.01   8.86 8.71 8.50   9.25
1992 8.43 8.76 8.94   8.85 8.67 8.51   8.13 7.97 7.92   8.09 8.30 8.21   8.39
1993 7.99 7.68 7.50   7.47 7.46 7.42   7.21 7.11 6.92   6.83 7.16 7.17   7.31
1994 7.06 7.15 7.67   8.32 8.60 8.40   8.61 8.51 8.64   8.93 9.17 9.20   8.38
1995 9.15 8.83 8.46   8.32 7.96 7.57   7.61 7.86 7.64   7.47 7.38 7.20   7.93
1996 7.03 7.08 7.62   7.93 8.07 8.32   8.25 8.00 8.23   7.92 7.62 7.60   7.81
1997 7.82 7.65 7.90   8.14 7.94 7.69   7.50 7.48 7.43   7.29 7.21 7.10   7.60
1998 6.99 7.04 7.13   7.14 7.14 7.00   6.95 6.92 6.72   6.71 6.87 6.74   6.94
1999 6.79 6.81 7.04   6.92 7.14 7.55   7.63 7.94 7.82   7.85 7.74 7.91   7.44
2000s
2000 8.21 8.32 8.24   8.15 8.52 8.29   8.15 8.03 7.91   7.80 7.75 7.38   8.05
2001 7.03 7.05 6.95   7.08 7.14 7.16   7.13 6.95 6.82   6.62 6.66 7.06   6.97
2002 7.00 6.89 7.01   6.99 6.81 6.65   6.49 6.29 6.09   6.11 6.07 6.05   6.54
2003 5.92 5.84 5.75   5.81 5.48 5.23   5.63 6.26 6.15   5.95 5.93 5.88   5.83
2004 5.71 5.63 5.45   5.83 6.27 6.29   6.06 5.87 5.75   5.72 5.73 5.75   5.84
2005 5.71 5.63 5.93   5.86 5.72 5.58   5.70 5.82 5.77   6.07 6.33 6.27   5.87
2006 6.14 6.25 6.32   6.51 6.60 6.68   6.76 6.52 6.40   6.36 6.24 6.13   6.41
2007 6.22 6.29 6.16   6.18 6.26 6.66   6.70 6.57 6.38   6.38 6.21 6.09   6.34
2008 5.76 5.92 5.97   5.92 6.04 6.32   6.43 6.48 6.04   6.20 6.09 5.29   6.03
2009 5.05 5.13 5.00   4.81 4.86 5.42   5.22 5.19 5.06   4.95 4.88 4.93   5.04
2010s
2010 5.03 4.99 4.97   5.10 4.89 4.74   4.56 4.43 4.35   4.22 4.30 4.71   4.69
2011 4.75 4.95 4.84   4.84 4.64 4.51   4.54 4.27 4.11   4.07 3.99 3.96   4.45
2012 3.92 3.89 3.95   3.91 3.80 3.67   3.55 3.60 3.50   3.38 3.35 3.34   3.66
2013 3.41 3.53 3.56   3.45 3.54 4.07   4.37 4.46 4.49   4.19 4.25 4.46   3.98
2014 4.43 4.30 4.34   4.34 4.19 4.16   4.13 4.12 4.16   4.04 4.00 3.86   4.17
2015 3.67 3.71 3.77   3.67 3.84 3.98   4.05 3.91 3.89   3.80 3.94 3.96   3.85
2016 3.87 3.66 3.69   3.60 3.60 3.57   3.44 3.44 3.46   3.47 3.77 4.20   3.65
2017 4.15 NA NA   NA NA NA   NA NA NA   NA NA NA*   4.15*
Source: Primary Mortgage Market Survey, Average of weekly rates
Data through 12/27/2016, *based on year-to-date values

Data tables are viz too

Data tables are a data visualization too. Artful tables can achieve as much or more than fancy statistical graphs. Check back in this space as I explore more ways to construct tables and deploy them together with other data visualization techniques I’ve been exploring here..

 Share!