TidyTuesday: Housing Prices
Feb 5, 2019
Christopher Yee
2 minute read

Instead of a static visualization I decided to build a barebones Shiny app this week. The purpose is to improve the interactivity of the final output - one of my 2019 goals to level up advanced R knowledge. You can find the full code here.

Analyzing data for #tidytuesday week of 2/5/2019 (source)

# LOAD PACKAGES
library(tidyverse)
library(scales)
library(shiny)

state_hpi_raw <- read_csv("https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2019/2019-02-05/state_hpi.csv")

Process the raw data

state_hpi <- state_hpi_raw %>%
  group_by(state, year) %>%
  summarize(us_avg = mean(us_avg),
            price_index = mean(price_index)) %>%
  mutate(pct_diff = (price_index / us_avg) - 1,
         segment = ifelse(pct_diff > 0, 'above', 'below'),
         segment = str_to_title(segment))

Build the UI level

  • Include a drop down menu to select output data by state abbreviation
ui <- fluidPage(
  "Housing Price Index: US Average vs State",
  selectInput(inputId = "select_state",
              label = "Choose a state",
              c(state.abb)),
  plotOutput("hpi1"),
  plotOutput("hpi2")
)

Build the server level

  • Plot 1: Time series for a given state average annual housing price index compared to the US average
  • Plot 2: Time series for the percentage difference of a given state housing price index against the US average
server <- function(input, output, session) {
  
  output$hpi1 <- renderPlot({
    state_hpi %>%
      filter(state == input$select_state) %>%
      group_by(year, state) %>%
      summarize(price_index = mean(price_index),
                us_avg = mean(us_avg)) %>% 
      ggplot() +
      geom_line(aes(year, price_index), size = 2, color = 'steelblue') +
      geom_col(aes(year, us_avg), alpha = 0.3, fill = 'grey54') +
      theme_bw() +
      labs(x = NULL,
           y = "Housing Price Index") + 
      theme_bw(base_size = 15) + 
      scale_y_continuous(limits = c(0,300)) 
  })
  
  output$hpi2 <- renderPlot({
    state_hpi %>%
      filter(state == input$select_state) %>%
      ggplot() + 
      geom_col(aes(year, pct_diff, fill = segment), alpha = 0.8) +
      geom_hline(yintercept = 0, lty = 'dashed') +
      scale_fill_brewer(palette = 'Set1', direction = -1) +
      scale_y_continuous(labels = percent_format(round(1))) +
      theme_bw(base_size = 15) +
      theme(legend.position = 'top') +
      labs(x = NULL,
           y = "Difference to US Average",
           fill = NULL)
    })  
}

Build the app level

shinyApp(ui, server)

Check out the final production build here

Future versions

Shiny was easier to use than expected and I look forward to building out this dashboard in the coming weeks. Here are some additional features I plan to include:

  • Geospatial data
  • Multiple facet selection
  • Break out sections for improved readability
  • Metric cards
  • Dynamic filtering for top_n values