hey 各位好久不见,今天提供一段有趣的小代码,之前刷到公众号闻道研学
的一篇推送MATLAB绘图技巧 | 设置颜色条的透明度(附完整代码)(https://mp.weixin.qq.com/s/bVx8AVL9jGlatja51v4H0A),文章希望绘图不但有颜色映射而且希望有透明度映射,同时希望颜色条也能体现透明度的变化,但是文章仅成功实现了颜色条透明度设置,这让我有了尝试的兴趣。
尝试的效果如下:
左侧为原始绘图效果,右侧为加入透明度变化。
1 一个接近答案的尝试
其实按照闻道研学
上的思路再多走两步,看似就能解决问题:
data = rand(12,12);
% 透明度范围 0 - 1 这里为了好看设置为 .3 - 1
AData = rescale(data, .3, 1);% 绘制由数值控制 colormap 和 透明度 的imagesc
imagesc(data, 'AlphaData',AData);
colormap(jet); % 坐标区域修饰
ax = gca;
ax.DataAspectRatio = [1,1,1]; % X-Y轴1:1
ax.TickDir = 'out'; % 刻度朝外
ax.Box = 'off';% 获取colorbar句柄
CBarHdl = colorbar;
% 句柄隐藏子对象生成需要时间因此pause一下
pause(1e-16)
% 修改colorbar透明度
CData = CBarHdl.Face.Texture.CData;
ALim = [min(min(AData)), max(max(AData))];
CData(4,:) = uint8(255.*rescale(1:size(CData, 2), ALim(1), ALim(2)));
CBarHdl.Face.Texture.ColorType = 'TrueColorAlpha';
CBarHdl.Face.Texture.CData = CData;
但是我发现在比较新的版本里,无论怎么保存图片都是无法保存下来右侧colorbar的透明度渐变的:
原因似乎是在存储为图片的时候,MATLAB会自动调整一次colorbar的大小,顺带着把Texture
这个玩意刷新了,那么有没有没刷新的东西呢,我发现可以直接修改Face
:
2 关于渐变colorbar的实现
我去年的时候回答过知乎的一个问题:如何在matlab里设置一个从透明到红色的colorbar?
- https://www.zhihu.com/question/631811249/answer/3307539169
当时给出的代码如下:
[X,Y] = meshgrid(-5:.1:5);
Z = Y.*sin(X) - X.*cos(Y);
% 绘制曲面,设置为纯红色,并设置根据Z数值调整透明度
s = surface(X,Y,Z,'EdgeColor','none','FaceColor',[1,0,0],...'FaceAlpha','flat','AlphaData',Z);
view(3)% 获取colorbar句柄
CBarHdl=colorbar;
% 句柄隐藏子对象生成需要时间因此pause一下
pause(1e-16)
% 每一列代表一个RGBA颜色
% 前三行每一列的[255; 0; 0]代表红色
% 最后一行0和255代表透明度
colorData = uint8([255, 255, 255, 255; ... 0, 0, 0, 0; ...0, 0, 0, 0; ...0, 0, 255, 255]);
% 设置隐藏Face子对象颜色映射模式为真实值RGBA,并修改颜色矩阵
set(CBarHdl.Face, 'ColorType','truecoloralpha', 'ColorData',colorData)
但是这仅仅是两个颜色的渐变,colorbar更加表层的Face
对象一般只存储了四个顶点的颜色,我们怎么把他变到十几种甚至上百种颜色呢,此时又想起我写的的一篇关于MATLAB一些基础对象的属性的博客:
- https://www.mathworks.com/matlabcentral/discussions/tips/844281-how-to-customize-legends-semitransparent-rounded-rectangle-legend
我在其中讲了一些基础对象的用法:
因此我们原本colorbar内部的Face
对象只是一个四边形,我们将其改成超级多小四边形,并为每一个小四边形赋予颜色和透明度:
data = rand(12,12);
% 透明度范围 0 - 1 这里为了好看设置为 .3 - 1
AData = rescale(data, .3, 1);% 绘制由数值控制 colormap 和 透明度 的surf
imagesc(data, 'AlphaData',AData);
colormap(jet); % 坐标区域修饰
ax = gca;
ax.DataAspectRatio = [1,1,1]; % X-Y轴1:1
ax.TickDir = 'out'; % 刻度朝外
ax.Box = 'off';% 获取colorbar句柄
CBarHdl = colorbar;
% 句柄隐藏子对象生成需要时间因此pause一下
pause(1e-16)
% 修改colorbar透明度
CData = CBarHdl.Face.Texture.CData;
ALim = [min(min(AData)), max(max(AData))];
CData(4,:) = uint8(255.*rescale(1:size(CData, 2), ALim(1), ALim(2)));warning off
CBarHdl.Face.ColorType = 'TrueColorAlpha';
VertexData = CBarHdl.Face.VertexData;
tY = repmat((1:size(CData,2))./size(CData,2), [4,1]);
tY1 = tY(:).'; tY2 = tY - tY(1,1); tY2(3:4,:) = 0; tY2 = tY2(:).';
tM1 = [tY1.*0 + 1; tY1; tY1.*0 + 1];
tM2 = [tY1.*0; tY2; tY1.*0];
CBarHdl.Face.VertexData = repmat(VertexData, [1,size(CData,2)]).*tM1 + tM2;
CBarHdl.Face.ColorData = reshape(repmat(CData, [4,1]), 4, []);
完美解决:
3 更多特殊情况
数值越高透明度越透明
data = rand(12,12);
% 透明度范围 0 - 1 这里为了好看设置为 .3 - 1
AData = rescale(- data, .3, 1);% 绘制由数值控制 colormap 和 透明度 的imagesc
imagesc(data, 'AlphaData',AData);
colormap(jet); % 坐标区域修饰
ax = gca;
ax.DataAspectRatio = [1,1,1]; % X-Y轴1:1
ax.TickDir = 'out'; % 刻度朝外
ax.Box = 'off';% 获取colorbar句柄
CBarHdl = colorbar;
% 句柄隐藏子对象生成需要时间因此pause一下
pause(1e-16)
% 修改colorbar透明度
CData = CBarHdl.Face.Texture.CData;
ALim = [min(min(AData)), max(max(AData))];
CData(4,:) = uint8(255.*rescale(size(CData, 2):-1:1, ALim(1), ALim(2)));warning off
CBarHdl.Face.ColorType = 'TrueColorAlpha';
VertexData = CBarHdl.Face.VertexData;
tY = repmat((1:size(CData,2))./size(CData,2), [4,1]);
tY1 = tY(:).'; tY2 = tY - tY(1,1); tY2(3:4,:) = 0; tY2 = tY2(:).';
tM1 = [tY1.*0 + 1; tY1; tY1.*0 + 1];
tM2 = [tY1.*0; tY2; tY1.*0];
CBarHdl.Face.VertexData = repmat(VertexData, [1,size(CData,2)]).*tM1 + tM2;
CBarHdl.Face.ColorData = reshape(repmat(CData, [4,1]), 4, []);
中间更透明
data = rand(12,12) - .5;
AData = rescale(abs(data), .1, .9);% 绘制由数值控制 colormap 和 透明度 的imagesc
imagesc(data, 'AlphaData',AData);
colormap(jet); % 坐标区域修饰
ax = gca;
ax.DataAspectRatio = [1,1,1]; % X-Y轴1:1
ax.TickDir = 'out'; % 刻度朝外
ax.Box = 'off';% 获取colorbar句柄
CBarHdl = colorbar;
% 句柄隐藏子对象生成需要时间因此pause一下
pause(1e-16)
% 修改colorbar透明度
CData = CBarHdl.Face.Texture.CData;
ALim = [min(min(AData)), max(max(AData))];
CData(4,:) = uint8(255.*rescale(abs((1:size(CData, 2)) - (1 + size(CData, 2))/2), ALim(1), ALim(2)));warning off
CBarHdl.Face.ColorType = 'TrueColorAlpha';
VertexData = CBarHdl.Face.VertexData;
tY = repmat((1:size(CData,2))./size(CData,2), [4,1]);
tY1 = tY(:).'; tY2 = tY - tY(1,1); tY2(3:4,:) = 0; tY2 = tY2(:).';
tM1 = [tY1.*0 + 1; tY1; tY1.*0 + 1];
tM2 = [tY1.*0; tY2; tY1.*0];
CBarHdl.Face.VertexData = repmat(VertexData, [1,size(CData,2)]).*tM1 + tM2;
CBarHdl.Face.ColorData = reshape(repmat(CData, [4,1]), 4, []);
其他绘图
其他绘图只要具有AlphaData
属性理论上都可以适用:
data = peaks(30);
AData = rescale(data, .2, 1);% 绘制由数值控制 colormap 和 透明度 的surf
surface(data, 'FaceAlpha','flat','AlphaData',AData);
colormap(jet(100)); % 坐标区域修饰
ax = gca;
ax.DataAspectRatio = [1,1,1]; % X-Y轴1:1
ax.TickDir = 'out'; % 刻度朝外
ax.Box = 'off';
view(3)% 获取colorbar句柄
CBarHdl = colorbar;
% 句柄隐藏子对象生成需要时间因此pause一下
pause(1e-16)
% 修改colorbar透明度
CData = CBarHdl.Face.Texture.CData;
ALim = [min(min(AData)), max(max(AData))];
CData(4,:) = uint8(255.*rescale(1:size(CData, 2), ALim(1), ALim(2)));warning off
CBarHdl.Face.ColorType = 'TrueColorAlpha';
VertexData = CBarHdl.Face.VertexData;
tY = repmat((1:size(CData,2))./size(CData,2), [4,1]);
tY1 = tY(:).'; tY2 = tY - tY(1,1); tY2(3:4,:) = 0; tY2 = tY2(:).';
tM1 = [tY1.*0 + 1; tY1; tY1.*0 + 1];
tM2 = [tY1.*0; tY2; tY1.*0];
CBarHdl.Face.VertexData = repmat(VertexData, [1,size(CData,2)]).*tM1 + tM2;
CBarHdl.Face.ColorData = reshape(repmat(CData, [4,1]), 4, []);