How to build a multi-layer joint chest in a subtitle

I am having a problem placing a Seaborn Jointplot inside a multi- Jointplot subplot .

 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) 

Note that only part of the Jointplot fits inside the subheading, while the rest remains in the other two frames. I would like distributions to be inserted inside subplots .

Can anyone help with this?

+11
python matplotlib pandas seaborn
Jan 27 '16 at 16:05
source share
2 answers

This cannot be done without hacking. jointplot calls the JointGrid method, which in turn creates a new figure object each time it is called.

Therefore, the hack consists in making two sovlokalnye lines ( JG1 JG2 ), then make a new figure, and then transfer the axis objects from JG1 JG2 to the new created figure.

Finally, we adjust the sizes and positions of the subheadings in the new shape that we just created.

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

This is a hack, because now we use the private _axstack and _add_key , which may not remain the same as they are now in matplotlib future versions.

enter image description here

+16
Jan 27 '16 at 18:06
source share

Moving axes in matplotlib is not as easy as before in previous versions. Below is the current version of matplotlib.

As indicated in several places ( this question , also this question ), several teams from the sea belt automatically create their own figure. This is hardcoded in the marine code, so there is currently no way to produce such graphs in existing numbers. These are PairGrid , FacetGrid , JointGrid , pairplot , jointplot and lmplot .

There is a sea ​​fork that would allow the seatpost to be equipped with the appropriate classes so that the plot was created in a pre-existing figure. To use this, you need to copy axisgrid.py from the fork to the folder with sea transport. Note that this limitation is currently used for use with matplotlib 2.1 (possibly also 2.0).

An alternative would be to create a sea shore shape and copy the axes to another shape. The principle of this is shown in this answer and can be extended to Searborn stories. The implementation is a bit more complicated than I originally expected. Below is the SeabornFig2Grid class, which can be called using an instance of the north grid (returning any of the above commands), the matplotlib shape and a subplot_spec , which is the gridspec grid 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): #/questions/110685/matplotlib-can-i-create-axessubplot-objects-then-add-them-to-a-figure-instance/689918#689918 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()) 

Using this class will look like this:

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

enter image description here

Please note that there may be several drawbacks from the copy axes, and the above has not been fully tested.

+3
Dec 05 '17 at 23:44
source share



All Articles