我正在收集数据并实时绘制数据。数据由运动捕捉系统产生。我有一个类DynamicDataset
,它只是一个2列矩阵的包装器(虽然它比那更细致),并且添加了新数据的事件通知器;另一个类DynamicPlotter
,用于侦听数据添加事件并动态更新绘图。适当的代码段:
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
基于MATLAB代码配置文件,set
中的updatePlot()
命令相当昂贵。我想知道是否有更好的方法来绘制个别积分?理想情况下,我会将单个点推入XData
和YData
并仅绘制该点,但我不知道这是否可行。
请注意,可能有多个lineseries对象(即同一图上的多个图表); plot()
将一个轴句柄作为参数,因此它不会考虑先前绘制的线句柄的属性(或者有没有办法让它这样做?);我只想做plot(x,y);hold all;
,但每次都会给我单独的线句,每个都对应一个点。
可能没有办法更快地绘制输入点,但我想我会问。
编辑:使用我正在使用的实际代码更新了OP,而不是使用了一个错误解释的通用示例。
答案 0 :(得分:4)
您在每次更新中处理的数据量很大(尽管只有一个点实际上正在发生变化),使您的代码为O(N ^ 2)。
通过使用第二个lineseries来构建大量数据,您可以在将每个点添加到一个简短的“活动”行之间交替,并且不经常向主要的lineseries添加大块。虽然这并没有完全避免O(N ^ 2),但它可以让你显着减少常数。
如果你这样做,请记住将“旧”的lineseries和“active”lineseries重叠一点,以便它们连接起来。
本质:
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
答案 1 :(得分:1)
您的代码可能需要很长时间才能运行的部分原因是因为您使用for循环来分配变量。根据您使用的Matlab版本,这将显着降低您的过程。我建议使用矢量化为你的x和y分配值,如下所示:
x = 1:1000;
y = cosd(x);
然后,您可以分配数据中的第一个点。
xi = x(1);
yi = y(1);
绘图时,指定XDataSource和YDataSource。
h = plot(xi, yi, 'YDataSource', 'yi', 'XDataSource', 'xi');
现在,当您循环更改值时,请使用refreshdata更新Xdata和Ydata值。使用drawnow函数更新图形窗口。
for k = 2:1000,
xi = x(1:k);
yi = y(1:k);
refreshdata(h, 'caller')
drawnow;
end
答案 2 :(得分:1)
您的代码很慢,因为您每次调用 updatePlot 时都会重新绘制所有值。因此,我只会在 updatePlot 中绘制最新点(这也是您所说的问题:理想情况下,我会将单点推入XData和YData并仅绘制该点,但是我不知道这是否可行。)
添加属性 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
修改 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