一、面积图概述
面积图是一种常见的数据可视化形式,它在折线图的基础上,将折线与坐标轴之间的区域进行填充,以此来展示数据随时间或其他连续变量的变化趋势。与折线图相比,面积图不仅能清晰呈现数据的变化情况,还能通过不同区域的堆叠展示多个数据系列之间的比例关系和累积效果。
面积图的主要应用场景包括:
- 时间序列分析:例如展示公司多年的营收、成本等财务数据变化,通过不同颜色区域表示不同业务板块的贡献,能直观看到各板块随时间的发展态势以及整体的增长或下降趋势。
- 比较数据构成:在分析市场份额时,用面积图可以清晰呈现不同品牌在各时间段所占份额,以及各品牌份额的动态变化。
- 展示累积效果:像统计项目的累计完成量、资源的累计使用量等,能方便观察到累积的速度和程度。
二、MATLAB 实现面积图代码详解
下面通过一段 MATLAB 代码来创建一个功能较为丰富的面积图,展示数据的变化趋势和相互关系,并带有交互功能。
(一)数据准备
clear; close all; clc;
% 创建示例数据
x = 1:10;
y1 = [3 5 4 6 8 7 9 10 11 13];
y2 = [1 2 3 5 4 6 7 8 7 9];
y3 = [2 3 2 4 3 5 6 7 6 8];
首先,clear
、close all
和clc
三条命令用于清理工作区环境,关闭所有已打开的图形窗口,并清空命令行窗口,确保后续代码运行在一个干净的环境中。
然后,定义了示例数据。x
是一个从 1 到 10 的序列,通常在实际应用中可以代表时间周期(如月份、季度)、样本编号等。y1
、y2
和y3
是三个不同的数据系列,它们将构成面积图的不同层次,这里的数据只是示例,实际使用时需替换为真实数据。(以上只是示例数据,以方便理解)
(二)创建图形对象
% 创建图形对象
fig = figure('Position', [100, 100, 900, 600], ...
'Color', [1 1 1], ...
'Name', '高级面积图可视化', ...
'NumberTitle', 'off');
figure
函数用于创建一个新的图形窗口。Position
属性指定了图形窗口在屏幕上的位置和大小,这里表示窗口距离屏幕左边 100 像素、距离顶部 100 像素,宽度为 900 像素,高度为 600 像素。Color
属性设置图形窗口的背景颜色为白色(在 RGB 颜色模式下,[1 1 1] 代表白色)。Name
属性为图形窗口赋予了一个名称 “高级面积图可视化”,方便在多个图形窗口中识别。NumberTitle
属性设置为off
,意味着图形窗口的标题栏不会显示默认的图形编号。
(三)字体设置
% 设置字体
set(0, 'DefaultAxesFontName', 'SimHei');
set(0, 'DefaultTextFontName', 'SimHei');
set(0, 'DefaultAxesFontSize', 12);
set
函数用于设置图形对象的属性。这里通过设置DefaultAxesFontName
和DefaultTextFontName
属性,将默认的坐标轴字体和文本字体都设定为黑体(SimHei
),当然可以根据不同需求设置不同字体。同时,DefaultAxesFontSize
属性将坐标轴字体大小设置为 12,确保文字在图形中具有合适的显示尺寸。
(四)绘制面积图
% 绘制面积图
hold on;
area1 = area(x, y1, 'FaceColor', [0.2, 0.6, 0.8], 'EdgeColor', 'none', 'FaceAlpha', 0.8);
area2 = area(x, y1+y2, 'FaceColor', [0.4, 0.8, 0.4], 'EdgeColor', 'none', 'FaceAlpha', 0.7);
area3 = area(x, y1+y2+y3, 'FaceColor', [0.9, 0.6, 0.3], 'EdgeColor', 'none', 'FaceAlpha', 0.6);
hold on
命令是一个非常重要的绘图控制指令,它的作用是保持当前图形窗口的状态,使得后续绘制的图形对象不会覆盖之前已经绘制好的图形,从而实现多个图形元素在同一窗口中叠加显示。接下来使用area
函数分别绘制三个面积图。每个area
函数调用中,第一个参数x
是横轴数据,第二个参数是纵轴数据。需要注意的是,y1+y2
和y1+y2+y3
这样的设置是为了实现面积图的堆叠效果,即后一个面积图在前一个的基础上进行叠加,展示多个数据系列的累积关系。FaceColor
属性用于设置面积图的填充颜色,这里分别设置了不同的颜色值,以区分不同的数据系列。EdgeColor
属性设置为none
,表示不显示面积图的边框,让图形看起来更加简洁美观。FaceAlpha
属性用于设置面积图的透明度,通过不同的透明度设置(0.8、0.7、0.6 ),使图形具有层次感,便于观察不同层次数据之间的关系。
(五)添加数据标签
% 添加数据标签
for i = 1:length(x)
text(x(i), y1(i)+0.5, num2str(y1(i)), 'HorizontalAlignment', 'center', ...
'VerticalAlignment', 'bottom', 'FontSize', 9, 'FontWeight', 'bold');
text(x(i), y1(i)+y2(i)+0.5, num2str(y2(i)), 'HorizontalAlignment', 'center', ...
'VerticalAlignment', 'bottom', 'FontSize', 9, 'FontWeight', 'bold');
text(x(i), y1(i)+y2(i)+y3(i)+0.5, num2str(y3(i)), 'HorizontalAlignment', 'center', ...
'VerticalAlignment', 'bottom', 'FontSize', 9, 'FontWeight', 'bold');
end
这段代码通过一个循环,使用text
函数为每个数据点添加数值标签。循环变量i
从 1 遍历到x
的长度,对于每个i
值:
-
text
函数的第一个参数x(i)
指定了标签在横轴上的位置,即对应数据点的横坐标。 -
第二个参数是标签在纵轴上的位置,通过在相应数据值的基础上加上一个偏移量(如
y1(i)+0.5
等),确保标签显示在合适的位置,避免与图形本身重叠。 -
num2str
函数将数值转换为字符串,以便在图形上显示。 -
HorizontalAlignment
属性设置为center
,表示标签在水平方向上居中显示。 -
VerticalAlignment
属性设置为bottom
,表示标签在垂直方向上底部对齐。 -
同时,还指定了标签的字体大小为 9,字体粗细为加粗,这样能使标签更加醒目,便于读者读取数据。
(六)添加标题和坐标轴标签
% 添加标题和标签
title('数据趋势面积图分析', 'FontSize', 18, 'FontWeight', 'bold', 'Color', [0.2 0.2 0.2]);
xlabel('时间/周期', 'FontSize', 14, 'FontWeight', 'bold');
ylabel('数值', 'FontSize', 14, 'FontWeight', 'bold');
title
函数用于为图形添加标题,这里设置标题为 “数据趋势面积图分析”,字体大小为 18,字体加粗(FontWeight
为bold
),颜色为浅灰色([0.2 0.2 0.2] ),使标题在图形中较为突出,概括图形的主要内容。
xlabel
和ylabel
函数分别用于添加横轴和纵轴的标签。这里横轴标签设置为 “时间 / 周期”,纵轴标签设置为 “数值”,字体大小均为 14,且字体加粗,明确了坐标轴所代表的含义,帮助读者理解图形展示的数据内容。
(七)设置坐标轴范围和样式
% 设置坐标轴范围和样式
xlim([min(x)-0.5 max(x)+0.5]);
ylim([0 max(y1+y2+y3)+5]);
grid on;
grid minor;
set(gca, 'GridLineStyle', ':', 'GridAlpha', 0.3, 'MinorGridAlpha', 0.1, ...
'LineWidth', 1.2, 'FontSize', 12, 'FontWeight', 'normal');
xlim
和ylim
函数分别用于设置横轴和纵轴的范围。xlim([min(x)-0.5 max(x)+0.5])
将横轴范围在数据的最小值和最大值基础上分别向外扩展了 0.5 个单位,这样可以避免数据点刚好位于坐标轴边缘,使图形看起来更美观和协调。ylim([0 max(y1+y2+y3)+5])
将纵轴范围从 0 开始,到三个数据系列总和的最大值再加上 5,确保所有数据都能在图形中完整显示,并且留有一定的空白区域。
grid on
命令打开主网格线,grid minor
命令进一步打开次网格线,帮助读者更精确地读取数据点的位置。set
函数用于进一步设置坐标轴的属性,gca
表示当前坐标轴(Get Current Axes)。这里设置网格线样式为虚线(GridLineStyle
为:
),主网格线透明度为 0.3(GridAlpha
为 0.3 ),次网格线透明度为 0.1(MinorGridAlpha
为 0.1 ),网格线宽度为 1.2(LineWidth
为 1.2 ),坐标轴字体大小为 12,字体粗细为正常(FontWeight
为normal
),通过这些设置优化了坐标轴的显示效果。
(八)添加图例
% 添加图例
legend({'数据系列A', '数据系列B', '数据系列C'}, 'Location', 'northeast', ...
'FontSize', 12, 'Box', 'off', 'Orientation', 'horizontal');
legend
函数用于为图形添加图例,帮助读者理解不同颜色区域所代表的数据系列。这里通过一个单元格数组{'数据系列A', '数据系列B', '数据系列C'}
指定了每个数据系列对应的名称。Location
属性设置图例的位置为图形的右上角(northeast
),FontSize
属性设置图例字体大小为 12,Box
属性设置为off
表示关闭图例的边框,使图例看起来更加简洁,Orientation
属性设置为horizontal
表示图例水平排列,合理的图例设置能让读者快速准确地解读图形。
(九)添加注释和参考线
% 添加注释和参考线
annotation('textbox', [0.15, 0.15, 0.2, 0.1], 'String', '趋势分析', ...
'FitBoxToText', 'on', 'BackgroundColor', [1 1 1], 'EdgeColor', [0.8 0.8 0.8]);
line([5 5], [0 max(y1+y2+y3)], 'Color', [0.7 0.7 0.7], 'LineStyle', '--', 'LineWidth', 1);
annotation
函数用于在图形中添加注释。这里添加了一个文本框注释,'textbox'
指定注释类型为文本框。[0.15, 0.15, 0.2, 0.1]
通过相对坐标指定了文本框的位置和大小(分别表示文本框左下角相对于图形左下角的横坐标、纵坐标,以及文本框的宽度和高度比例 )。String
属性设置文本框内的文本内容为 “趋势分析”,FitBoxToText
属性设置为on
表示文本框自动适应文本的大小,BackgroundColor
属性设置文本框背景颜色为白色([1 1 1] ),EdgeColor
属性设置文本框边框颜色为浅灰色([0.8 0.8 0.8] ),通过添加注释可以对图形中的某些重要信息或分析点进行说明。
line
函数用于在图形中添加一条参考线。这里绘制了一条在横轴值为 5 的位置,从纵轴 0 到三个数据系列总和最大值的虚线(LineStyle
为--
),颜色为浅灰色([0.7 0.7 0.7] ),线条宽度为 1(LineWidth
为 1 ),参考线可以辅助读者进行数据对比和分析。
(十)添加交互功能
% 添加交互功能
h = findobj(gca, 'Type', 'patch');
set(h, 'ButtonDownFcn', @(src,event) display_point_info(src,event,x,y1,y2,y3));
% 数据点信息显示函数
function display_point_info(~, ~, x, y1, y2, y3)
pos = get(gca, 'CurrentPoint');
x_pos = pos(1,1);
[~, idx] = min(abs(x - x_pos));
msgbox(sprintf('位置: %d\n系列A: %d\n系列B: %d\n系列C: %d\n总计: %d', ...
x(idx), y1(idx), y2(idx), y3(idx), y1(idx)+y2(idx)+y3(idx)), ...
'数据详情', 'modal');
end
首先,findobj
函数用于在当前坐标轴(gca
)中查找所有类型为patch
的对象,因为我们绘制的面积图对象属于patch
类型。找到这些对象后,通过set
函数为它们设置ButtonDownFcn
属性,即鼠标点击回调函数。当用户在面积图上点击鼠标时,就会触发这个回调函数。
回调函数display_point_info
的作用是获取鼠标点击位置的坐标,通过get(gca, 'CurrentPoint')
获取当前鼠标点击在坐标轴上的坐标pos
,然后提取横坐标x_pos
。接着,使用min
函数结合abs
函数找到距离点击位置横坐标最近的数据点索引idx
。最后,通过msgbox
函数弹出一个消息框,使用sprintf
函数格式化输出该数据点对应的详细信息,包括位置、各数据系列的值以及它们的总和,增强了图形的交互性,方便用户深入了解图形中的数据细节。
总代码:
clear; close all; clc;
% 创建示例数据
x = 1:10;
y1 = [3 5 4 6 8 7 9 10 11 13];
y2 = [1 2 3 5 4 6 7 8 7 9];
y3 = [2 3 2 4 3 5 6 7 6 8];
% 创建图形对象
fig = figure('Position', [100, 100, 900, 600], ...
'Color', [1 1 1], ...
'Name', '高级面积图可视化', ...
'NumberTitle', 'off');
% 设置字体
set(0, 'DefaultAxesFontName', 'SimHei'); % 黑体,兼容性更好
set(0, 'DefaultTextFontName', 'SimHei');
set(0, 'DefaultAxesFontSize', 12);
% 绘制面积图
hold on;
area1 = area(x, y1, 'FaceColor', [0.2, 0.6, 0.8], 'EdgeColor', 'none', 'FaceAlpha', 0.8);
area2 = area(x, y1+y2, 'FaceColor', [0.4, 0.8, 0.4], 'EdgeColor', 'none', 'FaceAlpha', 0.7);
area3 = area(x, y1+y2+y3, 'FaceColor', [0.9, 0.6, 0.3], 'EdgeColor', 'none', 'FaceAlpha', 0.6);
% 添加数据标签
for i = 1:length(x)
text(x(i), y1(i)+0.5, num2str(y1(i)), 'HorizontalAlignment', 'center', ...
'VerticalAlignment', 'bottom', 'FontSize', 9, 'FontWeight', 'bold');
text(x(i), y1(i)+y2(i)+0.5, num2str(y2(i)), 'HorizontalAlignment', 'center', ...
'VerticalAlignment', 'bottom', 'FontSize', 9, 'FontWeight', 'bold');
text(x(i), y1(i)+y2(i)+y3(i)+0.5, num2str(y3(i)), 'HorizontalAlignment', 'center', ...
'VerticalAlignment', 'bottom', 'FontSize', 9, 'FontWeight', 'bold');
end
% 添加标题和标签
title('数据趋势面积图分析', 'FontSize', 18, 'FontWeight', 'bold', 'Color', [0.2 0.2 0.2]);
xlabel('时间/周期', 'FontSize', 14, 'FontWeight', 'bold');
ylabel('数值', 'FontSize', 14, 'FontWeight', 'bold');
% 设置坐标轴范围和样式
xlim([min(x)-0.5 max(x)+0.5]);
ylim([0 max(y1+y2+y3)+5]);
grid on;
grid minor;
set(gca, 'GridLineStyle', ':', 'GridAlpha', 0.3, 'MinorGridAlpha', 0.1, ...
'LineWidth', 1.2, 'FontSize', 12, 'FontWeight', 'normal');
% 添加图例
legend({'数据系列A', '数据系列B', '数据系列C'}, 'Location', 'northeast', ...
'FontSize', 12, 'Box', 'off', 'Orientation', 'horizontal');
% 添加注释和参考线
annotation('textbox', [0.15, 0.15, 0.2, 0.1], 'String', '趋势分析', ...
'FitBoxToText', 'on', 'BackgroundColor', [1 1 1], 'EdgeColor', [0.8 0.8 0.8]);
line([5 5], [0 max(y1+y2+y3)], 'Color', [0.7 0.7 0.7], 'LineStyle', '--', 'LineWidth', 1);
% 添加交互功能
h = findobj(gca, 'Type', 'patch');
set(h, 'ButtonDownFcn', @(src,event) display_point_info(src,event,x,y1,y2,y3));
% 数据点信息显示函数
function display_point_info(~, ~, x, y1, y2, y3)
pos = get(gca, 'CurrentPoint');
x_pos = pos(1,1);
[~, idx] = min(abs(x - x_pos));
msgbox(sprintf('位置: %d\n系列A: %d\n系列B: %d\n系列C: %d\n总计: %d', ...
x(idx), y1(idx), y2(idx), y3(idx), y1(idx)+y2(idx)+y3(idx)), ...
'数据详情', 'modal');
end
面积图实现:
三、总结
通过上述 MATLAB 代码,我们成功创建了一个具有丰富功能和美观外观的面积图。从数据准备、图形对象创建,到各个元素的设置和交互功能的添加,每一步都经过精心设计。在实际应用中,大家可以根据具体的数据特点和展示需求,灵活调整代码中的参数,如数据内容、颜色、字体、标签文本等,以实现更加个性化和有效的数据可视化。希望本文能为大家在 MATLAB 绘制面积图方面提供有益的参考,让大家更好地利用面积图展示和分析数据。