Reshape subplots on a Seaborn PairGrid - python

I really like the functionality of Seaborn's PairGrid. However, I haven't been able to reshape the subplots to my satisfaction. For instance, the code below will return a figure with 1 column and 2 rows, reflecting the 1 x-variable and 2 y-variables.
import seaborn as sns
tips = sns.load_dataset('tips')
g = sns.PairGrid(tips,y_vars=['tip','total_bill'],x_vars=['size'], hue='sex')
g.map(sns.regplot,x_jitter=.125)
However, it would be much preferable for me to re-orient this figure to have 2 columns and 1 row. It appears these subplots live within g.axes, but how do I pass them back to a plt.subplots(1,2) type of function?

PairGrid chooses this alignment because both plots have the same x axis. So the simplest way to get the plots in landscape would be to swap x and y:
import seaborn as sns
tips = sns.load_dataset('tips')
g = sns.PairGrid(tips,x_vars=['tip','total_bill'],y_vars=['size'], hue='sex')
g.map(sns.regplot,y_jitter=.125)
(Note that you also have to change x_jitter to y_jitter to get the same result.)
If you don't want to do that, then I think PairGrid is not the right tool for you. You can also just use two subplots and create the plots using sns.regplot:
import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset('tips')
male = tips[tips.sex=='Male']
female = tips[tips.sex=='Female']
with sns.color_palette(n_colors=2):
fig, axs = plt.subplots(1,2)
sns.regplot(x='size', y='tip', data=male, x_jitter=.125, ax=axs[0])
sns.regplot(x='size', y='tip', data=female, x_jitter=.125, ax=axs[0])
sns.regplot(x='size', y='total_bill', data=male, x_jitter=.125, ax=axs[1])
sns.regplot(x='size', y='total_bill', data=female, x_jitter=.125, ax=axs[1])

Related

Subplot with two panels (plot and pie)

I would like to merge two graphs or panels using subplot. I tried using thisi script, but I didn't get that I would like. I have one plot and one pie. On the image, the plot should be to left and pie to right. How can I do?
import matplotlib.pyplot as plt
import seaborn as sns
fig1, ax1 = plt.subplots()
#pie
plt.subplot(2,1,1)
sns.countplot(df['data_si_o_no'])
#pie
ax1.pie(df['data_si_o_no'].value_counts(),
labels=['Not Disaster', 'Disaster'],
autopct='%1.2f%%',
shadow=True,
explode=(0.05, 0),
startangle=60)
fig1.suptitle('Distribution of the data', fontsize=24)
plt.subplot(2,2,1)
Few things to note:
To plot 2 subplots next to each other, the subplots should be 1,2 as that represents the # rows, # columns.
The ax1 will be broken into ax1[0], ax1[1] for the two plots. I have just used ax instead of ax1
As you are using seaborn for one of the count plot, you need to define ax=ax[0] while providing the parameters, so that matplotlib knows it is the first plot.
For the matplotlib pie plot/chart, you need to use ax[1]=..
With these changes, you should be able to see the required plots. Note that, as there was no data provided, I used dummy data (Female/Male) from Titanic dataset instead.
Code
import matplotlib.pyplot as plt
import seaborn as sns
fig1, ax = plt.subplots(1,2, figsize=(10,5)) # 1 row, 2 columns
#pie
sns.countplot(df['data_si_o_no'], ax=ax[0])
#pie
ax[1]=plt.pie(df['data_si_o_no'].value_counts(),
labels=['male', 'female'],
autopct='%1.2f%%',
shadow=True,
explode=(0.05, 0),
startangle=60)
fig1.suptitle('Distribution of the data', fontsize=24)
Plot

Make width of seaborn facets proportional to the range of data along the x axis

