colormap only 64 colors?

10 次查看(过去 30 天)
Jan
Jan 2019-6-26
评论: Jan 2019-6-27
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 个评论
Adam
Adam 2019-6-26
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 2019-6-26
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)

请先登录,再进行评论。

采纳的回答

Rik
Rik 2019-6-26
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 个评论
Jan
Jan 2019-6-27
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!

请先登录,再进行评论。

更多回答(0 个)

类别

Help CenterFile Exchange 中查找有关 Colormaps 的更多信息

产品


版本

R2017b

Community Treasure Hunt

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

Start Hunting!

Translated by