面向对象编程与MATLAB建立专门的图表
肯Deeley和大卫•桑普森MathWorks
发展先进MATLAB®可视化通常包括管理多个低级图形对象。这一点尤其包含图形动态更新的应用程序。这样的应用程序可能需要耗时的编程。
一个图表对象提供了一个高层次的应用程序编程接口(API)来创建定制的可视化。不仅提供了一个方便的可视化图表API为您的终端用户;它也无需用户实现底层图形编程。
MATLAB包括面向对象框架的开发定制图表通过以下集装箱超类:
matlab.graphics.chartcontainer.ChartContainer
(在R2019b介绍)matlab.ui.componentcontainer.ComponentContainer
(在R2020b介绍)
本文提供了一个循序渐进的指南,设计模式和最佳实践,创建和使用这个框架实现一个自定义的图表。与一个例子说明的步骤包含最佳直线的散点图。主题包括:
- 写一个标准表模板
- 写表的
设置
和更新
方法 - 封装数据和图形
- 为终端用户提供一个高级的API
- 包括交互控制
此外,我们已经创建了一些特定于应用程序的图表(图2)。您可以下载这些表格,连同本文中使用MATLAB代码,文件交换。
上面的代码是足够的静态可视化。然而,如果应用程序需要动态地修改数据,然后我们遇到一些挑战:
- 如果我们更换
XData
或YData
用一个新的数组长度相同的电流XData
,最佳适合行不是动态更新(图4)。年代。XData =。XData + 4;
- 的
散射
对象年代
发出警告,并执行任何图形更新,如果其数据属性(XData
或YData
)被设置为一个数组,长或短于当前数组。年代。XData = s.XData (1:50 0);
我们可以解决这些挑战,和其他人来说,通过设计一个图表,我们的名字ScatterFit
。
构建图表代码:函数或类?
函数封装代码作为一个可重用的单元,可以让你创建多个图表没有复制代码。
函数scatterfit(变长度输入宗量)%保证2或3的输入。narginchk (2、3)%我们支持金宝app调用语法scatterfit (x, y)或% scatterfit (f, x, y), f是图形。开关输入参数个数情况下2 f = gcf;x =变长度输入宗量{1};y =变长度输入宗量{2};否则%例3 f =变长度输入宗量{1};x =变长度输入宗量{2};y =变长度输入宗量{3};结束% switch / case%创建的图表坐标轴和散点图。ax =轴(“父”f);散射(ax, x, y, 6日“填充”)%计算并创建最佳线。m = fitlm (x, y);(ax,“上”)情节(ax, x, m.Fitted“线宽”2)持有(ax,“关闭”)结束% scatterfit函数
注意,这个函数需要两个数据输入(x和y)。您可以指定图形的父母f
(例如,一个图)作为第一个输入参数。
scatterfit (x, y)
指定了两个数据输入。scatterfit (f, x, y)
父母指定的图形和数据。
在第一种情况下,函数展品autoparenting行为——也就是说,一个图的图表将自动创建。
使用一个函数来创建一个图有一些缺点:
- 您不能修改后的数据表已创建。
- 更改图表数据,您需要再次调用该函数创建图表。
- 最终用户很难找到可配置图参数(例如,标签和装饰图形属性,如颜色、线型,等等)。
实现图表类所有代码封装和可重用性,函数的好处提供了同时也让你修改图表而无需重新创建它。
选择图表超类:ChartContainer
或ComponentContainer
吗?
必须实现为一个图表处理
类,以便它可以被修改。与MATLAB图形对象的一致性、图表应该支持的金宝app得到
/集
除了标准的语法属性点符号。这两个ChartContainer
和ComponentContainer
处理类和提供支持吗金宝app得到
/集
语法,这意味着您可以获得您的自定义图表从其中一个超类。
classdefScatterFit < matlab.ui.componentcontainer.ComponentContainer
结果,对于任何属性,如表1中所示的语法自动支持。金宝app
语法类型 | 访问 | 修改 |
---|---|---|
点符号 | x = SF.XData; |
科幻小说。XData = x; |
获取/设置 |
x =(科幻小说,“XData”); |
集(科幻“XData”x) |
选择一个超类基于图表的要求。如果表不需要交互的面向用户的控件,如按钮、下拉菜单、复选框,然后推导出图ChartContainer
;否则,使用ComponentContainer
。这是因为表超类提供了一个容器平铺的布局作为顶级图形对象,这个对象可以包含轴而不是用户控件。顶层容器是一个图形对象关联到一个组件面板——对象,它同时支持轴和用户控件。金宝app
注意,超类自动管理生命周期的图表框架,保证以下行为:
- 当删除图表图形(例如,通过关闭主图窗口),图表对象被删除。
- 当对象被删除的图表(例如,当它超出范围或当其处理被删除),图表图形删除。
超类的框架支持使用所有图表输入参数的名称-值对。金宝app这意味着没有输入参数需要指定在创建图表,和所有输入是可选的。
写作的图表设置
和更新
方法
我们现在需要实现两个特殊的方法,这两个框架所需的超类:
设置
:打电话时自动创建图表更新
:用户修改时自动调用某些图表属性
这些方法在我们的图表类,因为他们必须保护访问该属性的超类。
方法(访问=保护)函数设置(obj)结束%设置函数更新(obj)结束%更新结束%方法(访问=保护)
让我们看一下设置
方法。这是函数在类定义,我们初始化表。一个很好的起点是复制的代码scatterfit
函数设置
方法。然后,我们进行以下修改来支持所需的图表行为:金宝app
父图形。与上述方法不同
scatterfit
函数,如果没有父
输入指定,那么我们不自动创建一个图表。注意,这种行为是不同于方便等功能情节
和散射
展览autoparenting。在设置
主要方法,我们创建我们的图形对象(如轴、面板或布局),并将其母财产分配给顶级图形对象提供的超类。的getLayout
的方法ChartContainer
超类返回的引用顶级瓷砖布局。为ComponentContainer
图表,我们可以简单地将图形父母财产分配给对象本身。obj。一个xes = axes("Parent", obj.getLayout()); % ChartContainer obj.Axes = axes("Parent", obj); % ComponentContainer
如果
父
被指定为一个输入参数,那么它将自动的超类,连同其他图表创建期间提供的名称-值对。超类将分配指定的父母的父母顶级图形对象。图表图形。我们创建和存储任何图形对象所需的图表。大多数图表需要一个坐标轴对象一起一些轴线或补丁对象等内容。在
ScatterFit
图,我们需要一个散射
对象和一个行
对象。obj。ScatterSeries =散射(obj。轴,南南);obj。BestFitLine =线(obj。轴,南南);
注意,我们使用他们的数据属性设置为初始化这些图形
南
。如果用户指定了XData
和/或YData
在建筑,然后我们推迟更新散点图和对应的最佳线路集
方法(稍后讨论)。这个编码实践确保任何错误造成的用户在指定名称-值对将分别被捕获并处理。图形配置。我们配置图表图形通过设置所需的属性。例如,我们可以创建注释标签或标题等,设置轴的一个特定的视图,添加一个网格,或调整颜色,风格或线的宽度。
只要实际,我们使用原始对象(表2)来创建图表图形,因为高层便利的函数调用时重置许多现有轴属性。但是,也有例外原则:ScatterFit
,我们使用非散射函数来创建图形对象,因为它支持后续更改个人标记大小和颜色(而一行对象不)。金宝app
原始图形函数 | 高级图形函数 |
---|---|
行 |
情节 |
表面 |
冲浪 |
补丁 |
填满 |
我们将返回到图的更新方法。
封装图表数据和图形
在大多数图表、底层图形包含至少一个轴对象和它们的内容(例如,线或面对象)或轴同行对象(例如,传说或彩色)。图表还维护内部数据属性,以确保公共属性正确显示给最终用户。我们将底层图形和内部数据存储为私人图表属性。例如,ScatterFit
表维护以下私人属性。
属性(访问=私人)% XData属性的内部存储。XData_ =双。空(0,1)% YData属性的内部存储。YData_ =双。空(0,1)%逻辑标量指定是否需要计算。ComputationRequired = false ()结束%属性(访问=私人)
我们使用命名约定XData_
表明这是私人,内部版本的图表数据。相应的公共数据属性可见的用户将被命名为XData
。
属性(=私人访问,瞬态NonCopyable)%的图表坐标轴。轴(1)matlab.graphics.axis.Axes%的散射系列(x, y)数据。ScatterSeries matlab.graphics.chart.primitive.Scatter (1,1)%为最佳适合行线对象。BestFitLine matlab.graphics.primitive.Line (1,1)结束%属性(访问=私人、瞬态NonCopyable)
使用私人
内部表的属性数据和图形有三个主要目的。
- 私有财产限制低级图像的可见性,隐藏实现细节,减少视觉上的混乱在图表的API。
- 限制访问底层图形,减少绕过API的机会。
- 图表数据可以很容易地同步(例如,我们需要
XData
和YData
的属性ScatterFit
有关)。
内部图形属性,这是一个很好的练习来指定瞬态
和NonCopyable
属性。这些时确保图表对象行为正确保存到MAT-file或复制。额外的鲁棒性,使标签完成图形属性图表类工作时,我们也实现属性的验证。
提供一个可视化的API
设计一个图表的主要原因之一是提供一个方便、直观的API。我们装备ScatterFit
图表和容易辨认的属性,使用名称符合现有的图形对象的属性(图5)。
用户可以访问或修改这些属性表1中使用示例语法。相关图表图形动态更新以响应属性修改。例如,改变线宽
的属性表更新线宽
的最佳路线。
我们实现的部分图表的API使用依赖
属性。一个依赖
属性的值不是显式存储,而是来自其他属性的类。在一个图表中,依赖
依靠私人属性如低级图形或内部数据属性。
定义一个依赖
财产,我们第一次在一个属性中声明它的名字块与属性依赖
。这表明房产价值取决于其他属性在类。
属性(依赖)% x数据图表。XData(: 1)双{mustBeReal}%图表数据。YData(: 1)双{mustBeReal}结束%属性(依赖)
我们也需要指定属性依赖于其他类属性如何通过编写相应的get方法。该方法返回一个输出参数——的价值依赖
财产。在ScatterFit
图表,XData
财产的图表(图的公共接口的一部分)只是潜在的XData_
属性,该属性存储在内部的私有财产。
函数值= get.XData (obj)值= obj.XData_;结束% get.XData
还需要每个数据属性集
方法。这个分配到正确的内部图属性指定的值和触发任何必要的图形更新。
为ScatterFit
图表,我们支持动态修金宝app改(包括长度变化)的数据属性(XData
和YData
)。当用户设置(公共)XData
图,我们垫或截断相反的(私人)数据属性YData_
,这取决于新的数据向量比现有的数据分别是长还是短。回想一下,这集
方法将调用建设如果用户指定XData
当创建图表。
函数set.XData (obj,值)%马克一个更新的图表。obj.ComputationRequired= true();%决定如何修改图表数据。nX =元素个数(价值);纽约=元素个数(obj.YData_);如果nX <纽约%如果新的x数据太短然后截断图表数据。obj。YData_ = obj.YData_ (1: nX);其他的%,如果nX > =纽约,然后垫y数据。obj。YData_ (+ 1: nX, 1) =南;结束%如果%设置内部x数据。obj。XData_ =价值;结束% set.XData
注意,图表的更新
方法被调用时自动用户设置一个公共财产。为了避免不必要的和费时的计算,我们使用一个私有的,内部逻辑属性ComputationRequired
记录,集
方法,是否完整更新是必要的。
公共API的属性不需要新的计算时不需要改变得到
或集
方法。相反,我们只是刷新相应的内部对象的末尾更新
方法。通常,公共API属性包括装饰和化妆品方面的图表,如颜色,线宽、和风格,便宜的更新。
在ScatterFit
图表,更新
方法包含所需的代码设置的新数据散射
对象,再计算最佳路线并设置新的数据在相应的行
对象。
函数更新(obj)如果obj.ComputationRequired%更新散射与新数据系列。集(obj.ScatterSeries,“XData”obj.XData_,“YData”obj.YData_)%获得新的最佳线路。m = fitlm (obj。XData_,obj。YData_);%更新最佳线图形。[~,posMin] = min (obj.XData_);[~,posMax] = max (obj.XData_);集(obj.BestFitLine,“XData”obj。XData_([posMin, posMax]),“YData”,m。安装([posMin posMax]))%马克图干净。obj.ComputationRequired= false();结束%如果%更新图表的装饰性能。集(obj.ScatterSeries,“CData”obj.CData,“SizeData”obj.SizeData)结束%更新
我们实现了集
方法YData
在一个相同的方式,开关的角色X / YData
属性。
创建一个丰富的API适合终端用户,我们实现一个广泛的公共属性。注意,如标准属性父
,位置
,单位
,可见
都是继承了父类,不需要额外的图表中的实现。
添加图表注释的方法
在我们提供的API,熟悉的和易于使用的方法注释图表。这些注释的方法过载(有相同名称)相应的高级图形装饰功能。要使用这些方法,用户提供了一个参考图作为第一个输入参数,其次是输入的装饰功能。
包含(科幻小说,“x数据”,“字形大小”,12)
如果装金宝app修支持的函数,调用注释方法也可以使用一个输出返回一个引用图形对象进行进一步定制。例如,包含
函数返回一个文本对象。
xl =包含(科幻小说,“x数据”);
支持名金宝app称-值对和输出参数,方便使用细胞阵列变长度输入宗量
和varargout
。的语法变长度输入宗量{:}
产生一个以逗号分隔的输入参数。我们确定数量的输出从调用者使用nargout
。处理数量可变的输出参数(这些方法通常,0或1)我们使用语法[varargout {1: nargout}]
当调用装饰功能。一个典型的注释方法具有以下结构:
函数varargout =包含(obj,变长度输入宗量)[varargout {1: nargout}] =包含(obj。轴,变长度输入宗量{:});结束%包含
包括交互式控制图表
除了图表的API,我们可以包括控制图,为最终用户提供选项交互和修改(图6)。
我们初始化这些控件的图表设置
方法,使用组件应用程序构建。每个控件都有一个回调函数,实现为一个私有方法。这种方法有三个输入参数:
- 图表对象。
- 的引用源负责触发回调对象(对象)——这种情况下,源对象对应的用户控件。
- 事件数据。这是一个对象自动传递给回调函数通过MATLAB当用户与控制。事件数据对象包含关于事件的附加信息。
例如,考虑复选框的回调函数控制最佳直线的可见性。这个函数切换底层线对象的可见性基于复选框的值。
函数toggleLineVisibility (obj s ~)% TOGGLELINEVISIBILITY切换的可见性最佳。obj.BestFitLine。可见= s.Value;结束% toggleLineVisibility
每个控件的值必须与对应的同步表属性。为了达到这个目标,我们装备图属性依赖
属性,然后实现它得到
和集
方法。注意,除了更新内部图形对象集
方法也必须更新控制对象的值。
对应于最佳线可见性的代码如下所示。为了确保财产和复选框的值之间的兼容性,我们把财产matlab.lang.OnOffSwitchState
类型。这类支持任何兼容的语金宝app法表示真正的
和假
值,如1
和0
,以及“上”
和“关闭”
。
属性(依赖)%的可见性最佳。LineVisible matlab.lang.OnOffSwitchState (1,1)结束%属性(依赖)函数值= get.LineVisible (obj)值= obj.BestFitLine.Visible;结束% get.LineVisible函数set.LineVisible (obj,值)%更新属性。obj.BestFitLine。可见=价值;%更新”复选框。obj.BestFitLineCheckBox。值=价值;结束% set.LineVisible
将图表与程序设计师
MATLAB R2021a,图表使用的开发ComponentContainer
超类可以集成与应用程序设计师与应用程序设计师(图7)。你可以通过创建元数据与最终用户分享图表。安装图将出现在用户的应用程序设计师组件库,它可以使用交互式的帆布和其他组件。
总结
在本文中,我们描述的设计模式和最佳实践的实现自定义图表,使用ScatterFit
图表作为一个例子。许多常见的可视化任务,尤其是那些需要动态图形,可以执行使用一个适当的图表。设计和创建图表的前期开发需要时间和精力,但许多可视化工作流图表可以大大简化。
2021年出版的