Подписи к matshow() в многостраничном pdf

Я был вокруг этой проблемы в течение достаточно долгого времени, но я не смог найти ответ.

Итак, у меня есть список с матрицами, которые я хочу построить (ради этого вопроса у меня просто есть 2 случайные матрицы:

list = [np.random.random((500, 500)), np.random.random((500, 500))]

Затем я хочу построить каждый элемент списка, используя matshow на отдельной странице PDF-файла:

with PdfPages('file.pdf') as pdf:
    plt.rc('figure', figsize=(3,3), dpi=40)
    for elem in list:
        plt.matshow(elem, fignum=1)
        plt.title("title")
        plt.colorbar()
        plt.text(0,640,"Caption")
        pdf.savefig()  # saves the current figure into a pdf page
        plt.close()

Результат следующий:

Моя проблема с надписью. Вы можете видеть, что я поставил "Заголовок" на краю документа специально. Это потому, что иногда реальные надписи, которые я хочу вставить, слишком велики, чтобы поместиться на одной странице PDF.

Итак, как я могу настроить каждую страницу PDF в соответствии с содержанием заголовка (который может отличаться на каждой странице)? Например, можно ли было бы установить для каждого размера страницы значение А4 или А3, а затем построить / записать все на каждой странице?

Я уже пытался настроить plt.figure(figsize=(X, X)) с переменной X размер, но это просто меняет разрешение PDF, я думаю.

2 ответа

Решение

Вы можете использовать bbox_inches="tight" опция при сохранении файла. Это позволит адаптировать размер фигуры к ее содержанию. Так что тогда достаточно поместить текст в положение (0,0) в координатах рисунка и выровняйте его по верху. Это будет распространяться вниз и за пределы рисунка (поэтому рисунок, отображаемый на экране, не будет содержать этот текст), но с bbox_inches="tight" опция savefig, сохраненная фигура станет достаточно большой, чтобы содержать этот текст.
Использование пакета textwrap также позволит ограничить текст в горизонтальном направлении.

import numpy as np; np.random.seed(1)
import textwrap 
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages

p = np.ones(12); p[0] = 7
text2 = "".join(np.random.choice(list(" abcdefghijk"),p=p/p.sum(), size=1000))
text2 = textwrap.fill(text2, width=80)
texts = ["Caption: Example", "Caption 2: " + text2 ]

lis = [np.random.random((500, 500)), np.random.random((500, 500))]

with PdfPages('file.pdf') as pdf:
    for elem,text in zip(lis,texts):
        fig = plt.figure(dpi=100)

        grid_size = (3,1)

        plt.imshow(elem)
        plt.title("title")
        plt.colorbar()

        fig.text(0,0, text, va="top")

        plt.tight_layout()
        pdf.savefig(bbox_inches="tight")
        plt.close()

Я думаю, что сам придумал ответ на этот вопрос, который решает проблему с достаточным пространством для моего текста:

Тем не менее, идеальным ответом будет динамический размер каждой страницы в соответствии с количеством подписи.

В любом случае, мой ответ следующий (я по существу разделил каждую страницу в сетке из 3 строк, сделав верхние 2 строки для графиков, а последнюю просто для заголовка):

with PdfPages('file.pdf') as pdf:
    for elem in list:
        fig = plt.figure(figsize=(8.27, 11.69), dpi=100)

        grid_size = (3,1)

        plt.subplot2grid(grid_size, (0, 0), rowspan=2, colspan=1)

        plt.imshow(elem)
        plt.title("title")
        plt.colorbar()

        plt.subplot2grid(grid_size, (2, 0), rowspan=2, colspan=1)
        plt.axis('off')
        plt.text(0,1,"Caption")

        plt.tight_layout()
        pdf.savefig()
        plt.close()

Который производит следующее на каждой странице:

Может ли кто-нибудь найти лучшее решение?:)

Другие вопросы по тегам