管理图类的属性
当您将自定义图作为 ChartContainer
基类的子类进行开发时,您可以使用某些方法来使代码更加稳健、高效,并针对用户的需求而量身定制。这些方法侧重于如何定义和管理类的属性。使用的任何方法都应该有助于您要创建的可视化的类型和您要提供的用户体验。
初始化属性值 - 设置图的默认状态,以防用户在没有任何输入参量的情况下调用隐式构造函数。
验证属性值 - 在使用这些值执行计算或配置图中的一个基础图形对象之前,确保这些值有效。
自定义属性显示 - 当用户不带分号引用图对象时显示自定义属性列表。
优化
update
方法 - 当在某个耗时的计算中只用到部分属性时提高update
方法的性能。
初始化属性值
为您的类的所有公共属性指定默认值。如果用户在调用构造函数方法时忽略了一些名称-值对组参量,则这样做可配置有效的图。
对于存储坐标数据的属性,将初始值设置为 NaN
值或空数组,以便当用户未指定坐标时,默认图为空。根据您计划在类方法中调用的绘图函数的要求选择默认坐标。要了解这些要求,请参阅您计划使用的绘图函数的文档。
验证属性值
好的做法是在代码使用类属性值之前先验证这些值。一种方便的方法是在定义属性时验证属性的大小和类。例如,下面的属性块验证四个属性的大小和类。
properties IsoValue (1,1) double = 0.5 Enclose {mustBeMember(Enclose,{'above','below'})} = 'below' CapVisible (1,1) matlab.lang.OnOffSwitchState = 'on' Color (1,3) double {mustBeGreaterThanOrEqual(Color,0),... mustBeLessThanOrEqual(Color,1)} = [.2 .5 .8] end
IsoValue
必须为double
类的 1×1 数组。Enclose
的值必须为'above'
或'below'
。CapVisible
必须为matlab.lang.OnOffSwitchState
类的 1×1 数组。Color
必须为double
类的 1×3 数组,其中每个值都在[0,1]
范围内。
您还可以验证在您的图中存储基础图形对象的属性。要确定对象的类名,请在命令行调用对应的绘图函数,然后调用 class
函数获取类名。例如,如果您计划在 setup
方法中调用 patch
函数,请在命令行中带输出参量(输入参量与此无关)调用 patch
函数。然后将输出传递给 class
函数,以获取其类名。
x = patch(NaN,NaN,NaN); class(x)
ans = 'matlab.graphics.primitive.Patch'
使用 class
函数的输出来验证您的类中对应属性的类。例如,以下每个属性存储一个 Patch
对象。
properties (Access = private,Transient,NonCopyable) IsoPatch (1,1) matlab.graphics.primitive.Patch CapPatch (1,1) matlab.graphics.primitive.Patch end
有时,您可能希望定义可以存储不同形状和值类的属性。例如,如果您定义可以存储字符向量、字符向量元胞数组或字符串数组的属性,请省略大小和类验证或使用自定义属性验证方法。
有关验证属性的详细信息,请参阅验证属性值。
自定义属性显示
将图定义为 ChartContainer
基类的子类的好处之一是,它还继承 matlab.mixin.CustomDisplay
类。因此,当您以不带分号的方式引用图时,可以自定义 MATLAB® 在命令行窗口中显示的属性列表。要自定义属性显示,请重载 getPropertyGroups
方法。在该方法中,您可以自定义列出哪些属性以及列表的顺序。例如,假设有具有以下公共属性的 IsoSurfCapChart
类。
properties IsoValue (1,1) double = 0.5 Enclose {mustBeMember(Enclose,{'above','below'})} = 'below' CapVisible (1,1) matlab.lang.OnOffSwitchState = 'on' Color (1,3) double {mustBeGreaterThanOrEqual(Color,0),... mustBeLessThanOrEqual(Color,1)} = [.2 .5 .8] end
以下 getPropertyGroups
方法将标量对象属性列表指定为 Color
、IsoValue
、Enclose
和 CapVisible
。
function propgrp = getPropertyGroups(obj) if ~isscalar(obj) % List for array of objects propgrp = getPropertyGroups@matlab.mixin.CustomDisplay(obj); else % List for scalar object propList = {'Color','IsoValue','Enclose','CapVisible'}; propgrp = matlab.mixin.util.PropertyGroup(propList); end end
当用户以不带分号的方式引用此图的实例时,MATLAB 会显示自定义列表。
c = IsoSurfCapChart
c = IsoSurfCapChart with properties: Color: [0.2000 0.5000 0.8000] IsoValue: 0.5000 Enclose: 'below' CapVisible: on
有关自定义属性显示的详细信息,请参阅Customize Property Display。
优化 update
方法
在大多数情况下,您的类的 update
方法会重新配置图中依赖于公共属性的所有相关方面。有时,重新配置需要耗费大量时间进行大量计算。如果计算只涉及属性的子集,您可以将您的类设计为仅在必要时执行该代码。
优化 update
方法的一种方法是将这些组件添加到您的类中:
定义名为
ExpensivePropChanged
的私有属性,该属性接受logical
值。此属性指示大量计算中使用的任何属性是否已更改。为耗费大量资源的计算中涉及的每个属性编写一个
set
方法。在每个set
方法中,将ExpensivePropChanged
属性设置为true
。编写一个执行大量计算的受保护方法。
在
update
方法中编写一个条件语句,用于检查ExpensivePropChanged
的值。如果该值为true
,则会执行需要大量计算的方法。
以下代码提供这种设计的简化实现。
classdef OptimizedChart < matlab.graphics.chartcontainer.ChartContainer properties Prop1 Prop2 end properties(Access=private,Transient,NonCopyable) ExpensivePropChanged (1,1) logical = true end methods(Access = protected) function setup(obj) % Configure chart % ... end function update( obj ) % Perform expensive computation if needed if obj.ExpensivePropChanged doExpensiveCalculation(obj); obj.ExpensivePropChanged = false; end % Update other aspects of chart % ... end function doExpensiveCalculation(obj) % Expensive code % ... end end methods function set.Prop2(obj,val) obj.Prop2 = val; obj.ExpensivePropChanged = true; end end end
Prop2
参与大量计算。set.Prop2
方法设置 Prop2
的值,然后将 ExpensivePropChanged
设置为 true
。因此,下次运行 update
方法时,仅当 ExpensivePropChanged
为 true
时,才会调用 doExpensiveCalculation
。然后,update
方法继续更新图的其他方面。示例:具有自定义属性显示的优化的等值面图
定义一个 IsoSurfCapChart
类,用于显示 isosurface
和相关联的 isocaps
。包括以下特征:
使用大小和类验证的属性
自定义的属性显示
优化的
update
方法,仅当一个或多个相关属性发生变化时,该方法才会重新计算isosurface
和isocaps
要定义此类,请在位于 MATLAB 路径上的文件夹中创建名为 IsoSurfCapChart.m
的程序文件。然后按照表中的步骤实现该类。
步骤 | 实现 |
---|---|
从 |
classdef IsoSurfCapChart < matlab.graphics.chartcontainer.ChartContainer |
使用类和大小验证定义公共属性。
| properties VolumeData double = rand(25,25,25) IsoValue (1,1) double = 0.5 Enclose {mustBeMember(Enclose,{'above','below'})} = 'below' WhichCapPlane {mustBeMember(WhichCapPlane,{'all','xmin',... 'xmax','ymin','ymax','zmin','zmax'})} = 'all' CapVisible (1,1) matlab.lang.OnOffSwitchState = 'on' Color (1,3) double {mustBeGreaterThanOrEqual(Color,0),... mustBeLessThanOrEqual(Color,1)} = [.2 .5 .8] end |
定义私有属性。
|
properties(Access = private,Transient,NonCopyable) IsoPatch (1,1) matlab.graphics.primitive.Patch CapPatch (1,1) matlab.graphics.primitive.Patch SmoothData double = []; ExpensivePropChanged (1,1) logical = true end |
实现 |
methods(Access = protected) function setup(obj) ax = getAxes(obj); % Create two Patch objects obj.IsoPatch = patch(ax,NaN,NaN,NaN, 'EdgeColor', 'none', ... 'FaceColor',[.2 .5 .8],'FaceAlpha',0.9); hold(ax,'on'); obj.CapPatch = patch(ax,NaN,NaN,NaN,'EdgeColor', 'none', ... 'FaceColor','interp'); % Configure the axes view(ax,3) camlight(ax, 'infinite'); camlight(ax,'left'); lighting(ax, 'gouraud'); hold(ax,'off'); end |
实现 |
function update(obj) % Perform expensive computation if needed if obj.ExpensivePropChanged doExpensiveCalculation(obj); obj.ExpensivePropChanged = false; end % Update visibility of CapPatch and update color obj.CapPatch.Visible = obj.CapVisible; obj.IsoPatch.FaceColor = obj.Color; end |
实现 |
function doExpensiveCalculation(obj) % Update isosurface obj.SmoothData = smooth3(obj.VolumeData,'box',7); [F,V] = isosurface(obj.SmoothData, obj.IsoValue); set(obj.IsoPatch,'Faces',F,'Vertices',V); isonormals(obj.SmoothData,obj.IsoPatch); % Update isocaps [m,n,p] = size(obj.SmoothData); [Xc,Yc,Zc] = meshgrid(1:n,1:m,1:p); [Fc,Vc,Cc] = isocaps(Xc,Yc,Zc,obj.SmoothData,obj.IsoValue,... obj.Enclose,obj.WhichCapPlane); set(obj.CapPatch,'Faces',Fc,'Vertices',Vc,'CData',Cc); end |
实现 |
function propgrp = getPropertyGroups(obj) if ~isscalar(obj) % List for array of objects propgrp = getPropertyGroups@matlab.mixin.CustomDisplay(obj); else % List for scalar object propList = {'Color','IsoValue','Enclose','CapVisible',... 'WhichCapPlane','VolumeData'}; propgrp = matlab.mixin.util.PropertyGroup(propList); end end end |
对每个耗费大量资源的属性( |
methods function set.VolumeData(obj,val) obj.VolumeData = val; obj.ExpensivePropChanged = true; end function set.IsoValue(obj, val) obj.IsoValue = val; obj.ExpensivePropChanged = true; end function set.Enclose(obj, val) obj.Enclose = val; obj.ExpensivePropChanged = true; end end end |
接下来,创建一个三维体数据数组,然后创建 IsoSurfCapChart
的实例。
[X,Y,Z] = meshgrid(-2:0.1:2); v = (1/9)*X.^2 + (1/16)*Y.^2 + Z.^2; c = IsoSurfCapChart('VolumeData',v,'IsoValue',0.5)
c = IsoSurfCapChart with properties: Color: [0.2000 0.5000 0.8000] IsoValue: 0.5000 Enclose: 'below' CapVisible: on WhichCapPlane: 'all' VolumeData: [41×41×41 double]
更改 c
的颜色并隐藏 isocaps
。
c.Color = [1 0.60 0]; c.CapVisible = false;