2012-01-16 7 views
7

Sto provando a stampare un grafico a 600 dpi utilizzando il Matplotlib Python. Tuttavia Python tracciata 2 su 8 grafici e uscita l'errore:Matplotlib Agg Rendering errore di complessità

OverflowError: Agg rendering complexity exceeded. Consider downsampling or decimating your data. 

sto tramando un pezzo enorme di dati (7.500.000 i dati per colonna) quindi credo o che sarebbe stato qualche problema di sovraccarico o che ho bisogno di imposta un grande cell_block_limit.

Ho provato a cercare le soluzioni per modificare un cell_block_limit su Google, ma senza risultati. Quale sarebbe un buon approccio?

il codice come segue: -

 import matplotlib.pyplot as plt 
     from matplotlib.ticker import MultipleLocator, FormatStrFormatter 

     majorLocator = MultipleLocator(200) 
     majorFormatter = FormatStrFormatter('%d') 
     minorLocator = MultipleLocator(20) 

     fig = plt.figure() 
     ax = fig.add_subplot(111) 
     ax.xaxis.set_major_locator(majorLocator) 
     ax.xaxis.set_major_formatter(majorFormatter) 
     ax.xaxis.set_minor_locator(minorLocator) 
     ax.xaxis.set_ticks_position('bottom') 
     ax.xaxis.grid(True,which='minor') 
     ax.yaxis.grid(True) 
     plt.plot(timemat,fildata) 
     plt.xlabel(plotxlabel,fontsize=14) 
     plt.ylabel(plotylabel,fontsize=14)  
     plt.title(plottitle,fontsize=16) 
     fig.savefig(plotsavetitle,dpi=600) 
+0

e 'un sacco di dati, si considera un 1600x1200 avrebbe 'solo' 1.920.000 _pixels_ in là. che tipo di trama stai cercando di fare? Se si tratta di un istogramma, è possibile suddividerli, una linea potrebbe essere sottocampionata .. – wim

+0

sono i dati dall'accelerometro campionato a 1500 Hz per catturare lo shock ad alta frequenza. Sto cercando di fare la semplice trama Voltage (V) vs Time. Quindi, prima di tutto, generi una quantità simile di dati per un array temporale e tracciamo il segnale nel tempo. Sì, è enorme, ma in futuro sono sicuro che diventerà ancora enorme dal momento che stiamo facendo un esperimento da 2 ore a 4 ore. Per favore, dimmi come sottocampionare una linea ... grazie mille! –

+1

usa una sezione sugli ingressi (su entrambi gli assi). per esempio, per selezionare ogni 10 elemento di un array 'x' si usa' x [:: 10] ' – wim

risposta

15

Oltre al punto di @Lennart che non è necessario per la risoluzione completa, si potrebbe anche considerare un grafico simile al seguente.

Calcolo del max/media/min di un "Chunked" versione è molto semplice ed efficace se si utilizza una visualizzazione 2D della matrice originale e il axis parola chiave arg a x.min(), x.max(), ecc

Anche con il filtraggio, tracciare questo è molto più veloce di tracciare l'intero array.

(Nota: per tracciare questo numero di punti, è necessario abbassare un po 'il livello del rumore, altrimenti si otterrà lo OverflowError che hai citato. Se vuoi confrontare il set di dati "completo", cambia il y += 0.3 * y.max() np.random... linea per più come 0.1 o rimuoverlo completamente.)

import matplotlib.pyplot as plt 
import numpy as np 
np.random.seed(1977) 

# Generate some very noisy but interesting data... 
num = 1e7 
x = np.linspace(0, 10, num) 
y = np.random.random(num) - 0.5 
y.cumsum(out=y) 
y += 0.3 * y.max() * np.random.random(num) 

fig, ax = plt.subplots() 

# Wrap the array into a 2D array of chunks, truncating the last chunk if 
# chunksize isn't an even divisor of the total size. 
# (This part won't use _any_ additional memory) 
chunksize = 10000 
numchunks = y.size // chunksize 
ychunks = y[:chunksize*numchunks].reshape((-1, chunksize)) 
xchunks = x[:chunksize*numchunks].reshape((-1, chunksize)) 

# Calculate the max, min, and means of chunksize-element chunks... 
max_env = ychunks.max(axis=1) 
min_env = ychunks.min(axis=1) 
ycenters = ychunks.mean(axis=1) 
xcenters = xchunks.mean(axis=1) 

# Now plot the bounds and the mean... 
ax.fill_between(xcenters, min_env, max_env, color='gray', 
       edgecolor='none', alpha=0.5) 
ax.plot(xcenters, ycenters) 

fig.savefig('temp.png', dpi=600) 

enter image description here

+1

SUPERB! Modo estremamente informativo e innovativo per guardare i dati! +++ –

3

Con 600dpi si avrebbe dovuto fare la trama di 13 metri di larghezza per tracciare i dati senza decimando esso. :-)

Suggerirei di dividere in pezzi i dati di un paio di centinaia o forse anche di un migliaio di campioni e di estrarne il valore massimo.

Qualcosa di simile a questo:

def chunkmax(data, chunk_size): 
    source = iter(data) 
    chunk = [] 
    while True: 
     for i in range(chunk_size): 
      chunk.append(next(source)) 

     yield max(chunk) 

Ciò allora, con un chunk_size 1000 ti danno 7500 punti per tracciare, in cui si può quindi facilmente vedere dove nei dati shock arriva. (A meno che i dati non siano così rumorosi, dovresti fare una media per vedere se c'è un blocco o no, ma è anche facilmente risolvibile).

+0

grazie! Sembra che non ci sia davvero nessun altro modo per tracciare un grafico ad alta risoluzione. –

+1

FYI: Sebbene sia un eccellente suggerimento, il codice sopra riportato è molto inefficiente per gli array numpy. stare meglio facendo qualcosa come 'chunks = data.reshape ((- 1, chunk_size)); max_filtered = chunks.max (axis = 1)'. (Supponendo il caso semplice in cui la dimensione del blocco è un divisore pari della dimensione totale ... Un esempio generalizzato è solo una linea o due in più, però.) –

+0

@JoeKington: Oh, usa Numpy? Non ho capito. Sta davvero iterando su una serie numpy inefficiente? Oh bene. –