Diving into the R/Shiny code that defines the new NN ACS Download Tool
This content was presented to Nelson\Nygaard Staff at a Lunch and Learn webinar on Thursday, September 30th 2021, and is available as a recording here and embedded below.
Today we are diving into the code behind the current version (as of this presentation) of the NN ACS download tool. I’ll start by demoing the basic features of the tool.
The code for this tool is available within the following GitHub repository: https://github.com/PerkinsAndWill/nn-census-tools/tree/master/nn-acs-download
The tool provides an interface for downloading American Community Survey (ACS) data typically used in Nelson\Nygaard analyses. Currently, only 5-year estimates are available through the tool. Data is available at the country, tract, and block group level for 2010 - 2019 (as tables are available for particular years). More features and variables will continue to be added to the tool, please request features by taking this short survey. You can download the data with or without geometries (i.e. shapefiles), and you must join the data yourself after making any edits (if neccessary) to the tabular data.
This tool is a good opportunity to demonstrate the use of reactive elements within Shiny, as well as to give a refresher on the use of tidycensus
.
Here are all the different types of reactive elements I use in this application. Some of these you may have seen before, and some may be new. More information on all of these is provided in the excellent new book, Mastering Shiny by Hadley Wickham (available for free online).
observe({})
observe()
is the most generic reactive element – with it you create a reactive context where other reactive elements are monitored for changes. If one of those reactive elements changes (triggering the observe()
context), then all the code nested within the curly braces ({}
) runs. Any reactive element that is not isolate
d will be a trigger for an observe()
context. It is the most uncontrolled type of reactive element, and therefore is pretty flexible but can also cause issues if you are not careful.
observeEvent(<event>,{})
observeEvent()
is like observe()
, but it is only triggered when specific reactive elements (usually inputs) have their values change. You will often see in applications I have designed in the past that I use an actionButton
to trigger code, so that all that code is not running every time any input changes, but only when a particular button (e.g., Execute Filters) is pushed. This has benefits and drawbacks. It is likely, depending on the complexity of your app, that you will use a combination of observe()
and observeEvent()
.
render___({})
There are many render____()
functions that render plots, maps, tables (e.g., renderLeaflet()
and renderDT()
used here) to the appropriate output
slot specified in the UI. These are reactive to changes in input
s or any other reactive elements, unless those elements are isolate
d. In this code, I have the map render function (renderLeaflet
) responding to changes in the states selected only. Other changes are handled by an observeEvent
which directs the use of the leafletProxy()
function, which can update previously rendered maps in real time. It is important to be intentional about which elements will re-trigger a render___()
function to activate.
reactive({})
The use of the reactive()
function creates a single object (as the result of a block of code) that will change in response to any triggers specified within that block of code. I did not use any of these in this application, but they are useful when you have a series of steps that need to be executed with reactivity available at each step. Note that calls to reactive elements require parentheses after the name (e.g., my_reactive()
as opposed to my_reactive
) – this asks for the value of the reactive, rather than just referring to the name of the reactive, which can be useful if you are passing it within a function to be called at a later time.
ReactiveValues()
I use a reactiveValues()
object to store user selections (called user_selections
in the code) as they are toggled within the application. A reactiveValues()
object can be used like a list to store arbitrary data structures that can then be observed and updated. In this case, I have a limited set of names I am accessing within the user_selections
object. They are the following:
Direct user inputs
years_selected
: Years (of estimates) selected in picker by user.
voi_selection
: Selected variables of interest, selected by user from picker or table.
county_geoids
: Selected county geoid
s, selected by user from picker or leaflet map.
geog_level
: Geography level of estimate selected by user from radioGroupButtons
.
user_email
: Email of user typed into textInput
.
geom_include
: Boolean value corresponding to checkboxInput
where user indicates if they want to include geometry in download.
Information for county display map
state_ids
: FIPS identifiers for states selected by user in picker to generate county map. Used for filtering state/county data.
state_names
: State names selected by user in picker to generate county map.
state_county_meta
: Metadata table with identifiers and names for each county.
state_county_geoms
: Geometry for each county represented on map.
I won’t write too much on this here, as I have addressed this API at length in a previous webinar (September 17th, 2020 webinar focused on census data) and it is well addressed by the following resources:
Analyzing US Census Data: Methods, Maps, and Models in Rby Kyle Walker (available in web format for free or will be sold in print format)
4-hour DataCamp course on analyzing U.S. Census Data in R, taught by Kyle Walker
That said, I will walk through how the API is called within the ACS querying functions, and how I rename and modify variables for expected use within NN-specific analyses.
I will fill this in with miscellaneous questions received during the webinar.
This content was presented to Nelson\Nygaard Staff at a Lunch and Learn webinar on Thursday, September 30th, 2021, and is available as a recording here and embedded above.