如何用多部分海洋图迭代填充matplotlib gridspec? [英] How to iteratively populate matplotlib gridspec with a multipart seaborn plot?

查看:66
本文介绍了如何用多部分海洋图迭代填充matplotlib gridspec?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理的一些最小代码.有些参数可能看起来很多余,但是我没有费心删除所有参数.

Some minimal code of what I'm working on. Some parameters may seem redundant, but I didn't bother removing all of them.

import matplotlib
import matplotlib.gridspec as gridspec
matplotlib.use("macosx")
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

def plot_overlaid_2d_hist(data,
                          plot_axis_x,
                          plot_axis_y,
                          plot_axis_x_lab,
                          plot_axis_y_lab,
                          group_by = "group_name"):

    # don't mind this for now
    df = data

    # Figure aspect
    w, h = plt.figaspect(1)
    fig = plt.figure(figsize = (w, h))

    # Count the number of groups to make plots for
    n_groups = len(df.groupby(group_by))
    gs = gridspec.GridSpec(nrows = n_groups, ncols = 1)
    subplot_id = 0

    # Reshape data to make it work
    for name, group in df.groupby(group_by, sort = False):

        # Initialize subplot
        fig.add_subplot(gs[subplot_id, 0])

        # Check if we get subplots with pyplot
        if subplot_id == 0:
            col = "red"
        else:
            col = "blue"

        plt.plot(x, y, color = col)


        # instantiate JointGrid
        # g = sns.JointGrid(group[plot_axis_x],
        #                   group[plot_axis_y],
        #                   data = group,
        #                   space = 0,
        #                   xlim = (0, 1.2),
        #                   ylim = (0, 1))
        # 
        # # Fix labels
        # g = g.set_axis_labels(xlabel = str(plot_axis_x_lab),
        #                   ylabel = str(plot_axis_y_lab))
        # 
        # # center scatter plot on top
        # g = g.plot_joint(plt.scatter,
        #              s = 0.5,
        #              alpha = 1,
        #              linewidth = 1)
        # 
        # # marginals plot
        # g = g.plot_marginals(sns.distplot,
        #                  kde = True,
        #                  kde_kws = dict(linewidth = 2,
        #                                 alpha = 1,
        #                                 bw = "Scott"),
        #                  hist_kws = dict(alpha = 1))


        # Next plot in row +1
        subplot_id += 1

    # Output
    plt.tight_layout()  # Attempts to fix alignment of subplot layout and axis titles

    plt.show()

# quick data to check if the plots end up where they should
x = [0.5, 0.5, 0.4, 0.4]
y = [0.6, 0.4, 0.3, 0.4]
grp = ["a", "a", "b", "b"]


df = pd.DataFrame({"x":x,
                   "y":y,
                   "grp": grp})

plot_overlaid_2d_hist(data = df,
                      group_by = "grp",
                      plot_axis_x_lab = "x",
                      plot_axis_y_lab = "x",
                      plot_axis_y = "x",
                      plot_axis_x = "x")

在所有seaborn地块(g)注释掉的情况下运行代码表明,该代码对于本机pyplot很好用,但是当我添加多部分seaborn地块时,它们以单独的数字显示.我想让每个带有边距和散点的2D直方图填充自己的gridspec行/列.

Running the code with all seaborn plots (g) commented out shows that it works fine for native pyplot, but when I add in the multi-part seaborn plots, they show up in separate figures. What I would like is to have each 2D-histogram-with-marginals-and-scatter populate their own gridspec row/column.

推荐答案

看到此问题已经在

Seeing that this question has already been asked before here I moved this answer to the older question. I would like to delete it here, but cannot do so because it is accepted already.

正如在多个地方所指出的那样(此问题,也此问题),一些seaborn命令创建了自己的图形自动地.这被硬编码到seaborn代码中,因此当前无法在现有图形中生成此类图.这些是PairGridFacetGridJointGridpairplotjointplotlmplot.

As has been pointed out at several places (this question, also this issue) several of the seaborn commands create their own figure automatically. This is hardcoded into the seaborn code, so there is currently no way to produce such plots in existing figures. Those are PairGrid, FacetGrid, JointGrid, pairplot, jointplot and lmplot.

有一个季节性叉可用,它可以提供子图网格到相应的类,以便在预先存在的图形中创建图.要使用此功能,您需要将axisgrid.py从叉子复制到seaborn文件夹.请注意,目前仅限将其与matplotlib 2.1(也可能是2.0)一起使用.

