我认为这里需要一种在输出到 pdf 的图形中将表格输出到 pdf 文件的一致方式。
我的第一个想法是不要使用 matplotlib 后端,即
from matplotlib.backends.backend_pdf import PdfPages
因为它似乎在格式化选项方面有些限制,并且倾向于将表格格式化为图像(从而以不可选择的格式呈现表格的文本)
如果您想在不使用 matplotlib pdf 后端的情况下在 pdf 中混合数据帧输出和 matplotlib 图,我可以想到两种方法。
- 像以前一样生成 matplotlib 图形的 pdf,然后插入包含数据框表的页面。我认为这是一个困难的选择。
- 使用不同的库来生成 pdf。我在下面说明了一种选择。
首先,安装xhtml2pdf 库。这似乎有点不完整,但它是active on Github 并且有一些basic usage documentation here。您可以通过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 不受尊重。与这个问题特别相关的是,似乎不可能在桌子周围设置双边框
编辑
在响应 cmets 时,很明显一些用户(嗯,至少 @Keith 既回答了又奖励了赏金!)希望表格可选择,但绝对在 matplotlib 轴上。这在某种程度上更符合原始方法。因此 - 这是一种仅将 pdf 后端用于 matplotlib 和 matplotlib 对象的方法。我不认为该表看起来那么好 - 特别是分层列标题的显示,但我猜这是一个选择问题。我很感谢 this answer 和 cmets 为表格显示格式化轴的方式。
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()