File Exchange

image thumbnail

Perceptually improved colormaps

version 1.22 (5.56 MB) by

7 perceptual colormaps with rainbow-like colors and 1 with heat colors



View License

PMKMP Returns perceptually balanced colormaps
   PMKMP(N,SCHEME) returns an Nx3 colormap.
   usage: map=pmkmp(n,scheme);
%% Example1: 128-color rainbow with cubic-law luminance (default)
load mandrill;
%% Example2: 128-color palette for azimuthal data
b = repmat(a,[46 1]);
JUSTIFICATION: rainbow, or spectrum color schemes are considered a poor choice for scientific data display by many in the scientific community (see for example reference 1 and 2 in the help) in that they introduce artefacts that mislead the viewer. "The rainbow color map appears as if it is separated into bands of almost constant hue, with sharp transitions between hues. Viewers perceive these sharp transitions as sharp transitions in the data, even when this is not the casein how regularly spaced (interval) data are displayed (quoted from reference 1). This submission is intended to share the results of my efforts to create more perceptually balanced color maps. Please see output arguments section for descriptions.
See files examples.m, examples1.m, and example2.m and associated figures for more examples
See files MakeLabPlotUsingColorspace.m and CompareLabPlotsUsingColorspace.m for some demonstrations.
Extensive reference list and list of other FEX submissions of interest included in the help
Please visit my blog to read about the background research:

Author: Matteo Niccoli
e-mail address:
Release: 4.04
Release date: November 2014

Comments and Ratings (29)

Shaibal Ahmed

Tristan Ursell

Been using this in my publications for some time now ... wonderful set of colormaps!

Matteo Niccoli

HI MArtin. Thanks for the positive feedback. As for the error message, you are the first person to report it for pmkmp. Perhaps the 2007 release did not have these functions? It looks like others have encountered the problem and reported it elsewhere:

Martin Asmat

Very nice colormap. Thank you for the detailed info and references. When trying to use the code in matlab 2007 (Windows 7),I received the following error msg:
"Undefined function or method 'narginchk' for input arguments of type 'double'.

Error in ==> pmkmp at 332

It is interesting that I didn't see any of that when running it in matlab 2014b (in ubuntu) though. After commenting the lines corresponding to :
"narginchk" and "nargoutchk", the code seemed to work fine.

Matteo Niccoli