There is a seaborn fork available which would allow to supply a subplot grid to the respective classes such that the plot is created in a preexisting figure. To use this, you would need to copy the axisgrid.py from the fork to the seaborn folder. Note that this is currently restricted to be used with matplotlib 2.1 (possibly 2.0 as well).

另一种选择是创建一个海底人像并将轴复制到另一个人像. 此答案中显示了此原理,并且可以扩展到Searborn图.实现比我最初预期的要复杂一些.以下是可以通过Seaborn网格实例(上述任何命令的返回),matplotlib图形和subplot_spec(这是gridspec网格的位置)调用的类SeabornFig2Grid.

An alternative could be to create a seaborn figure and copy the axes to another figure. The principle of this is shown in this answer and could be extended to Searborn plots. The implementation is a bit more complicated that I had initially expected. The following is a class SeabornFig2Grid that can be called with a seaborn grid instance (the return of any of the above commands), a matplotlib figure and a subplot_spec, which is a position of a gridspec grid.

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import seaborn as sns
import numpy as np

class SeabornFig2Grid():

    def __init__(self, seaborngrid, fig,  subplot_spec):
        self.fig = fig
        self.sg = seaborngrid
        self.subplot = subplot_spec
        if isinstance(self.sg, sns.axisgrid.FacetGrid) or \
            isinstance(self.sg, sns.axisgrid.PairGrid):
            self._movegrid()
        elif isinstance(self.sg, sns.axisgrid.JointGrid):
            self._movejointgrid()
        self._finalize()

    def _movegrid(self):
        """ Move PairGrid or Facetgrid """
        self._resize()
        n = self.sg.axes.shape[0]
        m = self.sg.axes.shape[1]
        self.subgrid = gridspec.GridSpecFromSubplotSpec(n,m, subplot_spec=self.subplot)
        for i in range(n):
            for j in range(m):
                self._moveaxes(self.sg.axes[i,j], self.subgrid[i,j])

    def _movejointgrid(self):
        """ Move Jointgrid """
        h= self.sg.ax_joint.get_position().height
        h2= self.sg.ax_marg_x.get_position().height
        r = int(np.round(h/h2))
        self._resize()
        self.subgrid = gridspec.GridSpecFromSubplotSpec(r+1,r+1, subplot_spec=self.subplot)

        self._moveaxes(self.sg.ax_joint, self.subgrid[1:, :-1])
        self._moveaxes(self.sg.ax_marg_x, self.subgrid[0, :-1])
        self._moveaxes(self.sg.ax_marg_y, self.subgrid[1:, -1])

    def _moveaxes(self, ax, gs):
        #https://stackoverflow.com/a/46906599/4124317
        ax.remove()
        ax.figure=self.fig
        self.fig.axes.append(ax)
        self.fig.add_axes(ax)
        ax._subplotspec = gs
        ax.set_position(gs.get_position(self.fig))
        ax.set_subplotspec(gs)

    def _finalize(self):
        plt.close(self.sg.fig)
        self.fig.canvas.mpl_connect("resize_event", self._resize)
        self.fig.canvas.draw()

    def _resize(self, evt=None):
        self.sg.fig.set_size_inches(self.fig.get_size_inches())

该类的用法如下:

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import seaborn as sns; sns.set()
import SeabornFig2Grid as sfg


iris = sns.load_dataset("iris")
tips = sns.load_dataset("tips")

# An lmplot
g0 = sns.lmplot(x="total_bill", y="tip", hue="smoker", data=tips, 
                palette=dict(Yes="g", No="m"))
# A PairGrid
g1 = sns.PairGrid(iris, hue="species")
g1.map(plt.scatter, s=5)
# A FacetGrid
g2 = sns.FacetGrid(tips, col="time",  hue="smoker")
g2.map(plt.scatter, "total_bill", "tip", edgecolor="w")
# A JointGrid
g3 = sns.jointplot("sepal_width", "petal_length", data=iris,
                   kind="kde", space=0, color="g")


fig = plt.figure(figsize=(13,8))
gs = gridspec.GridSpec(2, 2)

mg0 = sfg.SeabornFig2Grid(g0, fig, gs[0])
mg1 = sfg.SeabornFig2Grid(g1, fig, gs[1])
mg2 = sfg.SeabornFig2Grid(g2, fig, gs[3])
mg3 = sfg.SeabornFig2Grid(g3, fig, gs[2])

gs.tight_layout(fig)
#gs.update(top=0.7)

plt.show()

请注意,复制轴可能会有一些缺点,并且尚未对上述内容进行彻底的测试.

Note that there might be several drawbacks from copying axes and the above is not (yet) tested thoroughly.

这篇关于如何用多部分海洋图迭代填充matplotlib gridspec?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