I have used FacetGrid() from the seaborn module to break a line graph into segments with labels for each region as the title of each subplot. I saw the option in the documentation to have the x-axes be independent. However, I could not find anything related to having the plot sizes correspond to the size of each axis.
The code I used to generate this plot, along with the plot, are found below.
import matplotlib.pyplot as plt
import seaborn as sns
# Added during Edit 1.
sns.set()
graph = sns.FacetGrid(rmsf_crys, col = "Subunit", sharex = False)
graph.map(plt.plot, "Seq", "RMSF")
graph.set_titles(col_template = '{col_name}')
plt.show()
Plot resulting from the above code
Edit 1
Updated plot code using relplot() instead of calling FacetGrid() directly. The final result is the same graph.
import matplotlib.pyplot as plt
import seaborn as sns
# Forgot to include this in the original code snippet.
sns.set()
graph = sns.relplot(data = rmsf_crys, x = "Seq", y = "RMSF",
col = "Subunit", kind = "line",
facet_kws = dict(sharex=False))
graph.set_titles(col_template = '{col_name}')
plt.show()
Full support for this would need to live at the matplotlib layer, and I don't believe it's currently possible to have independent axes but shared transforms. (Someone with deeper knowledge of the matplotlib scale internals may prove me wrong).
But you can get pretty close by calculating the x range you'll need ahead of time and using that to parameterize the gridspec for the facets:
import numpy as np, seaborn as sns
tips = sns.load_dataset("tips")
xranges = tips.groupby("size")["total_bill"].agg(np.ptp)
xranges *= 1.1 # Account for default margins
sns.relplot(
data=tips, kind="line",
x="total_bill", y="tip",
col="size", col_order=xranges.index,
height=3, aspect=.65,
facet_kws=dict(sharex=False, gridspec_kws=dict(width_ratios=xranges))
)

Set axis limits across faceted plot

How can I fix the x-axis on each of the plots in the following situation? Using xlim only affects the second plot axis, not both.
import pandas as pd
import matplotlib.pyplot as plt
sample = pd.DataFrame({'mean':[1,2,3,4,5], 'median':[10,20,30,40,50]})
sample.hist()
plt.xlim(0, 100)
Bonus, what is the correct pandas terminology for the two plots here? Subplots? Facets?
The correct terminology would be subplot or axes since hist returns the matplotlib axis instances:
axes = sample.hist()
for ax in axes.ravel():
ax.set_xlim(0,100)
Output:

Seaborn: how to make subplots with multiple line charts? sns.relplot doesn't seem to support it? [duplicate]

This question already has an answer here:
seaborn is not plotting within defined subplots
(1 answer)
Closed 1 year ago.
The seaborn documentation makes a distinction between figure-level and axes-level functions: https://seaborn.pydata.org/introduction.html#figure-level-and-axes-level-functions
I understand that functions like sns.boxplot can take an axis as argument, and can therefore be used within subplots.
But how about sns.relplot() ? Is there no way to put that into subplots?
More generally, is there any way to get seaborn to generate line plots within subplots?
For example, this doesn't work:
fig,ax=plt.subplots(2)
sns.relplot(x,y, ax=ax[0])
because relplot doesn't take axes as an argument.
Well that's not true. You can indeed pass axis objects to relplot. Below is a minimal answer. The key point here is to close the empty axis objects returned by relplot. You can then also use ax[0] or ax[1] to add additional curves to your individual subfigures just like you would do with matplotlib.
import seaborn as sns
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2)
xdata = np.arange(50)
sns.set(style="ticks")
tips = sns.load_dataset("tips")
g1 = sns.relplot(x="total_bill", y="tip", hue="day", data=tips, ax=ax[0])
g2 = sns.relplot(x="total_bill", y="tip", hue="day", data=tips, ax=ax[1])
# Now you can add any curves to individual axis objects
ax[0].plot(xdata, xdata/5)
# You will have to close the additional empty figures returned by replot
plt.close(g1.fig)
plt.close(g2.fig)
plt.tight_layout()
You can also make line plot solely using seaborn as
import seaborn as sns
import numpy as np
x = np.linspace(0, 5, 100)
y = x**2
ax = sns.lineplot(x, y)
ax.set_xlabel('x-label')
ax.set_ylabel('y-label')

How to change the figure size of a seaborn axes or figure level plot

