español - subplot matlab
MATLAB: ¿la mejor manera de actualizar dinámicamente una línea maneja ''XData e YData? (3)
Parte del motivo por el que su código puede tardar mucho tiempo en ejecutarse es porque está utilizando un bucle for para asignar sus variables. Dependiendo de la versión de Matlab que esté utilizando, esto reducirá significativamente su proceso. Sugiero usar la vectorización para asignar valores a tu x y y así:
x = 1:1000;
y = cosd(x);
A continuación, puede asignar los primeros puntos en sus datos.
xi = x(1);
yi = y(1);
Cuando trace, asigne XDataSource e YDataSource.
h = plot(xi, yi, ''YDataSource'', ''yi'', ''XDataSource'', ''xi'');
Ahora cuando realiza un bucle para cambiar los valores, use los datos de actualización para actualizar los valores de Xdata e Ydata. Use la función drawow para actualizar la ventana de figura.
for k = 2:1000,
xi = x(1:k);
yi = y(1:k);
refreshdata(h, ''caller'')
drawnow;
end
Estoy recopilando datos y trazando esos datos en tiempo real. Los datos son producidos por un sistema de captura de movimiento. Tengo una clase DynamicDataset
que es solo un contenedor alrededor de una matriz de dos columnas (aunque es más matizada que eso) con un notificador de eventos para nuevos datos agregados; otra clase DynamicPlotter
que escucha el evento de datos agregados y actualiza la trama de forma dinámica. Recortes de código apropiados:
classdef DynamicDataset < handle
properties
newestData = [];
data = []
end
events
DataAdded
end
methods
function append(obj, val)
obj.data(end+1,:) = val;
obj.newestData = val;
notify(obj, ''DataAdded'');
end
end
end
classdef DynamicPlotter < dynamicprops
properties
FH %# figure handle
AH %# axes handle
LH %# array of line handles - may have multiple lines on the plot
dynProps = {} %# cell array of dynamic property names -
%# use to access individual datasets
end
methods
function obj = DynamicPlotter(props) %# props is a cell array of dynamic
%# properties to store information
for i = 1:length(props)
addprop(obj, props{i});
obj.(props{i}) = DynamicDataset;
obj.dynProps = [obj.dynProps props{i}];
addlistener(obj.(props{i}), ''DataAdded'', @obj.updatePlot(i));
end
obj.createBlankPlot();
end
function createBlankPlot(obj)
obj.FH = figure;
obj.AH = axes;
hold all;
for i = 1:length(obj.dynProps)
obj.LH(i) = plot(nan); %# only used to produce a line handle
set(obj.LH(i), ''XData'', [], ''YData'', []);
end
end
function updatePlot(obj, propNum)
X = get(obj.LH(propNum), ''XData'');
Y = get(obj.LH(propNum), ''YData'');
X(end+1) = obj.(dynProps{propNum}).newestData(1);
Y(end+1) = obj.(dynProps{propNum}).newestData(2);
set(obj.LH(propNum), ''XData'', X, ''YData'', Y);
end
end
end
Basado en el perfil de código MATLAB, el comando set
en updatePlot()
es bastante caro. Me pregunto si hay una mejor manera de trazar puntos individuales a medida que se presenten. Idealmente, insertaría el único punto en XData
e YData
y dibujaría ese punto solamente, pero no sé si esto es posible.
Tenga en cuenta que puede haber múltiples objetos lineeries (es decir, múltiples gráficos en la misma parcela); plot()
toma un asa de ejes como argumento, por lo que no tendría en cuenta las propiedades de los tiradores de línea dibujados previamente (¿o hay alguna forma de hacerlo?); Pensé en hacer una plot(x,y);hold all;
pero eso me daría identificadores de línea separados cada vez, cada uno correspondiente a un solo punto.
Puede ser que no haya forma de hacer que trazar los puntos entrantes sea más rápido, pero pensé que lo haría.
EDITAR : OP actualizado con el código real con el que estoy trabajando, en lugar de usar un ejemplo genérico que está mal interpretado.
La cantidad de datos que maneja en cada actualización es grande (aunque solo un punto en realidad está cambiando), lo que hace que su código sea O (N ^ 2).
Al usar una segunda línea de líneas para crear un gran grupo de datos, puede alternar entre agregar cada punto a una línea "activa" corta y agregar bloques grandes de forma infrecuente a las líneas principales. Si bien esto no evita exactamente O (N ^ 2), le permite reducir la constante de manera significativa.
Si hace esto, recuerde superponer las lineeries "viejas" y lineeries "activas" en un punto, para que se conecten.
Esencialmente:
function updatePlot(obj, propNum)
X = get(obj.LHactive(propNum), ''XData'');
Y = get(obj.LHactive(propNum), ''YData'');
X(end+1) = obj.(dynProps{propNum}).newestData(1);
Y(end+1) = obj.(dynProps{propNum}).newestData(2);
if numel(X) > 100
Xold = [get(obj.LH(propNum), ''XData''); X(2:end)];
Yold = [get(obj.LH(propNum), ''YData''); Y(2:end)];
set(obj.LH(propNum), ''XData'', Xold, ''YData'', Yold);
X = X(end);
Y = Y(end);
end
set(obj.LHactive(propNum), ''XData'', X, ''YData'', Y);
end
Su código es lento, porque está repitiendo todos los valores cada vez que llama a updatePlot . Por lo tanto, solo trazaré el último punto en updatePlot (Este es también el problema que has planteado: idealmente insertaría el punto único en XData e YData y solo sacaré ese punto, pero no sé si esto es posible. )
agregar propiedad LH_point_counter
classdef DynamicPlotter < dynamicprops properties FH %# figure handle AH %# axes handle LH %# cell array of line handles - may have multiple lines on the plot % counter that counts home many points we have for each dynProps LH_point_counter = []; dynProps = {} %# cell array of dynamic property names - %# use to access individual datasets end
modificar updatePlot
function updatePlot(obj, propNum) % plot new point new_x = obj.(dynProps{propNum}).newestData(1); new_y = obj.(dynProps{propNum}).newestData(2); new_handle = plot(new_x, new_y); % add new handle to list of handles of this property counter_this_prop = obj.LH_point_counter(propNum); counter_this_prop = counter_this_prop + 1; obj.LH{propNum}(counter_this_prop) = new_handle; % save new counter value obj.LH_point_counter(propNum) = counter_this_prop; end