Как рисоватьИзменить фигуру matplotlib в холсте reportlab?

Я хотел бы добавить фигуру, сгенерированную с помощью matplotlib, на холст отчета, используя метод drawImage и без необходимости сначала сохранять фигуру на жестком диске.

Мой вопрос связан с: есть ли текучая среда matplotlib для ReportLab? , который был хорошо решен. Однако я не хочу использовать DocTemplates, Stories, Flowables и т.д. Как уже было сказано, я бы хотел поместить его в определенную позицию на холсте, используя drawImage.

Я попытался преобразовать рисунок matplotlib в изображение PIL, используя следующие методы:

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

Например, некоторый код, который не работает:

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

Попытка нарисовать imgdata приводит к ошибке:

AttributeError: 'cStringIO.StringO' object has no attribute 'rfind'

Во время рисования im дает:

AttributeError: rfind

Кто-нибудь сейчас решает эту проблему? Любая помощь будет принята с благодарностью.

Ответ 1

Проблема заключается в том, что drawImage ожидает либо объект ImageReader, либо путь к файлу, а не дескриптор файла.

Следующее должно работать:

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

Решение для Python 3 и встраивание фигуры matplotlib в виде векторного изображения (без растеризации). Повторное размещение здесь, когда я искал это довольно давно.

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 можно приобрести в conda-forge.