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?
- définissez la propriété
XDataSource
sur un nom, mettez à jour la variable et appelezrefreshdata
- efface l'original
plot
et appelle à nouveau la commandeplot
. - Utiliser
Set('Xdata',...')
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.
- clarté du Code - Comment est-il facile pour quelqu'un de lire votre code?
- Runtime - à quelle vitesse chaque méthode effectue sa tâche?
- 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.
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
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:
- 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.