Climate models predict massive shifts in temperature and precipitation over the next 100+ years. These changes will not be the same everywhere; they will appear in complex patterns across the earth’s landscapes. To visualize climate change over space and time, I used data driven design to compare maximum temperatures today against predictions for 2050 and 2070.

Drag the marker over a land area to see the predicted annual max temperature at each of the three dates. The map’s dynamic styling will highlight areas that currently share this approximate max temperature. For example, if you drag the marker to New York, Louisiana turns red. This shows that New York is predicted to have the same highest temperatures in 2070 as Louisiana has now.

Storing the data–why ∆s?

Climate data like that from WorldClim (the source for this visualization’s numbers) is usually formatted as rasters. The continous nature of the climate system–multivariate, and changing gradually over space–is better represented by rows and columns of pixels, rather than by discrete vector objects like points and polygons. However, their fixed resolution, high bit depths, and heavy filesize make the rasters unwieldy in web and mobile applications.

By vectorizing these data, we can take advantage of Mapbox tools to create a striking dynamic visualization. And by vectorizing into a triangular mesh–effectively an alternate rasterization–we can store arbitrary variables to represent time and other dimensions.

After a little bit of raster data wrangling, I used makesurface to “triangulate” the data and tippecanoe to create vector tiles. After uploading via Mapbox Studio, I could load and style these data dynamically using Mapbox GL JS.

Applying data driven styling

Each vector shape contains three points (or bands) of data corresponding to each of the three years. I represented the data as three separate layers, so they can be styled independently. When a marker is dragged to a new location, we locate the triangle polygon under it using queryRenderedFeatures, then use the band values from that polygon as the new data thresholds to style each layer’s fill-color paint property. Take the coordinates around Toledo, Spain as example:

// Polygon band values around Toledo, Spain:
// band_1: 315
// band_2: 366
// band_3: 386

var currentTemp = band_3;

map.setPaintProperty('temperature2070', 'fill-color', {
  property: 'band_1',
  stops: [
    [currentTemp - 20, 'rgba(250,111,116,0)'],
    [currentTemp - 10, 'rgba(250,111,116,0.75)'],
    [currentTemp + 10, 'rgba(250,111,116,0.75)'],
    [currentTemp + 20, 'rgba(250,111,116,0)']

map.setPaintProperty('temperature2050', 'fill-color', {
  property: 'band_2',
  stops: [
    [currentTemp - 20, 'rgba(179,108,163,0)'],
    [currentTemp - 10, 'rgba(179,108,163,0.75)'],
    [currentTemp + 10, 'rgba(179,108,163,0.75)'],
    [currentTemp + 20, 'rgba(179,108,163,0)']

map.setPaintProperty('temperature2016', 'fill-color', {
  property: 'band_3',
  stops: [
    [currentTemp - 20, 'rgba(62,113,154,0)'],
    [currentTemp - 10, 'rgba(62,113,154,0.75)'],
    [currentTemp + 10, 'rgba(62,113,154,0.75)'],
    [currentTemp + 20, 'rgba(62,113,154,0)']

Applying transparent fill-color ramps around triangles that fit within currentTemp value creates a clean multivariate display. Lastly, with the coordinate data returned from the dragged marker, we make a reverse geocoding request request to display the place name.

Looking to create vectorized versions of your own rasterized datasets? Reach out to us with any questions on Twitter: @Mapbox.