初级绘图

在未来的科研工作中, 关于matlab的其他知识可能未必会用到, 但是大概率会用到的就是使用matlab去作图.

matlab是一个很强大的绘图工具, 无论是统计图, 函数图像 还是三维图像都可以很好的呈现出来. matlab实际上使用的是初中学习的描点法来绘制函数图像的, 在坐标系中选择大量的坐标点, 用线把这些点连接起来, 就形成了最终我们想要的函数图像.

在画图的过程中使用最多的是plot()函数, 比如plot(x,y),就可以生成一幅y与x的函数图像, 其中y就是y轴上点的值, x是x轴上点的值, 这两个值应该是维度相同的向量值, 因为matlab需要描点, 描点连线即可形成图像. plot()还有更简单的使用方法, 直接plot(y), 其中y是x 的函数, 也就是说只给出y的向量值, 而缺省x的值, 在这种情况下, matlab生成的图像中, x的值是 0, 1, 2, …

在实际应用中, 我们更多的是采取第一种方式画图的, 第二种方式只是在下面作为例子讲解而已, 很少使用到, 毕竟缺省值不一定使我们想要的.

举个例子:

运行plot(cos(0:pi/20:2*pi));时 ,即可生成

image-20200704125140330

图像已经生成, 其实关于画图, 基本上就是学完了.

但是会发现这幅图还存在一些可以优化的地方, 既然要优化 , 就要继续往深了学习, 无论什么学科, 往深度方向发展都是没完没了的, 在实际的工程应用或者论文报告时, 也许用不到后面所讲的全部内容.

画多幅图

一幅图像需要一个plot()函数, 我想同时画两幅图像, 是否执行多个plot()就行了呢? 尝试一下

1
2
plot(cos(0:pi/20:2*pi));
plot(sin(0:pi/20:2*pi));

运行的结果是:

image-20200704130424123

显然, 这是正弦函数的图像. matlab在画图的过程中, 它会刷新, 或者叫覆盖, 在执行新的plot()函数时, 会覆盖掉上一个cos函数. 避免这种情况可以使用指令hold onhold off来提醒他等一等.

上述指令就可以修改为:

1
2
3
4
hold on
plot(cos(0:pi/20:2*pi));
plot(sin(0:pi/20:2*pi));
hold off

这样就可以吧两幅图像画在同一个坐标系里了.

image-20200704131036124

其实, 只需一个plot()函数, 就可以把多幅图像画在同一个坐标系里, 这时的plot()函数应该写成plot(X1,Y1,X2,Y2,...,Xn,Yn), 注意, 绘制多幅图像时, 每个图像的横坐标值就不可省略, 由于X和Y都是向量值, 如果省略将导致无法区分参数指定的是X还是Y. 所以, 上面的代码可以使用plot(0:40,cos(0:pi/20:2*pi),0:40,sin(0:pi/20:2*pi))代替. 其执行结果与上图是相同的, 不再重复贴出结果图.

如果想要把两个图像画在两个不同的图片背景里,从第二个图开始, 就需要在画图之前执行figure, 来获得一个figure, 在这个figure上来画图像, matlab默认会生成一个 figure.

上面的代码就得改成

1
2
3
4
hold on
plot(cos(0:pi/20:2*pi));
figure, plot(sin(0:pi/20:2*pi));
hold off

于是就会生成两幅图像:figure1figure2

image-20200704132329317

如果想要把多幅图画在同一个图片里, 而又不在同一个坐标轴里, 需要使用subplot()函数.这个函数的常用方法为subplot(m,n,x),其中, 参数m代表这张图片里有几行图像, n代表图像的列数, x指出当前图像在图片中的位置, 比如subplot(m,n,1)的位置如图:

image-20200704170516954

使用举例:

1
2
3
4
subplot(2,1,1);
plot(cos(0:pi/20:2*pi));
subplot(2,1,2);
plot(sin(0:pi/20:2*pi));

效果:

image-20200704171304935

绘图风格

上面画的图像都是matlab中的默认风格, 实际上plot()函数提供了一个参数字符串来对图像的风格进行修改, 于是函数要写成plot(x,y,'str'), 其中str是指定图像风格的字符串, 下面列出了str中可以指定的部分内容.

image-20200704132906604

举个例子, 来学习上表中的内容如何使用

绘制一个图像, 使用x作为数据标记, 用虚线连接, 颜色设置为绿色.

这个例子中要求的三要素对应上表中的符号标记分别为, x,--g, 所以str字符串就应该写进这三个元素, 比如x--g,这些元素的位置是可以交换的, 从表中也可以发现, 关于这些属性没有采用重复的字符标记, 因此是可以交换顺序的.