Hi Timothy, thank you for your feedback. And for the suggestion! I just got started with github and am building some tutorials on this in Python (you can check it at, but it did not occurr to me to upload the Matlab code as well. Great idea, I'll get to it as soon as I'm done with the Python tutorials.


Fantastic colormap! Have you though of placing your code and progress on github as well? That way we can fork, patch, or just update our copies very easily. Thank you again.

Hi Jakob, thanks for the positive feedback and for pointing that out. I am working on some additional colormaps so when I add those I will also fix the interp1 commands.

Works fine! An easy to use implementatoin of the color maps explained in the Mycarta blog. One minor issue: running the code I get a compatibility warning ("Warning: INTERP1(...,'CUBIC') will change in a future release. Use INTERP1(...,'PCHIP') instead."). Maybe this should be fixed in the next version.

Matteo Niccoli

Zack L-B: thanks, I must have loaded an older file accidentally. I just loaded the intended update (2014).

The current download appears to be the same as the February 2013 release.

Matteo Niccoli

John: I did not know you could do this:
>> X=(5:-1:-1)
X = 5 4 3 2 1 0 -1
>> X1=max(X,0)
X1 = 5 4 3 2 1 0 0
Wonderful, thanks for the great suggestion, I'll add that.

John D'Errico

John D'Errico (view profile)

Matteo - You could simply catch those spurious negative values from the interpolation using max(x,0) after interp1 has done its work.

Matteo Niccoli

John: thanks for the feedback. You are rigth, the function fails when called as
cmap = pmkmp(1);
The fact in itself that it fails does not worry me too much since these colormaps were intended for data series, so 1 color only would not be meaningful. But it is fair to add an extra check for minimum number of colors, so I added:
if n<2
error('n must be >= 2');
If someone wanted to set the display of their data to only one color, there are other ways, e.g.
Let me know what you think.

Matteo Niccoli

Joshua: I added the missing switch statements. THanks again.

Matteo Niccoli

Marius: thanks for spotting that. You are rigth, with a call like
you get a very small BUT negative value (-2.220446049250313e-16) for the Red in the last triplet. I think you are also rigth, it is because of interp1, specifically because I selected cubic as the interpolation method.
Since I want to retain that for the other colormaps, I am thinking of creating a separate function for the Edge colormap.

John Mahoney

Hi Matteo,
It looks like pmkmp fails if the number of colors requested is 1.
cmap = pmkmp(1);
Otherwise looks nice!



Marius (view profile)

Very nice idea, never thought about these color perception issues.

There is a small bug in pmkmp.m with my version of MATLAB ( (R2013a)). When using the edge colormap and n values around 100 (e.g. 128 or 64) I get

>> colormap(pmkmp(128,'edge'))
Error using colormap (line 99)
Colormap must have values in [0,1].

I think this is due to interp1 returning negative values under these circumstances.

Matteo Niccoli

Sebastian, John (and Petros, long overdue) thanks for the positive rating and feedback.

Joshua, thanks for the rating and comments, and also for spotting the error in the code. I just moved back to Canada after a year in Norway and my computer (with Matlab) is on a slow boat, I will re-submit with the corrected code asap.

Sebastian Hölz


I just had a long discussion with a colleague a few days ago on "big" anomalies in his plot, which were mainly due to the perception of the chosen colormap (jet).

I really like the "Edge" and "LinearL" colormaps and will must likely start to use them in the future.

John D'Errico

John D'Errico (view profile)

Nice job.


Joshua (view profile)

Really cool function, never thought about the perceived visual gradients in data due to luminosity mismatch. There was one error in the code where the 'linearl' and 'linlhot' were missing their switch statements. Here is the corrected switch statement on line 295 to access those last two color profiles:

switch lower(scheme)
    case 'isol'
        baseMap = IsoL;
    case 'cubicl'
        baseMap = CubicL;
    case 'edge'
        baseMap = Edge;
    case 'cubicyf'
        baseMap = CubicYF;
    case 'linearl'
        baseMap = LinearL
    case 'linlhot'
        baseMap = LinLhot
        error(['Invalid scheme ' scheme])

Matteo Niccoli

Colin, thank you for your positive comments. I just got back after a trip and saw your post. I will look into improving/clarifying use of examples.m asap. I may wait a bit to implement an updated as I have some add-ons modifications I am working on.


Colin (view profile)

Really interesting discussion/solution of a topic I hadn't given enough thought to.


p.s. It might be worth adding:


to the start of "examples.m". It took me a while to figure out why no figures were visible.

Alternatively you could consider using:

set(fign,'OuterPosition',[0.25 0.25 0.5 0.5],'units','normalized');


Colin (view profile)

indeed, perceptually better!



Replaced text labels in the screenshot


Uploaded new rainbow colormap with sawtooth shaped lightness profile. Included new example images and scripts, and deleted a few obsolete scripts. Updated reference links.


Added a new isoluminant colormap that wraps around the full hue range 0 - 2pi twice. Updated reference list with link to new blog post on IsoAZ and IsoAZ colormaps.


Corrected summary and added reference to a blog post by Steve Eddins for IsoAZ colormap


Replaced INTERP1(...,'CUBIC') with INTERP1(...,'PCHIP') as suggested by Jakob Nikolas in the comments. Added a new isoluminant colormap for cyclical (azimuth or phase).


On April 29th I loaded by mistake a previous release instead of the new one. This is the correct release.


Added missing switch statements for 'linearl' and 'linlhot'.
Added error check for minimum number of colors


Added a linear lightness rainbow colormap
Added a linear lightness adjusted heat colormap
Added first line to examples.m as suggested by COlin in the comments


Implemented Colin's first suggestion for examples.m


Added a 100% perceptual version of cube law rainbow and new examples and references.


updated contact email


flipped isoL colormap so red is on the high intensity side
added one more example
minor edits and typos corrected here and there


Added more examples and demonstrations


Added more examples in new file examples1.m
Added one of the reference papers (link disrupted)
Edited H1 line
Added justification paragraph
Modified REFERENCE AND acknowledgements in help
Removed MAC_OS hidden files

MATLAB Release
MATLAB 7.5 (R2007b)

Download apps, toolboxes, and other File Exchange content using Add-On Explorer in MATLAB.

» Watch video