管理图类的属性
当您将自定义图作为 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;
