这一章在干嘛?
第 3 章你学会了
plot,第 11 章你拿到了句柄这把「万能钥匙」——本章就是把两者合体:用句柄图形系统精确指挥每一种图。我们会过一遍 MATLAB 的二维图全家桶(柱图、面积图、火柴杆图、直方图、饼图、对数坐标),进入三维世界(plot3、mesh、surf、contour 思路),然后拆开图形的「底层积木」line/text/rectangle/patch,最后用文件数据 + 函数句柄做几个完整的实战绘图程序,顺带学 comet/movie 两种动画。学完本章,你能把任何数据画成任何想要的样子。
12.1 一份数据,四种画法:plot / bar / area / stem
12.7 核心图形对象:line / text / rectangle / patch
12.1 一份数据,四种画法:plot / bar / area / stem
到目前为止你用熟了 plot(折线)和 bar(柱状图),其实它们是一家人:同一份 - 数据,不同视觉编码。bar 画竖直柱状图,barh 画水平柱状图,area 画连续曲线并填充曲线下方区域,stem 画火柴杆图(stem plot,每根杆顶一个圆圈)。什么时候用哪个?看你想强调什么:趋势用 plot,比较离散量用 bar,强调累积量用 area,强调单点位置用 stem。这不是审美问题而是信息设计问题——同一份数据,换一种图型,读者的注意力就被引向不同的结论:柱状图诱导观众「比较相邻柱子的高低」,面积图诱导观众「感受总量随时间的累积」,火柴杆图诱导观众「逐点检查数值」。选错图型,等于把结论埋在了噪音里,这也是教材编程规范里「按需挑选最能突出关键信息的图型」的含义。
下面这个脚本用 的 subplot 布局,把同一份人口数据画成四种图(subplot 第三个参数是矩阵里的行优先编号——注意这和 MATLAB 矩阵「按列展开」的习惯相反,是个易错点):
% subplot_types.m
year = 2016:2020;
pop = [0.9 1.4 1.7 1.3 1.8];
subplot(2,2,1)
plot(year, pop)
title('plot'); xlabel('Year'); ylabel('Population (mil)')
subplot(2,2,2)
bar(year, pop)
title('bar'); xlabel('Year'); ylabel('Population (mil)')
subplot(2,2,3)
area(year, pop)
title('area'); xlabel('Year'); ylabel('Population (mil)')
subplot(2,2,4)
stem(year, pop)
title('stem'); xlabel('Year'); ylabel('Population (mil)')



