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

Posted

技术标签:

【中文标题】我应该如何更新 Matlab 中的绘图数据?【英文标题】:How should I update the data of a plot in Matlab? 【发布时间】:2012-10-17 15:32:23 【问题描述】:

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

    XDataSource 属性设置为某个名称,更新变量,然后调用refreshdata 抹掉原来的plot,再次调用plot命令。 使用Set('Xdata',...')

【问题讨论】:

相关:Real time plot in matlab 【参考方案1】:

简短的回答:总是使用 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) - 刷新数据

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(objfieldsk2),'ecruoSataD',10)
      objs = objs:,obj, objfieldsk2;
    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')

代码非常清晰。您想修改绘图的两个属性,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 秒。

【讨论】:

并且您可以将refreshdata 在 R2012b 中损坏的方法 (1) 添加到 @MattLab,感谢您提供的信息。我没有安装2012b。你能举个例子,或指出一些参考吗?您还可以将此事实添加为问题的另一个答案。 好点。我修正了“首选”代码中的一个错字——你叫set(h,'XDataSource',x),我认为是复制粘贴错字。第一个代码 sn-p 没有这些。否则,我明白你的意思。虽然另一方面,如果您有 100 个图要刷新,调用 refreshdata 是一行,而在重新计算输入数据后调用 set(h, ...) 100 次可能有点乏味。 另外:当你想在回调中编辑数据时,使用set('XData')refreshdata 更容易。您唯一需要搜索(或使用persistent 缓存)是图形句柄。我在尝试自动链接内容时遇到了麻烦,切换到 XData 后非常流畅。 h.XData = x; h.YData = y; 在我的机器上实际上比同等的 set(h,'XData',x,'YData',y); 快 33%。我已经在您的脚本中进行了测试,设置 i=1:1000 的总时间为 0.058861 秒与 0.088543 秒。【参考方案2】:

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

如果您在给定的轴上有多个线对象,则方法:

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

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

一个错误已提交给 Mathworks。

【讨论】:

【参考方案3】:

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

h = plot(nan);

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

【讨论】:

以上是关于我应该如何更新 Matlab 中的绘图数据?的主要内容,如果未能解决你的问题,请参考以下文章

MATLAB - 如何一起缩放子图?

通过将数字分组到一个范围内在 matlab / octave 中绘图

MATLAB | 绘图复刻 | 分层聚类分析图:树状图+热图

MATLAB | 绘图复刻 | 分层聚类分析图:树状图+热图

在C语言编程中,如何调用MATLAB的绘图功能?

如何在 Matlab 绘图图例中放置颜色条图标