Gestión de propiedades de clases de gráficas
Al desarrollar una gráfica personalizada como una subclase de la clase básica ChartContainer
, se pueden utilizar determinadas técnicas para hacer que el código sea más sólido y eficiente, y se ajuste mejor a las necesidades de los usuarios. Estas técnicas se centran en cómo definir y gestionar las propiedades de una clase. Utilice cualquiera que sea útil para el tipo de visualización que desee crear y la experiencia de usuario que desee ofrecer.
Inicialice los valores de las propiedades: defina el estado predeterminado de la gráfica en caso de que los usuarios llamen al constructor implícito sin argumentos de entrada.
Valide los valores de las propiedades: asegúrese de que los valores sean válidos antes de utilizarlos para realizar un cálculo o configurar uno de los objetos de gráficas subyacentes de la gráfica.
Personalice la visualización de las propiedades: indique una lista personalizada de propiedades cuando un usuario haga referencia al objeto de gráfica sin un punto y coma.
Optimice el método
update
: mejore el rendimiento del métodoupdate
cuando solo se utilice un subconjunto de propiedades en un cálculo que requiere mucho tiempo.
Inicializar los valores de las propiedades
Asigne valores predeterminados a todas las propiedades públicas de la clase. Al hacerlo, se configura una gráfica válida si el usuario omite algunos de los argumentos de par nombre-valor cuando llama al método constructor.
En cuanto a las propiedades que almacenan datos de coordenadas, defina los valores iniciales en valores NaN
o arreglos vacíos, de manera que la gráfica predeterminada esté vacía cuando el usuario no especifique las coordenadas. Seleccione las coordenadas predeterminadas según los requisitos de las funciones de representación a las que tenga previsto llamar en los métodos de la clase. Para obtener información sobre los requisitos, consulte la documentación de las funciones de representación que tenga previsto utilizar.
Validar los valores de las propiedades
Se recomienda comprobar los valores de las propiedades de la clase antes de que el código utilice dichos valores. Una manera cómoda de hacerlo es validar el tamaño y la clase de las propiedades según las vaya definiendo. Por ejemplo, este bloque de propiedades valida el tamaño y la clase de cuatro propiedades.
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
debe ser un arreglo 1 por 1 de clasedouble
.Enclose
debe contar con un valor de'above'
o'below'
.CapVisible
debe ser un arreglo 1 por 1 de clasematlab.lang.OnOffSwitchState
.Color
debe ser un arreglo 1 por 3 de clasedouble
, en el que cada valor se encuentre en el intervalo[0,1]
.
También se pueden validar las propiedades que almacenan los objetos de gráficas subyacentes de la gráfica. Para determinar el nombre de clase de un objeto, llame a la función de representación correspondiente en la línea de comandos y, a continuación, llame a la función class
para obtener el nombre de clase. Por ejemplo, si prevé llamar a la función patch
en el método setup
, llame a la función patch
en la línea de comandos con un argumento de salida (los argumentos de entrada no importan). A continuación, pase el resultado a la función class
para obtener su nombre de clase.
x = patch(NaN,NaN,NaN); class(x)
ans = 'matlab.graphics.primitive.Patch'
Utilice el resultado de la función class
para validar la clase para la propiedad correspondiente en la clase. Por ejemplo, cada una de las siguientes propiedades almacena un objeto Patch
.
properties (Access = private,Transient,NonCopyable) IsoPatch (1,1) matlab.graphics.primitive.Patch CapPatch (1,1) matlab.graphics.primitive.Patch end
De manera ocasional, podría querer definir una propiedad que pueda almacenar distintas formas y clases de valores. Por ejemplo, si define una propiedad que pueda almacenar un vectores de caracteres, un arreglo de celdas de vectores de caracteres o un arreglo de cadenas, omita la validación del tamaño y la clase o utilice un método de validación de propiedad personalizado.
Para obtener más información acerca de cómo validar propiedades, consulte Validate Property Values.
Personalizar la visualización de propiedades
Una de las ventajas de definir la gráfica como una subclase de la clase básica ChartContainer
es que también hereda de la clase matlab.mixin.CustomDisplay
. De esta manera, se puede personalizar la lista de propiedades que MATLAB® muestra en la ventana de comandos cuando se hace referencia a la gráfica sin un punto y coma. Para personalizar la visualización de propiedades, sobrecargue el método getPropertyGroups
. En dicho método, se pueden personalizar las propiedades que se enumeran y el orden de la lista. Por ejemplo, considere una clase IsoSurfCapChart
que cuente con las siguientes propiedades públicas.
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
El siguiente método getPropertyGroups
especifica la lista de propiedades de objetos escalares como Color
, IsoValue
, Enclose
y 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
Cuando el usuario hace referencia a una instancia de esta gráfica sin un punto y coma, MATLAB muestra la lista personalizada.
c = IsoSurfCapChart
c = IsoSurfCapChart with properties: Color: [0.2000 0.5000 0.8000] IsoValue: 0.5000 Enclose: 'below' CapVisible: on
Para obtener más información acerca de cómo personalizar la visualización de propiedades, consulte Customize Property Display.
Optimizar el método update
En la mayoría de los casos, el método update
de la clase reconfigura todos los aspectos relevantes de la gráfica que dependen de las propiedades públicas. A veces, la reconfiguración incluye un cálculo costoso que requiere mucho tiempo. Si el cálculo incluye solo un subconjunto de las propiedades, se puede diseñar la clase para que ejecute dicho código solo cuando sea necesario.
Una manera de optimizar el método update
es añadir estos componentes a la clase:
Defina una propiedad privada denominada
ExpensivePropChanged
que acepte un valorlogical
. Esta propiedad indica si ha cambiado alguna de las propiedades utilizadas en el cálculo costoso.Escriba un método
set
para cada propiedad implicada en el cálculo costoso. En cada métodoset
, establezca la propiedadExpensivePropChanged
entrue
.Escriba un método protegido que realice el cálculo costoso.
Escriba una instrucción condicional en el método
update
que compruebe el valor deExpensivePropChanged
. Si el valor estrue
, ejecute el método que realice el cálculo costoso.
El siguiente código ofrece una implementación simplificada de este diseño.
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
está implicado en el cálculo costoso. El método set.Prop2
establece el valor de Prop2
y, a continuación, establece ExpensivePropChanged
en true
. Por lo tanto, la próxima vez que el método update
se ejecute, llama a doExpensiveCalculation
únicamente si ExpensivePropChanged
es true
. A continuación, el método update
sigue actualizando otros aspectos de la gráfica.Ejemplo: Gráfica de isosuperficie optimizada con visualización de propiedades personalizada
Defina una clase de IsoSurfCapChart
para mostrar una isosurface
con sus correspondientes isocaps
. Incluye las siguientes funcionalidades:
Propiedades que utilizan validación de clase y tamaño
Una visualización de propiedades personalizada
Un método
update
optimizado que recalculaisosurface
eisocaps
únicamente si una o varias de las propiedades relevantes han cambiado
Para definir esta clase, cree un archivo de programa denominado IsoSurfCapChart.m
en una carpeta que se encuentre en la ruta de MATLAB. A continuación, implemente la clase siguiendo los pasos que aparecen en la tabla.
Paso | Implementación |
---|---|
Derive la clase a partir de la clase básica |
classdef IsoSurfCapChart < matlab.graphics.chartcontainer.ChartContainer |
Defina las propiedades públicas mediante la validación de tamaño y clase.
| 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 |
Defina las propiedades privadas.
|
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 |
Implemente el método |
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 |
Implemente el método |
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 |
Implemente el método |
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 |
Implemente el método |
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 |
Implemente los métodos |
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 |
A continuación, cree un arreglo de datos volumétricos y una instancia de 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]
Cambie el color de c
y oculte isocaps
.
c.Color = [1 0.60 0]; c.CapVisible = false;