1 Maps with basemaps

1.1 Introduction

In this chapter, you’ll learn how to use Mapbox to create interactive and static maps with basemaps.

We’ll use the following libraries and data.

library(tidyverse)
library(leaflet)
library(leaflet.mapboxgl)
library(sf)

africa <- read_sf("data/countries/africa.geojson")

leaflet.mapboxgl is on CRAN. You can install the package from GitHub by running the following line of code in the console.

remotes::install_github("rstudio/leaflet.mapboxgl")

1.1.1 Basemaps

You already know how to create static maps with geom_sf().

africa %>% 
  ggplot() + 
  geom_sf()

In the above plot, geom_sf() draws the boundaries represented in the geometry column. This map is informative, but sometimes you’ll want to plot your geospatial data on top of other features. For example, say we wanted a map of Africa with country names, major cities, rivers, streets, and lakes. We could incorporate this information by adding data sources to our ggplot2 plot, but this could quickly get time-consuming, and our data would start to take up a lot of space.

Luckily, there are easier ways of adding basemaps to your maps. A basemap is just a map that lies underneath the data you want to visualize. Basemaps can include any number of features. For example, a basemap could just be a satellite image, or could include features like rivers, streets, and geographic boundary names.

Here’s an example basemap from Mapbox, whose basemaps and tools we’ll use in this chapter.

Mapbox’s basemaps are interactive, and include more detail as you zoom in. For example, if we zoom in on Senegal, we’ll be able to see specific cities and some bodies of water.

If we zoom in further on Dakar, the basemap will include roads and airports.

Basemaps add context to your geospatial data and provide common elements you can use across different data sets. In this chapter, we’ll visualize the location of cholera deaths and water pumps on top of a basemap, allowing us to see the street locations of the deaths and water pumps.

In this chapter, we’ll use Mapbox to create both interactive and static maps that include basemaps. We will begin by using Mapbox Studio to create interactive maps and then use the Mapbox Static API to turn these interactive maps into PNG images.

1.1.2 Tiles

With interactive web maps, it is usually possible to both zoom and move around the map, which means you’ll only ever see a portion of the map at a time. Web maps handle this functionality by using tiles. Each tile contains data for a specific square sub-region of a map, and there are different sets of tiles for different zoom levels.

There are two types of tiles: raster and vector. Raster tiles store their data in pixels, like small pictures. Because they store their data in pixels, you can’t easily edit aspects of the tiles. For example, imagine you had a set of raster tiles with highways colored blue, and you wanted to change the color of all highways to yellow. You would have to change each pixel that corresponded to a highway.

Vector tiles store all data in vector format. This means that they can distinguish between different layers, such as roads, country borders, and lakes, and you can easily manipulate these elements before rendering. If you wanted to change the color of the highways in a vector tileset, all you’d have to do is change the way that highways layer is displayed, which is fast and easy with vector data. Vector tiles also make operations like tilting possible.

Below, we’ll walk you through the creation of two interactive Mapbox maps. When you’re done creating each map, you’ll have created a custom vector tileset with various layers and a set of rules for styling these layers.

1.1.3 Mapbox

Mapbox provides infrastructure for developers to create vector-tile maps and map applications. It has a library of vector-tile basemaps with data from OpenStreetMap, an open data effort that works like Wikipedia for maps.

Mapbox has its own JavaScript library, Mapbox GL JS, that it uses to write custom interactive web maps. Instead of explaining Mapbox GL JS, we’ll use Mapbox Studio, which is a web interface to Mapbox GL JS. In Studio, you can create and edit Mapbox maps and share them via URL. You can then use Mapbox’s Static API to create static versions of your maps.

To introduce you to Mapbox Studio, we’ll walk you through the creation of two maps that visualize John Snow’s data on the 1854 London cholera epidemic. The first map will use circles to represent the number of deaths at a given location. The second will be a heatmap.

There are many features of Mapbox Studio that we won’t cover here. You can read more about Studio in the Studio Manual.

1.2 Data

1.2.1 Background

In late August 1854, a severe cholera epidemic broke out in the Soho neighborhood of London. As recounted by Dr. John Snow