用循环 + cell 数组消灭重复代码
上面四段几乎一样的代码可以压缩成一个循环——把函数名存进 cell 数组,用
eval拼调用(教材示范写法,生产代码更推荐str2func,见 12.8 节):titles = {'plot', 'bar', 'area', 'stem'}; for i = 1:4 subplot(2,2,i) feval(titles{i}, year, pop) title(titles{i}); xlabel('Year'); ylabel('Population (mil)') end顺便回顾第 7 章的教训:
eval能跑但难调试,str2func+ 函数句柄是更安全的等价物。
12.1.1 矩阵数据画柱状图:分组与堆叠
给 bar 传一个矩阵,它会按行分组画柱,自动循环颜色区分每列。比如两行四列的年龄数据:
>> groupages = [8 19 43 25; 35 44 30 45];
>> bar(groupages)
>> xlabel('Group'); ylabel('Ages')
加 'stacked' 选项则变成堆叠柱状图——每列的值摞起来,柱顶高度等于该行所有值之和:
>> bar(groupages, 'stacked')
>> xlabel('Group'); ylabel('Ages')
常见坑:barh 的轴标签是「横着」的
barh里数据的角色互换:数据值沿 x 轴、类别沿 y 轴。所以xlabel/ylabel要跟bar写反,初学者照抄模板就会标错轴。
12.2 直方图与饼图
12.2.1 histogram:数据分布一眼看穿
直方图(histogram)是特殊的柱状图:把向量里的值按范围装进箱(bin),柱高表示落在每个箱里的数的个数——它回答的是「数据怎么分布」,而不是「每个点是多少」。(R2014b 起新函数 histogram 取代了旧的 hist。)
>> quizzes = [10 8 5 10 10 6 9 7 8 10 1 8];
>> histogram(quizzes)
>> xlabel('Grade'); ylabel('#'); title('Quiz Grades')
histogram 返回的句柄同样可以存进变量查看和修改属性——句柄思想在每种图上都通用:
注意直方图和普通柱状图的本质区别:柱状图的 x 轴是类别(哪一年、哪个部门),每根柱的高度来自一个独立的数;直方图的 x 轴是数值本身,数据被切箱统计,柱高是频数。把「成绩列表」画成 bar 会得到 12 根杂乱无章的柱(每根是一次测验),画成 histogram 才能看到「分数集中在 8~10 分」这个真正有用的结论。分析数据分布时,先想 histogram。
>> hhan = histogram(quizzes)
hhan =
Histogram with properties:
Data: [10 8 5 10 10 6 9 7 8 10 1 8]
Values: [1 0 0 0 1 1 1 3 1 4]
NumBins: 10
BinEdges: [0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 10.5]
BinWidth: 1
BinLimits: [0.5 10.5]
Normalization: 'count'
FaceColor: 'auto'
EdgeColor: [0 0 0]
Show all propertiesValues 直接告诉你每个箱的频数,做统计描述时非常好用(更多统计内容在第 14 章)。想指定箱数用 histogram(vec, n)。
12.2.2 pie:占比与标签
pie(vec) 画饼图:每个元素占总和的百分比,从圆顶开始逆时针排布。向量 [11 14 8 3 1] 总和 37,所以 11 占 30%、14 占 38%……:
>> pie([11 14 8 3 1])
再传一个字符串 cell 数组当第二参数,百分比就被替换成你的标签:
>> pie([11 14 8 3 1], {'A', 'B', 'C', 'D', 'F'})
饼图的百分比是「自动算」的
你传给 pie 的永远是原始数量,不是百分比——MATLAB 替你除以总和。所以别先把数据归一化再传进去,那样等于除了两次。
12.3 对数坐标
plot 的两根轴都是线性刻度。但信号处理、频率响应这类场景里,数据的数量级横跨 到 ,线性轴上小数值会被压成一条贴地的直线。MATLAB 备了三个函数:loglog(双对数)、semilogy(y 轴对数)、semilogx(x 轴对数)。看对比:
>> subplot(1,2,1)
>> plot(logspace(1,10))
>> title('plot')
>> subplot(1,2,2)
>> semilogy(logspace(1,10))
>> title('semilogy')
logspace(1,10) 生成从 到 的对数均匀间隔向量。线性轴下曲线的「前半生」完全看不清;换 semilogy 后,指数增长被「拉直」——对数坐标的价值就在这。
三个函数怎么选?口诀是「哪根轴跨数量级,就把哪根轴换成对数」:只有 y 跨数量级(比如电路的幅频响应)用 semilogy;只有 x 跨(比如频率从 1 Hz 扫到 1 MHz)用 semilogx;两边都跨(比如 Bode 图、幂律拟合)用 loglog。它们与 plot 的参数用法完全一致,换函数就行,零学习成本。
指数增长在对数轴上是直线
这不只是好看:如果 semilogy 画出来近似一条直线,就说明数据服从指数规律 ,因为两边取对数后 与 成线性关系。判断「数据是不是指数型」最快的方法就是对数轴一画。
12.4 动画基础:comet 与 movie
动画效果没法印在书页上,务必亲手敲进 MATLAB 跑一遍。
方式一:comet——彗星轨迹。对采样足够密的 ,comet 会从第一个点开始,逐点画出轨迹,后面拖着一条「彗尾」:
>> x = -2*pi : 1/100 : 2*pi;
>> y = sin(x);
>> comet(x, y)跑完后静止画面与 plot(x,y) 相同,但过程是动画——演示函数曲线「如何被画出来」特别直观。
方式二:getframe + movie——帧录制。在循环里每帧画一点,用 getframe 抓屏存进矩阵,最后 movie 回放:
% sinmovie.m —— 播放 sin 函数的「电影」
clear
x = -2*pi: 1/5 : 2*pi;
y = sin(x);
n = length(x);
for i = 1:n
plot(x(i), y(i), 'r*')
axis([min(x)-1 max(x)+1 min(y)-1 max(y)+1]) % 固定坐标轴!
M(i) = getframe;
end
movie(M)常见坑:动画坐标轴「呼吸抖动」
录帧时如果不固定
axis,MATLAB 每帧都会根据当前数据点自动调整坐标范围,画面就会缩缩放放像抽风。循环前用 axis 把坐标范围钉死(如上例用 min/max 外扩一点),所有帧共用同一坐标系,动画才平滑。
12.5 图形属性定制:柱宽与爆炸饼图
12.5.1 柱宽:bar/barh 的第三参数
bar(x, y) 默认柱宽 0.8。把宽度当第三参数传进去:小于 1 柱间留缝,等于 1 柱子贴在一起,大于 1 柱子互相重叠:
year = 2016:2020;
pop = [0.9 1.4 1.7 1.3 1.8];
for i = 1:4
subplot(1,4,i)
barh(year, pop, 0.4 + i*0.2) % 宽度依次 0.6/0.8/1.0/1.2
title(sprintf('Width=%.1f', 0.4 + i*0.2))
xlabel('Population (mil)'); ylabel('Year')
end
12.5.2 爆炸饼图:把最抢眼的扇区「拉出来」
pie 的第二参数也可以是逻辑向量:为 true 的扇区会从饼里「炸」出来分离。结合 max 可以自动突出占比最大的扇区:
>> gradenums = [11 14 8 3 1];
>> letgrades = {'A', 'B', 'C', 'D', 'F'};
>> which = gradenums == max(gradenums)
which =
0 1 0 0 0
>> pie(gradenums, which, letgrades)
>> title(strcat('Largest Fraction of Grades: ', letgrades(which)))
这个例子还展示了标题里动态生成内容的套路:letgrades(which) 是逻辑索引取出 'B',strcat 把它拼进标题——数据变了标题自动跟着变。
12.6 三维绘图
三维函数大多和二维版同名,只是加个「3」:plot3、bar3、bar3h、pie3、comet3、stem3。
12.6.1 plot3:三维空间中的点与线
给 plot3 传三个坐标向量即可:
>> x = 1:5;
>> y = [0 2 4 11 3];
>> z = 2:2:10;
>> plot3(x, y, z, 'k*')
>> grid
>> xlabel('x'); ylabel('y'); zlabel('z')
>> title('3D plot')
画完点工具栏的旋转图标(rotate 3D),按住鼠标可以任意转视角——三维图不转着看等于白画。zlabel 负责给 z 轴加标签,grid 加的三维网格能帮你建立空间感。想用代码固定视角,用 view(az, el):az 是方位角(绕 z 轴转多少度)、el 是仰角(从水平面抬高多少度),默认 view(-37.5, 30);view(2) 则切到正上方俯视,三维曲面立刻变成一张平面「地图」——这正是等高线图的视角。光照也能玩:surf 对象有 FaceLighting 属性,配合 camlight 给曲面打一盏灯,凸起和凹陷的立体感会强很多,这些属性都可以用第 11 章的句柄语法随时调整。
12.6.2 bar3 与 pie3:三维版的柱和饼
>> y = 1:6;
>> z = [33 11 5 9 22 30];
>> bar3(y, z)
>> xlabel('x'); ylabel('y'); zlabel('z'); title('3D bar')
bar3 也能直接吃矩阵——每行一组三维柱。经典的 spiral(5)(把 1~25 螺旋填进 矩阵)可视化效果很有意思:
>> mat = spiral(5)
mat =
21 22 23 24 25
20 7 8 9 10
19 6 1 2 11
18 5 4 3 12
17 16 15 14 13
>> bar3(mat)
>> title('3D spiral')
>> pie3([3 10 5 2])
三维动画版彗星就是 comet3(x, y, z),玩法同 comet。
12.6.3 mesh 与 surf:从「线框」到「曲面」
真正的高维数据()要用 mesh(网眼线框图)和 surf(曲面图,用颜色表现参数曲面)。MATLAB 还内置了形状生成器,sphere(n) 一次生成 阶的 x、y、z 三个方阵:
>> [x, y, z] = sphere(15);
>> size(x)
ans =
16 16
>> mesh(x, y, z)
>> title('Mesh of sphere')
>> [x, y, z] = sphere(15);
>> sh = surf(x, y, z);
>> title('Surf of sphere')
>> colorbar % 右侧色标,显示颜色对应的数值范围
曲面返回的句柄 sh 是 Surface 对象——第 11 章的句柄功夫在这里直接兑现。它的 FaceAlpha 属性控制透明度(0 全透、1 不透),改成 0.5 球变半透明,能看见背面:
>> sh
sh =
Surface with properties:
EdgeColor: [0 0 0]
LineStyle: '-'
FaceColor: 'flat'
FaceLighting: 'flat'
FaceAlpha: 1
...
>> sh.FaceAlpha = 0.5;
12.6.4 meshgrid:给 z = f(x,y) 造网格
自己的二元函数没有现成形状生成器,用 meshgrid 造 网格点,再逐点算 :
>> [x, y] = meshgrid(-2*pi: 0.1: 2*pi);
>> z = cos(x) + sin(y);
>> surf(x, y, z)
>> title('cos(x) + sin(y)')
>> xlabel('x'); ylabel('y'); zlabel('z')
meshgrid 在干嘛?
x是行向量、y是列向量,meshgrid把它们「织」成两个同尺寸矩阵:一个矩阵每行都复制 x,另一个每列都复制 y。这样 这种逐元素运算就能一次性对整张网格向量化求值——你写的公式和数学式一模一样,不用写双重循环。想看等高线,用contour(x,y,z),或用meshc/surfc把等高线垫在三维图底下(见教材「探索更多」)。
双 y 轴与更多玩法
plotyy可以给图同时配左右两根 y 轴,适合画两个量纲不同的量(比如温度和电流);xlim/ylim/zlim手动钉轴范围;errorbar画置信区间;datetime类型直接当 x 轴能自动排日期刻度。这些都在文档里等着你。
12.7 核心图形对象:line / text / rectangle / patch
第 11 章我们说 MATLAB 的图是对象树上的对象,最底层的「积木」叫核心图形对象(core graphics objects):line、text、rectangle、patch、image(image 在第 13 章讲)。plot、bar 这些高级函数,内部全是用这些积木拼出来的。直接操作积木,你能画出任何高级函数不直接支持的东西。
什么时候需要动用这些底层函数?三个典型信号:① 要画的几何形状没有现成函数——比如在数据图上圈一个异常区域、画一个传感器覆盖范围的圆;② 要精细控制某个元素的样式——plot 的一揽子参数不够用,需要单独给某条线某个标注上属性;③ 要做可复用的绘图组件——比如习题里反复出现的圆角矩形、冰球场、多面体,用积木搭一次,以后改几个属性就能换形状。掌握积木层之后,你与图形系统的关系就从「用户」变成了「作者」。
12.7.1 line:比 plot 更裸的画线
line(x, y, '属性名', 值, ...) 直接创建 Line 对象:
>> x = -2*pi: 1/5 : 2*pi;
>> y = sin(x);
>> hl = line(x, y, 'LineWidth', 6, 'Color', [0.5 0.5 0.5])
hl =
Line with properties:
Color: [0.5 0.5 0.5]
LineStyle: '-'
LineWidth: 6
...
一个「不靠 plot 画圆」的例子——先开白底窗口,用参数方程生成圆上的点,line 画成红色点线,再用 axis square 强制坐标框为正方形(否则「圆」会被拉成椭圆),最后 axis off 藏掉坐标轴:
>> figure('Color', [1 1 1])
>> pts = 0:0.1:2*pi;
>> line(cos(pts), sin(pts), 'LineStyle', ':', ...
'LineWidth', 4, 'Color', 'r')
>> axis square
>> axis off
12.7.2 text:在图上任意位置写字
text(x, y, '字符串') 在坐标 处(文本框左下角)写字。字符串里用 \命令 打特殊字符——希腊字母、箭头、数学符号:
>> x = -4:0.2:4;
>> y = sin(x);
>> hp = line(x, y, 'LineWidth', 3);
>> thand = text(2, 0, 'Sin(\pi)\rightarrow')
thand =
Text (Sin(\pi)\rightarrow) with properties:
String: 'Sin(\pi)\rightarrow'
FontSize: 10
...
Position: [2 0 0]
Units: 'data'
文本框的 Extent 属性记录实际占用的范围([x y 宽 高]),BackgroundColor 和 EdgeColor 默认都是 none(看不见)。改一改就有「标签框」效果:
>> thand.Extent
ans =
2.0000 -0.0321 0.6912 0.0613
>> set(thand, 'BackgroundColor', [0.8 0.8 0.8], ...
'EdgeColor', [1 0 0])
交互式放字的兄弟函数 gtext('字符串'):鼠标变成十字线,点哪字落哪(内部是 text + ginput 的组合,ginput 能把鼠标点击处的坐标存下来)。
12.7.3 rectangle:能带圆角的矩形
rectangle 不带参数时创建一个默认矩形:Position 为 [0 0 1 1](左下角在原点、宽高各 1),Curvature 为 [0 0](直角)——乍看窗口里好像啥都没有:
>> recthand = rectangle
recthand =
Rectangle with properties:
FaceColor: 'none'
EdgeColor: [0 0 0]
LineWidth: 0.5000
LineStyle: '-'
Curvature: [0 0]
Position: [0 0 1 1]![默认 rectangle:只有一条细黑边框贴着 [0,1]×[0,1] 区域,FaceColor 为 none 所以内部透明](../../images/matlab/ch12_25.jpg)
Curvature 是 rectangle 的灵魂:从 [0 0](直角)到 [1 1](正圆/椭圆)连续可调,介于中间就是圆角矩形。创建时可直接带属性,之后也能 set:
>> rh = rectangle('Position', [0.2 0.2 0.5 0.8], ...
'Curvature', [0.5 0.5]);
>> axis([0 1.2 0 1.2])
>> set(rh, 'LineWidth', 3, 'LineStyle', ':')
曲率从 0.2 涨到 0.8 的渐变过程(教材习题的运行结果):


