假设我想用新数据更新一个绘图,我应该选择哪种方法?
- 将
XDataSource
属性设置为某个名称,更新变量,并调用refreshdata
方法。 - 删除原始的
plot
,然后再次调用plot
命令。 - 使用
Set('Xdata',...')
方法。
假设我想用新数据更新一个绘图,我应该选择哪种方法?
XDataSource
属性设置为某个名称,更新变量,并调用 refreshdata
方法。plot
,然后再次调用 plot
命令。Set('Xdata',...')
方法。简短回答:始终使用Set('Xdata',...')
。
示例代码:
function PlotUpdate()
x = 0:.1:8;
y = sin(x);
h = plot(x,y);
y = sin(x.^3);
set(h,'XData',x,'YData',y);
end
长答案:
选择最佳方法应考虑三个相关因素。
现在,让我们分析可能的方法。
方法(1)- refreshdata
function PlotUpdate()
x = 0:.1:8;
y = sin(x);
h = plot(x,y);
set(h,'YDataSource','y')
set(h,'XDataSource','x')
y = sin(x.^3);
refreshdata(h,'caller');
end
M-lint会立即在这行代码y=sin(x.^3)
上发出警告。
The value assigned to variable `y` might be unused
为什么会发生这种情况?refreshdata
使用 eval
,而 m-lint
不知道你将使用 y
。读取你的代码时,可能会完全删除此行。这是因为你违反了封装原则。 refreshdata
从调用者工作区访问变量。另一种看待这个问题的方式是,假设你将图的处理传递给另一个函数。读者不知道你为什么写了 y = sin(x.^3);
,以及它如何与图的更新相关。
现在让我们讨论速度/运行时间。通过查看 refreshdata
的源代码,你会注意到两个丑陋的 for 循环,遍历你空间中的所有图形句柄变量。以下是第一个:
% gather up all the objects to refresh
objs = {};
for k = 1:length(h)
obj = h(k);
objfields = fields(obj);
for k2 = 1:length(objfields)
% search for properties ending in DataSource
if strncmpi(fliplr(objfields{k2}),'ecruoSataD',10)
objs = {objs{:},obj, objfields{k2}};
end
end
end
想象一下,你不只有一个图表,而是有100个图表,并且你只想更新第一个。这会非常缓慢,因为对于每个图表,你都要尝试找到需要的那个!(我将其留作练习,让读者自己弄清楚ecruoSataD
是什么,以及如何使用它。)
即使你将相关的图表作为参数传递,你仍然有第二个循环,运行了多次eval
。效率并不高。最后我会展示一下时间比较。
结论:难以理解,难以重构,运行缓慢
方法(2)-删除并重新绘制
function PlotUpdate()
x = 0:.1:8;
y = sin(x);
h = plot(x,y);
set(h,'YDataSource','y')
set(h,'XDataSource','x')
y = sin(x.^3);
delete(h);
h = plot(x,y);
end
这种方法非常清晰易懂。你删除了绘图,然后画了一个新的。但是正如我们将在最后的时间比较中看到的那样,这是最慢的方法。
结论: 易于理解,易于重构,运行速度非常慢
方法(3) - set('XData',...,'YData')
这段代码非常清晰。你想修改绘图的两个属性,即XData
和YData
,并确实这就是你所做的。此外,该代码运行速度非常快,可以从以下比较中看出。
function PlotUpdate()
x = 0:.1:8;
y = sin(x);
h = plot(x,y);
y = sin(x.^3);
set(h,'XData',x,'YData',y);
end
自从新的hg2图形引擎(R2014b及以上版本)推出以来,您也可以使用属性语法来指定数据,如果您更喜欢这种表示方法。function PlotUpdate()
x = 0:.1:8;
y = sin(x);
h = plot(x,y);
y = sin(x.^3);
h.XData = x;
h.YData = y;
end
结论:易于理解,易于重构,运行速度快
这里是时间比较的代码
function PlotUpdateTimeCompare()
x = 0:.1:8;
y = sin(x);
h = plot(x,y);
set(h,'YDataSource','y')
set(h,'XDataSource','x')
y = sin(x.^3);
tic
for i=1:100
refreshdata(h,'caller');
end
toc
tic
for i=1:100
delete(h);
h = plot(x,y);
end
toc
tic
for i=1:100
set(h,'XData',x,'YData',y);
end
toc
end
结果如下:
已用时间为0.075515秒。
已用时间为0.179954秒。
已用时间为0.002820秒。
refreshdata
在 R2012b 中已经失效。 - MattLabset(h,'XDataSource',x)
,我认为这是一个复制粘贴错误。第一个代码片段没有这些。否则,我理解你的观点。不过,另一方面,如果你有100个图表需要刷新,调用refreshdata
只需要一行代码,而在重新计算输入数据后调用100次set(h, ...)
可能会有点繁琐。 - angainorset('XData')
比使用 refreshdata
更容易。唯一需要寻找(或使用 persistent
缓存)的是图形句柄。我曾经尝试自动链接内容时遇到了麻烦,但切换到 XData 后非常顺畅。 - lemonzidrawnow
,并实现以下操作:h = plot(nan);
for i = 1:n
y = ...
set(h,'YData',y);
drawnow %update the graph
end