Search code examples
pythonmatplotlibpython-imaging-libraryreportlab

Write a matplotlib figure to a ReportLab PDF file without saving image to disk


I'm trying to find a way to write a matplotlib figure to a PDF via reportlab (4.0.6 open-source version). According to its doc, it should accept a PIL Image object, but I tried the following and it returned TypeError: expected str, bytes or os.PathLike object, not Image.

from reportlab.pdfgen import canvas
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvas

c = canvas.Canvas('test-pdf.pdf')

fig, ax = plt.subplots()
ax.plot([1, 2, 4], [3, 4, 6], '-o')
fig_canvas = FigureCanvas(fig)
fig_canvas.draw()
img = Image.fromarray(np.asarray(fig_canvas.buffer_rgba()))

c.drawImage(img, 0, 0)

c.showPage()
c.save()

I have seen this solution, but it's very old and uses other dependencies. Is there a way to achieve this just using PIL or numpy or any python3 first-party packages?


Solution

  • This can be done using a file-like object. First we use the method plt.savefig to write and the method reportlab ImageReader to read from it.

    import io
    from reportlab.pdfgen import canvas
    from reportlab.lib.utils import ImageReader
    import matplotlib.pyplot as plt
    
    c = canvas.Canvas('test-pdf.pdf')
    
    fig, ax = plt.subplots()
    ax.plot([1, 2, 4], [3, 4, 6], '-o')
    
    b = io.BytesIO()
    fig.savefig(b, format='png')
    
    image = ImageReader(b)
    c.drawImage(image, 0, 0)
    
    c.showPage()
    c.save()