也可以在已有MATLAB图表的基础上重新渲染图形元素或使用新的图形元素进行表现,从而创建新的图表。比如本节将要介绍的将二维柱状图中的柱形替换为三角形,将三维柱状图中的柱体替换为圆锥或圆柱等。
颜色渐变填充柱状图中的柱形
MATLAB中用bar函数创建的柱状图柱形是单色的,没有太多的变化。本例在bar函数创建的柱状图的基础上对柱形进行修改,即隐藏图表中原有的柱形,在原来的位置上用patch函数创建面片重新绘制柱形。Patch对象是可以渐变着色的,从而达到对柱状图中的柱形渐变着色的效果。
下面的代码按照上面的思路对柱状图中的柱形进行水平渐变着色。
data=[1 5 3 7 6]; %绘图数据
b=bar(data); %用bar函数绘柱状图
b(1).FaceColor='none'; %隐藏柱形的面
b(1).EdgeColor='none'; %隐藏柱形的边
for i=1:length(data) %对于每个柱形
x=b(1).XData(i); %柱形位置,底边中心x坐标
w=b(1).BarWidth; %柱形的宽度
xb=x-w/2; %柱形左边x坐标
xe=x+w/2; %柱形右边x坐标
h=b(1).YData(i); %柱形的高
vert=[xb 0;x 0;xe 0;xe h;x h;xb h]; %面片的顶点坐标数组,顶点从前往后编号
face=[1 2 3 4 5 6]; %顶点围成面,编号逆时针方向
vc=[0.42 0.75 0.75;1 1 1;0.42 0.75 0.75;0.42 0.75 0.75;1 1 1;0.42 0.75 0.75]; %顶点的颜色
%创建面片,即新的柱形,渐变填充
p=patch('Faces',face,'Vertices',vert,'FaceVertexCData',vc,'FaceColor','interp');
p.EdgeColor='none'; %无边线
end
ylim([0 max(data)*1.05])
xlabel('X')
ylabel('Y')
grid on
box on
运行代码生成图2-15中的左图。
图2-15 水平渐变填充柱状图
上面的代码中,每个柱形用面片重建时用了6个顶点,柱形中间的上下两点的颜色为白色。下面的代码用3种颜色从左到右渐变填充柱状图中的矩形,如图2-15中右图所示。
…
for i=1:length(data)
… %省略部分代码
vc=[0.54 0.61 0.8;0.98 0.91 0.75;0.95 0.75 0.77;0.95 0.75 0.77;0.98 0.91 0.75;0.54 0.61 0.8];
… %省略部分代码
end
…
下面的代码中,每个柱形用面片重建时用矩形的4个顶点,左下角和右上角的颜色为白色,右下角和左上角的颜色为兰色。
… %省略部分代码
for i=1:length(data)
… %省略部分代码
vert=[xb 0;xe 0;xe h;xb h]; %4个顶点
face=[1 2 3 4];
vc=[1 1 1;0.42 0.75 0.75;1 1 1;0.42 0.75 0.75]; %4个顶点的颜色
p=patch('Faces',face,'Vertices',vert,'FaceVertexCData',vc,'FaceColor','interp');
p.EdgeColor='none';
end
… %省略部分代码
运行代码生成图2-16中的左图,时对角颜色渐变的效果。
图2-16 柱状图的更多渐变填充
下面的代码中,每个柱形用面片重建时用矩形的4个顶点,左下角和左上角的颜色为兰色,右下角和右上角的颜色为白色。
… %省略部分代码
for i=1:length(data)
… %省略部分代码
vert=[xb 0;xe 0;xe h;xb h]; %4个顶点
face=[1 2 3 4];
vc=[0.42 0.75 0.75;1 1 1;1 1 1;0.42 0.75 0.75]; %4个顶点的颜色
… %省略部分代码
end
… %省略部分代码
运行代码生成图2-16中的右图。
图片填充柱状图中的柱形
2.3.1小节使用Patch对象重建柱状图中的柱形,实现了柱形的颜色渐变填充。本小节介绍用图片填充柱状图中的柱形,使用的是第4章介绍的纹理映射的方法。这里使用Surface对象重建柱形。
下面的代码用Surface对象重建MATLAB柱状图中的柱形,并用图片填充新柱形。
data=[1 5 3 7 6]; %绘图数据
b=bar(data); %用bar函数创建柱状图
b(1).FaceColor='none'; %隐藏原有柱形
b(1).EdgeColor='none';
c=imread('d:\pic.jpgx27;); %从图片文件读取图像
for i=1:length(data) %对于每个柱形
x=b(1).XData(i); %柱形底边中心x坐标
w=b(1).BarWidth; %柱形宽度
xb=x-w/2; %柱形左边x坐标
xe=x+w/2; %柱形右边x坐标
h=b(1).YData(i); %柱形高度
x=linspace(xb,xe,20); %准备数据用曲面重建柱形
y=linspace(0,h,20);
[X,Y]=meshgrid(x,y);
Z=zeros(size(X));
%用新数据创建曲面,纹理映射着色
sur=surface(X,Y,Z,'CData',flipud(c),'FaceColor','texturemap');
sur.EdgeColor='none'; %隐藏边线
end
ylim([0 max(data)*1.05])
xlabel('X')
ylabel('Y')
grid on
box on
运行代码生成图2-17。也可以给每个柱形填充不同的图片,大家可以自己尝试。
图2-17 柱状图的图片填充
修改柱状图中的矩形为三角形
2.3.1小节用矩形面片重建了MATLAB柱状图中的柱形,这里介绍用三角形面片进行重建。理论上讲,你也可以用其他任意图形进行重建,想象空间很大。用三角形面片重建,仍然需要获取原有柱形的位置和大小。
下面的代码实现MATLAB柱状图中柱形的三角形面片重建,并用渐变色进行填充。
data=[1 5 3 7 6];
figure;
set(gcf,'Color',[1 1 1]);
b=bar(data);
b(1).FaceColor='none';
b(1).EdgeColor='none';
for i=1:length(data)
x=b(1).XData(i);
w=b(1).BarWidth;
xb=x-w/2;
xe=x+w/2;
h=b(1).YData(i);
vert=[xb 0;xe 0;x h]; %3个顶点
face=[1 2 3]; %组成面
vc=[0.94 0.53 0.59;1 1 1;0.94 0.53 0.59]; %3个顶点的颜色
%创建三角形面片,插值着色
p=patch('Faces',face,'Vertices',vert,'FaceVertexCData',vc,'FaceColor','interp');
p.EdgeColor='none';
end
title('My Cone Bar')
xlabel('Categorical Variable')
ylabel('Numeric Variable')
grid on
box on
运行代码生成图2-18。
图2-18 用三角形替换柱状图中的矩形
用高度数据渐变填充柱状图中的柱形
2.3.1小节使用Patch对象重建柱状图中的柱形,实现了柱形的颜色渐变填充,当然也可以实现高度方向的颜色渐变填充。本小节介绍用Surface对象重建柱形,并使用Surface对象的CData属性实现用高度数据渐变填充柱形的效果。
下面的代码用Surface对象重建MATLAB柱状图中的柱形,并用高度数据实现渐变填充。
data=[1 5 3 7 6];
b=bar(data);
for i=1:length(data)
x=b(1).XData(i);
w=b(1).BarWidth;
xb=x-w/2;
xe=x+w/2;
h=b(1).YData(i);
x=linspace(xb,xe,20); %用Surface对象重建柱形
y=linspace(0,h,20);
[X,Y]=meshgrid(x,y);
Z=zeros(size(X));
sur=surface(X,Y,Z);
sur.CData=sur.YData; %用高度数据着色
sur.FaceColor='interp'; %插值着色
sur.EdgeColor='none';
end
运行代码生成图2-19。
图2-19 根据柱形的高度数据进行渐变填充
替换三维柱状图的长方柱体
对于用bar3函数创建的MATLAB三维柱状图,按照上面用曲面重建柱形的思路,可以将原有的长方柱体替换为圆锥或圆柱。
下面的代码用圆锥曲面重建MATLAB三维柱状图中的长方柱体。圆锥曲面可以用MATLAB中的cylinder函数快速绘制。
data=[1 5 3 7 6];
b=bar3(data);
b(1).FaceColor='none';
b(1).EdgeColor='none';
y=b(1).YData(:,2);
z=b(1).ZData(:,2);
r=(y(3)-y(2))/2; %底面半径
t=r:-r/40:0;
rc=t;
[X,Y,Z]=cylinder(rc); %用cylinder函数获取圆锥曲面的网格数据
for i=1:length(data)
y0=(y(2+6*(i-1))+y(3+6*(i-1)))/2; %y中心位置(0,y0,0)
z0=z(2+6*(i-1)); %高度
h(i)=surf(X,Y+y0,Z*z0); %用surf函数绘制圆锥,进行了平移和缩放
h(i).EdgeColor='none'; %隐藏边线
h(i).FaceColor='interp'; %渐变着色
hold on
end
ylabel('Y')
zlabel('Z')
% 删除X轴刻度线和刻度标签
ax=gca;
axx=ax.XAxis;
axx.TickLength=[0;0];
axx.TickLabels='';
%其他设置
grid on
box on
axis equal
camlight left
camlight right
lighting phong
colorbar('Position',[0.68 0.55 0.03 0.18]);
hold off
运行代码生成图2-20。
图2-20 将三维柱状图中的柱体替换为圆锥体 图2-21 将三维柱状图中的柱体替换为圆柱体
按照同样的思路,可以用圆柱重建MATLAB三维柱状图中的长方柱体。不同的是,圆柱曲面顶部是空的,需要添加一个圆形面进行封盖。下面是实现代码。
data=[1 5 3 7 6];
b=bar3(data);
b(1).FaceColor='none';
b(1).EdgeColor='none';
y=b(1).YData(:,2);
z=b(1).ZData(:,2);
r=(y(3)-y(2))/2; %底面半径
[X,Y,Z]=cylinder(r);
for i=1:length(data)
y0=(y(2+6*(i-1))+y(3+6*(i-1)))/2; %y中心位置(0,y0,0)
z0=z(2+6*(i-1)); %高度
% 用圆形面盖住圆柱面
theta=0:pi/10:2*pi;
rt=0:r/20:r;
[TT,RR]=meshgrid(theta,rt);
XT=RR.*cos(TT);
YT=y0+RR.*sin(TT);
ZT=z0*ones(size(XT));
h2=surf(XT,YT,ZT);
h2.EdgeColor='none';
h2.FaceColor='interp';
hold on
%绘制圆柱,平移和缩放
h=surf(X,Y+y0,Z*z0);
h.EdgeColor='none';
h.FaceColor='interp';
end
ylabel('Y')
zlabel('Z')
% 删除X轴刻度线和刻度标签
ax=gca;
axx=ax.XAxis;
axx.TickLength=[0;0];
axx.TickLabels='';
% 其他设置
grid on
box on
axis equal
camlight left
camlight right
lighting phong
colorbar('Position',[0.68 0.55 0.03 0.18]);
hold off
运行代码生成图2-21。
给线形图添加背景
3.5.2小节介绍了利用坐标系对象的Backdrop.Face.ColorBinding属性对二维坐标系的绘图区背景进行颜色渐变填充。这里介绍另外一种更加通用的方法。思路是用一个Surface对象重建绘图区背景,进行渐变色填充或图片填充。
下面是实现的代码。
tiledlayout(2,2);
dx=[1 2 3 4 5]; %绘折线的数据
dy=[1 5 3 7 6];
dxMin=min(dx);
dxMax=max(dx);
dyMin=min(dy);
dyMax=max(dy);
ax1=nexttile;
ax1.XLim=[dxMin dxMax];
ax1.YLim=[dyMin dyMax];
%用面片绘制绘图区背景矩形
vert=[dxMin,dyMin;dxMax,dyMin;dxMax,dyMax;dxMin,dyMax];
face=[1,2,3,4];
color=[1 0 0;1 1 0;0 1 0;0 0 1];
%面片,渐变色填充
p=patch('Vertices',vert,'Faces',face,...
'FaceVertexCData',color,'FaceColor','interp');
%绘折线
line(dx,dy,'LineWidth',1.5,'Color','w')
xlabel('X')
ylabel('Y')
box on
ax2=nexttile;
ax2.XLim=[dxMin dxMax];
ax2.YLim=[dyMin dyMax];
vert=[dxMin,dyMin;dxMax,dyMin;dxMax,dyMax;dxMin,dyMax];
face=[1,2,3,4];
color=[0.95 0.66 0.23;0.95 0.66 0.23;1 1 1;1 1 1];
%面片,上下渐变色填充
p=patch('Vertices',vert,'Faces',face,...
'FaceVertexCData',color,'FaceColor','interp');
%绘折线
line(dx,dy,'LineWidth',1.5,'Color','b')
xlabel('X')
ylabel('Y')
box on
ax3=nexttile;
ax3.XLim=[dxMin dxMax];
ax3.YLim=[dyMin dyMax];
x=linspace(dxMin,dxMax,20);
y=linspace(dyMin,dyMax,20);
[X,Y]=meshgrid(x,y);
Z=zeros(size(X));
sur=surface(X,Y,Z); %用曲面绘制绘图区背景
sur.CData=sur.YData; %用y向数据着色,数据与颜色查找表映射得到的颜色
sur.FaceColor='interp';
sur.EdgeColor='none';
line(dx,dy,'LineWidth',1.5,'Color','w') %绘折线
xlabel('X')
ylabel('Y')
box on
ax4=nexttile;
ax4.XLim=[dxMin dxMax];
ax4.YLim=[dyMin dyMax];
x=linspace(dxMin,dxMax,20);
y=linspace(dyMin,dyMax,20);
[X,Y]=meshgrid(x,y);
Z=zeros(size(X));
C=imread('d:\pic.jpgx27;); %在绘图区加载图片作为背景
sur=surface(X,Y,Z);
sur.FaceColor='texturemap'; %注意属性的设置
sur.CData=flipud(C); %颜色矩阵上下翻转
sur.EdgeColor='none';
line(dx,dy,'LineWidth',1.5,'Color','w')
xlabel('X')
ylabel('Y')
box on
运行代码生成图2-22。
图2-22 二维坐标系绘图区背景的渐变填充和图片填充
三维图添加坐标轴面板背景
将2.3.6小节的问题扩展到三维,可以在三维图中添加坐标轴面板背景。思路跟前面相同,可以用面片或曲面重建面板背景,然后进行设置。
下面的代码在两个坐标系中分别实现三维图形坐标轴面板的渐变色填充和图片填充。
tiledlayout(2,2);
[X,Y,Z]=peaks;
xMin=min(min(X));
xMax=max(max(X));
yMin=min(min(Y));
yMax=max(max(Y));
zMin=min(min(Z));
zMax=max(max(Z));
ax1=nexttile; % 在第一个坐标系中渐变色填充坐标轴面板
ax1.XLim=[xMin xMax];
ax1.YLim=[yMin yMax];
ax1.ZLim=[zMin zMax];
%x-y面板
vert1=[xMin,yMin,zMin;xMax,yMin,zMin;xMax,...
yMax,zMin;xMin,yMax,zMin];
face1=[1,2,3,4];
color1=[0.9 0.9 0.9;0.9 0.9 0.9;0.9 0.9 0.9;0.9 0.9 0.9];
p1=patch('Vertices',vert1,'Faces',face1,...
'FaceVertexCData',color1,'FaceColor','interp');
%x-z面板
vert2=[xMin,yMax,zMin;xMax,yMax,zMin;xMax,...
yMax,zMax;xMin,yMax,zMax];
face2=[1,2,3,4];
color2=[0.95 0.66 0.23;0.95 0.66 0.23;1 1 1;1 1 1];
p2=patch('Vertices',vert2,'Faces',face2,...
'FaceVertexCData',color2,'FaceColor','interp');
%y-z面板
vert3=[xMax,yMax,zMin;xMax,yMin,zMin;xMax,...
yMin,zMax;xMax,yMax,zMax];
face3=[1,2,3,4];
color3=[0.95 0.66 0.23;0.95 0.66 0.23;1 1 1;1 1 1];
p3=patch('Vertices',vert3,'Faces',face3,...
'FaceVertexCData',color3,'FaceColor','interp');
%绘制曲面
h1=surface(X,Y,Z);
h1.EdgeColor='none';
xlabel('X')
ylabel('Y')
zlabel('Z')
view(3)
camlight
ax2=nexttile; % 在第二个坐标系中图片填充坐标轴面板
ax2.XLim=[xMin xMax];
ax2.YLim=[yMin yMax];
ax2.ZLim=[zMin zMax];
%x-z面板
vert1=[xMin,yMin,zMin;xMax,yMin,zMin;xMax,...
yMax,zMin;xMin,yMax,zMin];
face1=[1,2,3,4];
color1=[0.9 0.9 0.9;0.9 0.9 0.9;0.9 0.9 0.9;0.9 0.9 0.9];
p1=patch('Vertices',vert1,'Faces',face1,...
'FaceVertexCData',color1,'FaceColor','interp');
C=imread('d:\pic.jpg');
%x-z面板
x1=linspace(xMin,xMax,20);
z1=linspace(zMin,zMax,20);
[X1,Z1]=meshgrid(x1,z1);
Y1=ones(size(X1))*yMax;
sur1=surface(X1,Y1,Z1);
sur1.FaceColor='texturemap';
sur1.CData=flipud(C);
sur1.EdgeColor='none';
%y-z面板
y2=linspace(yMin,yMax,20);
z2=linspace(zMin,zMax,20);
[Y2,Z2]=meshgrid(y2,z2);
X2=ones(size(Y2))*xMax;
sur2=surface(X2,Y2,Z2);
sur2.FaceColor='texturemap';
sur2.CData=flipud(C);
sur2.EdgeColor='none';
%绘制曲面
h2=patch(surf2patch(X,Y,Z,Z));
[f,v,c]=surf2patch(X,Y,Z,Z);
h2.FaceVertexCData=(h2.Vertices(:,3)-...
min(h2.Vertices(:,3)))/(max(h2.Vertices(:,3))...
-min(h2.Vertices(:,3)));
h2.FaceColor="interp";
h2.EdgeColor='none';
xlabel('X')
ylabel('Y')
zlabel('Z')
view(3)
camlight
运行代码生成图2-23。可见,左图中坐标轴面板的渐变色填充完美实现了,右图中坐标轴面板的图片填充也实现了,但是曲面无法正常着色了。
图2-23 三维坐标系绘图区背景的渐变填充和图片填充