Supposons que je veuille mettre à jour un tracé avec de nouvelles données. Quelle méthode dois-je choisir?
XDataSource
sur un nom, mettez à jour la variable et appelez refreshdata
plot
d'origine et appelez à nouveau la commande plot
.Set('Xdata',...')
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.
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.
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 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:
- 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.