Visualizing Near Surface Air Temperature

In the wake of the United Nation’s latest climate change report released last month, I wanted to write about our process in creating this map for the Bread for the World Institute as part of their attempt to raise awareness about the connection between climate change and hunger.

Maximum Near Surface Air Temperature on August 28, 2100

The Challenge

Our goals for this visualization were:

  • Communicate the impact of RCP 8.5 (the most pessimistic climate change scenario)
  • Allow the user to observe changes at different time intervals up until 2100
  • Visualize change at the global as well as the local level
  • Create a beautiful map using Mapbox GL

The Data

We started looking for datasets that projected the impact of climate change up until 2100 and came across the NASA Earth Exchange Global Daily Downscaled Projections (NEX-GDDP). This dataset contains the minimum and maximum daily temperature from 1950 to 2100 at a spatial resolution of 0.25 degrees (that works out at a value for every 25km x 25km). It has values for each of the two main climate change scenarios RCP 4.5 and RCP 8.5 and each of the 21 climate change models. That’s a lot of data, right?

The data is stored in the NetCDF format and the total size of the dataset is around 12TB with each individual file coming in at around 750MB. NetCDF is commonly used for storing scientific data. To take a look at the data, I grabbed a program called Panoply that allows you to view geo-gridded data in NetCDF format. It generates images like the one below:

Exploring the NEX-GDDP dataset in Panolpy


Panoply worked great for exploring the data, but we needed to get the values out of the NetCDF file and into GeoJSON. Using Panoply, we exported the data to a 12GB text file. The file contained the coordinates for the value, the value itself and a timestamp.

We then wrote a Node.js script using the great Line-by-Line module that extracted the data for the days we wanted, created a Feature for each row, pushed the temperature value to the Feature’s properties, and saved the FeatureCollection to file. The resulting GeoJSON was 125MB and contained more than a million point features. Here’s what it looked like in QGIS:

NetCDF data converted to GeoJSON and viewed in QGIS

Do you Tippecanoe?

We then uploaded our GeoJSON to Mapbox hoping that we’d see our beautiful gridded data in all its dreamy vector tile glory. However, after waiting for the file to process and pulling it into Studio, this is what we saw:

Hey! Where’s our grid gone?

Turns out the density of the Points were causing the conversion process to drop Features because the size of each tile was getting too large. We needed more control over the vector tile conversion process so (as Mapbox recommends) we turned to Tippecanoe.

Tippercanoe is a command line tool for building vector tile sets. It takes a GeoJSON (or a shapefile) as an input and outputs mbtiles. There are host of configuration options you can utilize to take control of the conversion process such as dropping unnecessary properties or adjusting the size limit per tile.

Using Tippercanoe we were able to export tiles that maintained the grid and didn’t drop any features but only up to zoom level 4. As we wanted the user to be able to zoom out far enough to see the entire world that just wasn’t going to cut it.

Looking good, but how about a global view?

After a bit more experimentation, we eventually disabled all the size restrictions using Tippecanoe and rolled our own tile server using Tilelive. The tiles themselves are quite large and you’ll notice they load quite slowly, but we were pleased with the result.

Repainting a million Features

Our next challenge was how to allow the user to switch between the different days so they could observe the changes over time. Initially, we created a different Tileset for each day but this led to a poor user experience when switching between layers because the tiles were loading too slowly (turns out there are limits on tile size for a reason). The app felt sluggish and unresponsive.

It then occurred to us that we could merge the temperature values from each of the three days into the same Feature’s properties and instead of switching layers, we could just adjust the Feature’s style using the setPaintProperty method. But how would Mapbox GL handle repainting over a million features on demand? Turns out, pretty well.

The Result

With the temperature data for each of the days accessible within each Feature not only could we repaint all the data on the fly, but it also allowed us to easily graph the values for 1950, 2017 and 2100 for any given point. This allows the user to compare the temperature change over time.

Here’s a few shots of the different regions of the world in 2017 and 2100 under RCP 8.5.

Africa: Maximum Near Surface Air Temperature on August 28, 2017 (left) and 2100 (right)
Asia: Maximum Near Surface Air Temperature on August 28, 2017 (left) and 2100 (right)
Southeast Asia: Maximum Near Surface Air Temperature on August 28, 2017 (left) and 2100 (right)
South America: Maximum Near Surface Air Temperature on August 28, 2017 (left) and 2100 (right)
North America: Maximum Near Surface Air Temperature on August 28, 2017 (left) and 2100 (right)

In Conclusion

The map made the Kantar Information is Beautiful Awards long list and we were pleased with the final result. Working with dense geospatial datasets is something we do regularly and in retrospect we would have been better splitting our data across several layers instead of one. This is the approach we are taking on our latest projects.

On display at the Maptian booth at SOTMUS 2018 Detroit

Maptian is a mapping and data visualization studio. If you’re looking for help visualizing climate data, drop us a line at