Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Faire un graph sous matplotlib et l' inserer dans reportlab

+4 votes

Matplotlib est très intéressant pour faire des graph, il fait un peu de PDF mais ça me convient pas. Reportlab est très bien pour faire des PDF.

J' essaie de faire un PDF et d'y inclure mon graph. Mais Reportlab accepte du JPEG là où Matplotlib donne du PNG.

J' ai essayé d' avoir une conversion dans la mémoire sans passer par un fichier sur le disque dur. Je suis peu habitué à utiliser le module io. J'ai pompé du code sur S.O. que j'ai traffiqué mais ça marche pas :

#!/usr/bin/python3
#-*- coding: utf-8 -*-


# How to use reportlab.platypus.Image with PNG that is created by matplotlib.pyplot.save_figure function  :
# https://gist.github.com/kokardy/5967661

# http://stackoverflow.com/questions/8598673/how-to-save-a-pylab-figure-into-in-memory-file-which-can-be-read-into-pil-image

import io
from io import StringIO, BytesIO


from PIL import ImageFileIO 
import matplotlib.pyplot as plt
from reportlab.platypus import Image 
from PIL import Image

from reportlab.pdfgen import canvas
from reportlab.lib.units import inch 

#plot your graphs *********************************----------------------

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs', 'Gogs'
sizes = [15, 30, 45, 5, 5]

colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral', 'magenta']
explode = (0, 0.1, 0, 0, 0.9) # only "explode" the 2nd slice (i.e. 'Hogs')

plt.pie(sizes, explode=explode, labels=labels, colors=colors,
        autopct='%1.1f%%', shadow=True, startangle=90)
# Set aspect ratio to be equal so that pie is drawn as a circle.
plt.axis('equal')


buffer = io.BytesIO()
plt.savefig(buffer, format='png')
buffer.seek(0)
im = Image.open(buffer)
im.show()

print(buffer)
print("\n")
print(im)


def hello(c):

    # move the origin up and to the left
    c.translate(inch,inch)
    # define a large font
    c.setFont("Helvetica", 14)
    # choose some colors

    c.setStrokeColorRGB(0.2,0.5,0.3)
    c.setFillColorRGB(1,0,1)
    # draw some lines
    c.line(0,0,0,1.7*inch)
    c.line(0,0,1*inch,0)
    # draw a rectangle
    c.rect(0.2*inch,0.2*inch,1*inch,1.5*inch, fill=1)
    # make text go straight up
    c.rotate(90)
    # change color
    c.setFillColorRGB(0,0,0.77)
    # say hello (note after rotate the y coord needs to be negative!)
    c.drawString(0.3*inch, -inch, "Hello World")    
    c.drawImage(buffer,50,75, width=2*inch, height=2*inch)


c = canvas.Canvas("hello.pdf")
# hello(c)
# c.showPage()
c.save()
buffer.close()  
demandé 7-Jul-2015 par buffalo974 (2,886 points)

2 Réponses

+3 votes

Je pense que convertir ton buffer png en jpeg avec quelque chose du genre devrait suffire :

im.seek(0)
buffer_jpg = BytesIO()
im.save(buffer_jpg, 'jpeg')
# plus loin
buffer_jpg.seek(0)
c.drawImage(buffer_jpg,50,75, width=2*inch, height=2*inch)

Par contre fait gaffe, tu importes deux fois Image depuis deux modules différents

from reportlab.platypus import Image 
from PIL import Image
répondu 9-Jul-2015 par jc (2,704 points)

je bute sur attributeerror rfind

http://stackoverflow.com/questions/18897511/how-to-drawimage-a-matplotlib-figure-in-a-reportlab-canvas

http://stackoverflow.com/questions/13953659/insert-image-into-reportlab-either-from-pil-image-or-stringio

j'essaie de voir ça ce weekend, si quelqu'un a déjà buté la-dessus je suis preneur ^^
code actuel:

import io
from io import StringIO, BytesIO

from PIL import Image as PILImage
from PIL import ImageFileIO


import matplotlib.pyplot as plt


from reportlab.platypus import Image  
from reportlab.lib.utils import ImageReader

from reportlab.platypus.flowables import Image as reportlabImage




from reportlab.pdfgen import canvas
from reportlab.lib.units import inch 

#plot your graphs *********************************----------------------

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs', 'Gogs'
sizes = [15, 30, 45, 5, 5]

colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral', 'magenta']
explode = (0, 0.1, 0, 0, 0.9) # only "explode" the 2nd slice (i.e. 'Hogs')

plt.pie(sizes, explode=explode, labels=labels, colors=colors,
        autopct='%1.1f%%', shadow=True, startangle=90)
# Set aspect ratio to be equal so that pie is drawn as a circle.
plt.axis('equal')


buffer_png = io.BytesIO()
plt.savefig(buffer_png, format='png')
buffer_png.seek(0)


print("buffer_png  ",buffer_png)
print("\n")
#print(im)

#im.seek(0)

#im.save(buffer_jpg, 'jpeg')



im = PILImage.open(buffer_png)
im.show()
im.seek(0)



buffer_jpg = BytesIO()
im.save(buffer_jpg, 'jpeg')
# plus loin
buffer_jpg.seek(0)


imgdata = buffer_jpg

c = canvas.Canvas("hello.pdf")

my_Image = ImageReader(imgdata)





def hello(c):

    # move the origin up and to the left
    c.translate(inch,inch)
    # define a large font
    c.setFont("Helvetica", 14)
    # choose some colors

    c.setStrokeColorRGB(0.2,0.5,0.3)
    c.setFillColorRGB(1,0,1)
    # draw some lines
    c.line(0,0,0,1.7*inch)
    c.line(0,0,1*inch,0)
    # draw a rectangle
    c.rect(0.2*inch,0.2*inch,1*inch,1.5*inch, fill=1)
    # make text go straight up
    c.rotate(90)
    # change color
    c.setFillColorRGB(0,0,0.77)
    # say hello (note after rotate the y coord needs to be negative!)
    c.drawString(0.3*inch, -inch, "Hello World")    
    c.drawImage(my_Image,50,75, width=2*inch, height=2*inch)


# http://stackoverflow.com/questions/18897511/how-to-drawimage-a-matplotlib-figure-in-a-reportlab-canvas    
c.drawImage(buffer_jpg,50,75, width=2*inch, height=2*inch)  

# http://stackoverflow.com/questions/13953659/insert-image-into-reportlab-either-from-pil-image-or-stringio

# plus loin
buffer_jpg.seek(0)


hello(c)
c.save()

c'est pas aussi facile que ça en à l'air avec reportlab...

+1 vote

D'après la doc sur http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.savefig

Most backends support png, pdf, ps, eps and svg.

Ça veut dire que généralement les backends supportent ces types de formats, mais certains backend en supportent d'autres. Tu peux enregistrer en jpg avec le backend Qt par exemple (si ma mémoire est bonne) :

import matplotlib
matplotlib.use('Qt4Agg', warn=False)
import matplotlib.pyplot as plt
répondu 29-Avr-2016 par Kontre (128 points)
edité 3-Mai-2016 par Kontre

C' est quoi un backend ?

La doc en anglais est là: http://matplotlib.org/faq/usage_faq.html#what-is-a-backend
En fait en interne matplotlib peut utiliser différentes bibliothèques pour afficher les tracés (Qt, GTK, Tk...). C'est généralement transparent pour l'utilisateur car c'est matplotlib qui traduit en interne à la bibliothèque utilisée. Mais tous les backends ne sont pas identiques, et par exemple tous ne proposent pas les mêmes types de fichiers lors de la sauvegarde.

...