I’ve been developing my mapping skills in R for a couple of months now. I started off using a couple of different packages but was quickly drawn to
mapshot function in the
mapview package available on CRAN).
This blog post aims to persuade you as to the merits of
leaflet especially when combined with shiny facilitating the development of some powerful apps for your users to explore data with. To demonstrate I simulate some data and pose a question: how do
X2 vary between schools within Local Education Authorities (LA) in England?
App - Cherry Picker
A Shiny app for mapping School specific variables by Local Education Authority with Leaflet in R.
The live app
App-cherry_picker allows the user to investigate correlations between two made-up variables (we call them
pears [stairs], more interesting names than
X2) drawn from a uniform distribution.
It demonstrates how cherry picking, or finding data that supports your viewpoint (and ignoring data that does not) can be easily done even with two totally uncorrelated variables. We also use this appletunity for fruit related puns or punnet-try.
Use the app
Give it a try: App-cherry_picker.
Clone the code
The code looks complicated right? Shiny can be tricky as it can be more difficult to debug than regular R. However, it’s not so bad, the code is developed iteratively, it’s not written in one session. Make sure you know what the end user wants and show it to them frequently for feedback. Gradually your app ‘ll evolve to meet the needs of the user. The interactivity is worth the extra effort and there are plenty of good tutorials available!
I started this app development by going to the Shiny gallery and copying code from an app which looked similar to the desired app I had in mind. You can do the same by copying my code as a starting point.
Use version control
Prior to app development of your own, make sure you are using version control such as git. Use Github (a repository hosting site; see here for the difference between git and Github) or other sites to share your code. This will make life a lot easier as explained here.
Shiny is special
Shiny is a package that contains a set of functions to build web applications within R. However, bear in mind:
- for the correct use of its functions, files need to be organised appropriately (note the ui, server and global files found within an App prefixed folder).
- the syntax of its functions are slightly different to base R.
ui.R is the app’s frontend and the
server.R is the backend (more detail).
global.R has its own niche uses such as pre-loading packages and data that can be used both in
server.R. For example, in my app I use it to read in all the core datasets and prepare the mapping data. I also call a custom function which is used to plot a school Marker on the Leaflet map.
Here we have one of the tabs that you can navigate to. This
tabPanel is one of four in the app that are contained within the
navbarPage (see ui.R). Each
tabPanel is seperated from one another by commas. It’s important to lay out your code sensibly to avoid misplacing a comma, fortunately R Studio takes care of this for you.
Note the use of HTML builder functions (e.g.
h4()) for constructing HTML documents (the output is an intereactive webpage).
Shiny is all about reactivity. The user picks a new LA of interest and the app adapts. The
selectInput is the important feature here that provides teh user the choice of LA and phase of schools. The user is provided with a list of schools through the
global.R assigned object
la_user_friendly_list. They pick the LA and that string can now be called by the
We use this information to filter our fruits (
pears joined data from
global.R) all-schools dataframe (including geospatial goordinates) and create a reactive object called
ks4_to_map() (this is vestigial name). In the following code we filter our dataframe by splitting the input string and extract the numeric LA Code (e.g. “202 - Camden” to 202). Thus any schools of that LA are filtered and further filtered by school phase and complete cases.
Great, we have the schools we need to plot in our LA. To provide the national perspective we can draw a histogram of all the school data using our
fruits dataframe object and then use our reactive object
ks4_to_map to add a
rug() of blue ticks to the bottom. Note how we assign this object, which is based on a reactive object, to
renderPlot renders a reactive plot that is suitable for assigning to an output slot.
Thus to render this object in the
ui.R we use the shiny function
plotOutput. You can find this line of code in the
absolutePanel in the
The same principles apply for creating the map, the
ks4_to_map() reactive object is transformed into a spatial points dataframe object called
ks4_sp_ll. Importantly we need to convert the esoteric northings and eastings, used by OS in the UK, to latitude and longitude. The credit for this solution should go to this tutorial.
Now we render the reactive leaflet object by assigning the output slot
output$mymap using the function
renderLeaflet. The online help is very good for Leaflet so I won’t go into all the details here. In the interactive map you can change the map tile set, plot circles for the different variables on and off, have the apples displayed and the pears variable as an outline, use markers to identify school names on the maps.
This package also facilitates row selection, so the user can click on schools of interest and explore them further. Here we use selected rows to help us in our cherry picking exercise. By clicking on potential cherries (i.e. where both apples and pears are relatively high) in the “Data Explorer” tab, this then draws red circles on a scatterplot of all schools’ apples and pears data for those highlighted schools. Does your selected school make it into the cherry picking region?
As you interact with the DT table (e.g.sort columns, search the table, or navigate through pages), DT will expose some information about the current state of the table to Shiny. At the moment, this information is available in the input object of the Shiny server function (suppose the table output id is
tableId). The important bit in the code is the suffixing of
_rows_selected on the
tableId (in this case creating
fruit_table_data_rows_selected), explained here.
People like Excel, let them save app outputs so that they can then open them in Excel.
Try it yourself
Try cloning my repo and replacing the data within the apples and pears columns in both of the respective csv files with some school data of interest (match on the URN). Then run the school_data_write_as_rds.R to write the data as the more memory efficient RDS (there’s no reason your app can’t directly read in the data as a csv). Now you have a similar app that will produce a map of your two variables of interest; albeit still called apples and pears! From this starting point you can continue to add and remove features to get your app into the user desired shape.
The future’s bright, the future’s Shiny!
Shiny map apps are awesome and can be useful for spotting patterns in data that might be worth a more robust statistical follow up investigation. It’s important to protect oneself from cherry picking for a unconciously favoured hypothesis as demonstrated with this app, where one could pick out numerous schools that are high for both apples and pears. If one only presented these schools in a discussion, one might think that there was good evidence for banning apples in schools. At the least to prevent everything from going pear shaped!