Steve on Image Processing

Concepts, algorithms & MATLAB

A New Colormap for MATLAB – Part 2 – Troubles with Rainbows 18

Posted by Steve Eddins,

Last week I showed you the new MATLAB colormap, parula. Parula has replaced jet as the default colormap in R2014b, which was released earlier this month.

This week I want to explain some of the motivations for replacing jet. Jet is an example of a rainbow colormap. A rainbow colormap is based on the order of colors in the spectrum of visible light. Some of you might know the mnemonic "Roy G. Biv" for remembering the order of colors: red, orange, yellow, green, blue, indigo, and violet.

Multiple methods exists for constructing rainbow colormaps, so they don't all look alike. Here is jet, the MATLAB version:

showColormap('jet','bar')

In my introductory post last week, I showed you a few visualization examples using jet, and I asked you some questions about them. Let's look at the questions again and figure out the answers.

Question 1: In the chart below, as you move from left to right along the line shown in yellow, how does the data change? Does it trend higher? Or lower? Or does it trend higher in some places and lower in others?

fluidJet
hold on
plot([100 160],[100 135],'y','LineWidth',3)
hold off
colormap(gca,'jet')

By my count there are six very distinct color changes as you move along the line from left to right. So what does that mean about the data?

I posed this question to someone who is very familiar with the jet colormap, and I was surprised by the response: "The data starts low, goes high, and then goes back low again."

"But what about all those other color stripes," I asked? "What do they mean?"

"That's just what jet does. I've learned to ignore all those stripes."

Oh! Well, it turns out that some of the color stripes are indeed mostly meaningless. But not all of them!

Here's what the data actually does along that path.

improfile(s.X,[100 160],[100 135])

Yes, the data starts low, goes high, and then goes back low. But if you ignore all the color stripes in between the blue and the red, then you miss the presence of the smaller-magnitude peak on the left. Alternatively, if you believe that all the color stripes are meaningful, then the yellow stripes seem to falsely suggest distinct data regions to the left and the right of the main peak.

Now let's compare with parula.

fluidJet
colormap(gca,parula)
hold on
plot([100 160],[100 135],'y','LineWidth',3)
hold off

You can see that now there are only four distinct color changes as you follow the yellow line. These changes correspond directly to real features in the data. There are no extraneous color stripes that do not correspond to real data features.

Question 2: In the filled contour plot below, which regions are high and which regions are low?

filledContour15
colormap(gca,rgb2gray(jet))

In the plot above, I have done a crude simulation of what a jet-based visualization looks like if printed on a grayscale printer. Here's the full color version:

colormap(gca,jet)

If you are familiar with jet and know therefore that blue is low and red is high, then you can probably look at the full-color version and give a reasonable interpretation of it. When rendered as grayscale, however, all hope is lost. The red and blue colors of jet are just about equally dark.

Here are the full-color and grayscale results with parula.

filledContour15
colormap(gca,parula)
filledContour15
colormap(gca,rgb2gray(parula))

With parula, dark consistently means low, and bright consistently means high.

The last questions relate to the three plots below (A, B, and C) showing different horizontal oscillations.

Question 3: Which horizontal oscillation (A, B, or C) has the highest amplitude?

Question 4: Which horizontal oscillation (A, B, or C) is closest to a pure sinusoid?

Question 5: In comparing plots A and C, which one starts high and goes low, and which one starts low and goes high?

subplot(2,2,1)
horizontalOscillation1
title('A')

subplot(2,2,2)
horizontalOscillation2
title('B')

subplot(2,2,3)
horizontalOscillation3
title('C')

colormap(jet)

The answers are subjective and might depend on your monitor and ambient lighting. But here's what I see.

The data pattern in image A has significantly higher visual contrast than either image B or image C. That suggests that the data oscillation in A has the highest amplitude.

The data patterns in images B and C both exhibit vertical stripes within each period of the oscillation. That strongly suggests that horizontal oscillations shown in B and C have some constant or almost-constant regions and that they go up and down in something like a stair-step pattern. To my eye, image A looks the most like a pure sinusoid.

And finally, the pattern in image A starts with a bright stripe on the left, whereas the image B pattern starts with a dark stripe. That suggests that oscillation A starts high, while oscillation B starts low (or maybe vice versa).

You probably won't be surprised to find out that these are all trick questions. Actually, oscillations A, B, and C are all sinusoids with exactly the same amplitude and shape. They differ only in their constant offsets, which place them in different regions of the jet colormap. Note especially that oscillations A and C are actually in phase with each other; they both start high and go low. The differences we see are all visual artifacts caused by the jet colormap.

Compare the result using parula:

colormap(parula)

With these examples, I wanted to show several ways in which the jet colormap, and rainbow colormaps in general, can mislead the viewer about properties of the data.

It turns out that some people have been writing about these problems with rainbow colormaps for years. Here's a summary of the main criticisms:

  • Rainbow colormaps confuse viewers because there is no natural perceptual ordering of the spectral colors. In addition to causing visual confusion (such as whether oscillations A and C above are in-phase or out-of-phase), the lack of perceptual ordering can slow down tasks because viewers have to refer to the color key more often in order to interpret the data.
  • Rainbow colormaps obscure small details in the data. The primary reason is that the green and especially the cyan sections of the rainbow colormap are perceptually indistinct, which makes the data in the corresponding ranges appear to be uniform or flat. (I haven't shown examples of this in the blog, yet, but there are examples in the technical paper mentioned below.)
  • Rainbow colormaps mislead viewers by suggesting data features that are not really there. These "phantom features" often take the form of false boundaries. This effect, in combination with perceptually indistinct green or cyan regions, can falsely segment the data.
  • Rainbow colormaps lose critical information about high and low data values when displayed or printed on a gray-scale device.
  • Rainbow colormaps can be difficult to interpret for some color-impaired viewers.

For a much more detailed summary of the literature and online sources regarding rainbow colormaps, see the paper "Rainbow Color Map Critiques: An Overview and Annotated Bibliography" on mathworks.com.

Next time I'll starting getting into colormap construction principles.


Get the MATLAB code

Published with MATLAB® R2014b

Note

Comments are closed.

18 CommentsOldest to Newest

Does MathWorks make any intellectual property claims to the parula colormap? Specifically I’m wondering whether you/your laywers consider it acceptable to extract and re-use the colormap values in non-Matlab plotting tools.

Anry replied on : 2 of 18

I might be in a minority here, but I don’t think that changing the default colormap was a good idea. For some (probably psychological) reason I hate cyan color (dirty blue/green to me), but I have also rational objections to parula colormap.
First, nobody uses color-coding for visual measurements; it is used mainly for a beautification. So, the argument that it is harder to measure the function shape with jet is kind of irrelevant, though I was able to easily spot two peaks in your first example. I don’t think that many people will find parula colors more attractive than jet.
Second, there is some intrinsic color order which is physically intuitive to humans, and this order is from the bottom of the deep cold blue ocean to the high hot red center of the sun.
Third, I totally agree that jet color-coded image looks horrible on gray tone printer. The case where it might be important is in the printed articles where the authors are not careful enough to show the original (not color-coded) gray-level plot. In that case, one still have the color original to view.
Finally, I still don’t see in parula colormap any “natural perceptual ordering”, or intuitively defined distances between colors (such as change in brightness). So, most of the jet criticisms that you’ve provided are still true for parula.

Jotaf replied on : 3 of 18

Actually I must strongly disagree with Anry. What is visually more intuitive than a dark-to-bright ordering? If you compare parula and jet, side by side, you will see that they (roughly) just got rid of the red portion — otherwise it still has mostly the same colors and in the same order! Also saying that you just use the jet map to make your papers pretty and not to convey information is not exactly a strong argument; most Matlab users are engineers and scientists. I think it would be nice to maybe have a couple more colormaps similar to parula but with other color orders (still dark-to-bright), but this would be only to provide more choice over the aesthetics.

Steve L replied on : 4 of 18

Anry,
Note that the JET colormap is still included in MATLAB. You can change your figure or axes colormap to use JET using the COLORMAP function; you can even set it as the default figure or axes Colormap if you like.

http://www.mathworks.com/help/matlab/default-property-values.html

Jotaf,

You can create your own custom colormaps either as an M-by-3 matrix stored in a MAT-file or as a function file that returns such a matrix. You can open parula.m to use it as a model in how to create your own function, or you could use the COLORMAPEDITOR interface to modify the colormap interactively then save the figure or axes Colormap property.

Anry—In 2D visualizations it is extremely common for viewers to use color variation to interpret the data. Here is an example (image credit NASA/MODIS):

I can look at this image and see that there are low concentration bands that run north and south of the equator. I can see that there are high concentrations along the edges of many of the continental land masses. The colors tell me this. Close examination of the color key at the bottom is not necessary for me to make this interpretation. The color is not there mainly for beautification, although I do think the colors are beautiful. If there is no color variation in the visualization above, then there is simply nothing to see at all.

Your contention that there is a blue-to-red color ordering that is physically intuitive to all humans is not borne out by the studies. Yes, a particular individual often will consistently order spectral colors in a way that seems intuitive to that person, but this ordering is not universally consistent from individual to individual. Brightness, however, is almost universally perceived as a consistent way to order colors. The parula colormap monotonically increases with brightness. Exploiting brightness variation also works much better for color-impaired viewers (and there are many of them!) than the spectral colors.

I have seen many examples of visualizations based on jet/rainbow colormaps that actually mislead the viewer about the underlying data. I’ve seen digital elevation models in which a smoothly rounded hill looks like a flat-top plateau with a cliff drop-off. I’ve seen fine spatial detail completely obscured by the perceptually flat regions of the jet colormap.

A user who saw an early MATLAB preview with the new colormap complained to us that the new colormap was “noisy.” In reality, it was the underlying data that was noisy. The jet colormap hid the noise, while the parula colormap revealed it.

I have written a paper on mathworks.com that summarizes many of the published literature and online sources of information about the use of rainbow colormaps. One paper found that radiologists made fewer diagnostic errors when using a perceptually uniform colormap when compared to using the rainbow colormap, despite the fact that most of those radiologists were more familiar with and comfortable with the rainbow colormap.

We recognize that a change in software behavior such as this can cause problems. However, for the reasons described above and elsewhere, we felt that the significant improvement in data visualization was worth it.

I’ve been following the reaction to the colormap change among a community of oceanographers and climate scientists. The general consensus there seems to be, “What took you so long?” An electrical engineering professor said, “I was just this week looking at a jet-colormap surface produced by one of my students, and I felt like the jet colormap totally obscured my ability to interpret what was really going on.”

On the other side, I must admit, I did see one scientist on Twitter give parula a one-word review: “Yuck.”

Hi Steve,
I was wondering what is the copyright status of this new colormap. Is the list of RBG values a property of MathWorks or can it be used by external (open source) projects ? (to be specific, I have Matplotlib in mind).

Thanks for you feedback!

best,
Pierre

Ted replied on : 7 of 18

What I think should be considered is that after many hours (days? years?) of exposure to the jet colormap, it seems that the visual system can become capable of quickly capitalizing on small hue differences (in addition to luminance) for making intuitive sense of amplitude variations in images. I can’t speak for others, but the fluid jet image above demonstrates exactly what I mean – some people may consider the “lines” artifacts, but some of us consider them features. Prior to looking at the plotted profile I was able to estimate a plot that looked extremely similar to the true profile, including the fine details such as the bump at ~60 that is nearly impossible to see in the Parula map.

I think the key advantage of Parula is that mapping amplitude to luminance is far more intuitive then mapping amplitude to hue. For people not used to interpreting colormaps, Parula will probably be much easier to understand than jet. It is also robust to greyscale printing, etc. Still, I find myself irritated with Parula and constantly switching back to jet because a lot of images seem to have lost a large degree of contrast, and small details (such as the bump at 60 in the jet plume profile) seem more difficult to detect.

Ted—It is true that jet has more contrast variation (in some parts of the scale) than parula. That’s because jet goes from dark to very bright in the first third of the colormap, and then goes from bright to dark in the last third. So there is higher contrast than parula, which goes from dark to bright over the entire scale. But in the middle third of the jet colormap, there is relatively little brightness variation. It is in this region that jet is known for its tendency to hide detail (such as a small bump), not reveal it.

Ted replied on : 9 of 18

Yes, but my point is that the hue shift in the middle third of the jet colormap does a relatively decent job of compensating for the lack of brightness variation – if you are trained to look for it. For example, I often need to know how close patches of data in a set spanning +/- pi are to zero, and Jet has worked very well because of the hue variation in the middle third of the colormap. In Jet, green = zero, which can be determined almost independently from the other values. This vs. grayscale in which “sort of dark” = 0 and Parula, where “sort of dark and kind of bluish” = 0.

I’m not arguing with Matlab’s change in default, (though I set mine back to jet), because Parula is undoubtedly more intuitive. I just think that rainbow maps have a bad reputation for being deceptive when you really just have to know what to look for. The non-linear luminance, in conjunction with hue variation, can be very effective for compressing a large dynamic range into an image.

Ted—Thanks for the additional insight. Your +/-/0 use case sounds like a good application for a divergent colormap. Jet does work better as a divergent colormap than parula. Other people have asked me about divergent colormaps, and I plan to write more about them a little later.

Nathaniel and Pierre—Thanks for your interest in the new parula colormap. Parula is the end result of a creative design effort over an extended period of time. I am pleased that you find it so appealing. The colormap is, however, MathWorks intellectual property, and it would not be appropriate or acceptable to copy or re-use it in non-MathWorks plotting tools.

You might look at other sources of high-quality colormaps. I have listed some in my technical paper on rainbow colormaps, published earlier this month on mathworks.com.

Hello Steve

Congratulations on Parula, it looks terrific, and great blog series.

Thanks so much for Thanks for including my material in the technical paper on rainbow colormaps.
You may want to add a link to this fantastic blog series is Rob Simmon’s Elegant Figures blog (at NASA’s Earth Observatory) titled Subtleties of color:
http://earthobservatory.nasa.gov/blogs/elegantfigures/2013/08/05/subtleties-of-color-part-1-of-6/
Also, I wanted to add a few clarifications regarding some points on your technical paper:
__(1) In my blog series I call the palette from the figure you re-used as Figure 11 “standard spectrum” with reference to itsubiquitous use in geophysical seismic interpretation software, which is clearly noted in my blog post.
__(2) I used a slight cube-rute curvature in my CubicYF even if as you ay this is already incorporated in the Lightness formula. My reason for doing so is that even lightness is not perfectly perceptual and sometimes the ‘just noticeable difference’ for darker colors is slightly larger than the one for lighter colors.
__(3) Yes, many would not recognize cubicYF as a rainbow because red is missing. This was a conscious choice because even with increasing lightness having yellow with red and green on either side would confuse people with deuteranopia (Type 1 of color vision deficiency). I have a great example here: http://mycarta.wordpress.com/2012/02/23/a-rainbow-for-everyone/. There’s a number of approaches to solve this: __a) a compromise like in this recent post of mine: http://mycarta.wordpress.com/2014/10/24/colormap-compromise; __b) having a darker yellow and lighter red as in Parula or in the linear lightness colormap from this post: http://mycarta.wordpress.com/2012/12/06/the-rainbow-is-deadlong-live-the-rainbow-part-5-cie-lab-linear-l-rainbow; __c) – reduced hue range as in CubicYF. Each has some benefits. The advantage of CubicYF is that red is free to be used for other datasets as in this great example on a post by Matt Hall (last figure): http://www.agilegeoscience.com/journal/2013/8/29/colouring-maps.html
Hope this helps the discussion. Matteo

Matteo—Thanks for the additional information. I did summarize the series by Simmon’s series (see pages 15-16), but the link I provided is to a different web site where the series was also published. I’ll consider making some edits to the paper.

Matteo—Following my experience with designing parula, I was no longer satisfied with that File Exchange contribution.

I mentioned the IEEE Spectrum version of the Rogowitz article in my annotated bibliography paper. I did not experiment systematically with the specific procedure described there.

Gary replied on : 16 of 18

Just a minor comment about colour-blind observers (or colour-impaired as you put it Steve). The vast majority (>99%) of colour-blind observers have what is called red-green colour blindness, this is due to an anomalous or missing long-wave or medium-wave cone pigment and results in confusion of certain reds and greens. They can see blues and yellows just fine. So for your new colour map nearly all colour-blind observers would see it just fine even without luminance differences (they have no problem distinguishing green from blue either, just reds and greens are confused). I like the monotonic luminance function though, but I’m afraid its not accurate to say that it helps the colour-impaired as it doesn’t in over 99% of cases. The type of colour-blind observer that would confuse the hues in parula would be whats called a tritanope or tritanomalous, missing the short-wave cone pigment or having an anomalous one. The reported frequency of this type of colour blindness (in the normal population) varies but figures range from 5/10000 to about 1/50000 (Wiki says less <1% for tritanopia but the figure is closer to 0.03%). I like the new colour map though. I enjoy your blog.

Gary replied on : 17 of 18

To add a little clarification, a red-green colour blind person may confuse one or two colours at the far right of your colour map where you go from yellow to reddish and back again to greenish (particularly a deutan in the yellowish to reddish), but the vast majority of the color map would not provide any difficulty to red-green colour blindness. To see for yourself run this bit of code:
parula_colours = colormap;
xyz_transform = makecform(‘srgb2xyz’);
xyz_colours = applycform(parula_colours, xyz_transform);
x = (xyz_colours(:,1)./sum(xyz_colours,2)); %x of 1931 CIE chart
y = (xyz_colours(:,2)./sum(xyz_colours,2)); %y of 1931 CIE chart
protan_confusion_point = [0.747, 0.253];
deutan_confusion_point = [1.080, -0.080];
tritan_confusion_point = [0.171, 0];
scatter(x,y, 80, parula_colours, ‘fill’);
Lines that radiate from the confusion points represent colours that will be confused by each type of colour-blind person (I just included the points not the code to draw the confusion lines).

Gary