web-dev-qa-db-fra.com

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

Supposons que je veuille 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. Supprimez le plot d'origine et appelez à nouveau la commande plot.
  3. Utilisez Set('Xdata',...')
33
Andrey Rubshtein

Réponse courte: utilisez toujours 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 existe trois mesures pertinentes permettant de choisir la meilleure méthode.

  1. Clarté du code - Est-il facile pour quelqu'un de lire votre code?
  2. Runtime - À quelle vitesse chaque méthode accomplit-elle sa tâche?
  3. Portabilité du code - À quelle vitesse pouvez-vous re-factoriser votre code?

Analysons maintenant les méthodes possibles.

Méthode (1) - Actualiser les données

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 émet 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 utiliserez y. Quelqu'un qui lit votre code pourrait tout aussi bien supprimer cette ligne. Cela est arrivé parce que vous avez brisé le principe d'encapsulation. refreshdata accède aux variables depuis l'espace de travail de l'appelant. Une autre façon de voir cela, supposons que vous passiez la poignée du tracé à une autre fonction. Le lecteur n'a aucune idée de pourquoi diable vous avez écrit y = sin(x.^3);, et comment cela va-t-il être lié à la mise à jour de l'intrigue.

Voyons maintenant la vitesse/l'exécution. En jetant un œil au code source de refreshdata, vous remarquerez deux vilaines boucles for, qui parcourent toutes les graphiques qui gèrent les variables 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 une parcelle, mais 100 parcelles et que vous souhaitez mettre à jour uniquement la première. Ce sera très lent, car pour chacune des parcelles, vous essayez de trouver celle dont vous avez besoin! (Je laisse au lecteur un exercice pour comprendre ce qu'est ecruoSataD et comment il est utilisé.)

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

Conclusion: difficile à comprendre, difficile à refactoriser, exécution lente


Méthode (2) - Supprimer et replacer

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, exécution très lente


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

Le code est vraiment clair. Vous souhaitez modifier deux propriétés de votre tracé, XData et YData. Et c'est exactement ce que vous faites. En outre, le code s'exécute très rapidement, 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 seconde.
Le temps écoulé est de 0,179954 secondes.
Le temps écoulé est de 0,002820 secondes.

54
Andrey Rubshtein

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.Falque

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

Si vous avez plusieurs objets ligne dans les axes donnés, alors Méthode:

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

générera une erreur dans MATLAB R2012b. Un exemple approprié est fourni dans la réponse d'Andrey.

Un bug a été soumis à Mathworks.

2
MattLab