The most terrible outbreak of cholera which ever occurred in this kingdom, is probably that which took place in Broad Street, Golden Square, and adjoining streets, a few weeks ago. Within two hundred and fifty yards of the spot where Cambridge Street joins Broad Street, there were upwards of five hundred fatal attacks of cholera in ten days. The mortality in this limited area probably equals any that was ever caused in this country, even by the plague; and it was much more sudden, as the greater number of cases terminated in a few hours. The mortality would undoubtedly have been much greater had it not been for the flight of the population.

(Snow 1855, 38)

In 1854, many mistakenly believed that cholera was spread through the air. However, because the deaths were concentrated in such a small area, Snow suspected that the outbreak was due to contaminated water from a community water pump at Broad and Cambridge streets.

On proceeding to the spot, I found that nearly all of the deaths had taken place within a short distance of the pump. There were only ten deaths in houses situated decidedly nearer to another street pump. In five of these cases the families of the deceased persons informed me that they always sent to the pump in Broad Street, as they preferred the water to that of the pump which was nearer. In three other cases, the deceased were children who went to school near the pump in Broad Street. Two of them were known to drink the water; and the parents of the third think it probable that it did so.

(Snow 1855, 39–40)

Snow reported his findings to the authorities responsible for the community water supply, who then removed the handle from the Broad Street pump. The epidemic soon ended.

Snow visualized his data by creating a map showing the location of local water pumps and deaths from the outbreak. This map helped overturn the prevailing belief that cholera was an airborne disease. As a result, London improved its water infrastructure and developed procedures to eliminate future cholera outbreaks.

1.2.2 Download data

Robin Wilson compiled Snow’s data and made it available on his website. We’ve formatted his data and converted the two files to GeoJSON to make them easy to upload to Mapbox. These two GeoJSON files are available in the data folder. Let’s read them in to see what they look like.

The original data can be downloaded here.

deaths <- read_sf("data/cholera/cholera_deaths.geojson")
pumps <- read_sf("data/cholera/cholera_pumps.geojson")
deaths
#> Simple feature collection with 250 features and 1 field
#> Geometry type: POINT
#> Dimension:     XY
#> Bounding box:  xmin: -0.14 ymin: 51.5 xmax: -0.133 ymax: 51.5
#> Geodetic CRS:  WGS 84
#> # A tibble: 250 × 2
#>   deaths      geometry
#>    <int>   <POINT [°]>
#> 1     15 (-0.137 51.5)
#> 2      8 (-0.139 51.5)
#> 3      8 (-0.135 51.5)
#> 4      8 (-0.134 51.5)
#> 5      7 (-0.135 51.5)
#> 6      5 (-0.136 51.5)
#> # … with 244 more rows
pumps
#> Simple feature collection with 8 features and 0 fields
#> Geometry type: POINT
#> Dimension:     XY
#> Bounding box:  xmin: -0.14 ymin: 51.5 xmax: -0.132 ymax: 51.5
#> Geodetic CRS:  WGS 84
#> # A tibble: 8 × 1
#>        geometry
#>     <POINT [°]>
#> 1 (-0.137 51.5)
#> 2  (-0.14 51.5)
#> 3  (-0.14 51.5)
#> 4 (-0.132 51.5)
#> 5 (-0.134 51.5)
#> 6 (-0.136 51.5)
#> # … with 2 more rows

Download cholera_deaths.geojson and cholera_pumps.geojson. Next, we’ll upload these files to Mapbox.

1.2.3 Upload data

If you don’t already have a Mapbox account, create one by going to https://account.mapbox.com/auth/signup/.

Earlier, we introduced you to the idea of tiles. We want to create a custom tileset that includes standard features like roads and location labels, but that also includes the locations of the water pumps and deaths due to the cholera outbreak. In order to create this custom tileset, we first need to upload our data and convert it into its own tileset.

  • Go to Mapbox Studio. If you’re elsewhere in Mapbox, you can click the astronaut icon in the upper-right and then click Studio.
  • Click on Tilesets in the upper-right corner.
  • Click the blue button labeled New tileset.
  • Upload cholera_deaths.geojson and cholera_pumps.geojson. You’ll have to upload one at a time.
  • The two tilesets should now appear in the list. Each tileset will have a random string identifier after its name. Below we will use a "*" to represent this identifier. If your tilesets did not appear, try refreshing your browser.

1.3 Circle map

You now have everything you need to create a map in Mapbox Studio. We’ll create the circle map first. At the end, you should have something that looks like this:

