当前位置: 首页 > 面试题库 >

将matplotlib对象加载到reportlab中

冷夜洛
2023-03-14
问题内容

我正在尝试将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,由于Pillow版本不兼容,我的另一部分代码就会中断。


问题答案:

这个问题的第一个答案中讨论的pdfrw示例有点笨拙的唯一原因是因为pdfrw文档很烂。由于苏茨基文档,这个例子的作者@拉里-
Meyn用于rst2pdf的vectorpdf扩展为为出发点,而 扩展是不是真的记录或者,
具有处理rst2pdf的怪癖以及pdfrw(和更超出您的需要,因为它可以使rst2pdf从预先存在的PDF的arbitray页显示任意矩形)。Larry设法使它工作起来真是太神奇了,而我的帽子也给了他。

我完全有资格这么说,因为我是pdfrw的作者,并且对rst2pdf做出了一些贡献,其中包括vectorpdf扩展名。

但是您可能还是想使用pdfrw

直到一个月前,我才真正开始关注stackoverflow,而pdfrw本身却停滞了好几年,但我现在就在这里,我认为您应该重新看一下pdfrw,即使文档仍然很烂。

为什么? 因为如果输出到png文件,则图像将被 栅格化 ,如果使用pdfrw,则图像将保持 矢量格式 ,这意味着它在任何比例下都看起来不错。

所以我修改了您答案的png示例

您的png示例不是一个完整的程序-尚未定义doc.build的参数,未定义样式,缺少一些导入等。但是它足够接近以获得一些意图并获得它加工。

编辑 - _我刚刚注意到该示例实际上是Larry的示例的修改版本,因此该示例仍然非常有价值,因为在某些方面它比此功能更全。

解决这些问题并获得一些输出后,我添加了一个能够使用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不够聪明,无法注意到重复项。

我相信可以通过将所有图输出到单个PDF的不同页面来解决此问题。我实际上没有使用matplotlib尝试过,但是pdfrw完全能够将现有pdf的每一页转换为单独的flowable。

因此,如果您有很多图,并且使最终的PDF太大,则可以调查一下,或者只是尝试其中一种PDF优化器,看看是否有帮助。无论如何,在不同的日子里这是一个不同的问题。



 类似资料:
  • 问题内容: 在angularjs中,我创建了一些加载JSON对象的对象: 在控制器中,我可以这样称呼它: 如您所见,我正在加载文件。 对文件执行相同的处理流程是什么? 在我的情况下 是对象列表。 有人知道如何使用或其他方式获取CSV数据吗? 问题答案: 您必须将CSV文件解析为一个数组。您可以在其他替代方法中看到此问题 然后,您将得到如下结果:

  • ReportLab是久经考验的,超强大的开源引擎,用于创建复杂的,数据驱动的PDF文档和自定义矢量图形。它是免费的,开源的,并且是用Python编写的。该软件包每月可下载50,000次以上,是标准Linux发行版的一部分,已嵌入许多产品中,并被选中为Wikipedia提供打印/导出功能。 多年来,ReportLab Toolkit不断发展,以直接响应大型机构的实际报告需求。该库实现了三个主要层:

  • 努力将json从URL上的文件(myData.json)加载到对象中,以便访问属性值。 --数据立即加载,我在应用程序中非常需要它。 -我将访问整个应用程序中的数据,而不仅仅是数据加载后立即发生的一个函数的一部分。 --我已确保文件中的数据格式正确。 按照jQuery API上的示例,我不应该做一些简单的事情,比如: 警报(jqxhr.my财产); 得到价值吗?我错过了哪一步?我试过做评估和其他类

  • 通过前面的学习,我们知道 模块能够快速地生成图像,但如果使用面向对象的编程思想,我们就可以更好地控制和自定义图像。 在 Matplotlib 中,面向对象编程的核心思想是创建图形对象(figure object)。通过图形对象来调用其它的方法和属性,这样有助于我们更好地处理多个画布。在这个过程中,pyplot 负责生成图形对象,并通过该对象来添加一个或多个 axes 对象(即绘图区域)。 Matp

  • 问题内容: 所以我在Python3.5上使用psycopg2将一些数据插入到postgresql数据库中。我想做的是有两列是字符串,最后一列只是一个dict对象。我不需要搜索字典,只需能够将其从数据库中拉出并使用它即可。 因此例如: 这有可能吗,如果可以的话,我将如何去做呢? 问题答案: 如果您的PostgreSQL版本足够新(9.4+)并且psycopg版本> = 2.5.4,则所有键都是字符串

  • 问题内容: 这是我正在使用的 json对象 我希望将此作为另一个键值对: 我尝试了concat,但是使用||给了我结果 符号,我cdnt进行迭代。我用过溢漏,但只删除了逗号。 如何将密钥对值添加到现有的json对象?我正在使用JavaScript。 问题答案: 这是最简单的方法,对我有用。