Mapboxgl is the gold standard of open-source mapping frameworks. It’s widely used from navigation apps to data visualizations for its performance and flexibility — yet, some of its features seem to be hardly ever used. A strong candidate for the most underrated feature in Mapbox is data-driven fill patterns.

In this tutorial we’ll learn how to make a visualization with the halftone pattern.

But first, why?

Halftone

Roy Lichtenstein. Source: Emily via flickr (CC BY-NC 2.0)

Source: Pbroks13 via Wikipedia (Public Domain)

Halftone is the variation in size of points in a regular pattern to create an illusion of gradient or mixing colors. (The oft-confused Ben-Day dots are a variation in spacing between points of similar size.) Both originated as printing techniques and thus use the subtractive CMYK color model. Nowadays, halftone maps evoke 60's-era pop art and newspaper under a magnifying glass.

But halftone’s not just for nostalgia.

It also how squids change color.

What’s more, it’s a useful data visualization technique, and it needs to be used more. Here’s why:

Bivariate Choropleth. You make red from yellow and what? Where did I put that color wheel?

Choropleths do a great job visualizing one value. But when we’re interested in two or more variables, they become drastically less intuitive. In the above map, can you tell if Fresno has more yellow than magenta? Or more yellow than Las Vegas? Unfortunately, while blending colors is simple to your screen, it’s less than intuitive for the human brain. Even using a human-centered color space doesn’t solve the problem that we’re bad at seeing a color for its parts.

By concentrating colors in dots, and by varying the radius according to our data, we provide a clear metric for comparison, even with 3 or more variables. Instead of expecting the user to dissect the color in their mind, we do the work on-screen. And with just one variable, the pattern provides a clearer view into data beneath.

Let’s get started!

Building a Halftone Map

First, we need an SVG icon to use as our pattern. Let’s start with this simple icon:

<svg height='8' width='8'>

<circle cx='4' cy='4' r='4' fill='#224444' />

</svg>

This draws a circle that touches its bounding box on all sides. Used as a fill-icon, it becomes this crowded grid of circles

But we need dots of various sizes. We could make them manually or use Illustrator, but I’m lazy so I wrote a python script to do the work for me. This script generates 8 steps with a resolution of 1/2 pixel, but you could go as precise as you like.

This script creates eight SVG icons, each containing a circle of a different size.

Now, upload all the generated SVGs to a Mapbox style, make a map with the style, and write that data-driven style expression:

And that’s basically it!

That wasn’t so bad, was it?

But there’s a lot more we can do!

Why not use squares, place our dots in a hexagonal pattern, or use lines of varying width?

In fact, any pattern could be used as a data driven style, so long as it has a variable property and is repeatable in a square grid.

Experimenting with wavy lines

For inspiration, check out the SVG Patterns Gallery, which also comes with a helpful tool to see what your pattern will look like. I corrected for Mapbox’- weird scaling with the following pen:

Use this to demo what your pattern will look like on amap.

To give my dots more energy, I put them in a diagonal grid, with two dots in each icon. For each color, the circles are placed in a different position to minimize overlap.

With a bit of extra styling, here’s what the result looks like: