2011-09-14 77 views
6

我正在收集數據並實時繪製數據。數據由動作捕捉系統生成。我有一個類DynamicDataset,它只是一個包含2列矩陣的包裝(雖然它比這更細緻),但是添加了新數據的事件通知程序;另一個類DynamicPlotter,用於監聽添加數據的事件並動態更新繪圖。相應的代碼片段:MATLAB - 動態更新線條處理'XData和YData的最佳方式?

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的代碼資料,在updatePlot()set命令是相當昂貴的。我想知道是否有更好的方法來繪製個人點,因爲他們來了?理想情況下,我會將單點推入XDataYData,並只畫出這一點,但我不知道這是否可能。

請注意,可能有多個lineseries對象(即在同一個plot上有多個圖形); plot()需要一個軸手柄作爲參數,所以它不會考慮先前繪製的線手柄的屬性(或者是否有辦法讓它這樣做?我以爲只是在做plot(x,y);hold all;,但每次都會給我單獨的線條手柄,每個手柄對應一個點。

這可能是因爲沒有辦法讓繪圖速度更快,但我想我會問。

編輯:更新OP與我正在使用的實際代碼,而不是使用一個通用的例子,這是誤解。

+0

我不知道你是否已經看到了這一點,但看看http://stackoverflow.com/questions/1693429/matlab-oop-is-it-slow-or-am-我做錯了什麼。基本上在matlab中使用類一般會導致性能不佳 – Marm0t

+0

謝謝,我以前見過。我的項目需要使用類,原因是我不會進入,所以沒有任何解決方法......但是'set'調用會很慢,因爲它是在方法內部調用的? –

+0

@ strictrude27:你應該改正addlistener行爲:'addlistener(obj。(props {i}),'DataAdded',@(src,ev)obj.updatePlot(i));'。你也可能想在'updatePlot'函數末尾添加'drawnow' – Amro

回答

4

您在每次更新中處理的數據量很大(儘管實際上只有一個點實際上在變化),使您的代碼爲O(N^2)。

通過使用第二個線路系列來建立一大組數據,您可以在將每個點添加到短「活動」線路以及不常將大塊添加到主線路系列之間交替。雖然這並不完全避免O(N^2),但它可以讓您顯着減少常數。

如果您這樣做,請記住將「舊」線條系列和「活動」線條系列重疊一點,以便它們連接。

本質:

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 
+0

這極大地縮短了劇情時間!如果您有更多想法可以進一步縮短時間,請告訴我.. –

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 
+0

這不幸的是不能滿足我的需求 - 我的數據實際上並不是在for循環中生成的,而是由運動捕捉系統實時生成的。上面的代碼片段只是表明我正在動態繪製數據。我會更新OP來反映我的具體情況;我試圖變得更一般,但我的例子顯然是誤導性的。 –

1

你的代碼是緩慢的,因爲你型重構您致電updatePlot所有值每次。因此,我將只繪製updatePlot(這也是你所說的問題:)的最新點理想情況下,我會將單點放入XData和YData中,並僅繪製該點,但我不知道這是否是可能的。

  1. 添加屬性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 
    
  2. 修改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 
    
+0

這可能會奏效 - 我確定不得不復制財產不會是世界上最昂貴的事情。但是,我想知道這將如何幹擾我的主軸手柄?我手動調整繪圖窗口和其他軸處理屬性,所以不斷寫這可能不是最好的選擇。 –

+1

該代碼不會重新複製任何屬性。它所做的只是將最新的句柄添加到句柄列表中 - 這是一個非常便宜的操作。你的手動軸調整是一個單獨的問題,你還沒有發佈代碼。 – memyself