2015-01-21 16 views
8

posso passare un oggetto StringIO per pd.to_csv() bene:Scrive sull'oggetto StringIO usando Pandas Excelwriter?

io = StringIO.StringIO() 
pd.DataFrame().to_csv(io) 

Ma quando si utilizza lo scrittore excel, sto avendo molta più difficoltà.

io = StringIO.StringIO() 
writer = pd.ExcelWriter(io) 
pd.DataFrame().to_excel(writer,"sheet name") 
writer.save() 

Restituisce un

AttributeError: StringIO instance has no attribute 'rfind' 

Sto cercando di creare un oggetto ExcelWriter senza chiamare pd.ExcelWriter() ma sto avendo qualche problema. Questo è quello che ho provato finora:

from xlsxwriter.workbook import Workbook 
writer = Workbook(io) 
pd.DataFrame().to_excel(writer,"sheet name") 
writer.save() 

Ma ora sto ottenendo un AttributeError: 'Workbook' object has no attribute 'write_cells'

Come posso salvare una dataframe panda in formato Excel a un oggetto StringIO?

+1

Non sono sicuro che tu possa, almeno non facilmente. L'argomento di 'to_excel' è un * percorso * per un file Excel, non un vero oggetto file. Perché vuoi creare comunque una rappresentazione in memoria di un file Excel? – BrenBarn

+0

Utilizzo di Flask per creare un report scaricabile. –

risposta

16

Pandas prevede un percorso del nome file per i costruttori di ExcelWriter sebbene ciascuno dei motori di scrittura supporti StringIO. Forse questo dovrebbe essere sollevato come una richiesta di bug/funzionalità in Pandas.

Nel frattempo ecco un esempio soluzione utilizzando il motore di Panda xlsxwriter:

import pandas as pd 
import StringIO 

io = StringIO.StringIO() 

# Use a temp filename to keep pandas happy. 
writer = pd.ExcelWriter('temp.xlsx', engine='xlsxwriter') 

# Set the filename/file handle in the xlsxwriter.workbook object. 
writer.book.filename = io 

# Write the data frame to the StringIO object. 
pd.DataFrame().to_excel(writer, sheet_name='Sheet1') 
writer.save() 
xlsx_data = io.getvalue() 

Aggiornamento: Come di Panda 0,17 ora è possibile farlo in modo più diretto:

# Note, Python 2 example. For Python 3 use: output = io.BytesIO(). 
output = StringIO.StringIO() 

# Use the StringIO object as the filehandle. 
writer = pd.ExcelWriter(output, engine='xlsxwriter') 

Vedi anche Saving the Dataframe output to a string nella documentazione di XlsxWriter.

+0

Grazie - la soluzione a una riga ha funzionato perfettamente! –

+3

Questo è stato appena aggiunto in panda, vedi qui: https://github.com/pydata/pandas/pull/10376. Sarà nella versione 0.17.0 (fine prova di luglio) – Jeff

5

Guardare la sorgente pandas.io.excel sembra non essere un problema se non ti dispiace usare xlwt come autore. Anche gli altri motori potrebbero non essere così difficili, ma xlwt salta fuori con facilità dal momento che il suo metodo di salvataggio prende uno stream o un filepath.

È necessario passare inizialmente un nome file solo per rendere felici i panda mentre controlla l'estensione del file sul motore per assicurarsi che sia un formato supportato. Ma nel caso del motore xlwt, inserisce il nome del file nell'attributo del percorso dell'oggetto e quindi lo usa nel metodo di salvataggio. Se modifichi l'attributo path nel tuo stream, salverà allegramente in quel flusso quando chiami il metodo di salvataggio.

Ecco un esempio:

import pandas as pd 
import StringIO 
import base64 

df = pd.DataFrame.from_csv('http://moz.com/top500/domains/csv') 
xlwt_writer = pd.io.excel.get_writer('xlwt') 
my_writer = xlwt_writer('whatever.xls') #make pandas happy 
xl_out = StringIO.StringIO() 
my_writer.path = xl_out 
df.to_excel(my_writer) 
my_writer.save() 
print base64.b64encode(xl_out.getvalue()) 

Questo è il modo veloce, facile e leggermente sporco per farlo. BTW ... un modo più semplice per farlo è sottoclassi ExcelWriter (o una delle sue sottoclassi esistenti, ad esempio _XlwtWriter) - ma onestamente c'è così poco coinvolto nell'aggiornamento dell'attributo path, ho votato per mostrarti la via più semplice piuttosto che andare il percorso leggermente più lungo.

2

Per coloro che non utilizzano xlsxwriter come loro engine= per to_excel qui è una soluzione di utilizzare openpyxl in memoria:

in_memory_file = StringIO.StringIO() 
xlw = pd.ExcelWriter('temp.xlsx', engine='openpyxl') 
# ... do many .to_excel() thingies 
xlw.book.save(in_memory_file) 
# if you want to read it or stream to a client, don't forget this 
in_memory_file.seek(0) 

spiegazione: la classe ExcelWriter involucro espone i motori cartella di lavoro individuale attraverso la proprietà .book.Per openpyxl puoi quindi utilizzare il metodo Workbook.save come al solito!