进阶绘图

前言

Matlab的绘图功能要远比上一篇文章中所介绍的强大的多 , 下面一幅图片源自网络 , 大致介绍了在什么情况下适合绘制什么类型的图像 , 在以后的论文中可以根据需要加以参考.

image-20200705160434836

平面绘图进阶

这里介绍一些平面图形的绘制过程中的其他功能 , 所需要的函数大致如下:

对数图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
x = logspace(-1,1,100); % 产生范围从10的-1次方到10的1次方中100维的等比数列
y = x.^2;
subplot(2,2,1);
plot(x,y);
title('Plot');
subplot(2,2,2);
semilogx(x,y); % 对x轴取对数
title('Semilogx');
subplot(2,2,3);
semilogy(x,y); % 对y轴取对数
title('Semilogy');
subplot(2,2,4);
loglog(x, y); % 对x轴和y轴同时取对数
title('Loglog');

结果图:

image-20200705163051684

对于对数图来说, 一般会加上网格线 . 对每个图形执行set(gca, 'XGrid' ,'on');可以加上网格线.

创建具有2个y轴的图

1
2
3
4
5
6
7
8
9
x = 0:0.01:20;
y1 = 200*exp(-0.05*x).*sin(x);
y2 = 0.8*exp(-0.5*x).*sin(10*x);
[AX,H1,H2] = plotyy(x,y1,x,y2); % AX是坐标轴的handle(句柄), H1是第一条曲线的句柄,H2是第二条曲线的句柄.
set(get(AX(1),'Ylabel'),'String','Left Y-axis')
set(get(AX(2),'Ylabel'),'String','Right Y-axis')
title('Labeling plotyy');
set(H1,'LineStyle','--');
set(H2,'LineStyle',':');

效果图:

image-20200705164402590

直方图

1
2
3
4
5
6
7
y = randn(1,1000); % 产生1行1000列的正态分布随机数向量
subplot(2,1,1);
hist(y,10); % 绘制10个条的直方图
title('Bins = 10');
subplot(2,1,2);
hist(y,50); % 绘制50个条的直方图
title('Bins = 50');

效果图:

image-20200705165120493

条形图

1
2
3
4
5
6
7
8
x = [1 2 5 4 8]; % x是一个向量
y = [x;1:5]; % y是一个矩阵
subplot(1,3,1); bar(x); % 参数为向量值时 , 结果图形按向量的每一维的数值独立绘制
title('A bargraph of vector x');
subplot(1,3,2); bar(y); % 参数为矩阵时, 结果图形按每一个行向量分组绘制
title('A bargraph of vector y');
subplot(1,3,3); bar3(y); % bar3() 绘制三维的条形图
title('A 3D bargraph');

结果图:

image-20200705165915726

可以在bar()绘图过程中指定stacked属性来让条形图叠加起来. 使用barh()函数改变条形图的方向.

1
2
3
4
5
6
7
8
x = [1 2 5 4 8];
y = [x;1:5];
subplot(1,2,1);
bar(y,'stacked'); % 把这些条叠加起来, 每一行作为一组
title('Stacked');
subplot(1,2,2);
barh(y); % 每一行作为一组 改变条形图的方向
title('Horizontal');

结果图:

image-20200705171216033

饼图

1
2
3
4
5
% 结果显示各个数值占总数的百分比
a = [10 5 20 30];
subplot(1,3,1); pie(a);
subplot(1,3,2); pie(a, [0,0,0,1]); % 参数向量的最后一维是1, 使最后一维的数值与图其他分开显示
subplot(1,3,3); pie3(a, [0,0,0,1]); % pie3绘制3维立体饼图

结果图:

image-20200705171610243


练习: 使饼图的所有块互相分开.

效果: image-20200705171953102

参考代码:

1
2
3
4
a = [10 5 20 30];
subplot(1,3,1); pie(a,[1 1 1 1]);
subplot(1,3,2); pie(a, [1 1 1 1]);
subplot(1,3,3); pie3(a, [1 1 1 1]);

极坐标图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
x = 1:100; theta = x/10; r = log10(x);
subplot(2,2,1); polar(theta,r); % polar()函数的两个参数 分别是角度和极径
theta = linspace(0, 2*pi); r = cos(4*theta);
subplot(2,2,2); polar(theta, r);

