Matplotlib et Pyplot.close () NE PAS libérer la mémoire? - qt4agg lié au backend

EDIT: Si j'ai explicitement changer le backend pour matplotlib de "Qt4Agg' juste "Apa", alors je suis en mesure d'exécuter mon code sans erreurs. je suppose que c'est un bug dans le backend?

j'écris un code pour traiter une quantité assez importante de données automatiquement. Le code analyse d'abord mes fichiers de données et stocke tous les bits pertinents. J'ai alors différentes fonctions pour produire chacun des graphiques dont j'ai besoin (il y a environ 25 tout.) Cependant, je continue à courir dans une sorte d'erreur de mémoire et je pense que C'est parce que Matplotlib / PyPlot ne libèrent pas la mémoire correctement.

chaque fonction de pointage se termine par un polyplot.fermer la commande (fig) et puisque je veux juste sauver les graphiques et ne pas les regarder immédiatement ils font pas inclure un polyplot.montrer.)(

si j'exécute les fonctions de pointage individuellement dans un interpréteur, alors je n'ai aucun problème. Cependant, si je fais une fonction séparée qui appelle chaque fonction de pointage à son tour, je tombe sur un "MemoryError: Could not allocate memory for path".

quelqu'un A rencontré un problème de ce genre? Il semblerait être lié à Matplotlib s'exécute de mémoire lors de tracer dans une boucle mais pyplot.close () ne règle pas mon problème.

voici à quoi ressemble une fonction de tracé typique dans mon code:

def TypicalPlot(self, title=None, comment=False, save=False, show=True):

    if title is None:
        title = self.dat.title

    fig = plt.figure()
    host = SubplotHost(fig, 111)
    fig.add_subplot(host)
    par = host.twinx()
    host.set_xlabel("Time (hrs)")
    host.set_ylabel("Power (W)")
    par.set_ylabel("Temperature (C)")
    p1, = host.plot(self.dat.timebase1, self.dat.pwr, 'b,', label="Power",
                    markevery= self.skip)
    p2, = par.plot(self.dat.timebase2, self.dat.Temp1, 'r,', 
                   label="Temp 1", markevery= self.skip)
    p3, = par.plot(self.dat.timebase2, self.dat.Temp2, 'g,', 
                   label="Temp 2", markevery= self.skip)
    p4, = par.plot(self.dat.timebase2, self.dat.Temp3, 'm,', 
                   label="Temp 3", markevery= self.skip)
    host.axis["left"].label.set_color(p1.get_color())
    # par.axis["right"].label.set_color(p2.get_color())
    #host.legend(loc='lower left')
    plt.title(title+" Temperature")

    leg=host.legend(loc='lower left',fancybox=True)
    #leg.get_frame().set_alpha(0.5)
    frame  = leg.get_frame()
    frame.set_facecolor('0.80')

    ### make the legend text smaller
    for t in leg.get_texts():
        t.set_fontsize('small')

    ### set the legend text color to the same color as the plots for added
    ### readability
    leg.get_texts()[0].set_color(p1.get_color())
    leg.get_texts()[1].set_color(p2.get_color())
    leg.get_texts()[2].set_color(p3.get_color())    
    leg.get_texts()[3].set_color(p4.get_color())        

    if show is True and save is True:
        plt.show()
        plt.savefig('temp.png')
    elif show is True and save is False:
        plt.show()
    elif show is False and save is True:
        plt.savefig('temp.png')
        plt.clf()
        plt.close(fig)

Si je maintenant s'exécuter dans un terminal

MyClass.TypicalPlot(save=True, show = False) 

alors je n'ai aucune erreur. La même chose est vraie pour toutes mes fonctions d'intrigue.

si je crée une nouvelle fonction qui fait ceci:

def saveAllPlots(self, comments = False):

        if self.comment is None: comment = False
        else: comment = True
        self.TypicalPlot(save=True, show=False, comment=comment)
        self.AnotherPlot(save=True, show=False)
        self.AnotherPlot2(save=True, show=False)
        self.AnotherPlot3(save=True, show=False)
        ...etc, etc, etc

puis il passe à travers environ la moitié des graphiques et puis je reçois "MemoryError: ne pouvait pas allouer la mémoire pour le chemin".

39
demandé sur Community 2012-05-17 13:05:50

2 réponses

je pense que la raison pour laquelle il fait ceci est parce que comme il passe par tous les différents graphes il court alors hors de la mémoire probablement parce qu'il ne le libère pas correctement.

pourquoi ne pas essayer de créer environ 3 programmes dont chacun fait quelques graphiques au lieu d'un programme faisant tous les graphiques:

Programme 1: Graphiques 1-8

Programme 2: Graphiques 9-16

Programme 3: Graphiques 17-25

Espérons que cette aide @FakeDIY : )

1
répondu Ruler Of The World 2016-02-23 17:12:40

j'ai rencontré un problème similaire une fois. Je suppose que matplotlib garde les références pour chaque parcelle en interne. Étant donné le code suivant, la création de trois chiffres distincts:

import matplotlib.pyplot as plt
import numpy as np

# block 1
f, ax = plt.subplots(1)
plt.plot(np.arange(10), np.random.random(10))
plt.title("first")
print 'first', sys.getrefcount(f), sys.getrefcount(ax)

# bock 2
f, ax = plt.subplots(1)
plt.plot(np.arange(10), np.random.random(10)+1)
plt.title("second")
print 'second', sys.getrefcount(f), sys.getrefcount(ax)

# block 3
f, ax = plt.subplots(1)
plt.plot(np.arange(10), np.random.random(10)+2)
plt.title("third")
print 'third', sys.getrefcount(f), sys.getrefcount(ax)

plt.show()

print 'after show', sys.getrefcount(f), sys.getrefcount(ax)

sortie:

first 69 26
second 69 26
third 69 26
after show 147 39

c'est contre-intuitif, car nous avons redéfini f et ax plusieurs fois. Sur chaque bloc, nous avons créé un nouveau personnage, qui peut être référencé par plt . La création d'une autre figure modifie les références les plus élevées accessibles par plt . Mais il doit y avoir une référence interne, qui permet à plt.show() d'afficher tous les chiffres. Ces références semblent être persistant et donc les chiffres ne seront pas collectés par le gc.

la solution que j'ai trouvée, était de changer les données du tracé. Avec le recul, c'était une meilleure approche de toute façon:

plt.ion()
f, ax = plt.subplots(1)
line = ax.plot(np.arange(10), np.random.random(10))[0]
plt.title('first')
plt.show()

for i, s in [(2, 'second'), (3, 'third')]:
    x = np.arange(10)
    y = np.random.random(10)+i
    line.set_data(x, y)
    ax.set_xlim(np.min(x), np.max(x))
    ax.set_ylim(np.min(y), np.max(y))
    plt.title(s)
    plt.draw()
    raw_input(s)

Seul inconvénient est que vous devez garder la fenêtre avec la figure ouverte. Et sans le raw_input le programme ne fera que passer par

1
répondu rikisa 2016-05-08 21:10:30