循环里不断挪 Position、录帧回放,就是第 12.4 节 movie 技术与 rectangle 的合体(教材习题 22 的效果):

曲率 + rectangle 还能画冰球场——长方形两端带半圆角,中间一条红线:

12.7.4 patch:多边形积木
patch 创建多边形贴片。最简单:传顶点坐标向量 + 颜色,三个点画一个红三角:
>> x = [0 1 0.5];
>> y = [0 0 1];
>> hp = patch(x, y, 'r')
hp =
Patch with properties:
FaceColor: [1 0 0]
FaceAlpha: 1
EdgeColor: [0 0 0]
LineStyle: '-'
Faces: [1 2 3]
Vertices: [3x2 double]
注意两个关键属性:Vertices 存顶点坐标;Faces 描述顶点怎么连线成面——顶点自动编号 1、2、3,Faces: [1 2 3] 表示按 1→2→3 连(默认再回到 1)。
更强大的姿势:用结构体传 Vertices + Faces,就能拼复杂多边形。五个顶点连三个三角形:
mypatch.Vertices = [ ...
0 0 % 顶点1
2 0 % 顶点2
1 2 % 顶点3
1 -2 % 顶点4
3 1]; % 顶点5
mypatch.Faces = [ ...
1 2 3 % 面1:顶点1-2-3
2 3 5 % 面2:顶点2-3-5
1 2 4]; % 面3:顶点1-2-4
patchhan = patch(mypatch, 'FaceColor', 'r', 'EdgeColor', 'k');
给每个面单独上色:FaceColor 设 'flat',再用 FaceVertexCData 提供每面的 RGB 行:
>> mycolors = [0 0 1; 0 1 1; 1 1 0]; % 蓝 / 青 / 黄
>> patchhan = patch(mypatch, 'FaceVertexCData', mycolors, ...
'FaceColor', 'flat');
patch 也能上三维——四个顶点四个面拼一个四面体,转着看:
polyhedron.Vertices = [ ...
0 0 0
1 0 0
0 1 0
0.5 0.5 1];
polyhedron.Faces = [ ...
1 2 3
1 2 4
1 3 4
2 3 4];
pobj = patch(polyhedron, ...
'FaceColor', [0.8 0.8 0.8], 'EdgeColor', 'black');
随机顶点的三角 patch 也是习题常客(黑边灰面):

