web-dev-qa-db-ja.com

pandasデータフレームの "Out []"テーブルを図として保存します

これは役に立たない機能のように思われるかもしれませんが、私にとっては非常に役立ちます。 CanopyIDE内で取得した出力を保存したいと思います。これはキャノピーに固有のものではないと思いますが、わかりやすくするために使用しています。たとえば、私のコンソールOut [2]は、これから欲しいものです。

enter image description here

フォーマットはとてもいいと思います。出力を保存するだけでなく、毎回これを再現するのは時間の無駄です。だから私の質問は、どうすればこの数字を把握できるのかということです。理想的には、実装は標準的な方法と同様であり、次のように実行できます。

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()

注:以前に非常によく似た質問があったことを認識しています( Pandasデータフレーム/シリーズデータを図として保存する方法? ))が、回答を受け取ったことはありませんそして、私は質問をより明確に述べたと思います。

18
user262536

これはややハックな解決策ですが、それで仕事は終わります。 .pdfが必要でしたが、ボーナス.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()

編集を歓迎します。

7
Keith

IDEがレンダリングしているのはHTMLテーブルだと思います。これは、ipythonノートブックが行うことです。

あなたはこうしてそれへのハンドルを得ることができます:

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

hTMLファイルに保存します。

my_file = open('some_file.html', 'w')
my_file.write(h.data)
my_file.close()
4

ここで必要なのは、pdfに出力されたグラフの中でテーブルをpdfファイルに出力する一貫した方法だと思います。

私の最初の考えは、matplotlibバックエンドを使用しないことです。

from matplotlib.backends.backend_pdf import PdfPages

書式設定オプションがいくらか制限されているように見え、テーブルを画像として書式設定することに傾いていたためです(したがって、テーブルのテキストを選択できない形式でレンダリングします)

Matplotlib pdfバックエンドを使用せずにデータフレーム出力とmatplotlibプロットをpdfに混在させたい場合は、2つの方法が考えられます。

  1. 前と同じようにmatplotlib図のPDFを生成し、その後にデータフレームテーブルを含むページを挿入します。これは難しい選択肢だと思います。
  2. 別のライブラリを使用してPDFを生成します。これを行うための1つのオプションを以下に示します。

まず、xhtml2pdfライブラリをインストールします。これは少しパッチが適用されているように見えますが、 Githubでアクティブ であり、いくつかの 基本的な使用法のドキュメントはこちら です。 pip、つまりpip install xhtml2pdfからインストールできます

それが済んだら、matplotlibの図、テーブル(すべてテキストを選択可能)、別の図を埋め込んだベアボーンの例を次に示します。 CSSなどをいじって、フォーマットを正確な仕様に変更することができますが、これで簡単に説明できると思います。

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)

執筆時点でxhtml2pdfにバグがあるようです。つまり、一部のCSSは尊重されていません。この質問に特に関係するのは、テーブルの周りに二重の境界線を付けることは不可能のように思われるということです


編集

回答のコメントで、一部のユーザー(少なくとも、回答と賞金の両方を授与した@Keith!)は、テーブルを選択可能にすることを望んでいることが明らかになりましたが、間違いなくmatplotlib軸上にあります。これは、元の方法にいくらか一致しています。したがって、これはmatplotlibオブジェクトとmatplotlibオブジェクトにのみpdfバックエンドを使用するメソッドです。テーブルの見栄えはあまり良くないと思います。特に階層列ヘッダーの表示はそうですが、それは選択の問題だと思います。 この回答 と、テーブル表示用に軸をフォーマットする方法についてのコメントに感謝します。

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()
2
J Richard Snape