我应该如何在Matlab中更新绘图数据?

时间:2012-10-27 17:53:15

标签: matlab plot graph matlab-figure matlab-guide

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

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

3 个答案:

答案 0 :(得分:54)

简答:始终使用 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. 代码可移植性 - 您可以多快对代码进行重新分解?
  4. 现在,让我们分析可能的方法。

    方法(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使用evalm-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) - 设置('XData',...,'YData')

    代码非常清楚。您想要修改地图的两个属性XDataYData。而这正是你所做的。此外,代码运行速度非常快,您可以从下面的比较中看到。

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

答案 1 :(得分:3)

您可以调用函数drawnow并执行类似的操作:

h = plot(nan);

for i = 1:n
  y = ...
  set(h,'YData',y);
  drawnow                 %update the graph
end

答案 2 :(得分:2)

  

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

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

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

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

已向Mathworks提交错误。