执行代码就可以写成plot(sin(0:pi/20:2*pi),'x--g');

执行结果为:

image-20200704134224483

更多示例和使用方法可以参考使用文档

学到这里, plot()函数就扩充为plot(X1,Y1,'str1',X2,Y2,'str2',...,Xn,Yn,'strn')的形式, 可以用这种函数模板来把不同风格的函数图像放在同一个坐标系中. 其中的str字符串可以省略. 上面画多幅图的例子可以进行风格指定的扩充, plot(0:40,cos(0:pi/20:2*pi),'o:k',0:40,sin(0:pi/20:2*pi)), 执行结果为:

image-20200704140338611

灵活使用上面的方式来修改图像风格, 已经可以绘制一幅清晰有表现力的图像了. 但是如果拿去做报告的话可能还有点欠缺, 当多幅图放在一个背景下的时候, 图例是很有必要的, 能够让读者清晰的了解到哪条曲线对应哪个函数.

在matlab中使用legend()函数来给图像增加图例, 该函数的使用方法为legend('L1','L2',...,'Ln')字符串中的内容就是对应曲线在图例中所显示的内容. 例如:

1
2
3
4
5
6
x=0:0.5:4*pi;
y=sin(x); h=cos(x); w=1./(1+exp(-x));
g=(1/(2*pi*2)^0.5).*exp((-1.*(x-2*pi).^2)./(2*2^2));
plot(x,y,'bd-',x,h,'gp:',x,w,'ro-',x,g,'c^-');
% 增加图例
legend('sin(x)','cos(x)','Sigmoid','Gauss function');

上述代码的执行结果为:

image-20200704140738643

对于一幅需要贴在论文中的图像, 这种程度的图像似乎还缺少一些东西. 比如图像的标题, 坐标轴的意义都没有指出.

matlab中图像的标题使用title()函数, 坐标轴的信息使用xlabel(),ylabel()zlabel()函数来分别指出.

比如:

1
2
3
4
5
6
x = 0:0.1:2*pi; y1 = sin(x); y2 = exp(-x);
plot(x, y1, '--*', x, y2, ':o');
xlabel('t = 0 to 2\pi'); % 使用转义字符来显示2π
ylabel('values of sin(t) and e^{-x}') % 指数函数的形式与Latex的写法很类似
title('Function Plots of sin(t) and e^{-x}');
legend('sin(t)','e^{-x}');

其执行结果为:

image-20200704141843819

关于图像外观风格上的调整, 还有很多其他的功能, 比如, 可以在图像上显示文本或添加注释, 这样可以更清晰地解释图像所表达的内容. 这里使用text()函数和annotation()函数来举例说明, 关于这两个函数更加详细的使用方法可以去matlab文档中查询.

1
2
3
4
5
6
7
x = linspace(0,3); %linspace函数用来生成100个点的等间距向量,两个参数分别是起始位置和终止位置
y = x.^2.*sin(x);
plot(x,y);
line([2,2],[0,2^2*sin(2)]); % 显示一条线
str = '$$ \int_{0}^{2} x^2\sin(x) dx $$'; % LaTeX数学表达式对应的字符串
text(0.25,2.5,str,'Interpreter','latex'); % 显示一个积分算式, 前两个参数指出文本内容显示的位置,第三个参数指出显示的内容, 后面两个参数大概是解析形式吧
annotation('arrow','X',[0.32,0.5],'Y',[0.6,0.4]); % 显示注释, 第一个参数指出注释类型是箭头,后面的参数是起点到终点x和y的坐标.

上述代码的运行结果:

image-20200704143639017


练习: 在同一坐标系中绘制下面两个函数, 要求效果如图所示.

函数: f=t2f=t^2g=sin(2πt)g=sin(2\pi t)

图示: image-20200704150054022

1
2
3
4
5
6
7
8
t=linspace(1,2);
f=t.*t;
g=sin(2*pi*t);
plot(t,f,'k',t,g,'or');
xlabel('Time(ms)');
ylabel('f(t)');
title('Mini Assignment #1');
legend('t^{2}','sin(2\pi t)','Location','northwest');% 增加Location属性, 使其显示在左上角.

图形调整

首先看下面两个图像的例子:

这两个图像是同一个函数的图像, 但是给人的视觉效果却有着很大的不同, 2图的显示效果明显要更好一些, 图像进行了加粗显示, 调整了坐标轴的字体等等. 其实对于一幅图像可以调整的地方有很多很多, 要想学习如何对图像进行调整, 首相要了解到一幅图像是如何构成的.

