35

假设我想用新数据更新绘图。我应该选择什么方法?

  1. XDataSource属性设置为某个名称,更新变量,然后调用refreshdata
  2. 擦除原来的plot,然后再次调用plot命令。
  3. 采用Set('Xdata',...')
4

3 回答 3

57

简短的回答:总是使用 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. 代码清晰度——别人阅读你的代码有多容易?
  2. 运行时- 每种方法执行其任务的速度有多快?
  3. 代码可移植性——重构代码的速度有多快?

现在,让我们分析可能的方法。

方法(1)——刷新数据

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 秒。

于 2012-10-27T17:53:14.513 回答
3

您可以调用该函数drawnow并执行以下操作:

h = plot(nan);

for i = 1:n
  y = ...
  set(h,'YData',y);
  drawnow                 %update the graph
end
于 2013-07-26T01:29:43.667 回答
2

假设我想用新数据更新绘图。我应该选择什么方法?

如果给定轴中有多个线对象,则方法:

  1. 将 XDataSource 属性设置为某个名称,更新变量,然后调用refreshdata

将在 MATLAB R2012b 中生成错误。安德烈的回答中提供了一个适当的例子。

一个错误已提交给 Mathworks。

于 2012-10-29T06:32:12.007 回答