R Highcharts: How to Make Interactive Maps for R and R Shiny

Reading time:
time
min
By:
Dario Radečić
April 25, 2024

R Shiny needs no introduction, as it’s one of the go-to frameworks for building amazing applications and dashboards. But most of them lack one thing - interactivity and motion. Truth be told, R’s standard visualization packages such as ggplot2 aren’t interactive, so that’s the main reason why.

Enter R Highcharts - a free package for making interactive and animated visualizations, straight from R! We’ve already discussed in our introduction article, drilldown article , and a dedicated Shiny article, so this one will serve as icing on the cake, as you’ll learn how to add interactive maps to your applications.

After reading, you’ll know how to make choropleth and bubble maps in R and R Shiny. We have a lot of ground to cover, so let’s dig in!

Looking to add interactive Google Maps to your Shiny app? Read our guide to find out how.

Table of contents:

How to Make Choropleth R Highcharts Maps

You can think of choropleth maps as a type of thematic map in which certain areas are shaded or patterned in proportion to the value of a variable being represented. 

Let’s say you’re a restaurant chain owner in the US and operate in numerous locations across all 50 states - you can use choropleth maps to visually represent the number of restaurants in each state. The darker the shade of color, let’s say blue, the more restaurants you have running there.

We’ll showcase something similar in this section.

The Dataset

To make our choropleth map with R Highcharts maps, we’ll use the US Airports List Dataset:

Image 1 - US airports dataset

In plain English, it shows the name and geolocation of each airport in the United States and also groups them by state. Sounds like a perfect use case for choropleth maps, doesn’t it?

Download the dataset CSV file and load it into R. Simply copy the following snippet - it will also get rid of a couple of missing values:

library(highcharter)
library(dplyr)


airports <- read.csv("airports.csv")
airports <- na.omit(airports)

head(airports)

Here’s what you should end up with:

Image 2 - Head of the US airports dataset in R

You now have everything needed to start building R Highcharts choropleth maps, so let’s start with that in the following section.

Base Highcharts Map

The idea now is to start small and continuously build up. You need a base map to get started and the one covering the United States sounds like a perfect candidate.

If you need more map options, make sure to check out the official website. Simply click on the region you’re interested in, open the example, and copy the relevant part of the URL.

For our case, `countries/us/us-all` sounds like a perfect candidate. Let’s wrap it into a call to `hcmap` to see what happens:

hcmap("countries/us/us-all", showInLegend = FALSE

This is the output you’ll get:

Image 3 - Base United States map

The foundation is there, but we have to build on it. No data is shown currently, and we have no idea what we’re representing. To solve this last issue, let’s add a title and subtitle:

hcmap("countries/us/us-all", showInLegend = FALSE) |>
  hc_title(text = "United States of America") |>
  hc_subtitle(text = "Airports in the USA")
Image 4 - Adding title and subtitle

You now know what you should be looking at, but the data isn’t there yet. Let’s fix that next.

Choropleth Map with Individual State Coloring

The idea now is to group the data by `STATE` and display the number of airports in each. To be more precise, we want to color each individual state. The darker the shade, the more airports the state has.

The `count()` function from `dplyr` does both the grouping and summarization for us:

count_by_state <- airports %>%
  count(STATE, sort = TRUE)

head(count_by_state)

Here are the results:

Image 5 - Airport count by state subset

Now in `hcmap()`, you can provide values for `data` and `value` parameters. Pass in your data frame and specify which column represents the values that will be used for coloring. The optional `name` parameter is here to change the series name on a tooltip, but more on that later.

Anyhow, here’s the updated snippet:

hcmap(
  "countries/us/us-all",
  showInLegend = FALSE,
  data = count_by_state,
  value = "n",
  name = "State"
) |>
  hc_title(text = "United States of America") |>
  hc_subtitle(text = "Airports in the USA")

Now we’re getting somewhere:

Image 6 - Coloring individual states

The above results are fine, and you can even see the counts when you hover over individual states.

But let’s kick things up a notch. We now want to display state names and draw a distinct line between individual states. This will further enrich the end result and will eliminate all the guesswork from the final user.

The `dataLabels`,`borderColor`, and `borderWidth` parameters are what you’re looking for. The last two are intuitive to understand, but the first needs some explanation. Here, you first need to enable labels and then specify what you want to see on it. Passing in `{point.name}` will return the name of the state in this case:

hcmap(
  "countries/us/us-all",
  showInLegend = FALSE,
  data = count_by_state,
  value = "n",
  name = "State",
  dataLabels = list(enabled = TRUE, format = "{point.name}"),
  borderColor = "#000000",
  borderWidth = 0.5
) |>
  hc_title(text = "United States of America") |>
  hc_subtitle(text = "Airports in the USA")

The map is looking much better now:

Image 7 - Adding labels to states

Next, let’s work on the tooltip. The goal is to take maximum control over what’s shown to the user when they hover over individual states. To keep things simple, we’ll only change the suffix through the `valueSuffix` modifier. If you need to, you can also tweak the `valuePrefix` and `valueDecimals` modifiers, but these aren’t applicable in our case.

Here’s the updated snippet:

hcmap(
  "countries/us/us-all",
  showInLegend = FALSE,
  data = count_by_state,
  value = "n",
  name = "State",
  dataLabels = list(enabled = TRUE, format = "{point.name}"),
  borderColor = "#000000",
  borderWidth = 0.5,
  tooltip = list(
    valueSuffix = " airport(s)"
  )
) |>
  hc_title(text = "United States of America") |>
  hc_subtitle(text = "Airports in the USA")

You can see the code change taking effect when hovering over individual states:

Image 8 - Tooltip customization

And finally, let’s discuss color. There’s no easy way to change the continuous color scale, unfortunately, so you’ll have to get creative. The `color_stops()` function returns a list of `n` colors you can pass into `hc_colorAxis()`. That’s the only way to modify the color of a choropleth map in R Highcharts.

Setting `n = 2` will give us a nice purple-to-yellow color palette:

hcmap(
  "countries/us/us-all",
  showInLegend = FALSE,
  data = count_by_state,
  value = "n",
  name = "State",
  dataLabels = list(enabled = TRUE, format = "{point.name}"),
  borderColor = "#000000",
  borderWidth = 0.5,
  tooltip = list(
    valueSuffix = " airport(s)"
  )
) |>
  hc_title(text = "United States of America") |>
  hc_subtitle(text = "Airports in the USA") |>
  hc_colorAxis(stops = color_stops(n = 2))

This is our final map:

Image 9 - Color customization

And that’s about it when it comes to choropleth maps in R Highcharts. The other common type is a point map (bubble map), so let’s explore how to work with it next.

How to Add Points to R Highcharts Maps

Bubble maps allow you to add individual markers, or data points, directly to the base map. These are fantastic for our dataset if we want to display the location of individual airports, instead of the overall counts.

Dataset Modifications

First things first, you’ll need to modify the underlying dataset. You now need access to `lat` and `lon` attributes, since these are required to determine the map location of individual airports. Let’s also keep track of the three-letter airport abbreviations and full names:

point_data <- data.frame(
  name = airports$IATA,
  full_name = airports$AIRPORT,
  lat = airports$LATITUDE,
  lon = airports$LONGITUDE
)

head(point_data)

You should end up with the following dataset:

Image 10 - Subset for bubble map

That’s all you need to get started with bubble maps with R Highcharts! Let’s explore the basics next. 

Create and Style Bubble Maps with R Highcharts

In Highcharts, you can create a bubble map by calling the `hc_add_series()` function and specifying the map `type` as `mappoint`. Also, pass in your dataset, and the library will figure out everything else for you:

hcmap("countries/us/us-all", showInLegend = FALSE) |>
  hc_add_series(
    data = point_data,
    type = "mappoint",
    name = "Airports"
  )

Now we’re getting somewhere:

Image 11 - Bubble map with airport locations

You now have the data points, but hovering over them reveals a mess. It’s a collection of useless data, and you have to change it.

We’ll get more detailed in a call to `tooltip`. The `pointFormat` attribute can accept HTML tags, which means you can take ultimate control over how things look like. We’ll use it to make the first line bold and also to split the contents into multiple lines.

The modified tooltip will show the airport's abbreviated name, full name, and geolocation rounded up to four decimal places:

hcmap("countries/us/us-all", showInLegend = FALSE) |>
  hc_add_series(
    data = point_data,
    type = "mappoint",
    name = "Airports",
    tooltip = list(
      pointFormat = "{point.name} - {point.full_name}
Location: ({point.lat:,.4f}, {point.lon:,.4f})" ) )

The map still looks the same, but hovering over data points reveals a night and day difference:

Image 12 - Tooltip customization

And finally, let’s discuss coloring. The `color` attribute can accept a variety of things, but since we’re showcasing individual locations, it’s best to keep things simple and use one color only. Appsilon’s blue works like a charm:

hcmap("countries/us/us-all", showInLegend = FALSE) |>
  hc_add_series(
    data = point_data,
    type = "mappoint",
    color = "#0090f9",
    name = "Airports",
    tooltip = list(
      pointFormat = "{point.name} - {point.full_name}
Location: ({point.lat:,.4f}, {point.lon:,.4f})" ) )

This is the final R Highcharts bubble map:

Image 13 - Bubble point color customization

You now know how to create choropleth and bubble maps with R Highcharts, but we still haven’t discussed R Shiny implementation. Well, that’s about to change.

R Highcharts Maps in R Shiny - How to Get Started

The R Shiny application you’re about to build is quite straightforward. It allows the user to change the marker color and add/remove states from the visualization. Not the most useful app, sure, but serves perfectly to showcase how to integrate R Highcharts maps with R Shiny.

Here are R Highcharts specifics you should know:

  • `highchartsOutput()` - Use this function in your `ui` to create a placeholder for your Highcharts visualization, either a chart or a map.
  • `renderHighcharts()` - Use it in `server()` to build a map from reactive datasets/values.

In the `server()` function, you’ll also want to make the dataset and marker color reactive. For the latter, we’re allowing the user to select one of three named colors from the dropdown menu, so `marker_color` needs to map the English name to hex color values.

When it comes to the dataset, you’ll want to use the `%in%` operator to show only the states the user has selected in a multi-select input.

The rest of the code snippet is standard Shiny stuff:

library(shiny)
library(dplyr)
library(highcharter)

airports <- read.csv("airports.csv")
airports <- na.omit(airports)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      tags$h3("Highcharts Maps"),
      # Control the marker color
      selectInput(inputId = "inColor", label = "Marker color:", choices = c("Red", "Yellow", "Blue"), selected = "Blue"),
      # Control the states that are shown on the map
      selectInput(inputId = "inState", label = "States:", choices = sort(unique(airports$STATE)), selected = sort(unique(airports$STATE)), multiple = TRUE)
    ),
    mainPanel(
      highchartOutput(outputId = "chartUSAMap", height = 500)
    )
  )
)

server <- function(input, output) {
  # Hold the dataset as a reactive value in which states are filtered based on user input
  data <- reactive({
    data.frame(
      name = airports$IATA,
      full_name = airports$AIRPORT,
      state = airports$STATE,
      lat = airports$LATITUDE,
      lon = airports$LONGITUDE
    ) %>%
      filter(state %in% input$inState)
  })

  # Map string color name to its hex code
  marker_color <- reactive({
    switch(input$inColor,
      "Red" = "#f90047",
      "Yellow" = "#f9d400",
      "Blue" = "#0090f9"
    )
  })

  # Render chart
  output$chartUSAMap <- renderHighchart({
    hcmap("countries/us/us-all", showInLegend = FALSE) |>
      hc_add_series(
        data = data(),
        type = "mappoint",
        color = marker_color(),
        name = "Airports",
        tooltip = list(
          pointFormat = "{point.name} - {point.full_name}
Location: ({point.lat:,.4f}, {point.lon:,.4f})" ) ) }) } shinyApp(ui = ui, server = server)

Here’s what you’ll see after running the app:

Image 14 - R Shiny app with R Highcharts maps

It could use some visual tweaking, but that’s a topic for another time. For now, we can safely conclude that R Highcharts maps have no trouble integrating with R Shiny, so you can have no doubt about using them in your projects.

Summing up R Highcharts Maps

When it comes to building engaging R Shiny apps, interactivity is the key. There’s no reason to opt for static charts if animated and interactive packages exist. R Highcharts is one of these packages, and you now know everything you need to produce full-fledged data-driven dashboards showcasing maps and charts.

Stay tuned to the Appsilon blog and our newsletter, Shiny Weekly, for further guides and tips on R Shiny and Highcharts, as there sure is plenty more to come.

Another superb R package for spatial visualization is Leaflet - Read our detailed guide to get started.

Have questions or insights?

Engage with experts, share ideas and take your data journey to the next level!

Is Your Software GxP Compliant?

Download a checklist designed for clinical managers in data departments to make sure that software meets requirements for FDA and EMA submissions.

Sign up for ShinyWeekly

Join 4,2k explorers and get the Shiny Weekly Newsletter into your mailbox
for the latest in R/Shiny and Data Science.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Explore Possibilities

Share Your Data Goals with Us

From advanced analytics to platform development and pharma consulting, we craft solutions tailored to your needs.

Talk to our Experts
data visualization
shiny