常见坑:Vertices 的顺序就是 Faces 的编号依据
Faces里写的 1、2、3……指的是 Vertices 矩阵的行号。先给哪个点、后给哪个点决定了连线路径;写错行号,多边形会「拧麻花」。改几何形状时先在纸上把顶点编号标清楚。
12.8 绘图实战:函数绘图与文件数据绘图
前面零件都认识了,现在组装成真正的程序。本节的例子都有共同的两段式结构:前半段是第 9 章的文件 I/O(fopen/fgetl/textscan/fclose),后半段是本章的绘图函数加第 11 章的句柄属性。三块知识拼在一起,才是一个能交付的数据可视化程序——从原始文件到最终图表,中间不借人手。
12.8.1 函数句柄 + cell 数组:一劳永逸的多视图绘图
这个函数接收三个参数: 向量、生成 的函数句柄、存着图类型的 cell 数组,自动为每种图类型开一个子图:
function plotxywithcell(x, fnhan, rca)
% plotxywithcell 接收 x 向量、函数句柄和图类型名 cell 数组
% 用 subplot 把所有图类型画在同一个窗口
lenrca = length(rca);
y = fnhan(x); % 用句柄算出 y
for i = 1:lenrca
subplot(1, lenrca, i)
funh = str2func(rca{i}); % 字符串 → 函数句柄
funh(x, y) % 调用对应的绘图函数
title(upper(rca{i}))
xlabel('x')
ylabel(func2str(fnhan)) % 句柄 → 函数名字符串
end
end>> anfn = @(x) x.^3;
>> x = 1:2:9;
>> rca = {'bar', 'area', 'plot'};
>> plotxywithcell(x, anfn, rca)


