参见英文答案 > Is there a matplotlib flowable for ReportLab? 4个
我正在尝试将matplotlib对象加载到reportlab中.
这是我的代码:
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
from reportlab.platypus import Paragraph, SimpleDocTemplate, Spacer, Image
from matplotlib import pyplot as plt
def __get_img_data():
"""
returns the binary image data of the plot
"""
img_file = NamedTemporaryFile(delete=False)
plt.savefig(img_file.name)
img_data = open(img_file.name + '.png', 'rb').read()
os.remove(img_file.name)
os.remove(img_file.name + '.png')
return img_data
def get_plot():
# HERE I PLOT SOME STUFF
img_data = __get_img_data()
plt.close()
return img_data
class NumberedCanvas(canvas.Canvas):
def __init__(self):
pass
class ReportTemplate:
def __init__(self):
pass
def _header_footer(self, canvas, doc):
pass
def get_data(self):
elements = []
elements.append('hello')
## HERE I WANT TO ADD THE IMAGE
imgdata = get_plot()
with open('/tmp/x.png', 'wb') as fh:
fh.write(imgdata)
im = Image('/tmp/x.png', width=usable_width, height=usable_width)
elements.append(im)
os.remove('/tmp/x.png')
######
doc.build(elements, onFirstPage=self._header_footer,\
onLaterPages=self._header_footer,\
canvasmaker=NumberedCanvas)
# blah blah
return obj
我的目标是将绘图图像插入报告中.
这工作正常,但我不想写入临时文件.
我尝试安装PIL,因为我读过一些人用PIL的图像库做的,但是一旦我安装PIL,我的另一部分代码因枕头版本不兼容而中断.
解决方法:
pdfrw文档很糟糕
pdfrw example在the first answer to this question中讨论的唯一原因是有点笨拙,因为pdfrw文档很糟糕.由于sucky doc,该示例的作者@ Larry-Meyn使用rst2pdf的vectorpdf扩展作为起点,并且该扩展也没有真正记录,并且必须处理rst2pdf以及pdfrw的怪癖(并且更多一般而言,它可以让rst2pdf从预先存在的PDF的任意页面中显示任意矩形.令人惊讶的是,拉里设法让它完全奏效,而我的帽子也归于他.
我完全有资格说这个,因为我是pdfrw的作者并为rst2pdf做了一些贡献,包括vectorpdf扩展.
但是你可能想要使用pdfrw
直到一个月前我还没有真正关注*,而且pdfrw本身已经萎靡了几年,但我现在在这里,我想你再看一下pdfrw,即使文档仍然很糟糕.
为什么?因为如果您输出到png文件,您的图像将被光栅化,如果您使用pdfrw,它将保持矢量格式,这意味着它将在任何比例下看起来都很好.
所以我修改了你的答案的png例子
你的png例子不是一个完整的程序 – doc.build的参数没有定义,样式没有定义,它缺少一些导入等等.但它足够接近一些意图获得它工作.
编辑 – 我刚刚注意到这个例子实际上是Larry示例的修改版本,因此that example仍然非常有价值,因为它在某些方面比这更具功能性.
在我修复了这些问题并获得了一些输出后,我添加了一个选项,可以使用png或pdf,这样你就可以看到差异.下面的程序将创建两个不同的PDF文件,您可以自己比较结果.
import cStringIO
from matplotlib import pyplot as plt
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
from reportlab.platypus import Paragraph, SimpleDocTemplate, Spacer, Image, Flowable
from reportlab.lib.units import inch
from reportlab.lib.styles import getSampleStyleSheet
from pdfrw import PdfReader, PdfDict
from pdfrw.buildxobj import pagexobj
from pdfrw.toreportlab import makerl
styles = getSampleStyleSheet()
style = styles['Normal']
def form_xo_reader(imgdata):
page, = PdfReader(imgdata).pages
return pagexobj(page)
class PdfImage(Flowable):
def __init__(self, img_data, width=200, height=200):
self.img_width = width
self.img_height = height
self.img_data = img_data
def wrap(self, width, height):
return self.img_width, self.img_height
def drawOn(self, canv, x, y, _sW=0):
if _sW > 0 and hasattr(self, 'hAlign'):
a = self.hAlign
if a in ('CENTER', 'CENTRE', TA_CENTER):
x += 0.5*_sW
elif a in ('RIGHT', TA_RIGHT):
x += _sW
elif a not in ('LEFT', TA_LEFT):
raise ValueError("Bad hAlign value " + str(a))
canv.saveState()
img = self.img_data
if isinstance(img, PdfDict):
xscale = self.img_width / img.BBox[2]
yscale = self.img_height / img.BBox[3]
canv.translate(x, y)
canv.scale(xscale, yscale)
canv.doForm(makerl(canv, img))
else:
canv.drawImage(img, x, y, self.img_width, self.img_height)
canv.restoreState()
def make_report(outfn, use_pdfrw):
fig = plt.figure(figsize=(4, 3))
plt.plot([1,2,3,4],[1,4,9,26])
plt.ylabel('some numbers')
imgdata = cStringIO.StringIO()
fig.savefig(imgdata, format='pdf' if use_pdfrw else 'png')
imgdata.seek(0)
reader = form_xo_reader if use_pdfrw else ImageReader
image = reader(imgdata)
doc = SimpleDocTemplate(outfn)
style = styles["Normal"]
story = [Spacer(0, inch)]
img = PdfImage(image, width=200, height=200)
for i in range(10):
bogustext = ("Paragraph number %s. " % i)
p = Paragraph(bogustext, style)
story.append(p)
story.append(Spacer(1,0.2*inch))
story.append(img)
for i in range(10):
bogustext = ("Paragraph number %s. " % i)
p = Paragraph(bogustext, style)
story.append(p)
story.append(Spacer(1,0.2*inch))
doc.build(story)
make_report("hello_png.pdf", False)
make_report("hello_pdf.pdf", True)
这种方法的缺点是什么?
第一个明显的缺点是现在需要pdfrw,但可以从PyPI获得.
下一个缺点是,如果你将大量的matplotlib图放入文档中,我认为这种技术将复制字体等资源,因为我不相信reportlab足够聪明,可以注意到重复项.
我相信这个问题可以通过将你的所有图输出到different pages of a single PDF来解决.我实际上没有尝试使用matplotlib,但是pdfrw完全能够转换each page of an existing pdf to a separate flowable.
因此,如果你有很多情节并且它使你的最终PDF太大,你可以调查一下,或者只是尝试一个PDF优化器,看看它是否有帮助.无论如何,对于不同的一天来说,这是一个不同的问题.