Enregistrez la table" Out [] " d'une base de données pandas comme une figure
Cela peut sembler être une fonctionnalité inutile, mais il serait très utile pour moi. Je voudrais enregistrer la sortie que je reçois à L'intérieur de Canopy IDE. Je ne pense pas que ce soit spécifique à la canopée, mais pour la clarté, c'est ce que j'utilise. Par exemple, ma console[2] est ce que je voudrais:
je pense que le formatage est assez agréable et reproduire ceci à chaque fois au lieu de simplement sauver la sortie serait une perte de temps. Donc ma question est, comment puis-je obtenir une poignée sur cette figure? Idéalement, l'implémentation serait similaire aux méthodes standard, tel qu'il pourrait être fait comme ceci:
from matplotlib.backends.backend_pdf import PdfPages
pp = PdfPages('Output.pdf')
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
df.plot(how='table')
pp.savefig()
pp.close()
NOTE: je me rends compte que d'une question très semblable a été posée ( comment sauvegarder les données Pandas dataframe / series comme une figure?) mais elle n'a jamais reçu de réponse et je pense que j'ai énoncé la question plus clairement.
3 réponses
Voici une solution un peu hackish, mais elle fait le travail. Vous avez voulu un .pdf, mais vous obtenez un bonus .png. :)
import numpy as np
import pandas as pd
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt
from PySide.QtGui import QImage
from PySide.QtGui import QPainter
from PySide.QtCore import QSize
from PySide.QtWebKit import QWebPage
arrays = [np.hstack([ ['one']*3, ['two']*3]), ['Dog', 'Bird', 'Cat']*2]
columns = pd.MultiIndex.from_arrays(arrays, names=['foo', 'bar'])
df =pd.DataFrame(np.zeros((3,6)),columns=columns,index=pd.date_range('20000103',periods=3))
h = "<!DOCTYPE html> <html> <body> <p> " + df.to_html() + " </p> </body> </html>";
page = QWebPage()
page.setViewportSize(QSize(5000,5000))
frame = page.mainFrame()
frame.setHtml(h, "text/html")
img = QImage(1000,700, QImage.Format(5))
painter = QPainter(img)
frame.render(painter)
painter.end()
a = img.save("html.png")
pp = PdfPages('html.pdf')
fig = plt.figure(figsize=(8,6),dpi=1080)
ax = fig.add_subplot(1, 1, 1)
img2 = plt.imread("html.png")
plt.axis('off')
ax.imshow(img2)
pp.savefig()
pp.close()
Modifications de bienvenue.
il s'agit, je crois, d'une table HTML que votre IDE rend. C'est ce que fait IPython notebook.
Vous pouvez obtenir une poignée comme ceci:
from IPython.display import HTML
import pandas as pd
data = pd.DataFrame({'spam':['ham','green','five',0,'kitties'],
'eggs':[0,1,2,3,4]})
h = HTML(data.to_html())
h
et l'enregistrer dans un fichier HTML:
my_file = open('some_file.html', 'w')
my_file.write(h.data)
my_file.close()
je pense que ce qui est nécessaire ici est une façon cohérente de outputing une table à un fichier pdf parmi les graphiques sortie au pdf.
ma première pensée est de ne pas utiliser le backend matplotlib i.e.
from matplotlib.backends.backend_pdf import PdfPages
parce qu'il semblait quelque peu limité dans les options de formatage et s'est penché vers le formatage de la table comme une image (rendant ainsi le texte de la table dans un format non sélectionnable)
si vous voulez mélanger la sortie dataframe et les tracés matplotlib dans un pdf sans utiliser le matplotlib PDF backend, je peux penser à deux façons.
- générez votre pdf de figures de matplotlib comme avant et insérez ensuite les pages contenant la table de datagramme. Je considère cela comme une option difficile.
- utilisez une autre bibliothèque pour générer le pdf. J'illustre une option pour le faire ci-dessous.
tout d'Abord, installez xhtml2pdf
bibliothèque. Cela semble un peu patchily soutenu, mais est active sur Github et a quelques utilisation de base de la documentation ici. Vous pouvez l'installer via pip
i.e. pip install xhtml2pdf
une fois que vous avez fait cela, Voici un exemple barebones intégrant une figure matplotlib, puis la table (tout le texte sélectionnable), puis une autre figure. Vous pouvez jouer avec CSS etc pour modifier le formatage à vos spécifications exactes, mais je pense que cela remplit le bref:
from xhtml2pdf import pisa # this is the module that will do the work
import numpy as np
import pandas as pd
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt
# Utility function
def convertHtmlToPdf(sourceHtml, outputFilename):
# open output file for writing (truncated binary)
resultFile = open(outputFilename, "w+b")
# convert HTML to PDF
pisaStatus = pisa.CreatePDF(
sourceHtml, # the HTML to convert
dest=resultFile, # file handle to recieve result
path='.') # this path is needed so relative paths for
# temporary image sources work
# close output file
resultFile.close() # close output file
# return True on success and False on errors
return pisaStatus.err
# Main program
if __name__=='__main__':
arrays = [np.hstack([ ['one']*3, ['two']*3]), ['Dog', 'Bird', 'Cat']*2]
columns = pd.MultiIndex.from_arrays(arrays, names=['foo', 'bar'])
df = pd.DataFrame(np.zeros((3,6)),columns=columns,index=pd.date_range('20000103',periods=3))
# Define your data
sourceHtml = '<html><head>'
# add some table CSS in head
sourceHtml += '''<style>
table, td, th {
border-style: double;
border-width: 3px;
}
td,th {
padding: 5px;
}
</style>'''
sourceHtml += '</head><body>'
#Add a matplotlib figure(s)
plt.plot(range(20))
plt.savefig('tmp1.jpg')
sourceHtml += '\n<p><img src="tmp1.jpg"></p>'
# Add the dataframe
sourceHtml += '\n<p>' + df.to_html() + '</p>'
#Add another matplotlib figure(s)
plt.plot(range(70,100))
plt.savefig('tmp2.jpg')
sourceHtml += '\n<p><img src="tmp2.jpg"></p>'
sourceHtml += '</body></html>'
outputFilename = 'test.pdf'
convertHtmlToPdf(sourceHtml, outputFilename)
Remarque: Il semble y avoir un bug dans xhtml2pdf au moment de la rédaction, ce qui signifie que certains CSS ne sont pas respectés. Ce qui est particulièrement pertinent à cette question, c'est qu'il semble impossible d'avoir des doubles bordures autour de la table
EDIT
en réponse aux commentaires, il est devenu évident que certains utilisateurs (au moins @Keith qui a répondu et a accordé une prime!) veulent la table selectable, mais certainement sur un axe matplotlib. Ceci est un peu plus conforme à la méthode originale. Donc, voici un méthode utilisant le pdf
backend pour matplotlib et matplotlib les objets. Je ne pense pas que le tableau semble aussi bon - en particulier l'affichage des en-têtes de colonne hiérarchiques, mais c'est une question de choix, je suppose. Je suis redevable à cette réponse et commentaires pour la façon de formater les axes pour l'affichage de table.
import numpy as np
import pandas as pd
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt
# Main program
if __name__=='__main__':
pp = PdfPages('Output.pdf')
arrays = [np.hstack([ ['one']*3, ['two']*3]), ['Dog', 'Bird', 'Cat']*2]
columns = pd.MultiIndex.from_arrays(arrays, names=['foo', 'bar'])
df =pd.DataFrame(np.zeros((3,6)),columns=columns,index=pd.date_range('20000103',periods=3))
plt.plot(range(20))
pp.savefig()
plt.close()
# Calculate some sizes for formatting - constants are arbitrary - play around
nrows, ncols = len(df)+1, len(df.columns) + 10
hcell, wcell = 0.3, 1.
hpad, wpad = 0, 0
#put the table on a correctly sized figure
fig=plt.figure(figsize=(ncols*wcell+wpad, nrows*hcell+hpad))
plt.gca().axis('off')
matplotlib_tab = pd.tools.plotting.table(plt.gca(),df, loc='center')
pp.savefig()
plt.close()
#Add another matplotlib figure(s)
plt.plot(range(70,100))
pp.savefig()
plt.close()
pp.close()