what sns plots pairplot multiple library kdeplot factorgrid facetgrid python python-3.x pandas matplotlib seaborn

python - sns - Cómo trazar varias parcelas conjuntas Seaborn en subtrama



sns multiple plots (2)

Tengo problemas para colocar Seaborn Jointplot dentro de una subplot 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)

Observe cómo solo una parte de la jointplot se coloca dentro de la subtrama y el resto se deja dentro de otros dos marcos de trama. Lo que me gustaría es tener ambas distributions también insertadas dentro de las subplots .

¿Alguien puede ayudarme con esto?


No se puede hacer fácilmente sin piratear. jointplot llama JointGrid método JointGrid , que a su vez crea un nuevo objeto de figure cada vez que se llama.

Por lo tanto, el truco es hacer dos gráficos de unión ( JG1 JG2 ), luego hacer una nueva figura, luego migrar los objetos de los ejes de JG1 JG2 a la nueva figura creada.

Finalmente, ajustamos los tamaños y las posiciones de las subtramas en la nueva figura que acabamos de crear.

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

Es un truco porque ahora estamos utilizando los métodos privados _axstack y _add_key , que podrían y no seguir siendo los mismos que ahora están en futuras versiones de matplotlib .


Mover ejes en matplotlib no es tan fácil como solía ser en versiones anteriores. Lo siguiente funciona con la versión actual de matplotlib.

Como se ha señalado en varios lugares ( esta pregunta , también este problema ), varios de los comandos nacidos en el mar crean su propia figura automáticamente. Esto está codificado en el código marino, por lo que actualmente no hay forma de producir tales tramas en las figuras existentes. Esos son PairGrid , FacetGrid , JointGrid , pairplot , jointplot y lmplot .

Hay una bifurcación naciente disponible que permitiría suministrar una cuadrícula de subtrama a las clases respectivas de modo que la trama se cree en una figura preexistente. Para usar esto, necesitará copiar el axisgrid.py de la bifurcación a la carpeta naciente. Tenga en cuenta que actualmente está restringido para ser utilizado con matplotlib 2.1 (posiblemente también 2.0).

Una alternativa podría ser crear una figura marina y copiar los ejes a otra figura. El principio de esto se muestra en esta respuesta y podría extenderse a las parcelas de Searborn. La implementación es un poco más complicada de lo que inicialmente esperaba. La siguiente es una clase SeabornFig2Grid que se puede llamar con una instancia de cuadrícula nacida en el mar (el retorno de cualquiera de los comandos anteriores), una figura matplotlib y una subplot_spec , que es una posición de una cuadrícula gridspec .

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://.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())

El uso de esta clase se vería así:

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

Tenga en cuenta que puede haber varios inconvenientes al copiar ejes y lo anterior (todavía) no se ha probado exhaustivamente.