《MATLAB基础和图形用户界面设计 课程设计
题目: Matlab PlotHelper:plot绘图辅助器
日期: 2021年04月27日
目 录 1 摘 要 3 2 功能描述 3 2.1 功能1:图窗实时编辑绘制功能 4 2.2 功能2:图窗保存功能 5 2.3 功能3:一些绘图小工具 10 2.4 功能4:代码生成 11 3 软硬件环境 13 3.1 运行环境 13 3.1.1 硬件环境 13 3.1.2 软件环境 13 3.2 开发环境 13 3.2.1 硬件环境 13 3.2.2 软件环境 13 4 主要功能实现方法简介 14 4.1 图窗属性初始化 14 4.2 图窗实时编辑绘制功能 14 4.3 图窗保存功能 17 4.4 一些与绘图相关的小工具 19 4.5 代码生成 20 5 实现效果显示 24 6 实践总结和感受 25 7 课程建议 25
1摘 要 平常使用Matlab数值计算总是绘制各种图像,最常用的是绘图plot二维图像绘制函数。绘制应使用legend、title、xlabel、ylabel、grid当函数美化图像,提高可读性时,也会使用print保存图片等函数,以便插入自己的文章等。 当大量使用时plot函数时,每次输入代码,看图片和更改图片都不方便。基于此,作者设计了一个Plot Helper,实时编辑原图窗,实时修改标题、坐标轴名称、图例等,高清输出非常方便。 使用本App,实时编辑标题、坐标轴名称、图例等标题、坐标轴名称、图例等;输出方便:一键选择png、jpg、eps、pdf、ps格式,四种清晰度供您选择;提供并提供代码生成功能,可直接复制图窗修改的代码,并粘贴到源代码。 2功能描述 本课程设计以此为基础Matlab App Designer GUI开发平台,设计一个Plot Helper实时编辑图窗,实现图窗修改和完善的功能。 最终实现设计Plot Helper使用界面如图21所示,图22所示 2-3所示。
图21 Plot Helper整体界面
(a)网格线 (b)坐标区设置 (c)文件格式 (d)清晰度 图22 Plot Helper其他设置
图 2-3 代码生成界面 2.功能1:图窗实时编辑绘制功能 实现图形窗口的实时编辑功能,实现当前图形窗口参数的实时更改,实时编辑标题、坐标轴名称、图例等功能。点击生成测试图按钮生成测试图(实际使用时直接修改当前图形窗口),然后点击绘制按钮初步完善当前图形窗口,如图24所示,并实时编辑,如图25所示。
图24 完善当前图窗
图25 实时编辑当前图窗 2.2功能2:图窗保存功能 在音乐播放器中实现图窗保存、复制等功能,方便打开文件夹,如图25所示。
图26 图窗保存区选项 (1)文件名:默认格式:未命名加当前时间,也可自行添加文件名。 (2)文件路径: 默认当前Matlab单击浏览按钮选择工作文件夹,如图2-7所示。 图2-7 路径选择界面 当您点击浏览但不选择文件夹时,弹出窗口提示将跳出,如图所示 2-8所示。
图 2-8存储文件夹提示 (3)文件格式选择功能:选择想要输出的格式,如图 2-9所示。 图 选择2-9文件格式 (4)清晰度选择功能:选择要输出的清晰度,如图所示 2-10所示。 图 2-10清晰度选择 (5)复制功能:点击【复制】按钮,将当前图窗直接粘贴到剪切板上,直接粘贴到剪切板上word如图所示 2-11所示。 图 2-11复制功能展示
图 2-12输出功能显示 (6)输出功能:点击【输出】按钮,根据上述格式、路径和清晰度输出图片,生成代码,如图所示 显示2-12输出功能。 (7)打开输出文件夹功能:点击【打开输出文件夹】按钮直接打开输出文件夹 2-13所示。 图 2-13打开输出文件夹功能显示 (8)快速看图功能:点击【快速看图】按钮,直接打开最近生成的图片如图所示 2-14所示。 图 2-14快速显示2-14 2.3功能3:一些绘图小工具 小工具栏集成了一些与绘图相关的小工具,如生成试图、显示当前图窗、关闭所有图窗、关闭当前图窗等Plot函数自查表,背景一键变白功能。 (1)生成测试图:生成正余弦函数曲线作为测试功能图,如图所示 2-15所示。
图 2-15生成测试图 (2)当前图窗显示:当前图窗被屏蔽后,点击当前图窗显示按钮显示当前图窗。 (3)关闭所有图窗:关闭所有图窗。 (4)关闭当前图窗:关闭当前处理的图窗。 (5)Plot函数自查表:打开plot函数自查表Matlab Plot Cheatsheet (源:https://github.com/Pjer-zhang/matlabPlotCheatsheet),如图 2-16所示。
图 2-16Matlab Plot Cheatsheet (6)背景一键变白:将当前图窗背景变白,如图所示 2-17所示。
图 2-17图窗背景变白 2.4功能4:代码生成 在编辑图窗时实时生成代码,并在代码生成界面显示,点击复制按钮,提示您选择文本并2s后自动复制(control c),如图 2-18、图 2-19所示。
图 点击2-18复制按钮
图 2-19复制效果 3软硬件环境 3.1运行环境 3.1.1硬件环境 处理器型号:Intel? Core? i5-8265U CPU @ 1.60GHz 1.80 GHz及以上 内存容量:8GB及以上 外存容量:1G及以上 3.1.2软件环境 操作系统:64位Windows7或Windows10 应用软件:安装Matlab R2020a或上述版本,或安装Matlab R2020a对应的Matlab Runtime,版本号9.8.0.1323502。 3.2开发环境 3.2.1硬件环境 设备名称 LAPTOP-MTB43AUP 处理器 Intel? Core? i5-8265U CPU @ 1.60GHz 1.80 GHz 机带 RAM 16.0 GB (15.8 GB 可用) 设备 ID C271EDB0-7F8D-4CE1-ADDE-A78FE92D6980 产品 ID 00342-35646-76079-AAOEM 系统类型 64 位置操作系统, 基于 x64 的处理器 笔和触控 本显示器无笔或触摸输入
3.2.2软件环境 Windows规格 版本 Windows 10 家庭中文版 版本号 20H2 安装日期 2021/3/18 内部版本的操作系统 19042.928 体验 Windows Feature Experience Pack 120.2212.551.0
主要功能实现方法简介 4.1图窗属性初始化 编写initPlotHelper(app)函数通过每个Flag判断这个属性是否变化的值,Flag值的变化手段为对应回调是否被调用,若被调用,则属性值变化,初始Flag均值为0Flag如果值没有变化,则相应的属性值为原始属性值。 function initPlotHelper(app) if app.PicXlabelFlag ~= 1 app.PH.PicXlabel = ‘x’;%Xlabel初始值为x end if app.PicTitleFlag ~= 1 app.PH.PicTitle = ‘Title’;%title初始值为Title end if app.PicYlabelFlag ~= 1 app.PH.PicYlabel = ‘y’;%ylabel初始值为y end if app.PicLegendFlag ~= 1 app.PH.PicLegend = {‘a’,‘b’};%legend初始值a,b end if app.PicFileNameFlag ~= 1 app.PH.FileName =strcat(‘未命名’,strrep(char(datetime(‘now),,,,); app.EditField_Filename.Value = app.PH.FileName;未命名的%默认输出 时间’ end if isempty(app.EditField_FilePath.Value) app.EditField_FilePath.Value = pwd; end if isempty(app.EditField_Filename.Value) msgbox(‘请输入文件名,默认未命名加当前时间’FileName’); end end 4.2图窗实时编辑绘制功能 在每个编辑区Value值的变化,调用PHplot(app)函数,实现实时编辑功能,即每次更改编辑框中的值,都会回调一次PHplot(app)函数将实时绘制图像,相应代码如下: function PHplot(app)% 绘制回调 initPlotHelper(app); if app.InterpreterMode == 0%的编译模式选择0tex1为latex %对xlabel、ylabel、title、legend等进行绘制 xlabel(app.PH.PicXlabel,‘interpreter’,‘tex’); ylabel(app.PH.PicYlabel,‘interpreter’,‘tex’); title(app.PH.PicTitle,‘interpreter’,‘tex’); if app.LegendMode== 0 legend off else legend(app.PH.PicLegend,‘interpreter’,‘tex’); end else %对xlabel、ylabel、title、legend等进行绘制 xlabel(app.PH.PicXlabel,‘interpreter’,‘latex’); ylabel(app.PH.PicYlabel,‘interpreter’,‘latex’); title(app.PH.PicTitle,‘interpreter’,‘latex’); if app.LegendMode == 0 legend off else legend(app.PH.PicLegend,‘interpreter’,‘latex’); end end end 网格线设置与坐标区设置通过各自的回调函数实现相应功能,如下所示: % Value changed function: DropDown_grid function DropDown_gridValueChanged(app, event) value = app.DropDown_grid.Value; if strcmp(value,‘关闭’) grid off; app.Code_Grid = ‘grid off; %不显示网格线’; elseif strcmp(value,‘主网格线’) grid on; app.Code_Grid = ‘grid on; %显示主网格线’; else grid minor; app.Code_Grid = [‘grid on; %显示主网格线’ newline ‘grid minor; %显示次网格线’]; end PHplot(app); end
% Value changed function: DropDown_axis
function DropDown_axisValueChanged(app, event)
value = app.DropDown_axis.Value;
switch value
case '普通'
axis normal;
app.Code_Axis = 'axis normal; %坐标轴普通模式';
case '自动'
axis auto;
app.Code_Axis = 'axis normal; %坐标轴自动模式';
case '单位长度相同'
axis equal
app.Code_Axis = 'axis normal; %坐标轴单位长度相同模式';
case '紧凑'
axis tight;
app.Code_Axis = 'axis normal; %坐标轴紧凑模式';
case '紧绕数据'
axis image;
app.Code_Axis = 'axis normal; %坐标轴紧绕数据模式';
case '方形'
axis square;
app.Code_Axis = 'axis normal; %坐标轴方形模式';
end
PHplot(app);
end
4.3图窗保存功能 对图窗的保存的核心为print函数,通过得到文件路径,文件名,文件格式,清晰度等并在print函数中组合起来实现图窗的保存。 文件路径选择按钮回调核心为uigetdir函数,通过app.EditField_FilePath.Value = uigetdir(pwd,‘Select a Folder’),将浏览的路径存到app.EditField_FilePath.Value值中,实现属性改变,代码如下: % Button pushed function: Button_PathSelect function Button_PathSelectPushed(app, event) if app.EditField_FilePath.Value == 0 msgbox(‘请选择一个文件夹,默认存储当前文件夹下’); app.EditField_FilePath.Value = pwd; else try app.EditField_FilePath.Value = uigetdir(pwd,‘Select a Folder’); catch msgbox(‘请选择一个文件夹,默认存储当前文件夹下’,‘Attention’); app.EditField_FilePath.Value = pwd; end end end 文件名若没有更改,即app.PicFileNameFlag值为0,则调用datetime(now),默认‘未命名+当前时间作为文件名’,代码如下: If app.PicFileNameFlag ~= 1 app.PH.FileName =strcat(‘未命名’,strrep(char(datetime(‘now’)),’:’,’-’)); app.EditField_Filename.Value = app.PH.FileName;%默认输出’未命名+时间’ end 文件格式通过switch对应每种选择的格式,得到app.FormatValue1与app.FormatValue2。 function DropDown_FileformatValueChanged(app, event) value = app.DropDown_Fileformat.Value; switch value case ‘.png’ app.FormatValue1 = ‘-dpng’; app.FormatValue2 = ‘.png’; case ‘.jpg’ app.FormatValue1 = ‘-djpeg’; app.FormatValue2 = ‘.jpg’; case ‘.eps’ app.FormatValue1 = ‘-depsc’; app.FormatValue2 = ‘.eps’; case ‘.ps’ app.FormatValue1 = ‘-dpsc’; app.FormatValue2 = ‘.ps’; case ‘.pdf’ app.FormatValue1 = ‘-dpdf’; app.FormatValue2 = ‘.pdf’; end end 清晰度通过switch对应每种选择的格式,得到app.Difinition。 % Value changed function: DropDown_DefinitionChoose function DropDown_DefinitionChooseValueChanged(app, event) value = app.DropDown_DefinitionChoose.Value; switch value case ‘VIP至尊清晰’ app.Difinition = ‘-r1200’; case ‘超清’ app.Difinition = ‘-r900’; case ‘高清’ app.Difinition = ‘-r600’; case ‘标清’ app.Difinition = ‘-r300’; end end 最终,通过【输出】按钮的回调将上述参数整合起来,进行输出,代码如下: % Button pushed function: Button_FilePrint function Button_FilePrintPushed(app, event) app.FinalPath = strcat(app.EditField_FilePath.Value,’’,app.PH.FileName,app.FormatValue2); print(gcf,app.FormatValue1,app.Difinition,app.FinalPath); app.Code_Print = strcat(‘print(gcf,’’’,app.FormatValue1,’’’,’’’,app.Difinition,’’’,’’’,app.FinalPath,’’’);%图片保存’); end 4.4一些与绘图有关的小工具 与绘图有关小工具的背后其实还是对函数的调用,下面小工具的实现依次如下: 4.4.1 生成测试图 点击【生成测试图】按钮,调用画正余弦曲线的代码: % Button pushed function: Button_testpic function Button_testpicPushed(app, event) x = linspace(-2pi,2pi); y1 = sin(x); y2 = cos(x); plot(x,y1,x,y2); figure(gcf); end 4.4.2 当前图窗显示 点击【当前图窗显示】按钮,通过gcf找到当前图窗,figure(gcf)显示出来: % Button pushed function: Button_findcurrentgcf function Button_findcurrentgcfPushed(app, event) figure(gcf); end 4.4.3 关闭所有图窗 点击【关闭所有图窗】按钮,调用close all: % Button pushed function: Button_deleteallpic function Button_deleteallpicPushed(app, event) close all; end 4.4.4 关闭当前图窗 点击【关闭当前图窗】按钮,调用close,关闭当前图窗: % Button pushed function: Button_deletenowpic function Button_deletenowpicPushed(app, event) close; end
4.4.5 Plot函数自查表 点击【Plot函数自查表】按钮,调用画Plot函数自查表的代码,此代码源于https://github.com/Pjer-zhang/matlabPlotCheatsheet,存为名为matlabplotsheet.m的函数,放在与.mlapp同路径的文件夹内: % Button pushed function: Button_plotsheet function Button_plotsheetPushed(app, event) matlabplotsheet; end 4.4.6 背景一键变白 点击【背景一键变白】按钮,通过set函数对当前gcf的属性进行更改: % Button pushed function: Button_backgroundwhite function Button_backgroundwhitePushed(app, event) set(gcf,‘Color’,‘w’); end 4.5代码生成 在每一个绘图函数调用下面再生成一段字符串,内容与代码一致,通过strcat函数字符串拼接的方式拼起来,最终整合成app.Final_Code元胞数组,存储所有的代码。 下面是总代码生成,分为Code_Title、Code_Xlabel、Code_Ylabel、Code_Legend、Code_Grid、Code_Axis、Code_Print七个部分,用newline实现换行功能: function Codegenerate(app) app.Final_Code = [app.Code_Title newline app.Code_Xlabel newline app.Code_Ylabel newline… app.Code_Legend newline app.Code_Grid newline app.Code_Axis newline app.Code_Print]; app.Text_Code.Value = app.Final_Code; end 分别的,在各自绘图代码实现下面加一行字符串的生成,增加后核心代码如下所示: function PHplot(app)% 绘制回调 initPlotHelper(app); if app.InterpreterMode == 0 xlabel(app.PH.PicXlabel,‘interpreter’,‘tex’); app.Code_Xlabel = strcat(‘xlabel(’’’,app.PH.PicXlabel,’’’,’‘interpreter’’,’‘tex’’);%横轴显示’); ylabel(app.PH.PicYlabel,‘interpreter’,‘tex’); app.Code_Ylabel = strcat(‘ylabel(’’’,app.PH.PicYlabel,’’’,’‘interpreter’’,’‘tex’’);%纵轴显示’); title(app.PH.PicTitle,‘interpreter’,‘tex’); app.Code_Title = strcat(‘title(’’’,app.PH.PicTitle,’’’,’‘interpreter’’,’‘tex’’);%标题显示’); if app.LegendMode == 0 legend off app.Code_Legend = ‘legend off %不显示图例’; else legend(app.PH.PicLegend,‘interpreter’,‘tex’); app.Code_Legend = strcat(‘legend(’’’,app.PH.PicLegend,’’’,’‘interpreter’’,’‘tex’’);%图例显示’); end else xlabel(app.PH.PicXlabel,‘interpreter’,‘latex’); app.Code_Xlabel = strcat(‘xlabel(’’’,app.PH.PicXlabel,’’’,’‘interpreter’’,’‘latex’’);%横轴显示’); ylabel(app.PH.PicYlabel,‘interpreter’,‘latex’); app.Code_Ylabel = strcat(‘ylabel(’’’,app.PH.PicYlabel,’’’,’‘interpreter’’,’‘latex’’);%纵轴显示’); title(app.PH.PicTitle,‘interpreter’,‘latex’); app.Code_Title = strcat(‘title(’’’,app.PH.PicTitle,’’’,’‘interpreter’’,’‘latex’’);%标题显示’); if app.LegendMode == 0 legend off app.Code_Legend = ‘legend off %不显示图例’; else legend(app.PH.PicLegend,‘interpreter’,‘latex’); app.Code_Legend = strcat(‘legend(’’’,app.PH.PicLegend,’’’,’‘interpreter’’,’‘latex’’);%图例显示’); end end Codegenerate(app); end
% Value changed function: DropDown_grid
function DropDown_gridValueChanged(app, event)
value = app.DropDown_grid.Value;
if strcmp(value,'关闭')
grid off;
app.Code_Grid = 'grid off; %不显示网格线';
elseif strcmp(value,'主网格线')
grid on;
app.Code_Grid = 'grid on; %显示主网格线';
else
grid minor;
app.Code_Grid = ['grid on; %显示主网格线' newline 'grid minor; %显示次网格线'];
end
PHplot(app);
end
% Value changed function: Switch_axis
function Switch_axisValueChanged(app, event)
value = app.Switch_axis.Value;
if strcmp(value,'On')
axis on;
app.Code_Axis = 'axis on; %坐标轴显示';
else
axis off;
app.Code_Axis = 'axis off; %坐标轴不显示';
end
PHplot(app);
end
% Value changed function: DropDown_axis
function DropDown_axisValueChanged(app, event)
value = app.DropDown_axis.Value;
switch value
case '普通'
axis normal;
app.Code_Axis = 'axis normal; %坐标轴普通模式';
case '自动'
axis auto;
app.Code_Axis = 'axis normal; %坐标轴自动模式';
case '单位长度相同'
axis equal
app.Code_Axis = 'axis normal; %坐标轴单位长度相同模式';
case '紧凑'
axis tight;
app.Code_Axis = 'axis normal; %坐标轴紧凑模式';
case '紧绕数据'
axis image;
app.Code_Axis = 'axis normal; %坐标轴紧绕数据模式';
case '方形'
axis square;
app.Code_Axis = 'axis normal; %坐标轴方形模式';
end
PHplot(app);
end
通过上述代码生成最终的代码后,在代码生成编辑框中显示,并通过键鼠模拟调用键盘的control+v实现代码的复制功能。代码如下: % Button pushed function: Button_Copy function Button_CopyPushed(app, event) %提示对话框 msgbox(‘请先选中文字哦,2s后自动复制’,‘Please’); pause(2)%等待2s % 创建鼠标键盘模拟代码 import java.awt.Robot; import java.awt.event.*; vb=actxserver(‘wscript.shell’); robot=Robot; % 快捷键操作: control+c vb.SendKeys(’^c’); end
5实现效果展示 最终,PlotHelper设计完成,可以实时进行图片编辑与代码生成,如图 5-1,并快捷复制粘贴图片与代码,如图 5-2,很方便快捷。
图 5-1 实时编辑与代码生成
图 5-2快捷复制粘贴
6实践总结及感想 课程感想:为期八周的Matlab GUI设计课程就到此结束了,自己其实打了一年数模还是有一定Matlab基础的,但就是不太系统,因为是用一块学一块的。上课时老师系统的输出总能让我学到一些新的东西,还学会了app的制作,做了音乐播放器和这个PlotHelper,收获蛮大的。 实践总结:其实app的制作还是要耗费不少心血的,从最开始有这个想法,到中间制作时不断试错尝试新方法,到最终app功能实现完毕,设计了个app专属图标,图标也花了半小时,如图 6-1,并写完整的实践报告,这其中前前后后总共花的时间加起来也不少于24小时了。
图 6-1自己设计的PlotHelper图标 之前自己用matlab做数模时,最后一步可视化都是要画图的,但一步很难画出满意的图,就要不断地调,要么重新运行,要么存数据一遍遍跑,看图怎么样,好看与否,调各种线型啊颜色啊标题啊等等,最后再输出,一遍遍重复的工作令我感觉不免有点枯燥,于是便诞生了制作Plot Helper的想法。从想法诞生到最终开花结果,现在想来还是很感动的。 不过自己这个功能有限,没有实现线型选择,粗细调整等等功能,最近关注了个up主“图通道”,做了个FigureBest软件,能美化各种图,二维三维图,还能一键设置线型等等,感觉自己就小巫见大巫了,要学的东西还是有很多的,可能以后还能增加新的功能。 7课程建议 最开始上这个课的时候其实有点疑惑,就是我觉得学appdesigner默认是有一定matlab基础的,没想到最开始前四周还是学基础的操作等等。 如果再来一次,我想可不可以在课程说明上注明有一定Matlab基础者可选,这样就会有更多时间可以用来学appdesign和实操制作了。