You can view our completed map here.

1.3.1 Create a style

In Mapbox, a style is a specification for how your map will be drawn. Behind the scenes, this specification is written in JavaScript, but you can edit it from Studio. You can think of a Mapbox style like ggplot2 code for a visualization: it includes information about which data to use, specifies how to map that data to visual elements, and controls features of the visualization not related to the data (e.g., background colors, basemap elements).

We’ll build our custom style by building on one of Mapbox’s existing styles.

  • Click on the Styles tab in the upper-right corner to take you back to the Styles page.
  • Click New style. Take a look at the different template styles that Mapbox offers. Some are better for displaying data than others. We want the cholera deaths and water pumps to be the focus of our map, so we’ll use a basemap with a subtle, light background. The Light style is the best option.
  • Select the Light style.
  • You should now be in Mapbox Studio and should see a basemap centered on Boston.
  • Name your map something informative. In the upper-left corner, you’ll see the default name of your map. If you used the Light style, your map will be named Light. Click on this name and change it to something like Cholera circles.

Your screen should now look like this:

1.3.2 Zoom in on London

The map is currently centered on Boston because the Light style’s default location is Boston. Move the map to London either by manually navigating or by searching for London in the search bar in the top-right corner.

1.3.3 Add the deaths layer

The individual unit of a Mapbox map is a layer. You can see a list of all the layers included in the Light basemap on the left side of Studio.

You can think of layers like ggplot2 geoms. Just like a geom, each layer maps data to a visual element (e.g., dots, lines, text), and you can control exactly how the data is mapped to that visual element.

You can edit an existing layer by clicking on its name. A layer editor will open. To hide the layer editor, click on the name of the layer again.

We’ll need three different layers to represent the deaths and pumps data. One layer will encode the deaths data as circles whose areas represent the number of deaths in that location. Another layer will represent the pump locations as circles. A final layer will label the pumps. First, we’ll add the deaths layer.

  • Click the gray Add layer button in the upper-left corner. Your map will immediately look different. Don’t worry, this isn’t because you’ve accidentally changed some feature. Mapbox is just highlighting all the layers without styling them.
  • You are now in the layer editor for a new layer. Notice that New layer now appears in the layer list on the left, and is highlighted to indicate that you’re currently editing this layer.
  • Notice that under Data sources in the layer editor, there are Active sources and Unused sources. Each of these sources is a tileset. Active sources are tilesets that the map currently uses to create different layers. Unused sources are available tilesets that the map does not currently use.
  • If you click on the name of a tileset, you’ll see all the available layers in that tileset. The tilesets included with Mapbox, like Mapbox Streets v8, each contain many different layers. Our custom tilesets (cholera_deaths-* and cholera_pumps-* ) each contain only one.

  • Click on your cholera_deaths-* tileset from the Unused sources list. Then, click on the layer titled cholera_deaths-* that appears underneath.

  • We’ve now created a layer. By default, this layer will be named cholera_deaths-* .

  • Notice that you’re currently in the Select data tab of the layer editor. The layer editor has two tabs: Select data and Style. In the Select data tab, you can choose your data and choose the layer type. You can think of the layer type as a geom. By default, the type for our current layer is Circle, which happens to be what we want. For some of the layers we’ll make later on, we’ll need to change the type.

  • If you click on the Style tab, the map’s appearance will go back to normal. In the Style tab, you can control the appearance of your layer. If you think of the Select data tab as where you choose the geom, the Style tab is where you specify the aesthetics. In the next section, you’ll use the Style tab to map number of deaths to circle area.
  • You should now see black dots on your map that represents the locations of deaths.

1.3.4 Scale the dots

Right now, all the dots are the same size. We want to scale them so that the area of the circle encodes the number of deaths.

  • We said that the Style tab controls the aesthetic mappings. For circles, one aesthetic mapping you can control are the radii of the circles.
  • To map the number of deaths to circle radii, we could select Style across data range from the Radius tab. However, this will linearly scale the radii of the circles by the number of deaths at that location. We actually want to scale the areas of the circles, not the radii, so we’ll have to use a custom formula.
  • Click Use a formula.

  • The formula we want to use takes the form x * sqrt(deaths), where x is a constant.
  • Start adding the formula to the formula box. Use sqrt() for square root. Click on Insert a data field and then on deaths to use the deaths variable.
  • Here’s what your map should look like without x:

  • Play around with different values of the constant x until you’re happy with the appearance of your dots. Your map should now look something like this:

In this screenshot, the editing sidebar for the deaths layer is hidden. You can hide the editing sidebar by clicking on the name of the layer you’re editing.

1.3.5 History

If you need to, you can undo actions by clicking on History in the menu on the right. Clicking the undo arrow will undo your last action. You can also click on the name of an action to revert your map further.

1.3.6 Style the dots

  • Make sure you’re on the Style tab of the cholera_deaths-* layer editor.
  • Use the Color tab to change the color of your circles to red.

  • At some zoom levels, the dots are over-plotted. Change the opacity of the dots in the Opacity tab. Then, add a border to the circles by adjusting the stroke width in the Stroke width tab.
  • When you’re done, your map should look something like this:

1.3.7 Add the pumps layer

Now, we’ll add a layer to represent the pump locations.

  • Again, click on Add layer to create a new layer.
  • Click on your cholera_pumps-* tileset from the unused sources list. Then, click on the cholera_pumps-* layer that appears underneath.
  • Go to the Style tab of the layer editor.

  • If you want to change the size of the circles, go to Radius and change the value of Circle radius.
  • You should now have a map that looks like this:

1.3.8 Add the pumps labels layer

It would be helpful to label the dots that represents pumps. In ggplot2, you could use geom_point() and geom_text() to create a plot with labeled points. Similarly, in Mapbox you have to add two layers to create labeled points: one for the points and one for the labels. We already added the point layer, so now we just have to add the label layer.

  • Add a new layer by clicking Add layer. Your cholera_pumps-* tileset is now an active source. Click on your cholera_pumps-* tileset then on the cholera_pumps-* layer that appears underneath.
  • By default, the layer will be named cholera_pumps-* (1). Change the name of the layer to cholera-pump-labels-* by clicking on the layer name towards the top of the layer editor.

  • By default, the layer type for the cholera-pump-labels-* layer is Circle, but we want text, not circles, for this layer. Change the layer type in the Type tab to Symbol.

  • Now, we need to set the labeling text. Move back to the Style tab, then type Pump in the text box. This will set every label to Pump.
  • The labels are directly on top of the dots. To offset the labels, first click on Position. This tab contains several variables related to the positioning of the text.

  • Use the Text offset tab to adjust the offsets. You should end up with something that looks like this:

Your map is complete!

1.3.9 Publish your map

Now, you just need to make your map visible to others by publishing.

  • When you publish your map, you’ll get a URL that points to your published map. Your published map will have a starting location and zoom level. Navigate to Default map position. If the Lock option is set to unlocked (the dot is towards the left and the oval is white), it means that your published map will default to the location and zoom level of your map when you click Publish. You want the Lock option to be unlocked. Then, move and zoom your map until you’re happy.

  • Publish your map by clicking the blue Publish button in the upper-right corner.

  • Click the Share… button next to Publish and copy the Share URL. This URL points to the shareable version of your map. Paste the URL into a new browser tab. Your map should open at the default location and zoom level that you set earlier. The Share URLs take the following form:

https://api.mapbox.com/styles/v1/{username}/{style_id}.html?fresh=true&title=true&access_token={access_token}#{zoom}/{latitude}/{longitude}

If your map does not default to the location that you set earlier, you may have to manually change your Share URL. To do so, replace your Share URLs zoom, latitude, and longitude with your desired values. Remember that you can find these values under Map position in Studio.

  • Once you have the correct Share URL, copy and store it somewhere. You’ll need this URL for the static API later on.

1.4 Heatmap

Now, we’ll create a heatmap. Your final result should look something like this:

You can view the map here.

1.4.1 Create a style

  • Go back to the Studio homepage.
  • Create a new map with a Light style basemap by clicking on New style and choosing the Light style.
  • Once the map has opened, change the name to something more informative, like Cholera heatmap.
  • Navigate to London.

1.4.2 Add the pumps layers

Mapbox can plot layers on top of each other. Each time you add a new layer, Mapbox places it on top of all other existing layers. This means that you’ll typically want to add layers from the bottom up. Our heatmap has a heatmap layer underneath the two pumps layers, so ordinarily you would add the heatmap layer first, and then add the pumps layers. We’ll add the pumps layers first just so we can demonstrate how to manually change the layer order.

