Main Content

本页的翻译已过时。点击此处可查看最新英文版本。

管理图类的属性

当您将自定义图作为 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 方法将标量对象属性列表指定为 ColorIsoValueEncloseCapVisible

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 方法时,仅当 ExpensivePropChangedtrue 时,才会调用 doExpensiveCalculation。然后,update 方法继续更新图的其他方面。

示例:具有自定义属性显示的优化的等值面图

定义一个 IsoSurfCapChart 类,用于显示 isosurface 和相关联的 isocaps。包括以下特征:

  • 使用大小和类验证的属性

  • 自定义的属性显示

  • 优化的 update 方法,仅当一个或多个相关属性发生变化时,该方法才会重新计算 isosurfaceisocaps

要定义此类,请在位于 MATLAB 路径上的文件夹中创建名为 IsoSurfCapChart.m 的程序文件。然后按照表中的步骤实现该类。

步骤实现

ChartContainer 基类派生而来。

classdef IsoSurfCapChart < matlab.graphics.chartcontainer.ChartContainer

使用类和大小验证定义公共属性。

  • VolumeDataIsoValueColorisosurface 的参数。

  • EncloseWhichCapPlaneCapVisibleisocaps 的参数。

    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

定义私有属性。

  • IsoPatchCapPatch 存储 isosurfaceisocapsPatch 对象。

  • SmoothData 存储三维体数据的经过平滑处理的版本。

  • ExpensivePropChanged 指示更新方法是否需要重新计算 isosurfaceisocaps

    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

实现 setup 方法。在本例中,调用 patch 函数两次,为 isosurfaceisocaps 创建 Patch 对象。将对象存储在对应的属性中,并配置坐标区。

    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

实现 update 方法。通过测试 ExpensivePropChanged 的值,决定是否调用 doExpensiveCalculation 方法。然后继续更新图的其他方面(开销较低)。

        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

实现 doExpensiveCalculation 方法,该方法对三维体数据进行平滑处理并重新计算 isosurfaceisocaps 的面和顶点。

        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

实现 getPropertyGroups 方法以自定义属性显示。

        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

对每个耗费大量资源的属性(VolumeDataIsoValueEnclose)实现 set 方法。在每个方法中,设置对应的属性值,然后将 ExpensivePropChanged 设置为 true

    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;

另请参阅

函数

相关主题