change the range of your sections in your colormap
55 次查看(过去 30 天)
显示 更早的评论
Hello,
I want my section to be red [-1 -0.1], green [-0.1 0.1], blue [0.1 1]. now it just divide it in 3 equal sections. However, if I try to implement limits, it gives the following error: 'must be a two element row vector'.
figure(4)
D = surf(X1,Y1,Zplane,H,'EdgeColor','flat');
set(gca,'clim',[-1,1])
cmap = [1 0 0; 0 1 0; 0 0 1];
colormap(cmap);
% xlim([0 84.83])
% ylim([0 63.60])
xlim([35 40])
ylim([35 40])
xlabel('x [\mum]')
ylabel('y [\mum]')
zlabel('z [\mum]')
colorbar
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1258175/image.png)
2 个评论
采纳的回答
DGM
2023-1-10
If nothing else,
% some data
x = linspace(-pi,pi,100);
y = x.';
Z = cos(x).*sin(y);
% idk how your H is defined, so i'm reusing Z
H = Z;
% make a map that puts the breakpoints where you need them
mapcolors = [1 0 0; 0 1 0; 0 0 1];
cmap = [repmat(mapcolors(1,:),[5 1]); ...
mapcolors(2,:); ...
repmat(mapcolors(3,:),[5 1])];
D = surf(x,y,Z,H,'EdgeColor','flat');
set(gca,'clim',[-1 1])
colormap(cmap);
xlabel('x [\mum]')
ylabel('y [\mum]')
zlabel('z [\mum]')
colorbar
更多回答(1 个)
DGM
2023-1-13
编辑:DGM
2023-1-13
When I answered this question, I was a bit hasty, as I thought I had seen a good example but couldn't find it. Well, it's days later, and I still can't find any good, complete examples. I'm going to expand on the crude example I gave so that this can stand as a reference. I don't think these examples are elegant or optimal, but in a sense I'm also attempting to invoke Cunningham's law.
Consider the following links
The easy, unsatisfactory answer
A number of threads asking about unequal interval colorbars are either asking about logscale applications, uniform-interval discrete colormapping, or they wind up with nonuniform interval mapping represented with a uniform-interval colorbar with mismatched ticklabels. The latter scenario being like this:
% intervals/categories in Z
zb = [-1 -0.1 0 1/3 1/sqrt(2) 0.91 1];
% interval/category colors
CT0 = 1-lines(numel(zb)-1);
% some fake data
x = linspace(-0.5,0.5,100);
y = x.';
Z = x+y;
% color data (2D map of indices into CT0)
% this can be generated however you see fit (imquantize(), etc)
C = ones(size(Z));
nk = numel(zb)-1;
for ck = 1:nk
if ck == 1
C(Z<zb(2)) = 1;
elseif ck == nk
C(Z>=zb(nk)) = nk;
else
C(Z>=zb(ck) & Z<zb(ck+1)) = ck;
end
end
% use direct mapping with indexed CData
hs = surf(x,y,Z,C);
hs.CDataMapping = 'direct';
shading flat
colormap(CT0) % map only has 6 colors
cb = colorbar; % ticks are uniformly spaced
cb.TickLabels = strrep(cellstr(num2str(zb(:),'%.4g')),' ','');
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1262730/image.png)
The way I see this question and some others, this result is inadequate. That's only one interpretation, but I'm going to pursue it for sake of example. Since the colorbar axis is a linear space and the color table (CT) is short, the breakpoints in the colorbar are accordingly uniformly spaced. You can fake the TickLabels, but it still misrepresents the relative scale of the intervals. I would rather the interval breakpoints be represented in their appropriate relative positions between the colorbar extents. This is obviously inappropriate for logscale needs, but for the example given, I think it's a reasonable requirement. Could the scaling be altered by editing hidden properties of the colorbar object? I don't know, but for now, I'm going to avoid undocumented options.
Caxis quantization via colortable expansion
So that brings us to the original answer I gave. There are various ways we might choose to quantize/classify our Z or color data, but we need to do it in a way that allows us to construct a colorbar that represents things with appropriate relative scale. Since the primary axis of the colorbar is (usually) linear, if we want breakpoints at arbitrary locations between its extents, this becomes a quantization problem.
We're basically left trying to do nonuniform quantization via a process that only allows uniform quantization. If we want a single breakpoint a quarter of the way between the endpoints, we'd need a colormap with 4 entries, but only 2 colors. In the original answer, while we needed only three colors for three intervals, the breakpoint locations meant we needed 11 colormap entries to get the breakpoints where they needed to be.
This is not generally a problem with exact solutions. Irrational numbers exist, and even if they didn't, we might not want or need an extremely long color table. While in the original answer, I just manually assembled the expanded color table, that's not generally a practical approach. I've attached a simple function that attempts to generate such an expanded color table. Give it a list of breakpoints, a short CT defining the interval colors, and you'll get a minimally-expanded CT within the given constraints.
So let's start with a basic setup as before, but now with an expanded CT:
% intervals/categories in Z (or C)
% the span of this vector defines caxis/clim
zb = [-1 -0.1 0 1/3 1/sqrt(2) 0.91 1];
% interval/category colors
CT0 = lines(numel(zb)-1);
% maximum table length
nmax = 256;
% generate expanded color table & info
[CT cidx] = intervalct(zb,CT0,nmax);
cidx1 = cidx(:,2); % trailing block indices
% some fake data
x = linspace(-0.5,0.5,100);
y = x.';
Z = x+y;
Implicit colormapping using CDataMapping = 'scaled'
How can we use this overgrown colorbar with our surf? The simple way would be like the original example. This may be convenient, but remember the map quantization isn't always exact as it was in that example. When you allow the implicit colormapping of your surf object be defined by breakpoints that aren't necessarily exactly where you wanted them to be, some of the boundaries can shift on the colormapped object. The effect is more likely when the maximum CT length is kept short.
%% implicit mapping (poor control over exact edge conditions)
% boundary locations on the surf are only as accurate as the map quantization
% note the shift in the -0.1, 1/sqrt(2), and 0.91 boundaries when N = 198
hs = surf(x,y,Z,Z); % here, C = Z; CDataMapping is 'scaled'
shading flat
colormap(CT)
cb = colorbar;
cb.Ticks = zb;
caxis(imrange(zb));
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1262735/image.png)
It's hard to tell from the static image, but the noted boundaries are slightly shifted. This set of breakpoints doesn't have any nice exact solution. For a much shorter CT, the error is bad enough that it's also noticeable on the colorbar.
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1262740/image.png)
Allowing for a long CT would have given a more accurate solution, but this serves as a warning. Slight sub-pixel inaccuracy in the color breakpoints (not the ticks!) of the colorbar are acceptable, but when chunks of a coarse surf() or pcolor are wrongly classified, that's not good.
Explicit colormapping (indexed)
Unless we always know that our set of breakpoints can allow in an exact quantization of caxis, what else can we do? The trick is to avoid using 'scaled' CDataMapping, since that relies on the accuracy of the expanded CT. The first example in this comment uses a basic means of constructing an explicit index map to use as CData. This allows the colorization of the surf to be directly controlled, and is independent of how the expanded CT was generated.
%% explicit (indexed) mapping (complicates colorbar scale)
% the inaccuracy of map quant only affects the colorbar display
% all colors on the surf are explicitly defined by masking or imquantize(), etc
% here, cb.Ticks and caxis refer to colormap indices
% so tick labels have to be generated explicitly to be in data units
% color data (index map into CT)
% this can be generated however you see fit (imquantize(), etc)
C = ones(size(Z));
nk = numel(zb)-1;
for ck = 1:nk
if ck == 1
C(Z<zb(2)) = 1;
elseif ck == nk
C(Z>=zb(nk)) = nk;
else
C(Z>=zb(ck) & Z<zb(ck+1)) = ck;
end
end
C = cidx1(C); % CT needs enough resolution to control cb spacing
hs = surf(x,y,Z,C);
hs.CDataMapping = 'direct';
shading flat
colormap(CT)
cb = colorbar;
cb.Ticks = [1; cidx1+1];
cb.TickLabels = strrep(cellstr(num2str(zb(:),'%.4g')),' ','');
caxis([1 cidx1(end)])
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1262745/image.png)
Explicit colormapping (RGB)
That works, but it's a bit of a nuisance to deal with the fact that the colorbar space is no longer in data units, but in CT indices. Instead of using indexed CData, we can use RGB CData.
%% explicit (RGB) mapping (cb/surf work, but are disconnected)
% the inaccuracy of map quant only affects the colorbar display
% all colors on the surf are explicitly defined by masking or imquantize(), etc
% here, cb.Ticks and caxis refer to data units, and labels automatically correspond
% color data as an RGB array
% this can be generated however you see fit (imquantize(), etc)
C = ones(size(Z));
nk = numel(zb)-1;
for ck = 1:nk
if ck == 1
C(Z<zb(2)) = 1;
elseif ck == nk
C(Z>=zb(nk)) = nk;
else
C(Z>=zb(ck) & Z<zb(ck+1)) = ck;
end
end
%C = ind2rgb(cidx1(C),CT); % could use expanded CT as before
C = ind2rgb(C,CT0); % but this is simpler
hs = surf(x,y,Z,C);
hs.CDataMapping = 'direct';
shading flat
colormap(CT) % still need full CT here though
cb = colorbar;
cb.Ticks = zb;
caxis(imrange(zb));
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1262750/image.png)
Again, are there other ways to approach this? Probably. Given the loose language used in threads related to the topic, it's a difficult objective to find with the search tool. Feel free to add links.
What would I do differently if I were trying to do this with something other than a surf() object? I don't know. I chose to use a surf() object, as it was relevant to the original question, and it makes it easier to bridge a gap between indirect/scaled colormapping and direct colormapping. I don't think this would be too difficult to make work with pcolor()/image() etc.
0 个评论
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Blue 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!