We’ll add the two pumps layers exactly as we did for the circles map.

  • First, add a layer for the pump dots. Click Add layer, then select the cholera_pumps-* layer from underneath your cholera_pumps-* tileset.

  • If you want, change the radius of the pumps circles. You’ll end up with a map that looks like this:

  • Next, add the pump labels layer. Select the cholera_pumps-* layer from your cholera_pumps-* tileset that will now appear in the active sources list.

  • Change the name of the layer to cholera-pump-labels-* and change the type to Symbol.

  • Change to the Style tab to set the text and adjust the offsets. Recall that the text offset setting is under the Position tab.

1.4.3 Add the deaths heatmap layer

  • Add the deaths layer by selecting the cholera_deaths-* layer from underneath your cholera_deaths-* tileset.

  • Change the layer type to Heatmap.

  • Change to the Style tab.
  • Right now, the deaths variable is not mapped to the intensity of the heatmap. If you zoom in on your heatmap, you’ll notice that each heatmap dot has the same intensity, regardless of the number of deaths at that location. To map deaths to intensity, we’ll use the Weight parameter. We’ll adjust the heatmap weights similarly to how we adjusted the radii of the circles for the previous map.
  • Click on Weight, then Style across data range. Select deaths and click Done. This maps deaths to the heatmap weight, but the default is a uniform relationship, so the weight doesn’t actually change across different values of deaths.

  • Change the way the weights are scaled by adjusting the minimum and/or maximum weight.

  • Your heatmap should now look something like this:

  • Now, adjust the heatmap radius (the radii of the individual circles) in the Radius tab. Experiment with different values.
  • Your map should now look like this:

1.4.4 Change the layer order

The heatmap currently rests on top of the pump layers, obscuring some of the pumps.

  • Change the order of the layers by dragging and dropping the layer names in the list on the left. You want the cholera_deaths-* to be below both of the pumps layers.

  • Your map should end up looking like this:

Your heatmap map is complete!

1.4.5 Publish your map

  • To finalize your map, again center your map on your data, then make sure the Lock option is unlocked.
  • Click the blue Publish button in the top-right to publish your map.
  • Click on Share… and then copy the Share URL. Again, paste this URL into a new browser tab to check that your map defaults to the correct location. If your map does not default to the location you set earlier, you may have to manually change the Share URL by following the steps we explained in 1.3.9.
  • Copy the Share URL and store it somewhere. You’ll need it for the next section.

1.5 Static maps

You can share your interactive Mapbox map via its Share URL, but you’ll sometimes want a static version to embed in documents that only support static images. In this section, you’ll learn how to create static versions of your two maps using the Mapbox Static API.

1.5.1 Mapbox Static API

The Static API is an interface to Mapbox’s servers. You can use this interface to request data from its servers to download to your computer. In order to download your specific map, you need to create an API call. This call tells the API exactly what data you want to download. You’ll need to tell the API which map to download and which location and zoom level to use in order to create a static version of an interactive map.

You create the API call by specifying parameters in a URL. Here’s what the basic Mapbox Static API call looks like:

https://api.mapbox.com/styles/v1/{username}/{style_id}/static/{longitude},{latitude},{zoom}/{width}x{height}?access_token={access_token}

This call will create a PNG version of a map.

We’ll guide you through the process of gathering each piece information. We’ll store each piece of information in a variable so that we can just use str_glue() at the end to create the call.

1.5.2 Username and access token

First, store your Mapbox username and access token in variables.

username <- "stanford-datalab"
access_token <- Sys.getenv("MAPBOX_ACCESS_TOKEN")

1.5.3 Style ID

Decide whether you want to first create a static version of your circles map or your heatmap. Then, find that’s map’s style ID. You can find the style ID in the Share URL you copied earlier.

If you don’t already have your map’s Share URL, you can retrieve it from the Styles page. To do so:

  • Click on Share & use next to the name of your map. Then, copy the Share URL.

The style ID for your map is the string that comes after your username and before the .html.

https://api.mapbox.com/styles/v1/stanford-datalab/cjsqj3qvi3zrf1fld8qvywggs.html?fresh=true&title=true&access_token=pk.eyJ1Ijoic3RhbmZvcmQtZGF0YWxhYiIsImEiOiJjajh1aW84OXYxMWh5MndwMG9jYnhpc3ZiIn0.pSqbBonZJw667NNhHNX1Kg#16.1/51.513564/-0.135852/0

Store your map’s style ID in a variable.

style_id <- "cjsqj3qvi3zrf1fld8qvywggs"

1.5.4 Longitude and latitude

Next, we need to figure which longitude and latitude to use. With the static API, the longitude and latitude indicate the center of the map.

We’ll use the sf package and the pumps and deaths data to figure out the exact center of our data.

Notice that the southernmost pump is far away from the rest of the data.

ggplot() +
  geom_sf(data = deaths, color = "red") +
  geom_sf(data = pumps)

We’ll exclude this pump and focus on where most of the data lies.

First, we need to find the latitude of each pump. Then, we can use slice_max() to filter out the southernmost pump.

pumps %>% 
  rowwise() %>% 
  mutate(latitude = st_coordinates(geometry)[[2]]) %>% 
  ungroup() %>% 
  slice_max(latitude, n = nrow(.) - 1) -> z3

Now, we’ll find the bounding box of all our data. Once we have the bounding box, we can find the center of the box.

bounding_box <-
  pumps %>% 
  rowwise() %>% 
  mutate(latitude = st_coordinates(geometry)[[2]]) %>% 
  ungroup() %>% 
  slice_max(latitude, n = nrow(.) - 1) %>% 
  st_geometry() %>% 
  c(deaths %>% st_geometry()) %>% 
  st_bbox() %>% 
  st_as_sfc() 

st_bbox() calculates the bounding box.

st_centroid() finds the centroid of the box.

centroid <-
  bounding_box %>% 
  st_centroid()

We can visualize all of these geospatial operations using geom_sf().

ggplot() +
  geom_sf(data = bounding_box) +
  geom_sf(data = deaths) +
  geom_sf(data = pumps) +
  geom_sf(data = centroid, color = "red", shape = 3, size = 3)

Finally, we’ll store the longitude and latitude of the centroid in variables so that we can use them later on in the static API call.

longitude <- st_coordinates(centroid)[[1]]
latitude  <- st_coordinates(centroid)[[2]]
longitude
#> [1] -0.136
latitude
#> [1] 51.5

1.5.5 Zoom and PNG size

Next, we need to figure out which zoom level and PNG width and height to use.

You can see the current longitude, latitude, and zoom level of your custom style in Studio by clicking on Map position.

Move your map to the center point you found in the previous section. Then, determine which zoom level best shows the data. Remember that we’re excluding the southernmost pump. Copy this zoom level.

Now, you need to figure out how to set the height and width of your PNG so that all your data is shown at your chosen zoom level. Unfortunately, you can’t see what different PNGs will look like in Studio.

The Static API playground shows the results of different static API calls.

Set the longitude and latitude to the values you found in the previous section. Set the zoom level to the value you just copied. Now, play around with different widths and heights until the PNG seems like it would include all the data (excluding the southernmost pump) and is a reasonable size.

The Static API playground doesn’t let you load custom styles, so you won’t be able to see the pumps and deaths data. This means you might have to move back-and-forth between the playground and Studio. In Studio, look for the features (roads, buildings, etc.) that bound the data. Then, in the playground, make sure you PNG includes those features.

You don’t have to perfect your zoom level, height, and width at this stage. We’ll show you how to further tweak them later on. Just try to roughly include all your data at a reasonable zoom level.

Store your chosen longitude, latitude, zoom, width, and height values in variables.

zoom <- [your zoom]
width <- [your width]
height <- [your height]

1.5.6 Create your API call

Now, you just have to add in all this information to the base call. str_glue() makes this easy.

api_call <- 
  str_glue(
    "https://api.mapbox.com/styles/v1/{username}/{style_id}/static/",
    "{longitude},{latitude},{zoom}/{width}x{height}?access_token={access_token}"
  )

api_call
#> https://api.mapbox.com/styles/v1/stanford-datalab/cjsqj3qvi3zrf1fld8qvywggs/static/-0.135851999982979,51.5135645380918,16.1/1200x800?access_token=pk.eyJ1Ijoic3RhbmZvcmQtZGF0YWxhYiIsImEiOiJjajh1aW84OXYxMWh5MndwMG9jYnhpc3ZiIn0.pSqbBonZJw667NNhHNX1Kg

