# How to find a suitable association of color with data value in a visualization?

I'm working on a software project that involves creating a visualizer for flood simulations. As part of this project, I've created a water gradient that shows water depth at particular points. To set what values will represent what colors, I go through the data and get the minimum and maximum values that occur and evenly distribute the colors according to that scale.

However, there are often times points in these simulations that have significantly deeper water at them than anywhere else in the simulation. This causes most of the points on the map to have very similar colors and this is not very informative and makes the areas where the water is deeper very hard to see.

My goal is to dedicate a larger range of colors to depths that occur more frequently. For example, if depths go from 0 to 12 but most depths are between 1 and 2, I want more color variation to occur within that range than does between say 11 and 12 or 4 and 5. It seems I need to use standard deviation or something involving normal distribution to do this, but I'm a bit fuzzy on how these things work and how I can use them to accomplish my goal.

Any help that can be provided will be appreciated. Thank you.

• Not positive I understand correctly but perhaps if you instead used the logarithm of your current scale it would look better. Do you have a picture you could show? Mar 9, 2013 at 23:18

It sounds like you might want to dedicate each color in your palette to approximately the same amount of data.

To illustrate, here is a histogram of a set of $110$ simulated depth readings: Imagine this were smoothed out. In so doing, the histogram could be evenly sliced into vertical segments of equal area, using as many slices as you like (I used $10$ pieces for this example.) To keep the areas equal, the slices have to be skinny where the histogram is high--that is, where there are lots of data--and fat where the histogram is low--that is, where there is little data. One way to accomplish the slicing easily is to plot the total amount of data ("cumulative proportion") against the depth. Slice the vertical axis into even intervals, then read the depths where the slices cross the plot: use those as the cutpoints for visualizing depths. The algorithm for computing the cutpoints from the data should be obvious and is simple to write in almost any programming language: sort the values, break the list into groups of approximately equal size, and choose cutpoints to separate the largest value in each group from the smallest value in the group that succeeds it.

• Brilliant. This is exactly what I wanted and it's a lot simpler than I had anticipated. Thank you so much for both clarifying my problem and providing an elegant solution. Mar 9, 2013 at 23:32

Though @whuber's answer provides just what you asked, I'd like to caution that what you ask may not be the best way to visually represent your data, for two reasons.

1. Viewers will naturally assume that colors are evenly distributed by value (depth) rather than by rank. You will have to work hard with your labeling to get the viewer's cognitive brain to overrule what their visual system is telling them.
2. Rank may not be more important to your viewers than actual depth. If there are lots of values between 0 and 1, say, does it matter analytically how those values are distributed?

You know your application best, of course, so I can't say what the right answer is, but below are some alternatives using data generated by

r = Sqrt((:x * :x + :y * :y) / 400);
t = ArcTan(:y, :x);
z = (12 * Exp(-r * r * 3)) * Abs(Sin(2 * Pi() * r) - r * Cos(3 * t))


The data goes from 0 to 12.5 with the following distribution: A 3-D surface plot show a some peaks, a shallow trough and a small mound: Now let's look at some 2-D contour plots.

Straight linear color mapping, which misses the smaller features as you've noticed: If the variation in the deep areas is unimportant, then clipping the color mapping allows more colors for the smaller depths while maintaining a linear mapping in that area: For comparison, here's the rank-colored view (sorry that my legend is in rank values instead of depth values): I'm not sure if that is a good representation for your application or not. The detail in the shallow trough is exaggerated. A log color mapping is similar and has the advantages of having some real interpretation and can be consistent across data sets, but log is still not perceptual (apologies again for the legend): Finally, here's an approach in a slightly different direction that can be combined with any of the above to increase resolution: a multi-hued color mapping. In this case, the coloring is linear and clipped: Post-finally, an approach that my software doesn't readily allow is to use a multi-hued piece-wise linear color mapping, which I've seen in some elevation maps. For instance, the low altitudes are greens in 50 ft increments, the mid altitudes are tans in 200 ft increments and the highs are grays in 800 ft increments.

Bottom line: it's better if the viewer's brain works with your visual perception system instead of against it.

• Thanks for the reply. I implemented whuber's answer and found that, as you mentioned and as I somewhat expected, it produced a graphic that was very deceptive and not very intuitive in terms of actual depth. I think the solution I've settled on is making a sharper contrast between "shallow" colors and "deep" colors so that I can maintain an even and intuitive gradient while still making it easier for the user to see potential problem areas. Mar 10, 2013 at 19:06
• Blues are a particularly good choice in many cases because the human visual system is much more sensitive to variations in hue in that region. Mar 10, 2013 at 19:07
• @cardinal: So long as your observers are younger. There is a loss of short-wavelength sensitivity with age (e.g. ncbi.nlm.nih.gov/pubmed/3230483). Mar 14, 2013 at 8:15