因为对matlab绘图函数不熟悉,整整花了6个多小时,才终于绘制出了封面那张理想的图。
敲到码穷处,坐看云起时。
数学建模系列文章——总结篇:《数模美一国一退役选手的经验分享[2021纪念版]》.
这是2011年国赛数模B题《交巡警服务平台的设置与调度》,用 第一问 给的数据来作的图。
接下来我将依次讲解其步骤,作图的 详细说明 在代码的注释里。
clc,clear,close all;
[all_data_1,QY] = xlsread('cumcm2011B附件2_全市六区交通网路和平台设置的数据表.xls',1,'A2:E583'); % 附件1的数据
all_data_2 = xlsread('cumcm2011B附件2_全市六区交通网路和平台设置的数据表.xls',2,'A2:B929'); % 附件2的数据
all_data_3 = xlsread('cumcm2011B附件2_全市六区交通网路和平台设置的数据表.xls',3,'B2:B81'); % 附件3的数据
all_data_4_1 = xlsread('cumcm2011B附件2_全市六区交通网路和平台设置的数据表.xls',4,'B2:B18'); % 附件4的数据
all_data_4_2 = xlsread('cumcm2011B附件2_全市六区交通网路和平台设置的数据表.xls',4,'C2:C14'); % 附件4的数据
ind = all_data_1(:,1); % 数据点的编号
zuo_x = all_data_1(:,2); % 数据点的横坐标
zuo_y = all_data_1(:,3); % 数据点的纵坐标
QuYu = QY; % 数据点所在的区域【一共有A、B、...、F七个区域】
FaAnLv = all_data_1(:,5); % 数据点的发案率
QiDian_ind = all_data_2(:,1); % 交通道路的起点编号
ZhongDian_ind = all_data_2(:,2); % 交通道路的终点编号
说明:①Excel数据 需要放在 matlab当前运行的文件夹里面。
②xlsread()函数的用法详见本文最后的 参考附录【5】。
③数据 在文章最后的 参考附录【7】 。
% 第一种添加结构体成员的方法
t = 1; % 用 t 来记录结构体的序号
for i = 1:size(ind)
% Table(t) = struct('ind',ind(i),'ZuoBiao',[zuo_x,zuo_y],'QuYu',QuYu(i),'FaAnLv',FaAnLv(i));
Table(t) = struct('ind',ind(i),'X',zuo_x(i),'Y',zuo_y(i),'QuYu',QuYu(i),'FaAnLv',FaAnLv(i));
t = t + 1;
end
%---------------------------------
% 第二种添加结构体成员的方法---------
for i = 1:size(ind)
Table(i).NextJieDian = []; % 先初始化
end
for i = 1:size(all_data_2,1) % 遍历每条边,然后把 起点 和 终点 连起来【双边都要连】
Table(QiDian_ind(i)).NextJieDian = [Table(QiDian_ind(i)).NextJieDian,ZhongDian_ind(i)];
Table(ZhongDian_ind(i)).NextJieDian = [Table(ZhongDian_ind(i)).NextJieDian,QiDian_ind(i)];
end
for i = 1:size(all_data_3)
Table(all_data_3(i)).PingTai = 1; % 是交巡警平台,则标记为1,否则不标记
end
for i = 1:size(all_data_4_1)
Table(all_data_4_1(i)).QuanShiQu_ChuRuKou = 1; % 是全市区出入口,则标记为1,否则不标记
end
for i = 1:size(all_data_4_2)
Table(all_data_4_2(i)).A_Qu_ChuRuKou = 1; % 是A区出入口,则标记为1,否则不标记
end
%---------------------------------
说明:①结构体 的 详细用法详见本文最后的 参考附录【6】 。
②代码里的结构体名为 “Table” ,其封装结果 如下图所示。其中,“[ ]” 表示 “空” 。
hold on;
for i = 1:size(Table,2)
if Table(i).QuYu == 'A' % 如果是 A 区,才执行下面的语句【注:我这里是用"1"来判断的】
for j = 1:length(Table(i).NextJieDian)
if 1 <= Table(i).NextJieDian(j) && Table(i).NextJieDian(j) <= 92 % 由 Excel附件一 可知,A区的数据点的编号范围为[1,92]
cur_xx = [Table(i).X,Table(Table(i).NextJieDian(j)).X]; % 获取 起点和终点 的两个数据点的横坐标
next_yy = [Table(i).Y,Table(Table(i).NextJieDian(j)).Y]; % 获取 起点和终点 的两个数据点的纵坐标
plot(cur_xx,next_yy,'b-'); % 用蓝色(blue)的短线连接 起点和终点
end
end
end
end
说明:①这里的 plot()函数 的使用和我们往常 使用的角度 不一样。(这两行代码,查了很多资料,调了将近两个小时 )
因为我画直线的时候是 一根一根地并以离散的形式来 连的【关键点】⭐️⭐️⭐️。
本文后面还会再强调一次这关键点。
运行结果如下:
p_ZuoBiao = []; % 交巡警平台的坐标矩阵: 第一列装 数据点的横坐标;第二列装 数据点的纵坐标
A_c_ZuoBiao = []; % A区出入口的坐标矩阵: 第一列装 数据点的横坐标;第二列装 数据点的纵坐标
A_j_ZuoBiao = []; % A区交通路口的坐标矩阵:第一列装 数据点的横坐标;第二列装 数据点的纵坐标
for i = 1:size(Table,2)
if Table(i).QuYu == 'A' % 如果是 A 区,才执行下面的语句【注:我这里是用"1"来判断的】
if Table(i).PingTai == 1 % 如果该数据点是 A区的交巡警平台
p_ZuoBiao = [ p_ZuoBiao ; [Table(i).X,Table(i).Y] ];
end
if Table(i).A_Qu_ChuRuKou == 1 % 如果该数据点是 A区的城区出入口
A_c_ZuoBiao = [ A_c_ZuoBiao ; [Table(i).X,Table(i).Y] ];
else % 否则该数据点就是 A区的交通路口
A_j_ZuoBiao = [ A_j_ZuoBiao ; [Table(i).X,Table(i).Y] ];
end
end
end
三个散点矩阵的数据如下:
scatter(p_ZuoBiao(:,1),p_ZuoBiao(:,2),60,'ks');
scatter(A_c_ZuoBiao(:,1),A_c_ZuoBiao(:,2),20,'MarkerEdgeColor','b','MarkerFaceColor','r');
scatter(A_j_ZuoBiao(:,1),A_j_ZuoBiao(:,2),10,'filled','b');
legend('A区交巡警平台','出入A区的路口','A区的交通路口');
运行结果如下:
为什么 会出现这么多 “data1、data2、…” 的标签呢?❔ ❔ ❔
因为我们画直线的时候是 一根一根地并以离散的形式来 连的【关键点】⭐️⭐️⭐️。
操作步骤 分3步,如下图所示:
✈️ ✈️ ✈️ ✈️ ✈️ ✈️ ✈️ ✈️ ✈️
.
整张图就完成啦 !
瞧瞧最终的成果图吧!
第一步:读取所有数据
第二步:将数据包装入结构体
第三步:绘制交通路线图(不含散点)
第四步:筛选第一问所要用到的散点数据
第五步:集中绘制散点图
第六步:细节优化→图例修整、坐标说明+标题
①图例修整
②坐标说明+标题
最后,我没有详细地阐述其原理,只阐述了有什么用、怎么用。详细原理可以参考本文最后的 参考附录 。
因为评论区在2022.5.3之前的很多评论 表示无法实现理想效果,故笔者将其源码重新拼接+完善,并贴出如下:
【数据 在文章最后的 参考附录[7] 。放在与代码同一目录文件夹即可】
感谢大家对问题的指出!
clc
clear
close all
clc,clear,close all;
[all_data_1,QY] = xlsread('cumcm2011B附件2_全市六区交通网路和平台设置的数据表.xls',1,'A2:E583'); % 附件1的数据
all_data_2 = xlsread('cumcm2011B附件2_全市六区交通网路和平台设置的数据表.xls',2,'A2:B929'); % 附件2的数据
all_data_3 = xlsread('cumcm2011B附件2_全市六区交通网路和平台设置的数据表.xls',3,'B2:B81'); % 附件3的数据
all_data_4_1 = xlsread('cumcm2011B附件2_全市六区交通网路和平台设置的数据表.xls',4,'B2:B18'); % 附件4的数据
all_data_4_2 = xlsread('cumcm2011B附件2_全市六区交通网路和平台设置的数据表.xls',4,'C2:C14'); % 附件4的数据
ind = all_data_1(:,1); % 数据点的编号
zuo_x = all_data_1(:,2); % 数据点的横坐标
zuo_y = all_data_1(:,3); % 数据点的纵坐标
QuYu = QY; % 数据点所在的区域【一共有A、B、...、F七个区域】
FaAnLv = all_data_1(:,5); % 数据点的发案率
QiDian_ind = all_data_2(:,1); % 交通道路的起点编号
ZhongDian_ind = all_data_2(:,2); % 交通道路的终点编号
% 第一种添加结构体成员的方法
t = 1; % 用 t 来记录结构体的序号
for i = 1:size(ind)
% Table(t) = struct('ind',ind(i),'ZuoBiao',[zuo_x,zuo_y],'QuYu',QuYu(i),'FaAnLv',FaAnLv(i));
Table(t) = struct('ind',ind(i),'X',zuo_x(i),'Y',zuo_y(i),'QuYu',QuYu(i),'FaAnLv',FaAnLv(i));
t = t + 1;
end
%---------------------------------
% 第二种添加结构体成员的方法---------
for i = 1:size(ind)
Table(i).NextJieDian = []; % 先初始化
end
for i = 1:size(all_data_2,1) % 遍历每条边,然后把 起点 和 终点 连起来【双边都要连】
Table(QiDian_ind(i)).NextJieDian = [Table(QiDian_ind(i)).NextJieDian,ZhongDian_ind(i)];
Table(ZhongDian_ind(i)).NextJieDian = [Table(ZhongDian_ind(i)).NextJieDian,QiDian_ind(i)];
end
for i = 1:size(all_data_3)
Table(all_data_3(i)).PingTai = 1; % 是交巡警平台,则标记为1,否则不标记
end
for i = 1:size(all_data_4_1)
Table(all_data_4_1(i)).QuanShiQu_ChuRuKou = 1; % 是全市区出入口,则标记为1,否则不标记
end
for i = 1:size(all_data_4_2)
Table(all_data_4_2(i)).A_Qu_ChuRuKou = 1; % 是A区出入口,则标记为1,否则不标记
end
%---------------------------------
%---------获取坐标------------------------
p_ZuoBiao = []; % 交巡警平台的坐标矩阵: 第一列装 数据点的横坐标;第二列装 数据点的纵坐标
A_c_ZuoBiao = []; % A区出入口的坐标矩阵: 第一列装 数据点的横坐标;第二列装 数据点的纵坐标
A_j_ZuoBiao = []; % A区交通路口的坐标矩阵:第一列装 数据点的横坐标;第二列装 数据点的纵坐标
for i = 1:size(Table,2)
if Table(i).QuYu == 'A' % 如果是 A 区,才执行下面的语句【注:我这里是用"1"来判断的】
if Table(i).PingTai == 1 % 如果该数据点是 A区的交巡警平台
p_ZuoBiao = [ p_ZuoBiao ; [Table(i).X,Table(i).Y] ];
end
if Table(i).A_Qu_ChuRuKou == 1 % 如果该数据点是 A区的城区出入口
A_c_ZuoBiao = [ A_c_ZuoBiao ; [Table(i).X,Table(i).Y] ];
else % 否则该数据点就是 A区的交通路口
A_j_ZuoBiao = [ A_j_ZuoBiao ; [Table(i).X,Table(i).Y] ];
end
end
end
%----------------------------------------
%---------先画散点------------------------
figure(1);hold on;
scatter(p_ZuoBiao(:,1),p_ZuoBiao(:,2),60,'ks');
scatter(A_c_ZuoBiao(:,1),A_c_ZuoBiao(:,2),20,'MarkerEdgeColor','b','MarkerFaceColor','r');
scatter(A_j_ZuoBiao(:,1),A_j_ZuoBiao(:,2),10,'filled','b');
legend('A区交巡警平台','出入A区的路口','A区的交通路口');
%----------------------------------------
%---------再画连线------------------------
for i = 1:size(Table,2)
if Table(i).QuYu == 'A' % 如果是 A 区,才执行下面的语句【注:我这里是用"1"来判断的】
for j = 1:length(Table(i).NextJieDian)
if 1 <= Table(i).NextJieDian(j) && Table(i).NextJieDian(j) <= 92 % 由 Excel附件一 可知,A区的数据点的编号范围为[1,92]
cur_xx = [Table(i).X,Table(Table(i).NextJieDian(j)).X]; % 获取 起点和终点 的两个数据点的横坐标
next_yy = [Table(i).Y,Table(Table(i).NextJieDian(j)).Y]; % 获取 起点和终点 的两个数据点的纵坐标
plot(cur_xx,next_yy,'b-'); % 用蓝色(blue)的短线连接 起点和终点
end
end
end
end
%----------------------------------------
%---------重画一遍散点(更好看)---------------
scatter(p_ZuoBiao(:,1),p_ZuoBiao(:,2),60,'ks');
scatter(A_c_ZuoBiao(:,1),A_c_ZuoBiao(:,2),20,'MarkerEdgeColor','b','MarkerFaceColor','r');
scatter(A_j_ZuoBiao(:,1),A_j_ZuoBiao(:,2),10,'filled','b');
legend('A区交巡警平台','出入A区的路口','A区的交通路口');
%------------------------------------------
[1] 《MATLAB中scatter函数的用法(绘制散点图)》
这里面有关于 scatter 的详细用法总结
链接: https://blog.csdn.net/xuxinrk/article/details/80212221.
[2] 《MATLAB中关于scatter用法的官方文档》
和参考附录[1]类似,但肯定 官方原版的说明书 更好
链接: https://ww2.mathworks.cn/help/matlab/ref/scatter.html#btrli6p-1.
[3] 《matlab绘制X,Y二维散点图并标出序号》
需要在散点图上标序号时可以参考这篇
链接: https://blog.csdn.net/qq_29596177/article/details/53284364?utm_source=blogxgwz1.
[4] 《用matlab画散点图,并指定点与点之间的连线》
如果作的散点图是 稀疏矩阵 ,可以参考这篇,学用gplot()函数
链接: https://blog.csdn.net/heavenmark/article/details/82794488.
[5] 《MATLAB中关于xlsread用法的官方文档》
链接: https://ww2.mathworks.cn/help/matlab/ref/xlsread.html?searchHighlight=xlsread&s_tid=srchtitle.
[6] 《MATLAB中关于struct用法的官方文档》
链接: https://ww2.mathworks.cn/help/matlab/ref/struct.html?searchHighlight=struct&s_tid=srchtitle.
[7] 《2011高教社杯全国大学生数学建模竞赛赛题 B题 数据》
链接: http://www.mcm.edu.cn/html_cn/node/a1ffc4c5587c8a6f96eacefb8dbcc34e.html.
数学建模系列文章——总结篇:《数模美一国一退役选手的经验分享[2021纪念版]》.
码字 码图不易,多多支持~ ❤️
感谢大家对问题的指出!(特别感谢对于2022.5.3之前的评论主) ⭐️⭐️