colormap only 64 colors?

19 views (last 30 days)
Jan
Jan on 26 Jun 2019
Commented: Jan on 27 Jun 2019
Hi everyone,
I'm using a countourf plot with a colorbar to visualize the error in a simulation. The idea is that when the error is within a certain interval +/- allowed error that the plot shows a green color with a gradient to darker green as the error approaches the error limits. For errors larger outside of the allowed limit, the color should vary from dark red to bright red for the highest errors.
I made a function to create a colormap for this which gives me a colormap with a length of 1251. When I apply this colormap the resulting colors in the plot are not correct and when i request the colormap again from the figure, it has been reduced to a length of 64.
In this example I want the z-values outside of +/- 5 to have a red color and within +/- 5 a green color. As you can see in the picture a level of -1.9 is flagged as red.
Code:
clc
clear all
close all
Npoints = 1e3;
x = linspace(-250,250,Npoints);
[X,Y] = meshgrid(x,x);
Z = X.*Y.*1e-3;
fig = figure;
contourf(X,Y,Z)
colorbar(gca);
% Custom map
ErrorLim = 5;
cMax = max(max(abs(caxis)),ErrorLim);
caxis('manual')
caxis([-1 1]*cMax);
custom_map = CreateColorMapTwoSided(caxis,ErrorLim);
figure(fig)
cmap = colormap(gca,custom_map);
length(custom_map)
length(colormap
Function to create the map:
function colorMap = CreateColorMapTwoSided(lims,Threshold)
res = 1e-1;
x = lims(1):res:lims(2);
Npoints = length(x);
colorMap = zeros(Npoints,3);
if max(lims) <= Threshold
Lh = floor(Npoints/2);
idx = 1:Lh;
colorMap(idx,2) = linspace(0.5,1,length(idx));
idx = Lh+1:Npoints;
colorMap(idx,2) = linspace(1,0.5,length(idx));
else
% Identify the thresholds:
idx1 = find(x>=-Threshold,1,'first');
idx2 = find(x<=Threshold,1,'last');
% First red part
colorMap(1:idx1-1,1) = linspace(1,0.5,idx1-1)';
% Green part is divided in 2 gradients:
L1 = idx2 - idx1;
Lh = floor(L1/2);
colorMap(idx1:idx1+Lh,2) = linspace(0.5,1,length(idx1:idx1+Lh))'; % First green part leading up to 0
colorMap(idx1+Lh:idx2,2) = linspace(1,0.5,length(idx1+Lh:idx2))'; % Second green part starting at 0
% Second red part:
L2 = Npoints - idx2;
colorMap(idx2+1:end,1) = linspace(0.5,1,L2)';
figure
plot(x,colorMap(:,2),'g')
hold on
plot(x,colorMap(:,1),'r')
grid on
end
end
Red and green colums as a function of the z values from my own function:
colormap.png
Resulting picture:
error_plot_example.png
  10 Comments
Adam
Adam on 26 Jun 2019
Your issue appears to be more with contourf. If I use imagesc then it works as expected, but I am not familiar with contourf. Clearly it only uses a small subset of your colourmap elements though as there are only 4 or 5 distinct colours that change according to thresholds/levels. I don't know off-hand how these are mapped onto the colourmap, but I suspect these negative values are just falling into a large bin that is coloured by red and only after the next threshold value is passed does it move to the next colour which happens to be in the green part of your colourmap. I guess maybe it just uses colours that occur at e.g. 0, 25, 50, 75, 100% of your colourmap if it only uses 5 colours to bin the values.
Rik
Rik on 26 Jun 2019
Just another data point: I tested Guillaume's code on ML6.5, and even there the behavior is the same, so this has been the case for quite a while. (even if I had to remove assert, because that didn't exist yet)

Sign in to comment.

Accepted Answer

Rik
Rik on 26 Jun 2019
Your choice of function has a mismatch with what you want. The line below could help, but will stay an approximate:
contourf(X,Y,Z,min(size(custom_map,1),150))
Don't set the number of levels too high, or you will have a long time for the call to finish (150 is already quite high).
If you want a direct correlation, use imagesc, or a function like surf. If you're ok with hardcoding the colors (removing the flexibility of caxis) you can even use ind2rgb.
  1 Comment
Jan
Jan on 27 Jun 2019
I ended up solving it with surf.
Code:
clc
clear all
close all
Npoints = 1e3;
x = linspace(-250,250,Npoints);
[X,Y] = meshgrid(x,x);
Z = X.*Y.*1e-3;
% Custom color map
ErrorLim = 20;
fig = figure;
surf(X,Y,Z,'linestyle','none')
CreateColorMapTwoSided(gca,ErrorLim);
view(0,90)
axis tight
Function:
function colorMap = CreateColorMapTwoSided(ax,Threshold)
% Create colorbar
cbar = colorbar(ax);
% Match bar with threshold
cbar_range = max(max(cbar.Limits),Threshold);
lims = [-1, 1]*cbar_range;
caxis(lims);
res = 1e-1;
x = lims(1):res:lims(2);
Npoints = length(x);
colorMap = zeros(Npoints,3);
if max(lims) <= Threshold
Lh = floor(Npoints/2);
idx = 1:Lh;
colorMap(idx,2) = linspace(0.5,1,length(idx));
idx = Lh+1:Npoints;
colorMap(idx,2) = linspace(1,0.5,length(idx));
else
% Identify the thresholds:
idx1 = find(x>=-Threshold,1,'first');
idx2 = find(x<=Threshold,1,'last');
% First red part
colorMap(1:idx1-1,1) = linspace(1,0.5,idx1-1)';
% Green part is divided in 2 gradients:
L1 = idx2 - idx1;
Lh = floor(L1/2);
colorMap(idx1:idx1+Lh,2) = linspace(0.5,1,length(idx1:idx1+Lh))'; % First green part leading up to 0
colorMap(idx1+Lh:idx2,2) = linspace(1,0.5,length(idx1+Lh:idx2))'; % Second green part starting at 0
% Second red part:
L2 = Npoints - idx2;
colorMap(idx2+1:end,1) = linspace(0.5,1,L2)';
% figure
% plot(x,colorMap(:,2),'g')
% hold on
% plot(x,colorMap(:,1),'r')
% grid on
end
% Apply colormap to plot:
colormap(ax,colorMap);
end
This gives me the following figure:
error_plot_example.png
which is exactly what I wanted. Thanks!

Sign in to comment.

More Answers (0)

Categories

Find more on Colormaps in Help Center and File Exchange

Products


Release

R2017b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!