2011-01-14 10 views
13

Chcę osadzić wykresy matplotlib w plikach PDF generowanych bezpośrednio przez ReportLab - tj. Nie zapisując jako PNG, a następnie osadzając plik PNG w pliku PDF (uważam, że otrzymam lepszą jakość).Czy dla ReportLab istnieje płynny matplotlib?

Czy ktoś wie, czy dla ReportLab jest płynny matplotlib?

Dzięki

+3

Innym rozwiązaniem byłoby, aby zapisać rysunek w formacie PDF lub EPS (lub innym formacie wektorowym), a następnie osadzić w wersji wektorowej w pliku PDF. To by przynajmniej rozwiązało problemy z jakością ... Matplotlib wykonuje dobrą robotę zapisywania formatów wektorowych, jak rastrowe pliki .png itp. –

+0

Rozważ zapisanie figury matplotlib jako svg; następnie używając 'svglib' do użycia go w' reportlab' jak opisano w [tej odpowiedzi] (https://stackoverflow.com/questions/5835795/generating-pdfs-from-svg-input). – ImportanceOfBeingErnest

Odpowiedz

3

Nie ma jednego, ale to, co robię w moim wykorzystania matplotlib z ReportLab jest generowanie PNG, a następnie osadzić PNG tak, że nie trzeba również użyć PIL. Jeśli jednak korzystasz z PIL, uważam, że powinieneś być w stanie wygenerować i osadzić EPS za pomocą MatPlotLib i ReportLab.

3

Darmowa biblioteka PDFRW nadaje się do umieszczania plików PDF w raporcie. W rzeczywistości jest notatka w pliku PDFRW guestbook od osoby, która rozwiązała dokładnie ten problem w plikach Matplotlib PDF. Być może to ty?

19

Oto rozwiązanie przy użyciu 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

Zauważyłem nowe pytanie [i odpowiedź] (http://stackoverflow.com/a/31910275/3577601) na ten sam temat i nie zdawałem sobie sprawy, dopóki nie [zmodyfikowałem] (http://stackoverflow.com/a/32021013/3577601), który koduje, że sam był zmodyfikowaną wersją tego kodu. Powinienem był przeczytać to uważniej - po prostu patrzyłem na plik vectorpdf na górze i przestałem czytać ... –

+0

Po prostu krótka notka: ta odpowiedź jest zepsuta przez Python3 i bieżący pdrw w PyPI. – Oz123