A Simple Choropleth w/ Tangram & Leaflet

Ryan M. Cooper
5 min readFeb 12, 2017

Just a short post here. One thing I’ve been trying to understand better is how to load external data for use in, say, a Leaflet map. I previously wrote about how you could use jQuery to pull in GeoJSON from outside your project directory. In poking around, I happened up Mapzen’s Tangram Play, a web-based interface for styling Tangram scene files. Tangram is a powerful platform for compiling and styling features for a vector basemap. While Mapzen gets you started with OSM data, you can also pull in data from external data sources.

::RECORD SCRATCH::

Yeah! You can load in GeoJSON, TopoJSON, Mapbox Vector Tiles, and raster tiles from external sources. This seemed right up my alley so I thought I’d give testing out this functionality a go. In what follow, I’ll take you through the process of creating a map using Tangram.

Goal

Let’s make a choropleth map of Kentucky counties, styled based on change in population from 2000 to 2010. We will make a map that consists of three layers (from bottom to top):

  1. Carto Positron basemap tiles without labels
  2. Kentucky counties sourced from external GeoJSON, styled and loaded into the map using Tangram
  3. Carto Positron label tiles

Setting up

A map that includes a Tangram scene is going to require a couple files. First, we’ll create and index.html file where we’ll put your HTML, CSS, and most of JavaScript for our map. We could separate these three elements out, but it’s not necessary. This file should include Leaflet v1 and Tangram’s JavaScript API. We’ll get the map script set up to focus on Kentucky.

We’ll also need a YAML file, scene.yaml, where we’ll load and style our external GeoJSON data. We’ll set it up to include sources, styles, and layers properties.

Making the map

Most of the rest of our work will take place in that scene.yaml file we created. Later, we’ll pull our scene into the map script in index.html, but first we need to set the scene.

Add data sources

For our sources property, we’ll add our Kentucky counties GeoJSON and the label-free Carto basemap tiles.

sources:
counties:
type: GeoJSON
url: https://gist.githubusercontent.com/maptastik/df8e483d5ac1c6cae3dc4a7c02ea9039/raw/9cd46849bddcfa90aab240772a12275408d6d8d0/kyCounties.geojson
carto_nolabel:
type: Raster
url: http://a.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png

We’ll assign an alias to each of the datasets we’ll be requesting, specify the type of data, and the URL where the data can be retrieved.

Enable layer blending

Tangram doesn’t really allow us to specify opacity for layers. Instead, we can blend layers together based on different blend-types. We only need the area of each county to blend with the Carto basemap. The multiply method will work well for us, but for future maps we may need to experiment a little bit to get the right look. We’ll store these parameters as _alpha_polygons for later reference.

styles:
_alpha_polygons:
base: polygons
blend: multiply

Configure layer style and order

We can now create layers from the data sources we loaded earlier. With Tangram, we can create multiple layers from a single data source. This presents some pretty cool cartographic possibilities. In our case, we’ll only be making one layer from each data source. For each layer, we will specify an alias, indicate the data source, and give drawing instructions.

Layers are drawn in numeric order. More specifically, the lowest order value will be drawn first, the highest last. We will have the Carto basemap drawn first, our counties layer last.

layers:
basemap:
data: {source: carto_nolabel}
draw:
raster:
order: 0
counties:
data: {source: counties}
draw:
lines:
color: '#000000'
width: 1px
order: 1
polygons:
style: _alpha_polygons
order: 1
color: |
function() {
var cat = feature.CH00_10;
var color = cat >= 5 ? '#2196F3' :
cat < 5 && cat >= 1 ? '#90CAF9':
cat < 1 && cat > -1 ? '#FFFDE7':
cat <= -1 && cat > -5 ? '#ef9a9a':
cat <= -5 ? '#f44336':
'#000'
return color;
}

There are a few of things to note here. First, when drawing our counties, we split the outline (lines) and fill (polygons) as two separate parameters within the same layer. Second we added that blending method, _alpha_polygons, to our polygons via the the style parameter.

polygons:
style: _alpha_polygons

This blends the basemap with our counties layer and sort of creates the illusion of opacity. Finally, we can pass JavaScript as a parameter. We did this to color our polygons based on CH00_10 value for each county. You can pass JavaScript as a parameter by beginning the code block with a pipe (|) value.

Add scene to map

Now that we’ve configured the scene, we can add it to the map. We can achieve this via Tangram.leafletLayer(), passing scene.yaml as an option (line 32).

Tangram scene on top of raster tiles. (See full map)

Add label layer

Now you may be wondering why we didn’t include the label raster tiles as a data source in the scene file. In messing around, I found that the alpha channel that normally ensures all the space around the labels is transparent is instead represented as filled. Since that layer should be drawn last, it obscures the counties and label-free basemap.

The counties and basemap are drawn, but are obscured by the white space in the labels layer. (See full map)

Fortunately, since we’re using Leaflet v1, we can use the new pane feature to add our label layer on top of our scene layer.

map.createPane('labels');
map.getPane('labels').style.zIndex = 650;
var labels = L.tileLayer(<TILE LAYER URL>, {
attribution: <ATTRIBUTION>,
pane: 'labels'
}).addTo(map);

By adding the labels layer to a pane drawn at a higher zIndex than our scene layer, the labels get placed on top of the scene. Why Tangram doesn’t respect the transparency in the labels layer, I do not know.

Our completed map! (See full map)

Final Thoughts

In this post we walked through how to use Tangram to load and style external data for use in a Leaflet map. Because Tangram is primarily meant for basemaps, it seems there’s not really any feature access to the data in our scene layer. As such, as far as I can tell, you aren’t able to access feature data on click or hover events. Tangram might not be the library you need for enabling user-interaction with your map’s data.

That said, I’ve presented a pretty narrow use of Tangram. I was mostly interested in loading external data, which Tangram seems to do quite easily. But I’ve barely scratches the surface of what Tangram can do and I’d encourage you to check out some of Mapzen’s examples to get a better sense of how you can use it to make really interesting, dynamic maps. If you want to dig deeper into Mapzen, I suggest working through their thorough yet accessible tutorials.

--

--

Ryan M. Cooper

Despite my credentials, I’m a master of nothing. I do mappy and, increasingly, codey things. Currently with Raleigh Parks, Recreation and Cultural Resources.