theta = linspace(0, 2*pi, 6);
% 此函数第三个参数6 指定了等差数列的长度. 也就是从0到2π五等分, 取6个端点的值.
r = ones(1,length(theta));
% ones函数 一个参数时代表生成全1的方阵维数. 此处两个参数, 这两个参数表示生成全1矩阵的行数和列数. 这里为1行6列
subplot(2,2,3); polar(theta,r);
% 这幅图的两个向量都是6维向量 根据matlab中绘图的基本原理可知, 此处只在坐标系中描了6个点. 进一步分析发现第六个点的位置在极坐标中是重合的,也就是相当于5个点,连接着五个点, 形成的图形是正五边形.按此思路可以绘制其他正多边形.

theta = linspace(0, 2*pi); r = 1-sin(theta); % 此为心形曲线函数
subplot(2,2,4); polar(theta , r);

结果图:

image-20200705173452925

折线图和离散序列图

1
2
3
x = linspace(0, 4*pi, 40); y = sin(x);
subplot(1,2,1); stairs(y); % 绘制折线图函数
subplot(1,2,2); stem(y); % 绘制离散序列图函数

结果图:

image-20200705173850984


练习:

  • 绘制函数图像: f(t)=sin(πt24)f(t)=\sin \left(\frac{\pi t^{2}}{4}\right)
  • 使用stem()函数在图像中加入取样点图像.

参考效果图:

image-20200705181453015

参考代码:

1
2
3
4
5
6
7
8
9
clear
t=linspace(0,3*pi); % t的范围
x=0:0.25:3*pi; % 采样点序列
f= sin((pi*t.*t)/4); % 函数曲线解析式
y= sin((pi*x.*x)/4); % 采样函数解析式
hold on %开始绘图
plot(t,f);
stem(x,y);
hold off

箱线图和误差条

箱线图使用方法参考文档

误差条示例代码:

1
2
3
4
x=0:pi/10:pi; y=sin(x);
e=std(y)*ones(size(x));
% std为标准差函数.
errorbar(x,y,e) % 前两个参数绘制函数图形, 第三个参数提供误差条大小.

结果图:

image-20200705182544058

fill()函数

fill()函数实现绘制一个图形, 并在图形内部填充颜色.

1
2
3
4
5
6
7
8
9
t =(1:2:15)'*pi/8; % 正8边形8个顶点的角度值
x = cos(t); % 8个顶点在直角坐标下的横坐标值
y = sin(t); % 8个顶点在直角坐标系下纵坐标值
fill(x,y,'r'); % 在直角坐标系下绘制正8边形 ,绘图原理上面已经介绍过 , 描出8个顶点,连线.
axis square off;
text(0,0,'STOP','Color', 'w',... % 设置文本相关属性
'FontSize', 80, ...
'FontWeight','bold',...
'HorizontalAlignment', 'center');

结果图:

image-20200705194953074


练习: 绘制如下图形.

示例图片: image-20200705195038929

参考代码:

1
2
3
4
5
6
7
8
>t = 0:pi/2:2*pi;
>x = cos(t);
>y = sin(t);
>h = fill(x,y,'y');
>set(h,'LineWidth',5);
>axis square off;
>text(0,0,'WAIT','Color','k','FontSize',70,...
>'FontWeight','bold','HorizontalAlignment','center');

色彩空间

matlab使用一个三维向量[R G B]来描述颜色. RGB的值有两种设置方式, 第一种是设置成0到1之间的一个数值, 数值的大小代表整体颜色中该颜色的成分的多少. 例如 [1 0 0]代表红色, [0 0 0]代表黑色, [1 1 1]代表白色. 第二种设置方式是设置成0到255之间的整数值, 数值的大小代表该颜色分量成分的多少, 这种表示方式实际上就是用8位2进制来表示颜色数值, 由于八位2进制可以转化成2个十六进制数, 所以关于RGB颜色还可以用6位16进制数来表示.但matlab似乎不支持这种颜色表示方式

下面图片中给出一些常用颜色的数值:

image-20200705201651644


练习: 修改下面的绘图代码, 使之成为示例图片的效果

代码:

