Comment dois-je mettre à jour les données d'un tracé dans Matlab?

Supposons que je souhaite mettre à jour un tracé avec de nouvelles données. Quelle méthode dois-je choisir?

  1. définissez la propriété XDataSource sur un nom, mettez à jour la variable et appelez refreshdata
  2. efface l'original plot et appelle à nouveau la commande plot.
  3. Utiliser Set('Xdata',...')
32
demandé sur gnovice 2012-10-27 21:53:14

3 réponses

réponse Courte : toujours utiliser Set('Xdata',...').

Exemple de code:

function PlotUpdate()   
    x = 0:.1:8;
    y = sin(x);
    h = plot(x,y);
    y = sin(x.^3);    
    set(h,'XData',x,'YData',y);
end

Réponse Longue:

Il y a trois mesures pertinentes par lesquelles on devrait choisir la meilleure méthode.

  1. clarté du Code - Comment est-il facile pour quelqu'un de lire votre code?
  2. Runtime - à quelle vitesse chaque méthode effectue sa tâche?
  3. portabilité du Code - à quelle vitesse pouvez-vous re-factoriser votre code?

Maintenant, analysons les méthodes possibles.

Méthode(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 immédiatement un avertissement dans la ligne y=sin(x.^3)

The value assigned to variable `y` might be unused

Pourquoi cela arrive-t-il? refreshdata utilise eval et m-lint ne peut pas savoir que vous allez utiliser y. Quelqu'un qui lit votre code, pourrait aussi bien supprimer complètement cette ligne. Cela s'est produit parce que vous avez enfreint le principe d'encapsulation. refreshdata accède aux variables depuis l'espace de travail de l'appelant. Une autre façon de jeter un oeil à cela, supposons que vous passez la poignée de l'intrigue à une autre fonction. Le lecteur n'a aucune idée de pourquoi sur terre vous avez écrit y = sin(x.^3);, et comment cela va-t-il être lié à la mise à jour de l'intrigue.

Parlons maintenant de la vitesse / de l'exécution. En regardant le code source refreshdata, vous remarquerez deux boucles For laides, qui traversent tous les des variables graphiques dans votre espace. Voici le premier:

% 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

Imaginez que vous n'avez pas un tracé, mais 100 tracé et que vous voulez mettre à jour uniquement le premier. Ce sera très lent, car pour chacune des parcelles, vous essayez de trouver celle dont vous avez besoin! (Je pars comme un exercice pour le lecteur de comprendre ce qui est ecruoSataD, et comment il est utilisé.)

Même si vous donnez le tracé pertinent comme argument, vous avez toujours la deuxième boucle, qui s'exécute plusieurs fois eval. Pas vraiment efficace. Je vais montrer une comparaison de temps à la fin.

Conclusion : difficile à comprendre, Difficile à refactoriser, lent runtime


Méthode (2) - Supprimer et re-parcelle

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

Cette méthode est assez claire pour le lecteur. Vous avez supprimé l'intrigue et en avez dessiné une nouvelle. Cependant, comme nous le verrons à la fin de la comparaison temporelle, c'est la méthode la plus lente.

Conclusion : Facile à comprendre, facile à refactoriser, très lent d'exécution


Méthode (3) - set ('XData',..."YData')

Le code est vraiment clair. Vous souhaitez modifier un deux propriétés de votre parcelle, XData et YData. Et c'est exactement ce que vous faites. En outre, le code fonctionne très vite, comme vous pouvez le voir dans la comparaison ci-dessous.

function PlotUpdate()   
    x = 0:.1:8;
    y = sin(x);
    h = plot(x,y);
    y = sin(x.^3);          
    set(h,'XData',x,'YData',y);
end

Depuis le nouveau moteur graphique hg2 (R2014b et plus), vous pouvez également utiliser la syntaxe de propriété pour spécifier des données si vous préférez cette notation:

function PlotUpdate()   
    x = 0:.1:8;
    y = sin(x);
    h = plot(x,y);
    y = sin(x.^3);          
    h.XData = x;
    h.YData = y;
end

Conclusion : Facile à comprendre, facile à refactoriser, exécution rapide


Voici le code de comparaison de temps

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

Et les résultats:

Le temps écoulé est de 0,075515 secondes.
Le temps écoulé est de 0,179954 secondes.
Le temps écoulé est de 0,002820 secondes.

53
répondu Andrey Rubshtein 2016-04-13 15:16:40

Vous pouvez appeler la fonction drawnow et faire quelque chose comme ça :

h = plot(nan);

for i = 1:n
  y = ...
  set(h,'YData',y);
  drawnow                 %update the graph
end
3
répondu R.Falque 2013-07-26 01:29:43

Supposons que je souhaite mettre à jour un tracé avec de nouvelles données. Quelle méthode dois-je choisir?

Si vous avez plus d'un objet de ligne dans les axes donnés, alors la méthode:

  1. définissez la propriété XDataSource sur un nom, mettez à jour la variable et appelez refreshdata

Va générer une erreur dans MATLAB R2012b. un exemple approprié est fourni dans la réponse D'Andrey.

Un bogue a été soumis à Mathworks.

2
répondu MattLab 2012-10-29 06:32:12