Microbreweries and Interactive Maps With Leaflet
This post is about interactive data visualizations and some powerful new tools that are available to the R community. Moving beyond static data graphics toward interactive experiences allows us to present our audience with much more complex information in an easily digestable way. To empower these interactive graphics, we're going to utilize tools such as HTML and javascript, technologies that drive the web-based interactive experiences you have every day. But the best part is that we'll benefit from these technologies without having to learn anything about web development. We're going to create some amazing things using only R!
As a guiding example, I'm going to revist a post from Paul at spatioanalytics. In that post, Paul visualized the locations of microbreweries in Virginia using Plotly, a super cool company that allows you to create and deploy interactive graphics on their web-based service. Here, we're going to do this all ourselves, with help from a new R package called leaflet. So let's jump right in.
Here's some boiler-plate stuff. We need to install the package manually from github and then load it.
devtools::install_github("rstudio/leaflet") library(leaflet) library(ggmap)
So first thing, let's grab some location that we might want to put on a map. I'll use a function from the ggmap package.
somePlace <-ggmap::geocode("Washington,DC") somePlace > somePlace lon lat 1 -77.03687 38.90719
So we have a dataframe (with one row) and lat/lon coordinates for some arbitrary point in Washington, DC. We're going to use functions from the leaflet package to generate a map around this point.
leaflet(somePlace) %>% addTiles() %>% addMarkers()
Now we have this draggable, zoomable, interactive map with a single line of R!
A little explanation of what we just did. In case it's unfamiliar, I'll first point out that we're using the forward pipe %>% thing. The forward pipe was introduced in the magrittr package and has now been adopted in lots of places. The idea is that we can pass the output of a function as the input to the next function. This allows us to write code that reads left to right and is more aligned with our logic. For example,
# this is nested and confusing, we have to read it inside-out sqrt(sum(c(1,2,3))) # this is sequential and awesome, it reads left to right c(1,2,3) %>% sum() %>% sqrt()
So back to leaflet. The first funciton we use is called leaflet() and this returns a base leaflet object, sort of the starting point for everything we might do. We passed our data frame as an argument to leaflet(), and so any later functions that might require data will look to this data frame.
We then sent the output of leaflet() to another function, addTiles(). This is because the output of leaflet() doesn't have enough visual information to actually create a map - we haven't provided enough detail yet about what we want. The function addTiles() updates the leaflet object by providing the visual look and feel through different "tiles". In fact, there's many different styles of map we could make, just by choosing different tiles. Here's some examples.
leaflet(somePlace) %>% addProviderTiles("Stamen.Watercolor") %>% addMarkers()
leaflet(somePlace) %>% addProviderTiles("Stamen.Toner") %>% addMarkers()
The full list of available tiles is here.
And so the third function in this simple example is addMarkers(). This function's purpose is pretty obvious and results in the big blue marker thing on the map. What it does is look through the provided data frame for any columns that are similar to "lat" or "lon" and then plots them. And it'll do so for every row in the data frame, so it's effortless to put lots of points on a map, as we'll see below. There are also a few other other functions that are similar and plot slightly different things. You might be able to guess what addCircles() or addPolyLines() are capable of, but as an example,
leaflet(somePlace) %>% addProviderTiles("Stamen.Toner") %>% addCircles(radius=400,color='firebrick')
So let's move on to our more interesting example - the breweries. I've scraped a list of microbreweries in Virginia and gotten their names, websites, addresses and so. Since I want lat/lon info as well, I've used ggmap::geocode() to estimate those as well. The result is a dataframe called 'breweries' that has 106 rows and looks like this.
> names(breweries) [1] "Name" "Address" "Phone" "Website" "lat" "lng" > head(breweries[,c(1,4:6)]) Name Website lat lng 1 Wolf Hills Brewing Co www.wolfhillsbrewing.com 36.71231 -81.96560 2 Blue Mountain Brewery www.bluemountainbrewery.com 37.96898 -78.83499 3 Quattro Goomba Brewery www.goombabrewery.com/ 38.98597 -77.61748 4 Hops Grill & Brewery www.hopsonline.com 38.83758 -77.05116 5 Port City Brewing Co www.portcitybrewing.com 38.80800 -77.10137 6 Loose Shoe Brewing Co www.looseshoebrewing.com 37.56500 -79.06352
So let's put em on a map.
leaflet(breweries) %>% addTiles() %>% addMarkers()
Pretty effortless I'd say! This is great except we don't know which brewery is which, it's just anonymous points on a map. We could try to add some text to a map, but remember our goal is to utilize web-based interactivity. So we're going to take advantage of a click-based popup by inserting the Name column of the data frame.
leaflet(breweries) %>% addTiles() %>% addMarkers(popup=breweries$Name)
And one final trick to make it just a little smoother. We want to add a hyperlink to the website in the popup. Since our data frame has a column for all the websites, we could do this easily in a similar way to what we just did with the Name column. But we can take it a step further. Now I promised you that we don't need to know any web development stuff in order to make these maps (and we don't!). But if you happen to have a little side knowledge, you can embed any HTML or javascript that you want. In this case, I'm going to use HTML's < a > tag for hyperlinks, so that each brewery name actually links out to its website.
popup_style<-paste0("<a href=http://",breweries$Website," target='_blank'>",breweries$Name,"</a>") leaflet(breweries) %>% addTiles() %>% addMarkers(popup=popup_style)
Now we can easily zoom around and explore Virginia's thriving craft-brew industry! You have to admit that's a pretty awesome thing we were able to create with just a couple lines of R. And the interactivity allows us to encode a lot information (locations, names, and website of all the breweries) in a simple exerience that any viewer can explore at their own pace. As you might guess, this is just the beginning of what we can do with leaflet, and there's a great guide at RStudio's site.
If you're like me, you're very excited about incorporating web-based interactivity in your data analyses with R. This general idea of wrapping javascript-based experiences into an easy-to-use R package is something that's gaining a lot of traction lately. To me, this is one of the most exciting innovations in the R community in the last couple years and is taking off in many exciting directions. If you want to learn more, I'm developing a course for DataSociety entitled "Advanced Visualization With R". In the course, we'll explore many of these web-based technologies including Leaflet, rCharts, Shiny and more, so look to sign up later this summer!