Choosing the right color palette for visualizing data on a map can be tricky.
But when what you need is to improve local contrast to better see the details,
you can use a technique called histogram equalization. I implemented one version
with D3 and describe the experiment here.
Planet OS is handling a lot of climate and environmental data from sensors
around the world for multiple projects. As a data visualization engineer, I’m
always learning new tricks to makes sense of data. Visualizing data on maps
can be challenging. Some colleagues smarter than myself asked me if we could
have a color palette using histogram equalization. So I went to Wikipedia.
Histogram equalization is a method in image processing of contrast adjustment
using the image’s histogram.
So with hints from this example, from this other one, and from this SO answer,
I tried to understand it enough to make a version using D3 scales. It turned
out to be very simple. First, to prove that I have it right, I had as a goal
to reproduce the example from the Wikipedia page.
|
Original untreated image
|
|
Equalized result |
This picture is not the best example, because a simple linear range already
makes it better.
d3.scale.linear().domain(d3.extent(values)).range(['#000', '#fff']);
|
Image with values rescaled linearly
|
But the goal is to get more contrast using the histogram equalization method.
In the way I understand it, we have to compute a histogram of the values, to
put them into “buckets”, in a way that better distributes the values to get
higher local contrast. My first thought was to use d3.scale.quantile() to
compute the histogram and then use the quantiles as an input to a linear scale
that will interpolate the colors between them.
Here’s how I compute the quantiles and how I feed it to my linear scale:
var quantiles =
d3.scale.quantile().domain(values).range(d3.range(numberOfBuckets)).quantiles();
d3.scale.linear().domain(quantiles).range(grayScale);
It’s too simple, it can’t be right. Let’s try it on the test image to see if
it gives the same results as the Wikipedia example.
|
Image equalized using a D3.js histogram equalization
|
Pretty close. Let’s try it on some maps then, now using a
ColorBrewer
palette (Spectral11). This represents the mean period of wind waves at ground
or water surface level, taken from the WaveWatchIII dataset.
|
Wind wave map using a linear color palette
|
|
Same map using the same palette but equalized using D3.js histogram
equalization
|
This needs more polishing, but the histogram equalization works pretty well.
The code is available
here
with the picture from Wikipedia and
here
with the above map.
Happy D3 coding!
Originally published at planetos.com on January 13, 2016. Inspired by nice
algorithms explained
here.