avviso su troppe figure aperte

In uno script in cui creo molte figure con fix, ax = plt.subplots(...) , ottengo l’avviso RuntimeWarning: sono state aperte più di 20 cifre. Le figure create tramite l’interfaccia di pyplot ( matplotlib.pyplot.figure ) vengono mantenute fino alla chiusura esplicita e possono consumare troppa memoria.

Tuttavia, non capisco perché ottengo questo avviso, perché dopo aver salvato la figura con fig.savefig(...) , lo cancello con fig.clear(); del fig fig.clear(); del fig . In nessun punto del mio codice, ho più di una cifra aperta alla volta. Tuttavia, ricevo l’avvertimento su troppe figure aperte. Che cosa significa / come posso evitare di ricevere l’avviso?

Usa .clf o .cla sul tuo object figura invece di creare una nuova figura. Da @DavidZwicker

Supponendo di aver importato pyplot come

 import matplotlib.pyplot as plt 

plt.cla() cancella un asse , ovvero l’asse attualmente attivo nella figura corrente. Lascia intatti gli altri assi.

plt.clf() cancella l’intera figura corrente con tutti i suoi assi, ma lascia aperta la finestra, in modo che possa essere riutilizzata per altri grafici.

plt.close() chiude una finestra , che sarà la finestra corrente, se non diversamente specificato. plt.close('all') chiuderà tutte le figure aperte.

La ragione per cui del fig non funziona è che la pyplot stato pyplot mantiene un riferimento alla figura intorno (come deve essere se saprà qual è la ‘figura corrente’). Ciò significa che anche se si elimina il riferimento alla figura, esiste almeno un riferimento live, quindi non verrà mai raccolto.

Dal momento che sto sondando la saggezza collettiva qui per questa risposta, @JoeKington menziona nei commenti che plt.close(fig) rimuoverà un’istanza di figura specifica dalla macchina di stato pylab ( plt._pylab_helpers.Gcf ) e permetterà che sia raccolta dei rifiuti

Ecco un po ‘più di dettaglio per espandere la risposta di Hooked . Quando ho letto per la prima volta quella risposta, mi mancava l’istruzione per chiamare clf() invece di creare una nuova figura . clf() da solo non aiuta se poi vai a creare un’altra figura.

Ecco un esempio banale che causa l’avviso:

 from matplotlib import pyplot as plt, patches import os def main(): path = 'figures' for i in range(21): _fig, ax = plt.subplots() x = range(3*i) y = [n*n for n in x] ax.add_patch(patches.Rectangle(xy=(i, 1), width=i, height=10)) plt.step(x, y, linewidth=2, where='mid') figname = 'fig_{}.png'.format(i) dest = os.path.join(path, figname) plt.savefig(dest) # write image to file plt.clf() print('Done.') main() 

Per evitare l’avviso, devo richiamare le subplots() all’esterno del ciclo. Per continuare a vedere i rettangoli, ho bisogno di passare clf() a cla() . Ciò cancella l’asse senza rimuovere l’asse stesso.

 from matplotlib import pyplot as plt, patches import os def main(): path = 'figures' _fig, ax = plt.subplots() for i in range(21): x = range(3*i) y = [n*n for n in x] ax.add_patch(patches.Rectangle(xy=(i, 1), width=i, height=10)) plt.step(x, y, linewidth=2, where='mid') figname = 'fig_{}.png'.format(i) dest = os.path.join(path, figname) plt.savefig(dest) # write image to file plt.cla() print('Done.') main() 

Se stai generando grafici in lotti, potresti dover usare sia cla() che close() . Mi sono imbattuto in un problema in cui un batch poteva contenere più di 20 grafici senza lamentarsi, ma si lamentava dopo 20 batch. L’ho risolto usando cla() dopo ogni trama e close() dopo ogni batch.

 from matplotlib import pyplot as plt, patches import os def main(): for i in range(21): print('Batch {}'.format(i)) make_plots('figures') print('Done.') def make_plots(path): fig, ax = plt.subplots() for i in range(21): x = range(3 * i) y = [n * n for n in x] ax.add_patch(patches.Rectangle(xy=(i, 1), width=i, height=10)) plt.step(x, y, linewidth=2, where='mid') figname = 'fig_{}.png'.format(i) dest = os.path.join(path, figname) plt.savefig(dest) # write image to file plt.cla() plt.close(fig) main() 

Ho misurato la performance per vedere se valeva la pena di riutilizzare la figura all’interno di un batch e questo piccolo programma di esempio ha rallentato da 41 a 49 secondi (20% più lento) quando ho chiamato close() dopo ogni trama.

Se si intende conservare consapevolmente molti grafici, ma non si vuole essere avvertiti, è ansible aggiornare le opzioni prima di generare cifre.

 import matplotlib.pyplot as plt plt.rcParams.update({'figure.max_open_warning': 0}) 

Ciò impedirà l’emissione dell’avviso senza modificare nulla sul modo in cui la memoria viene gestita.