这里 str2func(字符串转句柄)和 func2str(句柄转字符串)是一对反向工具,加上 cell 数组循环,函数就「通用」了——换任何 、加任何图类型,都不用改函数本体。这正是第 11 章函数句柄思想的实战兑现。
12.8.2 读文件画图实战一:按行解析 A#B# 格式
文件 ab16.dat 每行长这样(A、B 两个部门四个季度的销售额):
A5.2B6.4
A3.2B5.5
A4.4B4.3
A4.5B2.2脚本逐行读入字符串,用第 7 章的 strtok 切分、str2double 转数字,每个季度画一个子图,并用 set(gca, 'XTickLabel', ...) 把 x 轴刻度标签从数字 1/2 换成 A/B:
fid = fopen('ab16.dat');
if fid == -1
disp('File open not successful')
else
for i = 1:4
aline = fgetl(fid); % 读一行字符串
aline = aline(2:end); % 去掉开头的 'A'
[compa, rest] = strtok(aline, 'B'); % 按'B'切开
compa = str2double(compa);
compb = str2double(rest(2:end)); % rest 以 'B' 开头,去掉它
subplot(1,4,i)
bar([compa, compb])
set(gca, 'XTickLabel', {'A', 'B'}) % 刻度标签换成 A、B
axis([0 3 0 8])
ylabel('Sales (millions)')
title(sprintf('Quarter %d', i))
end
closeresult = fclose(fid);
if closeresult ~= 0
disp('File close not successful')
end
end



