MATLAB | 透明度渐变颜色条

文摘   2024-06-10 00:12   山东  
请尊重原创劳动成果
转载请注明本文链接
及文章作者:slandarer

hey 各位好久不见,今天提供一段有趣的小代码,之前刷到公众号闻道研学的一篇推送MATLAB绘图技巧 | 设置颜色条的透明度(https://mp.weixin.qq.com/s/bVx8AVL9jGlatja51v4H0A),文章希望绘图不但有颜色映射而且希望有透明度映射,同时希望颜色条也能体现透明度的变化,但是文章仅成功实现了颜色条透明度设置,这让我有了尝试的兴趣。

尝试的效果如下:

左侧为原始绘图效果,右侧为加入透明度变化。

1 一个接近答案的尝试

其实按照闻道研学上的思路再多走两步,看似就能解决问题:

data = rand(12,12); 
% 透明度范围 0 - 1 这里为了好看设置为 .3 - 1
AData = rescale(data, .31);

% 绘制由数值控制 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([255255255255; ... 
                     0,   0,   0,   0; ...
                     0,   0,   0,   0; ...
                     0,   0255255]);
% 设置隐藏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, .31);

% 绘制由数值控制 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, .31);

% 绘制由数值控制 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, .21);

% 绘制由数值控制 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, []);


slandarer随笔
slandarer个人公众号,目前主要更新MATLAB相关内容。
 最新文章