1
2
3
4
5
G = [46 38 29 24 13]; S = [29 27 17 26 8];
B = [29 23 19 32 7]; h = bar(1:5, [G' S' B']);
title('Medal count for top 5 countries in 2012 Olympics');
ylabel('Number of medals'); xlabel('Country');
legend('Gold', 'Silver', 'Bronze')

示例图片:

image-20200705201858311

参考代码:

1
2
3
4
5
6
7
8
9
10
G = [46 38 29 24 13]; S = [29 27 17 26 8];
B = [29 23 19 32 7];
h = bar(1:5, [G' S' B']);
% 颜色可能与上图存在差异, 基本设置方法相同.
set(h(1),'FaceColor',[0.929 0.694 0.125]);
set(h(2),'FaceColor',[0.6 0.6 0.6]);
set(h(3),'FaceColor',[0.8 0.6 0]);
title('Medal count for top 5 countries in 2012 Olympics');
ylabel('Number of medals'); xlabel('Country');
legend('Gold', 'Silver', 'Bronze')

在matlab中绘制三维图像时, 虽然三维图像看起来很好看, 但是我们从一个角度观察三维图像很难看出图像上的数值信息, 比如在下面代码绘制的图像中, 就很难看清楚图像最低点的空间坐标是多少.

1
2
3
4
[x, y] = meshgrid(-3:.2:3,-3:.2:3);
z = x.^2 + x.*y + y.^2; surf( x, y, z); box on;
set(gca,'FontSize', 16); zlabel('z');
xlim([-4 4]); xlabel('x'); ylim([-4 4]); ylabel('y');

上述代码中用到的绘制三维图像的函数, 将在下一节做介绍.

结果图:

image-20200705210550976

为了了解更多关于图像的数值信息, 可以使用imagesc()函数, 来实现图像颜色的投影.

加入代码

1
imagesc(z); axis square; xlabel('x'); ylabel('y');

得到图像:

image-20200705210926512

这样, 我们就能够得知三维图像上每个颜色对应的x轴坐标和y轴坐标. 但是这个图片无法得知z轴的数值信息, 要想得知关于z轴的数值信息, 可以执行colorbar;指令, 或者点击上图中红色方框中的按钮.得到下图:

image-20200705211328739

由此图, 我们就可以了解到图像的三维坐标信息了.

可以使用colormap()函数来调整图像的颜色渲染方式, 比如colormap(cool)冷色系渲染, colormap(hot)暖色系渲染, colormap(gray)灰度渲染. 其效果分别如下图:

image-20200705211745281

image-20200705211824743

image-20200705211859311

matlab内置了许多colormap, 下图中列举部分内容, 可以使用colormap([NAME])来进行修改:

image-20200705212051893

在matlab中的colormap实际上就是一个矩阵, 这个矩阵有三列, 分别代表RGB的数值.我们可以通过执行a=colormap(gray)来观察a变量的内容, 执行后可以发现a是一个64×364\times 3的矩阵, 其部分内容如下图:

image-20200705212722456

了解这个原理之后, 我们就可以自定义一个colormap.

1
2
3
4
5
6
7
8
x = [1:10; 3:12; 5:14];
imagesc(x);
colorbar;

map = zeros(256,3);
map(:,2) = (0:255)/255;
colormap(map);

效果图:

image-20200705212932698

三维绘图

其实对于matlab来说, 所有的二维图像也不是二维图像, 二维曲线只是三维曲线的一部分, 我们绘制的每一幅二维图像中, 都可以通过点击工具栏中的三维旋转按钮 观察其空间效果; 下图是通过三维旋转按钮观察该曲线在空间某一角度的效果:

image-20200705214119703

三维绘图的主要函数有:

  • plot3: 三维点或线图
  • surf: 曲面图
  • surfc: 曲面图下的等高线图
  • surface: 基本曲面图
  • meshc: 网格曲面图下的等高线图
  • contour: 矩阵的等高线图
  • contourf: 填充的二维等高线图

plot3()函数和plot()函数区别不大, 下面是一个应用plot3()绘制三维图像的例子, 其中plot3()的绘图数据要传入三个参数, 即空间点的坐标, matlab依旧是完成描点连线工作.

1
2
3
4
x=0:0.1:3*pi; z1=sin(x); z2=sin(2.*x); z3=sin(3.*x);
y1=zeros(size(x)); y3=ones(size(x)); y2=y3./2;
plot3(x,y1,z1,'r',x,y2,z2,'b',x,y3,z3,'g'); grid on;
xlabel('x-axis'); ylabel('y-axis'); zlabel('z-axis');

结果图像:

image-20200705214424785

示例代码:

1
2
3
t = 0:pi/50:10*pi;
plot3(sin(t),cos(t),t)
grid on; axis square;

结果图像:

image-20200705220139029

示例代码:

1
2
3
4
5
6
turns = 40*pi;
t = linspace(0,turns,4000);
x = cos(t).*(turns-t)./turns;
y = sin(t).*(turns-t)./turns;
z = t./turns;
plot3(x,y,z); grid on;

结果图像:

image-20200705220233609

上面的例子中, 绘图所描的点可以使用线来连接起来. 但是对于空间曲面的绘制, 我们不是需要用点连成线 而是需要用点来组成面. 这时需要使用到mesh()函数和surf()函数. matlab绘制z=f(x,y)z=f(x,y)的图像要分一下几部进行.

  1. 指定x和y的范围和取值向量
  2. 使用[X Y]meshgrid(x,y)来生成x和y两个自变脸组成的网格点矩阵
  3. 使用mesh()surf()函数来绘制空间曲面

下面介绍meshgrid()函数的用法. 比如我们的x和y两个向量分别是x=-2:1:2,y=-2:1:2, 执行[X Y]meshgrid(x,y)后生成的X矩阵和Y矩阵如下:

image-20200705221707504

这两个矩阵就是用来绘图的坐标矩阵, Z轴坐标的计算也应该使用X,Y矩阵得出.示例代码:

1
2
3
4
5
x = -3.5:0.2:3.5; y = -3.5:0.2:3.5;
[X,Y] = meshgrid(x,y);
Z = X.*exp(-X.^2-Y.^2);
subplot(1,2,1); mesh(X,Y,Z);
subplot(1,2,2); surf(X,Y,Z);

结果图形:

image-20200705222037110

下面介绍contour()函数, 这个函数实现的是将三维曲面的投影操作, 和imagesc()函数的效果有相似之处.

示例代码:

1
2
3
4
5
6
7
8
9
10
x = -3.5:0.2:3.5;
y = -3.5:0.2:3.5;
[X,Y] = meshgrid(x,y);
Z = X.*exp(-X.^2-Y.^2);
subplot(1,2,1);
mesh(X,Y,Z);
axis square;
subplot(1,2,2);
contour(X,Y,Z);
axis square;

结果图像:

image-20200705222551861

contour()更多使用方法:

1
2
3
4
5
6
7
8
9
x = -3.5:0.2:3.5; y = -3.5:0.2:3.5;
[X,Y] = meshgrid(x,y); Z = X.*exp(-X.^2-Y.^2);
subplot(1,3,1); contour(Z,[-.45:.05:.45]); % 会依据这个指定的向量来投影划分, 这个向量省略了小数点前面的0
axis square;
subplot(1,3,2); [C,h] = contour(Z);
clabel(C,h); % 使用clabel指令来让图片标记数值
axis square;
subplot(1,3,3); contourf(Z); % 使用contourf()函数来填充颜色 f就是fill的意思
axis square;

练习: 综合使用上面介绍的使用方法, 绘制如下示例图片.

示例图片: image-20200705223940063

参考代码:

1
2
3
4
5
6
x = -3.5:0.2:3.5; y = -3.5:0.2:3.5;
[X,Y] = meshgrid(x,y);
Z = X.*exp(-X.^2-Y.^2);
[C,h]=contourf(Z,[-.45:.05:.45]);
clabel(C,h);
axis square;

下面介绍meshc()函数和surfc()函数, 在上面两个函数多加个c实际上就是把投影图像和三维曲面图像放在同一个图片里, 比如:

1
2
3
4
x = -3.5:0.2:3.5; y = -3.5:0.2:3.5;
[X,Y] = meshgrid(x,y); Z = X.*exp(-X.^2-Y.^2);
subplot(1,2,1); meshc(X,Y,Z);
subplot(1,2,2); surfc(X,Y,Z);

结果图像:

image-20200705224259526

可以使用view()函数来调整观察三维图形的视角, view()函数需要输入两个参数, 这两个参数相当于柱坐标系中的两个角度参数,如图:

image-20200705224524799

除了调整角度, 还可以使用light()函数来调整光线. 由于感觉越学越向着美术绘图方向发展了, 所以关于light()函数不做过多介绍.

最后举一个炫酷的绘图例子:

1
2
3
4
5
6
load cape
X=conv2(ones(9,9)/81,cumsum(cumsum(randn(100,100)),2));
surf(X,'EdgeColor','none','EdgeLighting','Phong',...
'FaceColor','interp');
colormap(map); caxis([-10,300]);
grid off; axis off;

由于使用了随机函数, 每次执行的效果会不一样.

image-20200705225045607image-20200705225117545

资料链接

参考视频 参考讲义