12.8.3 读文件画图实战二:textscan + 双图联排
文件 compsales.dat 每行是「数值 + 部门缩写」:
5.2 X
3.3 A
5.8 P
2.9 Qtextscan 用格式串 '%f %s' 一次性把数字读进一个 cell、缩写读进另一个 cell,然后左柱图右饼图各来一份:
fid = fopen('compsales.dat');
if fid == -1
disp('File open not successful')
else
filecell = textscan(fid, '%f %s'); % {数字列, 缩写列}
subplot(1,2,1)
bar(filecell{1})
xlabel('Division'); ylabel('Sales (millions)')
set(gca, 'XTickLabel', filecell{2}) % 柱图 x 轴用缩写
subplot(1,2,2)
pie(filecell{1}, filecell{2}) % 饼图用缩写当标签
title('Sales in millions by division')
closeresult = fclose(fid);
if closeresult ~= 0
disp('File close not successful')
end
end

12.8.4 更多实战:面积图、参数化绘图、堆叠水平柱
教材习题里还有三个典型:从文件读 “x 0 y 1” 格式的坐标对画面积图;给绘图函数做可选参数(nargin 判断传没传线宽/颜色);三年份收入与房价的堆叠水平柱图:



套路总结:文件 → 字符串 → 数字 → 图
所有「读文件画图」都是同一套流水线:
fopen检查 fid 是否为 -1 → 逐行fgetl(或整体textscan)→ 字符串切片 +str2double→ 向量化画图 →fclose检查返回值是否为 0。第 9 章的文件 I/O 加上本章的绘图函数,就是你以后处理任何实验数据、日志数据的标准姿势。
12.9 保存与打印绘图
图画好了,怎么带走?
- 复制:Figure 窗口菜单 Edit → Copy Figure,然后到 Word 里粘贴。
- 另存为:File → Save As,支持 .jpg、.tif、.png 等常见图像格式,也支持 MATLAB 专用的 .fig 格式——.fig 保存的是完整图形对象,下次在 MATLAB 里打开还能继续用句柄改属性。
- Generate Code:如果图不是纯代码画的(比如你在 Property Editor 里手动改过),File → Generate Code 能生成一个重建这张图的脚本——手调出来的效果从此可复现。
- 程序化保存/打印:
print命令。脚本里光写一个print就用默认设置打印当前窗口;指定文件名则保存为文件:
print -dtiff -r400 plot.tif % 存成 400 dpi 的 tif-dtiff 指定 tif 格式,-r400 指定分辨率 400 dpi。写报告批量出图时全靠它。
12.10 通关标准与自测
本章通关标准:
- 给你一份未知向量,能在 30 秒内决定用 histogram(看分布)、pie(看占比)、bar/barh(比大小)、stem(看点位)还是 semilogy(看指数规律),并说明理由——选图本身就是分析。
- 能用
meshgrid+surf画出任意 ,并用返回的句柄改出半透明效果(FaceAlpha)。- 能徒手用 line/text/rectangle/patch 组合画出一个「plot 函数画不出来」的图形(比如带圆角的框 + 标注 + 填充三角),并解释 Vertices/Faces 的关系。
1.
bar直接传矩阵和加'stacked'选项,柱子高度含义有什么不同?不加选项时按行分组:每个位置并排几根柱,各自代表矩阵的一列,高度是单个值;加
'stacked'后每列的值摞起来,柱顶高度等于该行所有值之和。分组便于逐列比较,堆叠便于看总量和构成。
2. 为什么画三维图后一定要旋转着看?哪个函数能把 z = cos(x)+sin(y) 的图变成「等高线视角」?
三维曲面的投影有遮挡,默认视角可能正好把关键结构藏在背面——不旋转很容易误读数据。用工具栏 rotate 3D 图标交互旋转;想要俯视等高线效果用
view(2)切到正上方视角,或直接用contour(x,y,z)、meshc/surfc画等高线。
3.
mesh和surf画的都是同一批 (x,y,z) 矩阵,区别到底是什么?
mesh只画网格线框(每条网格线是一个 Line),曲面内部是空的;surf画填充曲面,每个网格面的颜色由 z 值经 colormap 映射而来。所以 surf 更适合展示「面的形状 + 数值高低」,mesh 更适合看清结构、避免遮挡。两者都返回句柄,都能用 FaceAlpha 调透明度。
会得到什么?[0.5 0.5] 呢?
[1 1]是最大曲率——宽高不相等时得到椭圆,宽高相等(配合 axis square)就是正圆。[0.5 0.5]是中间状态:四个角变成半径为边长一半的圆弧,即圆角矩形。Curvature 两个分量分别控制水平/垂直方向的弯曲程度,从 0 到 1 连续可调。
具体在描述什么?
五个顶点按 Vertices 矩阵的行号编号为 1~5,这个 Faces 矩阵声明了三个三角面:面 1 连接顶点 1→2→3,面 2 连接顶点 2→3→5,面 3 连接顶点 1→2→4(每个面默认闭合)。想给不同面上色,把 FaceColor 设为 ‘flat’ 并给 FaceVertexCData 传入「每面一行 RGB」的矩阵即可。
6. movie 录制的动画画面不停抖动缩放,最可能漏写了哪一行?
循环里的
axis([...])。没固定坐标范围时,MATLAB 每帧都按当前画的数据点重新自适应坐标轴,画面就会随数据点移动而缩放。在每帧绘制后用axis([min(x)-1 max(x)+1 min(y)-1 max(y)+1])之类的固定范围把坐标系钉死,动画立刻稳定。