Как стать автором
Обновить

Сохранение графиков matplotlib в pdf файл

Время на прочтение3 мин
Количество просмотров8.4K

Есть несколько графиков 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 файл

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

Теги:
Хабы:
0
Комментарии2

Публикации

Изменить настройки темы

Истории

Работа

Python разработчик
135 вакансий
Data Scientist
62 вакансии

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн