Сохранение сюжетов matplotlib в pdf файл

от автора

Есть несколько сюжетов matplotlib. Необходимо сохранить их в единый pdf файл. Что делать?


Способ I. Сохранение одного сюжета на одной странице с помощью PdfPages.

Этот способ можно реализовать с помощью двух вариантов.

Использование магии matplotlib:

from matplotlib.backends.backend_pdf import PdfPages import matplotlib.pyplot as plt import numpy as np  # Создание файла. pdf = PdfPages("Figures.pdf")  # Создание сюжетов и их сохранение. FUNCTIONS = [np.sin, np.cos, np.sqrt, lambda x: x**2] X = np.linspace(-5, 5, 100) for function in FUNCTIONS:     plt.plot(X, function(X))     pdf.savefig()     plt.close()   # Сохранение файла pdf.close()

Использование непосредственного доступа к фигурам:

from matplotlib.backends.backend_pdf import PdfPages import matplotlib.pyplot as plt import numpy as np  # Создание массива фигур. FUNCTIONS = [np.sin, np.cos, np.sqrt, lambda x: x**2] X = np.linspace(-5, 5, 100) figures = [] for function in FUNCTIONS:     figure = plt.figure()     axes = figure.subplots()     axes.plot(X, function(X))      figures.append(figure) # Массив фигур. # figures = []  # Создание файла и сохранение каждой фигуры. pdf = PdfPages("Figures.pdf") for figure in figures:     pdf.savefig(figure)   # Сохранение файла pdf.close()

Получим:

Конечный pdf файл
Конечный pdf файл

Способ II. Сохранение несколько сюжетов на одной странице с помощью PdfPages.

from matplotlib.backends.backend_pdf import PdfPages import matplotlib.pyplot as plt import numpy as np  # Константы FUNCTIONS = [np.sin, np.cos, np.sqrt, lambda x: x**2, np.tan] X = np.linspace(-5, 5, 100)   # Количество строк и столбоц на одной строке ROWS = 2 COLUMNS = 2  # Создание файла. pdf = PdfPages("Figures.pdf")  # Цикл по страницам index = 0 for page in range(len(FUNCTIONS)//(ROWS*COLUMNS)+1):     # Создаем фигуру с несколькими осями.     figure = plt.figure(figsize=(12, 12))     axes = figure.subplots(ROWS, COLUMNS)      # Цикл по строкам и столбцам     for row in range(ROWS):         for column in range(COLUMNS):             if index < len(FUNCTIONS):                 axes[row, column].plot(X, FUNCTIONS[index](X))                  index += 1      # Сохраняем страницу     pdf.savefig(figure)   # Сохранение файла pdf.close()

Получим:

Конечный pdf файл
Конечный pdf файл

Так сделать не получится, если у нас есть массив уже конкретных построенных фигур. По той простой причине, на фигуре уже отрисовано то, что нужно, и так, как нужно. Да и к тому же, каждая фигура имеет свое значение dpi и size, которые влияют на отрисовку. Конечно, все это можно учесть, усложнив алгоритм, но намного проще перейти к 3 способу.

Способ III. Использование reportlab.

Наиболее универсальный способ.

import matplotlib.pyplot as plt import numpy as np from io import BytesIO from reportlab.pdfgen import canvas from reportlab.lib.units import cm from reportlab.lib.utils import ImageReader  # Создание массива фигур. FUNCTIONS = [np.sin, np.cos, np.sqrt, lambda x: x**2] X = np.linspace(-5, 5, 100) figures = [] for function in FUNCTIONS:     figure = plt.figure()     axes = figure.subplots()     axes.plot(X, function(X))      figures.append(figure) # Массив фигур. # figures = []   # Отступ indent = 1.5  # Создаем canvas и устанавливаем текущее значение высоты c = canvas.Canvas("Figures.pdf") c.setTitle("Figures") height = indent  # Цикл по фигурам. for figure in figures:     # dpi и размер (в дюймах) графика     dpi = figure.get_dpi()     figureSize = figure.get_size_inches()     # Создаем рамку вокруг графика.     # Это не обязательно, но так удобнее вырезать распечатанный график ножницами.     figure.patches.extend(         [plt.Rectangle((0, 1/(dpi*figureSize[1])), width=1-2/(dpi*figureSize[0]),                        height=1-2/(dpi*figureSize[1]),                        transform=figure.transFigure, figure=figure, clip_on=False,                        edgecolor="black",                        facecolor="none", linewidth=1)])       # Рендер фигуры.     image = BytesIO()     figure.savefig(image, format="png")     image.seek(0)     image = ImageReader(image)       # Размер фигуры в см.     figureSize = figure.get_size_inches()*2.54      # A4 210×297 мм     # Если выходим за пределы листа, то добавляем новый лист     if height + figureSize[1] + indent > 29.7:         height = indent         c.showPage()      # Добавляем image в pdf     c.drawImage(image, (10.5-figureSize[0]/2)*cm, height*cm,                 figureSize[0]*cm, figureSize[1]*cm)     height += figureSize[1]  # Сохраняем. c.save()

Получим:

Конечный pdf файл
Конечный pdf файл

Спасибо за прочтение статьи. Удачи!

ссылка на оригинал статьи https://habr.com/ru/post/544132/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *