복붙노트

[PYTHON] Subplot에 여러 개의 Seaborn Jointplot을 그라인딩하는 방법

PYTHON

Subplot에 여러 개의 Seaborn Jointplot을 그라인딩하는 방법

Seaborn Jointplot을 다중 열 서브 플로트에 배치하는 데 문제가 있습니다.

import pandas as pd
import seaborn as sns

df = pd.DataFrame({'C1': {'a': 1,'b': 15,'c': 9,'d': 7,'e': 2,'f': 2,'g': 6,'h': 5,'k': 5,'l': 8},
          'C2': {'a': 6,'b': 18,'c': 13,'d': 8,'e': 6,'f': 6,'g': 8,'h': 9,'k': 13,'l': 15}})

fig = plt.figure();   
ax1 = fig.add_subplot(121);  
ax2 = fig.add_subplot(122);

sns.jointplot("C1", "C2", data=df, kind='reg', ax=ax1)
sns.jointplot("C1", "C2", data=df, kind='kde', ax=ax2)

조인트 플롯의 일부분 만이 서브 플롯 내부에 배치되고 나머지는 다른 두 플롯 프레임 안에 어떻게 남겨져 있는지 주목하십시오. 내가 원하는 것은 두 분포를 서브 플로트 안에 삽입하는 것입니다.

아무도 이것으로 도울 수 있습니까?

해결법

  1. ==============================

    1.해킹 없이는 쉽게 할 수 없습니다. jointplot은 JointGrid 메서드를 호출합니다.이 메서드는 호출 될 때마다 새 Figure 개체를 만듭니다.

    해킹 없이는 쉽게 할 수 없습니다. jointplot은 JointGrid 메서드를 호출합니다.이 메서드는 호출 될 때마다 새 Figure 개체를 만듭니다.

    따라서 해킹은 두 개의 조인트 플롯 (JG1 JG2)을 만든 다음 새 그림을 만든 다음 JG1 JG2에서 생성 된 새 그림으로 축 객체를 마이그레이션하는 것입니다.

    마지막으로, 방금 만든 새 그림에서 하위 그림의 크기와 위치를 조정합니다.

    JG1 = sns.jointplot("C1", "C2", data=df, kind='reg')
    JG2 = sns.jointplot("C1", "C2", data=df, kind='kde')
    
    #subplots migration
    f = plt.figure()
    for J in [JG1, JG2]:
        for A in J.fig.axes:
            f._axstack.add(f._make_key(A), A)
    
    #subplots size adjustment
    f.axes[0].set_position([0.05, 0.05, 0.4,  0.4])
    f.axes[1].set_position([0.05, 0.45, 0.4,  0.05])
    f.axes[2].set_position([0.45, 0.05, 0.05, 0.4])
    f.axes[3].set_position([0.55, 0.05, 0.4,  0.4])
    f.axes[4].set_position([0.55, 0.45, 0.4,  0.05])
    f.axes[5].set_position([0.95, 0.05, 0.05, 0.4])
    

    현재는 _axstack 및 _add_key private 메소드를 사용하고 있기 때문에 해킹입니다. matplotlib의 향후 버전과 동일하거나 동일하지 않을 수도 있습니다.

  2. ==============================

    2.이전 버전에서 사용했던 것처럼 matplotlib에서 축을 이동하는 것은 쉽지 않습니다. 아래는 현재 버전의 matplotlib로 작업하고 있습니다.

    이전 버전에서 사용했던 것처럼 matplotlib에서 축을 이동하는 것은 쉽지 않습니다. 아래는 현재 버전의 matplotlib로 작업하고 있습니다.

    여러 장소 (이 질문,이 문제도)에서 지적 되었 듯이, 여러 가지 해상 지휘 명령은 자동으로 자신의 형상을 생성합니다. 이것은 해상 코드에 하드 코드되어 있으므로 현재는 기존 그림에 그러한 플롯을 생성 할 방법이 없습니다. PairGrid, FacetGrid, JointGrid, pairplot, jointplot 및 lmplot입니다.

    플롯이 기존 그림에 생성되도록 각 클래스에 서브 플롯 그리드를 제공 할 수있는 해상 포크 (seaborn fork)가 있습니다. 이것을 사용하려면 포크에서 seaborn 폴더로 axisgrid.py를 복사해야합니다. 이것은 현재 matplotlib 2.1 (2.0도 가능)과 함께 사용하도록 제한되어 있습니다.

    다른 방법으로는 해골 그림을 만들고 축을 다른 그림으로 복사하는 것입니다. 이것의 원리는이 답변에 나와 있으며 Searborn 구획으로 확장 될 수 있습니다. 구현은 처음에 예상했던 것보다 조금 더 복잡합니다. 다음은 seaborn 그리드 인스턴스 (위 명령 중 하나의 반환), matplotlib 그림 및 gridspec 그리드의 위치 인 subplot_spec으로 호출 할 수있는 SeabornFig2Grid 클래스입니다.

    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()
    

    축 복사에서 몇 가지 단점이있을 수 있으며 위의 테스트는 철저히 테스트되지 않았습니다.

  3. from https://stackoverflow.com/questions/35042255/how-to-plot-multiple-seaborn-jointplot-in-subplot by cc-by-sa and MIT license