一幅图像由很多对象组成, 这和面向对象的思想很类似, 像数据结构中所介绍的树一样, 很多对象有它的子对象和父对象. 对于一幅matlab图像来说, 组成图像的第一个对象, 是figure, 画一幅图之前, 先生成一个figure对象, 在这个对象中生成一个子对象axes坐标轴对象, 在坐标轴对象中又可以生成一个line对象来最终形成函数图像. 其中axes对象还包括text,surface等等. 对于每一个对象都有许多属性, 可以通过查询文档来了解这些属性, 通过修改这些属性来达到我们想要的绘图效果.

想要修改对象的属性, 我们需要在matlab中指定我们要修改的对象, 并且指定对象的属性.下面列举出新涉及到的一些函数.

  • gca: 当前坐标区或图
  • gcf: 当前图窗的句柄
  • allchild: 查找指定对象的所有子级
  • ancestor: 图形对象的父级
  • delete: 删除文件或对象
  • findall: 查找所有图形对象

可以通过get()函数来获得对象的属性, 使用set()函数来修改对象的相应属性.

例如:

1
2
3
x = linspace(0, 2*pi, 1000);
y = sin(x); h = plot(x,y);
get(h)

绘制的图形如下:

image-20200704155545256

并且在命令行窗口显示许多h的属性.可以尝试执行get(gca), 对比结果有什么不同. 结果都是一系列的属性, 不容易发现是否有不同之处, 可以执行y=gca; 有一个很明显的区别可以在工作区中发现:

image-20200704155255312

可以看到, 它们不属于同一个对象.

观察上面所画的图像, 有一个很不美观的地方在于x轴相对于图形来说过长, 导致图像的右边一部分没有内容.考虑使用set()函数来修改相应的属性, 首先应该明确是哪个对象恶属性, 显然是axes的属性, 也就是gca的属性.因此可以通过下面的代码来修改坐标轴的边缘极限值.

1
2
set(gca,'XLim', [0, 2*pi]);
set(gca,'YLim', [-1.2, 1.2]);

修改后图像:

image-20200704160311843

还可以继续对其他属性进行修改.

  1. 设置字号

    1
    set(gca,'FontSize', 25);

    效果图:

    image-20200704160503424

  2. 设置xtick和xticklabel

    1
    2
    set(gca,'XTick', 0:pi/2:2*pi);
    set(gca,'XTickLabel', 0:90:360);

    效果图:

    image-20200704162016680

  3. 设置x轴显示和π\pi有关

    1
    2
    set(gca,'FontName','symbol');
    set(gca,'XTickLabel', {'0', 'p/2', 'p', '3p/2', '2p'});

    效果图:

    image-20200704162828109

  4. 修改线的风格和宽度

    1
    2
    set(h, 'LineStyle','-.',...
    'LineWidth', 7.0, 'Color', 'g');

使用delete(h)函数可以删除图像中的线.

下面的例子在绘图的过程中直接对属性进行设置.

1
2
3
4
5
x=rand(20,1);
set(gca,'FontSize', 18);
plot(x,'-md','LineWidth', 2, 'MarkerEdgeColor','k',...
'MarkerFaceColor','g','MarkerSize', 10);
xlim([1, 20]);

图形如下:

image-20200704163756514

下面的例子对figure中的属性进行修改.

1
2
x = linspace(0, 2*pi, 1000); y = sin(x);
plot(x,y); set(gcf, 'Color', [1 1 0]);% 把figure的颜色属性改为黄色 后面的向量是[r g b]

效果如下:

image-20200704152948123

可以通过figure('Position', [left, bottom, width, height]);来修改figure的大小以及出现的位置.其参数的意义如下图:

image-20200704165938425

对于图片的调整还有以下常用指令:

  • grid on/off
  • box on/off
  • axis on/off
  • axis normal
  • axis square
  • axis equal
  • axis equal tight
  • axis image
  • axis ij
  • axis xy

练习: 把上一个练习中的图形显示效果做如下修改.

image-20200704164031382

1
2
3
4
5
6
7
8
9
10
11
clear
t=linspace(1,2);
f=t.*t;
g=sin(2*pi*t);
h=plot(t,f,'k',t,g,'or','MarkerFaceColor','b');
xlabel('Time(ms)');
ylabel('f(t)');
title('Mini Assignment #1');
legend('t^{2}','sin(2\pi t)','Location','northwest');
set(gca,'FontSize',16,'XTickLabel', 1:0.2:2);
set(h(1),'LineWidth',3); % 我不确定有两条线时怎么修改线的属性

参考效果:

image-20200704165510996

图像存储

使用saveas(gcf,'<filename>','<formattype>');来存储当前图像, 两个参数可以使用的值及其意义如下:

image-20200704170933987

资料链接

参考视频 参考讲义