Main Content

チャート クラスのプロパティの管理

ChartContainer 基底クラスのサブクラスとしてカスタム チャートを作成する際には、特定の手法を使ってコードをよりロバストに、効率的に、またユーザーのニーズに沿ったものにできます。これらの手法では、ユーザー クラスのプロパティを定義し管理する方法に焦点を当てます。作成される可視化のタイプと提供されるユーザー エクスペリエンスに役立つものは、すべて使用します。

  • プロパティ値の初期化 — ユーザーが入力引数なしで暗黙的なコンストラクターを呼び出す場合に備えて、チャートの既定の状態を設定します。

  • プロパティ値の検証 — 値を使って計算を実行したり、チャート内の基となるグラフィックス オブジェクトの 1 つを構成する前に、その値が有効であることを確認します。

  • プロパティ表示のカスタマイズ — ユーザーがセミコロンなしでチャート オブジェクトを参照すると、プロパティのカスタマイズされたリストを提示します。

  • update メソッドの最適化 — 時間のかかる計算にプロパティのサブセットのみが使用されている場合、update メソッドのパフォーマンスを改善します。

プロパティ値の初期化

ユーザー クラスのパブリック プロパティすべてに対し既定値を割り当てます。そうすることで、ユーザーがコンストラクター メソッドを呼び出す際に名前と値のペアの引数をいくつか省略しても、有効なチャートが構成されます。

座標のデータを保存するプロパティでは、初期値を NaN 値または空の配列に設定し、ユーザーが座標を指定しない場合は既定のチャートが空になるようにします。ユーザー クラスのメソッドで呼び出す予定のプロット関数の要件に従って、既定の座標を選択します。要件の詳細については、使用予定のプロット関数のドキュメンテーションを参照してください。

プロパティ値の検証

ユーザー クラス プロパティの値をコードで使用する前に、それらの値を検証することをお勧めします。これを行う便利な方法は、プロパティを定義する際にそのサイズとクラスを検証することです。たとえば、次のプロパティ ブロックでは、4 つのプロパティのサイズとクラスが検証されます。

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 は、それぞれの値が範囲 [0,1] 内にある、クラス double の 1 行 3 列の配列でなければならない。

チャートにおいて、基となるグラフィックス オブジェクトを保存するプロパティを検証することもできます。オブジェクトのクラス名を判定するには、コマンド ラインで対応するプロット関数を呼び出し、続いて関数 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

場合によっては、異なった形状とクラスの値を格納できるプロパティを定義することもできます。たとえば、文字ベクトル、文字ベクトルの cell 配列、または string 配列を格納できるプロパティを定義する場合は、サイズとクラスの検証を省略するか、カスタムのプロパティ検証法を使用します。

プロパティ検証の詳細については、プロパティ値の検証を参照してください。

プロパティ表示のカスタマイズ

チャートを ChartContainer 基底クラスのサブクラスとして定義する利点の 1 つは、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 メソッドは、スカラー オブジェクトのプロパティ リストを ColorIsoValueEnclose、および 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

プロパティ表示のカスタマイズの詳細については、プロパティ表示のカスタマイズを参照してください。

update メソッドの最適化

ほとんどの場合、ユーザー クラスの update メソッドは、パブリック プロパティに依存するチャートのあらゆる関連特性を再構成します。場合によっては、再構成には時間のかかる高負荷な計算が伴います。計算にプロパティのサブセットのみが関与する場合は、そのコードが必要な場合にのみ実行されるようにユーザー クラスを設計できます。

update メソッドを最適化する 1 つの方法は、以下のコンポーネントをユーザー クラスに追加することです。

  • logical 値を受け入れる ExpensivePropChanged というプライベート プロパティを定義する。このプロパティは、高負荷な計算に使用されるプロパティのいずれかが変更されたかどうかを示します。

  • 高負荷な計算に関与する各プロパティ用に 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 の値を設定し、続いて ExpensivePropChangedtrue に設定します。したがって、次に update メソッドが実行されるときは、ExpensivePropChangedtrue である場合にのみ doExpensiveCalculation が呼び出されます。その後、update メソッドはチャートの他の特性を引き続き更新します。

例: カスタマイズされたプロパティ表示をもつ最適化された等値面チャート

isocaps の関連付けられた isosurface を表示するために IsoSurfCapChart クラスを定義します。以下の機能を含めます。

  • サイズとクラスの検証を使用するプロパティ

  • カスタマイズされたプロパティ表示

  • 1 つ以上の関連プロパティが変更された場合にのみ isosurface および isocaps を再計算する、最適化された update メソッド

このクラスを定義するために、MATLAB パス上にあるフォルダー内に IsoSurfCapChart.m というプログラム ファイルを作成します。次に、表にある手順に従ってクラスを実装します。

手順実装

ChartContainer 基底クラスから派生させます。

classdef IsoSurfCapChart < matlab.graphics.chartcontainer.ChartContainer

クラスとサイズの検証を使用するパブリック プロパティを定義します。

  • VolumeDataIsoValue、および Colorisosurface のパラメーター。

  • EncloseWhichCapPlane、および CapVisibleisocaps のパラメーター。

    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 は、update メソッドが 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 を 2 回呼び出して、isosurfaceisocapsPatch オブジェクトを作成します。対応するプロパティにオブジェクトを保存し、座標軸を構成します。

    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 メソッドを実装します。各メソッド内で、対応するプロパティ値を設定し、続いて ExpensivePropChangedtrue に設定します。

    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;

参考

クラス

関数

関連するトピック