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

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Есть несколько сюжетов 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/


Интересные статьи

Интересные статьи

Всем привет. Когда я искал информацию о журналировании (аудите событий) в Bitrix, на Хабре не было ни чего, в остальном рунете кое что было, но кто же там найдёт? Для пополнения базы знаний...
Устраивать конкурсы в инстаграме сейчас модно. И удобно. Инстаграм предоставляет достаточно обширный API, который позволяет делать практически всё, что может сделать обычный пользователь ручками.
Привет, читатели Хабра. Этой статьей мы открываем цикл, который будет рассказывать о разработанной нами гиперконвергентной системе AERODISK vAIR. Изначально мы хотели первой же статьей рассказа...
Небольшое предисловие Стеганография, если кто не помнит, — это сокрытие информации в каких-либо контейнерах. Например, в картинках (обсуждалось тут и тут). Можно также скрыть данные в служебных ...
Сегодня мы поговорим о перспективах становления Битрикс-разработчика и об этапах этого пути. Статья не претендует на абсолютную истину, но даёт жизненные ориентиры.