Choropleth Maps in R

How to make a choropleth map in R. A choropleth map shades geographic regions by value.


Plotly Studio: Transform any dataset into an interactive data application in minutes with AI. Try Plotly Studio now.

Note: We are retiring documentation for R, MATLAB, Julia, and F# in November 2025. Learn more about this change here.

A Choropleth Map is a map composed of colored polygons. It is used to represent spatial variations of a quantity. This page documents how to build outline choropleth maps, but you can also build choropleth tile maps using our Mapbox trace types.

Base Map Configuration

Plotly figures made with plot_ly have a layout.geo object which can be used to control the appearance of the base map onto which data is plotted.

Introduction: main parameters for choropleth outline maps

Making choropleth maps requires two main types of input:

  1. Geometry information:
    1. This can either be a supplied GeoJSON file where each feature has either an id field or some identifying value in properties; or
    2. one of the built-in geometries within plot_ly: US states and world countries (see below)
  2. A list of values indexed by feature identifier.

The GeoJSON data is passed to the geojson argument, and the data is passed into the z argument of choropleth traces.

Note the geojson attribute can also be the URL to a GeoJSON file, which can speed up map rendering in certain cases.

GeoJSON with feature.id

Here we load a GeoJSON file containing the geometry information for US counties, where feature.id is a FIPS code.

library(plotly)
library(rjson)

data <- fromJSON(file="https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json")
data$features[[1]]
## $type
## [1] "Feature"
## 
## $properties
## $properties$GEO_ID
## [1] "0500000US01001"
## 
## $properties$STATE
## [1] "01"
## 
## $properties$COUNTY
## [1] "001"
## 
## $properties$NAME
## [1] "Autauga"
## 
## $properties$LSAD
## [1] "County"
## 
## $properties$CENSUSAREA
## [1] 594.436
## 
## 
## $geometry
## $geometry$type
## [1] "Polygon"
## 
## $geometry$coordinates
## $geometry$coordinates[[1]]
## $geometry$coordinates[[1]][[1]]
## [1] -86.49677  32.34444
## 
## $geometry$coordinates[[1]][[2]]
## [1] -86.71790  32.40281
## 
## $geometry$coordinates[[1]][[3]]
## [1] -86.81491  32.34080
## 
## $geometry$coordinates[[1]][[4]]
## [1] -86.89058  32.50297
## 
## $geometry$coordinates[[1]][[5]]
## [1] -86.91760  32.66417
## 
## $geometry$coordinates[[1]][[6]]
## [1] -86.71339  32.66173
## 
## $geometry$coordinates[[1]][[7]]
## [1] -86.71422  32.70569
## 
## $geometry$coordinates[[1]][[8]]
## [1] -86.41312  32.70739
## 
## $geometry$coordinates[[1]][[9]]
## [1] -86.41117  32.40994
## 
## $geometry$coordinates[[1]][[10]]
## [1] -86.49677  32.34444
## 
## 
## 
## 
## $id
## [1] "01001"

Data indexed by id

Here we load unemployment data by county, also indexed by FIPS code.

df = read.csv("https://raw.githubusercontent.com/plotly/datasets/master/fips-unemp-16.csv", header = T, colClasses = c("fips"="character"))
head(df)
##    fips unemp
## 1 01001   5.3
## 2 01003   5.4
## 3 01005   8.6
## 4 01007   6.6
## 5 01009   5.5
## 6 01011   7.2

Choropleth Map Using GeoJSON

library(plotly)
library(rjson)

url <- 'https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json'
counties <- rjson::fromJSON(file=url)
url2<- "https://raw.githubusercontent.com/plotly/datasets/master/fips-unemp-16.csv"
df <- read.csv(url2, colClasses=c(fips="character"))
g <- list(
  scope = 'usa',
  projection = list(type = 'albers usa'),
  showlakes = TRUE,
  lakecolor = toRGB('white')
)
fig <- plot_ly()
fig <- fig %>% add_trace(
    type="choropleth",
    geojson=counties,
    locations=df$fips,
    z=df$unemp,
    colorscale="Viridis",
    zmin=0,
    zmax=12,
    marker=list(line=list(
      width=0)
    )
  )
fig <- fig %>% colorbar(title = "Unemployment Rate (%)")
fig <- fig %>% layout(
    title = "2016 US Unemployment by County"
)

fig <- fig %>% layout(
    geo = g
  )

fig