简体   繁体   English

Python matplotlib:在多个页面中保存为pdf

[英]Python matplotlib: Save to pdf in multiple pages

I am trying to do the following:我正在尝试执行以下操作:

I have created a figure, using matplotlib, with several subplots.我使用 matplotlib 创建了一个图形,其中包含几个子图。 More specifically, 2x4 subplots更具体地说,2x4 子图

The output is great for showing it on the screen, but not for saving it to pdf.输出非常适合在屏幕上显示,但不适用于将其保存为 pdf。

If I just use save_fig , it prints a single page pdf document, with the 2x4 grid.如果我只使用save_fig ,它会打印一个带有 2x4 网格的单页 pdf 文档。

What I would like to do, is re-arrange my subplots, to let's say a 2x4 grid (choosing which subplot goes where, would be good, but not necessary) and printing it to a 2-page pdf with 4 subplots each.我想要做的是重新排列我的子图,假设一个 2x4 网格(选择哪个子图去哪里,会很好,但不是必需的)并将其打印到 2 页 pdf,每个 4 个子图。 (in order to be able to fit it to A4 page size) (为了能够适应 A4 页面大小)

Is this possible?这可能吗?

Thank you in advanced!先谢谢了!

I would suggest to create 3 figures.我建议创建 3 个数字。 One for showing and 2 for saving and plot the same data to them.一个用于显示,2 个用于保存和绘制相同的数据。

import matplotlib.pyplot as plt
import numpy as np


data = np.sort(np.cumsum(np.random.rand(24,16), axis=0), axis=0)

def plot(ax, x, y, **kwargs):
    ax.plot(x,y, **kwargs)

colors = ["crimson", "indigo", "limegreen", "gold"]
markers = ["o", "", "s", ""]
lines = ["", "-", "", ":"]

# figure 0 for showing
fig0, axes = plt.subplots(nrows=2,ncols=4)

for i, ax in enumerate(axes.flatten()):
    plot(ax, data[:,2*i], data[:,2*i+1], marker=markers[i%4], ls=lines[i%4],color=colors[i%4])


# figure 1 for saving
fig1, axes = plt.subplots(nrows=1,ncols=4)
for i, ax in enumerate(axes.flatten()):
    plot(ax, data[:,2*i], data[:,2*i+1], marker=markers[i], ls=lines[i],color=colors[i])

#figure 2 for saving
fig2, axes = plt.subplots(nrows=1,ncols=4)
for i, ax in enumerate(axes.flatten()):
    plot(ax, data[:,2*i+4], data[:,2*i+1+4], marker=markers[i], ls=lines[i],color=colors[i])

#save figures 1 and 2
fig1.savefig(__file__+"1.pdf")
fig2.savefig(__file__+"2.pdf")

#close figures 1 and 2
plt.close(fig1)
plt.close(fig2)
#only show figure 0
plt.show()

As I needed something similar for my work, I put some effort into automating the process of grouping plots into figures depending on the display medium.由于我的工作需要类似的东西,我付出了一些努力,根据显示介质将绘图分组为图形的过程自动化。 At first I had the idea to do each plot only once and just add the subplots to the figures to be saved in the pdf, but sadly, according to a comment in this answer , this is not possible, so everything needs to be re-plotted.起初我的想法是每个情节只做一次,只需将子情节添加到要保存在 pdf 中的数字中,但遗憾的是,根据此答案中的评论,这是不可能的,所以一切都需要重新绘制。 The code shows the general idea of how this can be automated using PdfPages :代码显示了如何使用PdfPages实现自动化的总体思路:

from matplotlib import pyplot as plt
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages


def niter(iterable, n):
    """
    Function that returns an n-element iterator, i.e.
    sub-lists of a list that are max. n elements long.
    """
    pos = 0
    while pos < len(iterable):
        yield iterable[pos:pos+n]
        pos += n


def plot_funcs(x, functions, funcnames, max_col, max_row):
    """
    Function that plots all given functions over the given x-range,
    max_col*max_row at a time, creating all needed figures while doing
    so.
    """

    ##amount of functions  to put in one plot    
    N = max_col*max_row

    ##created figures go here
    figs = []

    ##plotted-on axes go here
    used_axes = []

    ##looping through functions N at a time:
    for funcs, names in zip(niter(functions, N), niter(funcnames,N)):

        ##figure and subplots
        fig, axes = plt.subplots(max_col, max_row)

        ##plotting functions
        for name,func,ax in zip(names, funcs, axes.reshape(-1)):
            ax.plot(x, func(x))
            ax.set_title(name)
            used_axes.append(ax)

        ##removing empty axes:
        for ax in axes.reshape(-1):
            if ax not in used_axes:
                ax.remove()

        fig.tight_layout()
        figs.append(fig)

    return figs

##some functions to display
functions = [
    lambda x: x, lambda x: 1-x, lambda x: x*x, lambda x: 1/x, #4
    np.exp, np.sqrt, np.log, np.sin, np.cos,                  #5
    ]
funcnames = ['x','1-x', 'x$^2$', '1/x', 'exp', 'sqrt', 'log', 'sin','cos']

##layout for display on the screen
disp_max_col = 3
disp_max_row = 2

##layout for pdf
pdf_max_col = 2
pdf_max_row = 4

##displaying on the screen:
x = np.linspace(0,1,100)
figs = plot_funcs(x, functions, funcnames, disp_max_row, disp_max_col)
plt.show()


##saving to pdf if user wants to:
answer = input('Do you want to save the figures to pdf?')
if answer in ('y', 'Y', 'yes', ''):

    ##change number of subplots
    N = disp_max_col*disp_max_row
    figs = plot_funcs(x, functions, funcnames, pdf_max_row, pdf_max_col)

    ##from https://matplotlib.org/examples/pylab_examples/multipage_pdf.html
    with PdfPages('multipage_pdf.pdf') as pdf:
        for fig in figs:
            plt.figure(fig.number)
            pdf.savefig()

The core function, plot_funcs takes max_col and max_row keywords and then creates figures with the according amount of subplots.核心函数plot_funcs max_colmax_row关键字,然后创建具有相应数量的子图的图形。 It then loops through a given list of functions to be plotted, each on its own subplot.然后循环遍历要绘制的给定函数列表,每个函数都在自己的子图中。 Unused subplots are removed.未使用的子图被删除。 Finally a list of all figures is returned.最后返回所有数字的列表。

In my example, I have 9 different functions, which I first show on the screen in a 2x3 layout (making a total of two figures, one with 6 subplots and one with 3 subplots).在我的示例中,我有 9 个不同的函数,我首先在屏幕上以 2x3 布局显示它们(总共有两个图形,一个有 6 个子图,一个有 3 个子图)。 If the user is happy, the plots are redone in a 2x4 layout (again two figures, but this time one with 8 subplots and 1 with 1 subplot) and then saved to a file called multipage_pdf.pdf , following the example in the documentation .如果用户满意,绘图会以 2x4 布局重做(同样是两个图,但这次一个有 8 个子图,1 个有 1 个子图),然后按照文档中示例保存到名为multipage_pdf.pdf 的文件中

Tested on python 3.5在 python 3.5 上测试

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM