简体   繁体   English

将多个 seaborn 图保存到一个 pdf 文件中

[英]Save multiple seaborn plots into one pdf file

At the moment I'm learning how to work with matplotlib and seaborn and the concept behind it seems quite strange to me.目前我正在学习如何使用matplotlibseaborn ,它背后的概念对我来说似乎很奇怪。 One would expect the sns.countplot function to return an object that has a .plot() and .save() fuction so one could work with the plot in a different function.人们会期望sns.countplot函数返回一个具有.plot().save()函数的对象,以便可以在不同的函数中处理绘图。 Instead it seems that every call to sns.countplot overwrites the previous object (see MWE).相反,似乎每次调用sns.countplot覆盖前一个对象(参见 MWE)。

So one the one hand It would be grate if someone could provide a explanation of the matplotlib and seaborn interface (or have some good doku linked).所以一方面,如果有人可以提供matplotlibseaborn接口的解释(或者有一些好的 doku 链接), seaborn太好了。 Since all the doku I read wasn't of any great help.由于我阅读的所有 doku 都没有任何帮助。

On the other hand I have a function that returns some plots, which I want to save as an .pdf file with one plot per page.另一方面,我有一个返回一些图的函数,我想将其保存为.pdf文件,每页一个图。 I found this similar question but can't copy the code over in a way to make my MWE work.我发现了这个类似的问题,但无法以某种方式复制代码以使我的 MWE 工作。

from matplotlib.backends.backend_pdf import PdfPages
import seaborn as sns


def generate_plots():

    penguins = sns.load_dataset("penguins")

    countplot_sex = sns.countplot(y='sex', data=penguins)
    countplot_species = sns.countplot(y='species', data=penguins)
    countplot_island = sns.countplot(y='island', data=penguins)

    # As showes
    # print(countplot_sex) -> AxesSubplot(0.125,0.11;0.775x0.77)
    # print(countplot_species) -> AxesSubplot(0.125,0.11;0.775x0.77)
    # print(countplot_island) -> AxesSubplot(0.125,0.11;0.775x0.77)
    # All three variables contain the same object

    return(countplot_sex, countplot_species, countplot_island)


def plots2pdf(plots, fname):  # from: https://stackoverflow.com/a/21489936
    pp = PdfPages('multipage.pdf')

    for plot in plots:
        pass
        # TODO save plot
        # Does not work: plot.savefig(pp, format='pdf')

    pp.savefig()
    pp.close()


def main():
    plots2pdf(generate_plots(), 'multipage.pdf')


if __name__ == '__main__':
    main()

My Idea is to have a somewhat decent software architecture with one function generating plots and another function saving them.我的想法是有一个有点像样的软件架构,一个函数生成绘图,另一个函数保存它们。

The problem is that by default, sns.countplot will do its plotting on the current matplotlib Axes instance.问题是,默认情况下, sns.countplot将在当前 matplotlib Axes 实例上进行绘图。 From the docs :文档

ax matplotlib Axes, optional ax matplotlib 轴,可选

Axes object to draw the plot onto, otherwise uses the current Axes.要在其上绘制绘图的 Axes 对象,否则使用当前 Axes。

One solution would be to define a small function that creates a new figure and Axes instance, then passes that to sns.countplot , to ensure it is plotted on a new figure and does not overwrite the previous one.一种解决方案是定义一个创建新图形和 Axes 实例的小函数,然后将其传递给sns.countplot ,以确保它绘制在新图形上并且不会覆盖前一个图形。 This is what I have shown in the example below.这就是我在下面的例子中所展示的。 An alternative would be to just create 3 figures and axes, and then pass each one to the sns.countplot function yourself.另一种方法是只创建 3 个图形和轴,然后自己将每个图形和轴传递给sns.countplot函数。

Then in your plots2pdf function, you can iterate over the Axes, and pass their figure instances to the PdfPages instance when you save.然后在您的plots2pdf函数中,您可以遍历 Axes,并在保存时将它们的图形实例传递给PdfPages实例。 (Note: Since you create the figures in the generate_plots function, an alternative would be to return the figure instances from that function, then you have them ready to pass into the pp.savefig function, but I did it this way so the output from your function remained the same). (注意:由于您在generate_plots函数中创建了图形,因此另一种方法是从该函数返回图形实例,然后您准备好将它们传递到pp.savefig函数中,但我是这样做的,因此输出来自您的功能保持不变)。

from matplotlib.backends.backend_pdf import PdfPages
import seaborn as sns
import matplotlib.pyplot as plt

def generate_plots():

    penguins = sns.load_dataset("penguins")

    def my_countplot(y, data):
        fig, ax = plt.subplots()
        sns.countplot(y=y, data=data)
        return ax

    countplot_sex = my_countplot(y='sex', data=penguins)
    countplot_species = my_countplot(y='species', data=penguins)
    countplot_island = my_countplot(y='island', data=penguins)

    return(countplot_sex, countplot_species, countplot_island)


def plots2pdf(plots, fname):

    with PdfPages(fname) as pp:

        for plot in plots:

           pp.savefig(plot.figure)

def main():
    plots2pdf(generate_plots(), 'multipage.pdf')


if __name__ == '__main__':
    main()

A screenshot of the multipage pdf produced:生成的多页 pdf 的屏幕截图:

在此处输入图片说明

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

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