2011-01-14 8 views
13

Ich möchte Matplotlib-Diagramme in PDFs einbetten, die direkt von ReportLab generiert wurden - d. H. Nicht zuerst als PNG speichern und dann das PNG in das PDF einbetten (ich denke, dass ich bessere Ausgabequalität bekomme).Gibt es eine matplotlib, die für ReportLab fließfähig ist?

Weiß jemand, ob es für ReportLab eine matplotlib gibt?

Dank

+3

Eine andere Möglichkeit wäre die Figur als pdf oder eps zu speichern (oder einem anderen Vektor-Format) und bettet dann die Vektorversion im pdf. Das würde zumindest die Qualitätsprobleme umgehen ... Matplotlib kann Vektorformate sowie Raster-PNGs usw. gut speichern. –

+0

Betrachten Sie das Speichern der Matplotlib-Figur als svg; Verwenden Sie dann 'svglib', um es in' reportlab' zu verwenden, wie in [diese Antwort] beschrieben (https://stackoverflow.com/questions/5835795/generating-pdfs-from-svg-input). – ImportanceOfBeingErnest

Antwort

3

Es gibt nicht eine, aber was ich in meinem eigenen Gebrauch von matplotlib mit ReportLab tun ist, PNGs zu generieren und einbinden dann die PNG-Dateien so, dass ich PIL nicht auch verwenden müssen. Wenn Sie jedoch PIL verwenden, sollten Sie EPS mit MatPlotLib und ReportLab generieren und einbetten können.

3

Die kostenlose Bibliothek PDFRW eignet sich für die Platzierung von PDFs in reportlab. In der Tat gibt es eine Notiz in der PDFRW guestbook von jemandem, der genau dieses Problem mit Matplotlib PDFs gelöst hat. Vielleicht warst du es?

19

Hier ist eine Lösung mit pdfrw:

#!/usr/bin/env python 
# encoding: utf-8 
"""matplotlib_example.py 
    An simple example of how to insert matplotlib generated figures 
    into a ReportLab platypus document. 
""" 

import matplotlib 
matplotlib.use('PDF') 
import matplotlib.pyplot as plt 
import cStringIO 

from pdfrw import PdfReader 
from pdfrw.buildxobj import pagexobj 
from pdfrw.toreportlab import makerl 

from reportlab.platypus import Flowable 
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT 
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer 
from reportlab.lib.styles import getSampleStyleSheet 
from reportlab.rl_config import defaultPageSize 
from reportlab.lib.units import inch 

PAGE_HEIGHT=defaultPageSize[1]; PAGE_WIDTH=defaultPageSize[0] 
styles = getSampleStyleSheet() 

class PdfImage(Flowable): 
    """PdfImage wraps the first page from a PDF file as a Flowable 
which can be included into a ReportLab Platypus document. 
Based on the vectorpdf extension in rst2pdf (http://code.google.com/p/rst2pdf/)""" 

    def __init__(self, filename_or_object, width=None, height=None, kind='direct'): 
     from reportlab.lib.units import inch 
     # If using StringIO buffer, set pointer to begining 
     if hasattr(filename_or_object, 'read'): 
      filename_or_object.seek(0) 
     page = PdfReader(filename_or_object, decompress=False).pages[0] 
     self.xobj = pagexobj(page) 
     self.imageWidth = width 
     self.imageHeight = height 
     x1, y1, x2, y2 = self.xobj.BBox 

     self._w, self._h = x2 - x1, y2 - y1 
     if not self.imageWidth: 
      self.imageWidth = self._w 
     if not self.imageHeight: 
      self.imageHeight = self._h 
     self.__ratio = float(self.imageWidth)/self.imageHeight 
     if kind in ['direct','absolute'] or width==None or height==None: 
      self.drawWidth = width or self.imageWidth 
      self.drawHeight = height or self.imageHeight 
     elif kind in ['bound','proportional']: 
      factor = min(float(width)/self._w,float(height)/self._h) 
      self.drawWidth = self._w*factor 
      self.drawHeight = self._h*factor 

    def wrap(self, aW, aH): 
     return self.drawWidth, self.drawHeight 

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

     xobj = self.xobj 
     xobj_name = makerl(canv._doc, xobj) 

     xscale = self.drawWidth/self._w 
     yscale = self.drawHeight/self._h 

     x -= xobj.BBox[0] * xscale 
     y -= xobj.BBox[1] * yscale 

     canv.saveState() 
     canv.translate(x, y) 
     canv.scale(xscale, yscale) 
     canv.doForm(xobj_name) 
     canv.restoreState() 

Title = "Hello world" 
pageinfo = "platypus example" 
def myFirstPage(canvas, doc): 
    canvas.saveState() 
    canvas.setFont('Times-Bold',16) 
    canvas.drawCentredString(PAGE_WIDTH/2.0, PAGE_HEIGHT-108, Title) 
    canvas.setFont('Times-Roman',9) 
    canvas.drawString(inch, 0.75 * inch, "First Page/%s" % pageinfo) 
    canvas.restoreState() 


def myLaterPages(canvas, doc): 
    canvas.saveState() 
    canvas.setFont('Times-Roman',9) 
    canvas.drawString(inch, 0.75 * inch, "Page %d %s" % (doc.page, pageinfo)) 
    canvas.restoreState() 

def go(): 
    fig = plt.figure(figsize=(4, 3)) 
    plt.plot([1,2,3,4]) 
    plt.ylabel('some numbers') 
    imgdata = cStringIO.StringIO() 
    fig.savefig(imgdata,format='PDF') 
    doc = SimpleDocTemplate("document.pdf") 
    Story = [Spacer(1,2*inch)] 
    style = styles["Normal"] 
    for i in range(5): 
     bogustext = ("This is Paragraph number %s. " % i) *20 
     p = Paragraph(bogustext, style) 
     Story.append(p) 
     Story.append(Spacer(1,0.2*inch)) 
     pi = PdfImage(imgdata) 
     Story.append(pi) 
     Story.append(Spacer(1,0.2*inch)) 
    doc.build(Story, onFirstPage=myFirstPage, onLaterPages=myLaterPages) 


if __name__ == '__main__': 
    go() 
+0

Ich bemerkte eine neue Frage [und Antwort] (http://Stackoverflow.com/a/31910275/3577601) zu dem gleichen Thema und erkannte erst, als ich [http://stackoverflow.com/a/32021013/3577601), dass es sich um eine modifizierte Version dieses Codes handelt. Ich hätte das genauer lesen sollen - ich habe mir einfach die vectorpdf-Dateien oben angesehen und aufgehört zu lesen ... –

+0

Nur eine kurze Anmerkung: Diese Antwort ist mit Python3 und dem aktuellen pdrw in PyPI gebrochen. – Oz123

Verwandte Themen