问题
I would like to add a figure generated with matplotlib to a reportlab canvas using the method drawImage and without having to save the figure to the hard drive first.
My question is related to: Is there a matplotlib flowable for ReportLab?, which was nicely solved. However, I do not wish to use DocTemplates, Stories, Flowables, etc. As said, I would like put it at a certain position in the canvas using drawImage.
I have tried to convert the matplotlib figure to a PIL image using the following methods:
1) http://www.icare.univ-lille1.fr/wiki/index.php/How_to_convert_a_matplotlib_figure_to_a_numpy_array_or_a_PIL_image
2) http://matplotlib.org/faq/howto_faq.html#matplotlib-in-a-web-application-server
For example, some code that fails to work is:
import Image
import matplotlib.pyplot as plt
import cStringIO
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch, cm
fig = plt.figure(figsize=(4, 3))
plt.plot([1,2,3,4])
plt.ylabel('some numbers')
imgdata = cStringIO.StringIO()
fig.savefig(imgdata, format='png')
imgdata.seek(0) # rewind the data
im = Image.open(imgdata)
c = canvas.Canvas('test.pdf')
#c.drawImage(imgdata, cm, cm, inch, inch)
c.drawImage(im, cm, cm, inch, inch)
c.save()
Trying to draw imgdata
results in the error:
AttributeError: 'cStringIO.StringO' object has no attribute 'rfind'
While drawing im
gives:
AttributeError: rfind
Does somebody now how to solve this issue? Any help would be greatly appreciated.
回答1:
The problem is that drawImage expects either an ImageReader object or a filepath, not a file handle.
The following should work:
import Image
import matplotlib.pyplot as plt
import cStringIO
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch, cm
from reportlab.lib.utils import ImageReader
fig = plt.figure(figsize=(4, 3))
plt.plot([1,2,3,4])
plt.ylabel('some numbers')
imgdata = cStringIO.StringIO()
fig.savefig(imgdata, format='png')
imgdata.seek(0) # rewind the data
Image = ImageReader(imgdata)
c = canvas.Canvas('test.pdf')
c.drawImage(Image, cm, cm, inch, inch)
c.save()
回答2:
Solution for Python 3, and embedding matplotlib figure as a vector image (no rasterization). Reposting here as I searched for this quite some time.
import matplotlib.pyplot as plt
from io import BytesIO
from reportlab.pdfgen import canvas
from reportlab.graphics import renderPDF
from svglib.svglib import svg2rlg
fig = plt.figure(figsize=(4, 3))
plt.plot([1,2,3,4])
plt.ylabel('some numbers')
imgdata = BytesIO()
fig.savefig(imgdata, format='svg')
imgdata.seek(0) # rewind the data
drawing=svg2rlg(imgdata)
c = canvas.Canvas('test2.pdf')
renderPDF.draw(drawing,c, 10, 40)
c.drawString(10, 300, "So nice it works")
c.showPage()
c.save()
svglib is available from conda-forge.
来源:https://stackoverflow.com/questions/18897511/how-to-drawimage-a-matplotlib-figure-in-a-reportlab-canvas