supprimer la barre de couleur de la figure dans matplotlib
ça devrait être facile mais j'ai du mal avec ça. Fondamentalement, j'ai un subplot dans matplotlib que je dessine un tracé hexbin à chaque fois qu'une fonction est appelée, mais chaque fois que j'appelle la fonction j'obtiens une nouvelle barre de couleur, donc ce que je voudrais vraiment faire est de mettre à jour la barre de couleur. Malheureusement, cela ne semble pas fonctionner puisque l'objet auquel la barre de couleur est attachée est recréé par subplot.hexbin.
def foo(self):
self.subplot.clear()
hb = self.subplot.hexbin(...)
if self.cb:
self.cb.update_bruteforce() # Doesn't work (hb is new)
else:
self.cb = self.figure.colorbar(hb)
je suis maintenant dans cet endroit ennuyeux où je suis essayer de supprimer les axes de barre de couleur tout à fait et simplement le recréer. Malheureusement, quand j'efface les axes de la barre de couleur, les axes des sous-lots ne récupèrent pas l'espace, et s'appellent eux-mêmes.intrigue secondaire.reset_position () ne fait pas ce que je pensais qu'il ferait.
def foo(self):
self.subplot.clear()
hb = self.subplot.hexbin(...)
if self.cb:
self.figure.delaxes(self.figure.axes[1])
del self.cb
# TODO: resize self.subplot so it fills the
# whole figure before adding the new colorbar
self.cb = self.figure.colorbar(hb)
est-ce que quelqu'un a des suggestions?
très apprécié! Adam
8 réponses
je pense que le problème est qu'avec del
vous annulez la variable, mais pas la barre de couleur de l'objet référencé.
Si vous voulez que la barre de couleur soit retirée de la parcelle et disparaisse, vous devez utiliser la méthode remove
de l'instance de barre de couleur et pour ce faire, vous devez avoir la barre de couleur dans une variable, pour laquelle vous avez deux options:
- maintenir la barre de couleur dans une valeur au moment de la création, comme indiqué dans d'autres réponses par exemple
cb=plt.colorbar()
- récupérez une barre de couleur existante, que vous pouvez faire en suivant (et upvoting :)) ce que j'ai écrit ici: comment récupérer une instance de barre de couleur à partir de la figure dans matplotlib puis:
cb.remove()
plt.draw() #update plot
Voilà ma solution. Pas très élégant, mais pas terrible hack.
def foo(self):
self.subplot.clear()
hb = self.subplot.hexbin(...)
if self.cb:
self.figure.delaxes(self.figure.axes[1])
self.figure.subplots_adjust(right=0.90) #default right padding
self.cb = self.figure.colorbar(hb)
cela fonctionne pour mes besoins puisque je n'ai jamais un seul sous-lot. Les personnes qui rencontrent le même problème en utilisant plusieurs sous-lots ou en dessinant la barre de couleur dans une position différente auront besoin de tweak.
j'ai réussi à résoudre le même problème en utilisant fig.clear() et de l'affichage.clear_output ()
import matplotlib.pyplot as plt
import IPython.display as display
import matplotlib.tri as tri
from pylab import *
%matplotlib inline
def plot_res(fig):
ax=fig.add_axes([0,0,1,1])
ax.set_xlabel("x")
ax.set_ylabel('y')
plotted=ax.imshow(rand(250, 250))
ax.set_title("title")
cbar=fig.colorbar(mappable=plotted)
display.clear_output(wait=True)
display.display(plt.gcf())
fig.clear()
fig=plt.figure()
N=20
for j in range(N):
plot_res(fig)
j'ai eu un problème similaire et a joué un petit peu. J'ai proposé deux solutions qui pourraient être un peu plus élégantes:
-
effacer la figure entière et ajouter le sous-lot (+barre de couleur si désiré) à nouveau.
-
S'il y a toujours une barre de couleur, vous pouvez simplement mettre à jour les axes avec une échelle automatique qui met également à jour la barre de couleur.
j'ai essayé avec imshow, mais je suppose que cela fonctionne de la même façon pour les autres méthodes de pointage.
from pylab import *
close('all') #close all figures in memory
#1. Figures for fig.clf method
fig1 = figure()
fig2 = figure()
cbar1=None
cbar2=None
data = rand(250, 250)
def makefig(fig,cbar):
fig.clf()
ax = fig.add_subplot(111)
im = ax.imshow(data)
if cbar:
cbar=None
else:
cbar = fig.colorbar(im)
return cbar
#2. Update method
fig_update = figure()
cbar3=None
data_update = rand(250, 250)
img=None
def makefig_update(fig,im,cbar,data):
if im:
data*=2 #change data, so there is change in output (look at colorbar)
#im.set_data(data) #use this if you use new array
im.autoscale()
#cbar.update_normal(im) #cbar is updated automatically
else:
ax = fig.add_subplot(111)
im = ax.imshow(data)
cbar=fig.colorbar(im)
return im,cbar,data
#Execute functions a few times
for i in range(3):
print i
cbar1=makefig(fig1,cbar1)
cbar2=makefig(fig2,cbar2)
img,cbar3,data_update=makefig_update(fig_update,img,cbar3,data_update)
cbar2=makefig(fig2,cbar2)
fig1.show()
fig2.show()
fig_update.show()
Ne veux rien enlever à l'auteur de ce blog post (Joseph de Long) mais c'est clairement la meilleure solution que j'ai trouvé jusqu'à présent. Il comprend des morceaux de code, de grandes explications et de nombreux exemples.
pour résumer, à partir de n'importe quelle sortie d'un axe ax de la commande: parcelle , image , scatter , collection , etc. tels que:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(5,5), dpi=300)
ax = fig.add_subplot(1, 1, 1)
data = ax.plot(x,y)
# or
data = ax.scatter(x, y, z)
# or
data = ax.imshow(z)
# or
data = matplotlib.collection(patches)
ax.add_collection(data)
vous créez un axe de barre de couleur en utilisant le make_axes_locatable et l'axe original de la parcelle.
from mpl_toolkits.axes_grid1 import make_axes_locatable
# the magical part
divider = make_axes_locatable(ax)
caxis = divider.append_axes("right", size="5%", pad=0.05)
fig.colorbar(data, cax=caxis)
plt.show()
la barre de couleurs créée aura la même taille que la figure ou le sous-placage et vous pouvez la modifier largeur , emplacement , rembourrage en utilisant le diviseur .appendic_axes commande.
j'utilise matplotlib 1.4.0. Voici comment je résous ce problème:
import matplotlib
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
# A contour plot example:
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = 10.0 * (Z2 - Z1)
#
# first drawing
fig = plt.figure()
ax = fig.add_subplot(111) # drawing axes
c = ax.contourf(Z) # contour fill c
cb = fig.colorbar(c) # colorbar for contour c
# clear first drawimg
ax.clear() # clear drawing axes
cb.ax.clear() # clear colorbar axes
# replace with new drawing
# 1. drawing new contour at drawing axes
c_new = ax.contour(Z)
# 2. create new colorbar for new contour at colorbar axes
cb_new = ax.get_figure().colorbar(c_new, cax=cb.ax)
plt.show()
ci-dessus le code dessine une courbe de remplissage de contour avec la barre de couleur, l'éclaircir et dessiner une nouvelle courbe de contour avec la nouvelle barre de couleur à la même figure.
en utilisant
cb.ax
je suis capable d'identifier la barre de couleur axes et effacer les anciennes barre de couleur.
Et en spécifiant cax=cb.ax
dessine simplement la nouvelle barre de couleur dans les anciens axes de barre de couleur.
j'ai dû enlever les barres de couleur parce que je traçais un pcolormesh et ajoutant barre de couleur à une figure dans une boucle. Chaque boucle créerait une nouvelle barre de couleur et après dix boucles j'aurais dix barres de couleur. Ce qui était mauvais.
pour supprimer les barres de couleur, je nomme le pcolormesh et la barre de couleur une variable, puis à la fin de ma boucle je supprime chacun. Il est important de supprimer la barre de couleur avant en enlevant le pcolormesh.
Code Psudo:
for i in range(0,10):
p = plt.pcolormesh(datastuff[i])
cb = plt.colorbar(p)
plt.savefig('name_'+i)
cb.remove()
p.remove()
encore une fois, il a fallu enlever la barre de couleur avant le pcolormesh
"on_mappable_changed" a fonctionné dans mon cas. Cependant, selon docs, la méthode "typiquement ... ne devrait pas être appelé manuellement."
if self.cb:
self.cb.on_mappable_changed(hb)
else:
self.cb = self.fig.colorbar(hb)