cargando objeto matplotlib en reportlab

Estoy tratando de cargar un objeto matplotlib en reportlab. Aquí está mi código:

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 

Mi objective es insertar la imagen de la ttwig en el informe. Esto funciona bien pero no quiero escribir en un archivo temporal. Intenté instalar PIL porque leí a algunas personas que lo hacen con la biblioteca de imágenes de PIL, pero tan pronto como instalo PIL, otra parte de mi código se rompe debido a versiones incompatibles de Pillow.

Related of "cargando objeto matplotlib en reportlab"

la documentación de pdfrw apesta

La única razón por la que el ejemplo de pdfrw que se analiza en la primera respuesta a esta pregunta es un poco torpe es porque la documentación de pdfrw es muy mala. Debido al sucky doc, el autor de ese ejemplo @ Larry-Meyn usó la extensión vectorpdf para rst2pdf como punto de partida, y esa extensión tampoco está realmente documentada, y tiene que lidiar con las peculiaridades de rst2pdf y pdfrw (y es más general de lo que necesita, ya que puede permitir que rst2pdf muestre un rectángulo arbitrario desde una página de arbitray de un PDF preexistente). Es increíble que Larry haya logrado que funcionara, y mi sombrero está fuera de su scope.

Estoy perfectamente calificado para decir esto, porque soy el autor de pdfrw e hice algunas contribuciones a rst2pdf, incluida la extensión vectorpdf.

Pero probablemente quieras usar pdfrw de todos modos

Realmente no estaba prestando atención a stackoverflow hasta hace un mes, y pdfrw en sí mismo languideció por unos años, pero ahora estoy aquí, y creo que sería mejor que eches un vistazo a pdfrw, aunque la documentación todavía apesta. .

¿Por qué? Porque si imprime en un archivo png, su imagen se rasterizará , y si usa pdfrw, permanecerá en formato vectorial , lo que significa que se verá bien en cualquier escala.

Así que modifiqué el ejemplo png de tu respuesta

Su ejemplo de png no fue un progtwig completo: los parámetros de doc.build no se definieron, los estilos no se definieron, faltaron algunas importaciones, etc. Pero fue lo suficientemente cerca como para reunir cierta intención y obtenerlo trabajando.

Editar : me acabo de dar cuenta de que este ejemplo era en realidad una versión modificada del ejemplo de Larry, por lo que ese ejemplo sigue siendo muy valioso porque de alguna manera es un poco más completo que este.

Después de solucionar esos problemas y obtener algunos resultados, agregué una opción para poder usar png o pdf, para que pueda ver la diferencia. El progtwig a continuación creará dos archivos PDF diferentes, y usted puede comparar los resultados por sí mismo.

 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.restreState() 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) 

¿Cuáles son las desventajas de este enfoque?

El primer inconveniente obvio es que ahora hay un requisito para pdfrw, pero eso está disponible en PyPI.

El siguiente inconveniente es que si está colocando una gran cantidad de gráficos de matplotlib en un documento, creo que esta técnica replicará recursos como fonts, porque no creo que reportlab sea lo suficientemente inteligente como para notar los duplicados.

Creo que este problema se puede resolver mediante la salida de todos sus gráficos a diferentes páginas de un solo PDF . De hecho, no lo he intentado con matplotlib, pero pdfrw es perfectamente capaz de convertir cada página de un pdf existente en un flujo separado .

Por lo tanto, si tiene muchos gráficos y está haciendo su PDF final demasiado grande, podría analizarlo o simplemente probar uno de los optimizadores de PDF y ver si ayuda. En cualquier caso, ese es un problema diferente para un día diferente.

He encontrado 2 soluciones:

1: usando un paquete llamado pdfrw: ¿Existe un flujo de matplotlib para ReportLab?

2: una forma más sencilla de limpiar:

 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() canv.drawImage(self.img_data, x, y, self.img_width, self.img_height) canv.restreState() def make_report(): 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='png') imgdata.seek(0) image = ImageReader(imgdata) doc = SimpleDocTemplate("hello.pdf") 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, onFirstPage=myFirstPage, onLaterPages=myLaterPages, canvasmaker=PageNumCanvas)