If you copy and paste this link into a browser, you should see an image of your map. If you only see the basemap, and not whatever features you added, your map might be set to Private. If this happens, you’ll need to change your map to Public. The easiest way to do this is to go to your Styles homepage. Then, click on the three dots next to your map and select Make public.

1.5.7 Download your PNG

Now, we need to download the image. Use download.file() to download your image as a PNG.

file_circles_map <- "images/cholera_circles_map.png"
download.file(url = api_call, destfile = file_circles_map)

The result should be a downloaded PNG, which you can view from RStudio or a browser. If you were able to see your PNG by pasting api_call into a browser, but your PNG did not download, you may need to set a different download method using the method argument of download.file(). You can see all available methods in the documentation for download.file().

1.5.8 Display your image

To include your image in an R Markdown document, use knitr::include_graphics.

knitr::include_graphics(file_circles_map)

Now you can see the exact image that your API parameters produce. If you’re not happy with the image, all you have to do is adjust your parameters slightly, and then rerun your code. It’s difficult to adjust longitude and latitude values by hand, so we recommend adjusting the width, height, and zoom first. If you think you do need to change the longitude and latitude, you may have to go back to Studio or the static API.

Here’s a function that includes all the code to make this process a bit easier. The function creates the API call, downloads the image, and displays the image using knitr. All you need to do is pass in the parameters.

mapbox_png <- function(
  username,
  style_id,
  longitude,
  latitude,
  zoom,
  width,
  height,
  access_token,
  path
) {
  str_glue(
    "https://api.mapbox.com/styles/v1/{username}/{style_id}/static/",
    "{longitude},{latitude},{zoom}/{width}x{height}?access_token={access_token}"
  ) %>% 
    download.file(url = ., destfile = path)
  
  knitr::include_graphics(path = path)
}

1.6 leaflet.mapboxgl

The package leaflet.mapboxgl extends the leaflet package to allow you to add Mapbox vector tiles to leaflet maps. leaflet.mapboxgl has many advantages. First, we’ll use leaflet.mapboxgl::addMapboxGL() to display our Mapbox maps in R. Note that leaflet.mapboxgl requires RStudio version 1.2 or later to display your plots.

  • You’ll need a Mapbox access token and style URL. You can retrieve your public access token by going to your Mapbox account page.

  • Your style URL is different than the share URL you found earlier. To find your style URL, first go to the Styles page. Then, click on the three dots next to your style and copy the style URL.

  • Store your style URL and access token in variables.
style_url <- "mapbox://styles/stanford-datalab/cjsqj3qvi3zrf1fld8qvywggs"
access_token <- Sys.getenv("MAPBOX_ACCESS_TOKEN")

Now, we can display our map. addMapboxGL() adds Mapbox vector tiles to a leaflet map. You can adjust the height and width of a leaflet plot with the height and width arguments.

leaflet(width = 950, height = 800)  %>%
  addMapboxGL(
    accessToken = access_token,
    style = style_url
  )

Another advantage of leaflet.mapboxgl is that you can add any leaflet function to your map. We’ll use this functionality to add tooltips, which you can’t do in Mapbox Studio.

The function addCircleMarkers() adds circles to a leaflet plot. You can use the label argument to set the text of a tooltip.

Note that you have to set data = deaths inside addCircleMarkers() in order to reference the data.

leaflet(width = 950, height = 800) %>% 
  addMapboxGL(
    accessToken = access_token,
    style = style_url
  ) %>%
  addCircleMarkers(
    radius = ~ 5 * sqrt(deaths),
    opacity = 0,
    fillOpacity = 0,
    label =
      case_when(
        deaths$deaths == 1 ~ "1 death",
        deaths$deaths > 1  ~ str_c(deaths$deaths, " deaths"),
        TRUE ~ NA_character_
      ),
    data = deaths
  )

We already have circles encoding the number of deaths, so we’ve set the opacity and fillOpacity of the circle markers to 0. This makes them invisible so you can still see the layers we added in Mapbox Studio.

References

Snow, John. 1855. On the Mode of Communication of Cholera. 2nd ed. London: John Churchill.