How do I change the size of my image so it's suitable for printing?
For example, I'd like to use to A4 paper, whose dimensions are 11.7 inches by 8.27 inches in landscape orientation.
You can also set figure size by passing dictionary to rc parameter with key 'figure.figsize' in seaborn set method:
import seaborn as sns
sns.set(rc={'figure.figsize':(11.7,8.27)})
Other alternative may be to use figure.figsize of rcParams to set figure size as below:
from matplotlib import rcParams
# figure size in inches
rcParams['figure.figsize'] = 11.7,8.27
More details can be found in matplotlib documentation
You need to create the matplotlib Figure and Axes objects ahead of time, specifying how big the figure is:
from matplotlib import pyplot
import seaborn
import mylib
a4_dims = (11.7, 8.27)
df = mylib.load_data()
fig, ax = pyplot.subplots(figsize=a4_dims)
seaborn.violinplot(ax=ax, data=df, **violin_options)
Note that if you are trying to pass to a "figure level" method in seaborn (for example lmplot, catplot / factorplot, jointplot) you can and should specify this within the arguments using height and aspect.
sns.catplot(data=df, x='xvar', y='yvar',
hue='hue_bar', height=8.27, aspect=11.7/8.27)
See https://github.com/mwaskom/seaborn/issues/488 and Plotting with seaborn using the matplotlib object-oriented interface for more details on the fact that figure level methods do not obey axes specifications.
first import matplotlib and use it to set the size of the figure
from matplotlib import pyplot as plt
import seaborn as sns
plt.figure(figsize=(15,8))
ax = sns.barplot(x="Word", y="Frequency", data=boxdata)
You can set the context to be poster or manually set fig_size.
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
np.random.seed(0)
n, p = 40, 8
d = np.random.normal(0, 2, (n, p))
d += np.log(np.arange(1, p + 1)) * -5 + 10
# plot
sns.set_style('ticks')
fig, ax = plt.subplots()
# the size of A4 paper
fig.set_size_inches(11.7, 8.27)
sns.violinplot(data=d, inner="points", ax=ax)
sns.despine()
fig.savefig('example.png')
This can be done using:
plt.figure(figsize=(15,8))
sns.kdeplot(data,shade=True)
In addition to elz answer regarding "figure level" methods that return multi-plot grid objects it is possible to set the figure height and width explicitly (that is without using aspect ratio) using the following approach:
import seaborn as sns
g = sns.catplot(data=df, x='xvar', y='yvar', hue='hue_bar')
g.fig.set_figwidth(8.27)
g.fig.set_figheight(11.7)
This shall also work.
from matplotlib import pyplot as plt
import seaborn as sns
plt.figure(figsize=(15,16))
sns.countplot(data=yourdata, ...)
For my plot (a sns factorplot) the proposed answer didn't works fine.
Thus I use
plt.gcf().set_size_inches(11.7, 8.27)
Just after the plot with seaborn (so no need to pass an ax to seaborn or to change the rc settings).
See How to change the image size for seaborn.objects for a solution with the new seaborn.objects interface from seaborn v0.12, which is not the same as seaborn axes-level or figure-level plots.
Adjusting the size of the plot depends if the plot is a figure-level plot like seaborn.displot, or an axes-level plot like seaborn.histplot. This answer applies to any figure or axes level plots.
See the the seaborn API reference
seaborn is a high-level API for matplotlib, so seaborn works with matplotlib methods
Tested in python 3.8.12, matplotlib 3.4.3, seaborn 0.11.2
Imports and Data
import seaborn as sns
import matplotlib.pyplot as plt
# load data
df = sns.load_dataset('penguins')
sns.displot
The size of a figure-level plot can be adjusted with the height and/or aspect parameters
Additionally, the dpi of the figure can be set by accessing the fig object and using .set_dpi()
p = sns.displot(data=df, x='flipper_length_mm', stat='density', height=4, aspect=1.5)
p.fig.set_dpi(100)
Without p.fig.set_dpi(100)
With p.fig.set_dpi(100)
sns.histplot
The size of an axes-level plot can be adjusted with figsize and/or dpi
# create figure and axes
fig, ax = plt.subplots(figsize=(6, 5), dpi=100)
# plot to the existing fig, by using ax=ax
p = sns.histplot(data=df, x='flipper_length_mm', stat='density', ax=ax)
Without dpi=100
With dpi=100
# Sets the figure size temporarily but has to be set again the next plot
plt.figure(figsize=(18,18))
sns.barplot(x=housing.ocean_proximity, y=housing.median_house_value)
plt.show()
Some tried out ways:
import seaborn as sns
import matplotlib.pyplot as plt
ax, fig = plt.subplots(figsize=[15,7])
sns.boxplot(x="feature1", y="feature2",data=df) # where df would be your dataframe
or
import seaborn as sns
import matplotlib.pyplot as plt
plt.figure(figsize=[15,7])
sns.boxplot(x="feature1", y="feature2",data=df) # where df would be your dataframe
The top answers by Paul H and J. Li do not work for all types of seaborn figures. For the FacetGrid type (for instance sns.lmplot()), use the size and aspect parameter.
Size changes both the height and width, maintaining the aspect ratio.
Aspect only changes the width, keeping the height constant.
You can always get your desired size by playing with these two parameters.
Credit: https://stackoverflow.com/a/28765059/3901029

Categories

Resources