Is there a restriction on catplot with subplot? - python

Seaborn's catplot does not seem to be able to work with plt.subplots(). Am not sure whats the issue here but i dont seem to be able to put them side by side.
#Graph 1
plt.subplot(121)
sns.catplot(x="HouseStyle",y="SalePrice",data=df,kind="swarm")
#Graph 2
plt.subplot(122)
sns.catplot(x="LandContour",y="SalePrice",data=df,kind="swarm")
Output:

Catplot is a figure-level function whereas you cannot use axes. Try using stripplot instead.
fig, axs = plt.subplots (1, 2, figsize=(25, 15))
sns.stripplot(x='category_col', y='y_col_1', data=df, ax=axs[0])
sns.stripplot(x='category_col', y='y_col_2', data=df, ax=axs[1])

You need to pass the created axis to seaborn's catplot while plotting. Following is a sample answer demonstrating this. A couple of things
I would suggest using add_subplot to create subplots like yours
The catplot will still return an axis object which can be closed using plt.close() where the number inside the brackets correspond to the figure count. See this answer for more details on close()
Complete reproducible answer
import seaborn as sns
import matplotlib.pyplot as plt
exercise = sns.load_dataset("exercise")
fig = plt.figure()
ax1 = fig.add_subplot(121)
g = sns.catplot(x="time", y="pulse", hue="kind", data=exercise, ax=ax1) # pass ax1
ax2 = fig.add_subplot(122)
g = sns.catplot(x="time", y="pulse", hue="kind", data=exercise, ax=ax2) # pass ax2
plt.close(2)
plt.close(3)
plt.tight_layout()

Thank you Sheldore for giving an idea of using close(). I tried this way and it worked.
_, ax = plt.subplots(2, 3, figsize=(20,10))
for n, feat in enumerate(cat_feats):
sns.catplot(x='feat', kind='count', data=df, ax=ax[n//3][n%3])
plt.close()

Related

Plotting a boxplot and histogram side by side with seaborn

I'm trying to plot a simple box plot next to a simple histogram in the same figure using seaborn (0.11.2) and pandas (1.3.4) in a jupyter notebook (6.4.5).
I've tried multiple approaches with nothing working.
fig, ax = plt.subplots(1, 2)
sns.boxplot(x='rent', data=df, ax=ax[0])
sns.displot(x='rent', data=df, bins=50, ax=ax[1])
There is an extra plot or grid that gets put next to the boxplot, and this extra empty plot shows up any time I try to create multiple axes.
Changing:
fig, ax = plt.subplots(2)
Gets:
Again, that extra empty plot next to the boxplot, but this time below it.
Trying the following code:
fig, (axbox, axhist) = plt.subplots(1,2)
sns.boxplot(x='rent', data=df, ax=axbox)
sns.displot(x='rent', data=df, bins=50, ax=axhist)
Gets the same results.
Following the answer in this post, I try:
fig, axs = plt.subplots(ncols=2)
sns.boxplot(x='rent', data=df, ax=axs[0])
sns.displot(x='rent', data=df, bins-50, ax=axs[1])
results in the same thing:
If I just create the figure and then the plots underneath:
plt.figure()
sns.boxplot(x='rent', data=df)
sns.displot(x='rent', data=df, bins=50)
It just gives me the two plots on top of each other, which I assume is just making two different figures.
I'm not sure why that extra empty plot shows up next to the boxplot when I try to do multiple axes in seaborn.
If I use pyplot instead of seaborn, I can get it to work:
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5))
ax1.hist(df['rent'], bins=50)
ax2.boxplot(df['rent'])
Results in:
The closest I've come is to use seaborn only on the boxplot, and pyplot for the histogram:
plt.figure(figsize=(8, 5))
plt.subplot(1, 2, 1)
sns.boxplot(x='rent', data=df)
plt.subplot(1, 2, 2)
plt.hist(df['rent'], bins=50)
Results:
What am I missing? Why can't I get this to work with two seaborn plots on the same figure, side by side (1 row, 2 columns)?
Try this function:
def creating_box_hist(column, df):
# creating a figure composed of two matplotlib.Axes objects (ax_box and ax_hist)
f, (ax_box, ax_hist) = plt.subplots(2, sharex=True, gridspec_kw={"height_ratios": (.15, .85)})
# assigning a graph to each ax
sns.boxplot(df[column], ax=ax_box)
sns.histplot(data=df, x=column, ax=ax_hist)
# Remove x axis name for the boxplot
ax_box.set(xlabel='')
plt.show()

How to show seaborn plots next to each other? Using pyplot-style (not OO)?

I want show three plots with the same data but in different kinds of plots.
The following Code would show them one below the other:
plt.figure()
sns.displot(t['Age'], kind="kde", rug = True)
sns.displot(t['Age'], kind="hist", bins = 25)
sns.displot(t['Age'], kind="ecdf")
plt.show()
With pyplot plots and the none-OO style i could do something like this:
plt.figure(figsize=(12,4))
plt.subplot(131)
plt.hist(t['Age'], bins = 22)
plt.subplot(132)
plt.hist(t['Age'], bins = 33)
plt.subplot(133)
plt.hist(t['Age'], bins = int(t['Age'].max() - t['Age'].min()))
plt.show()
Which looks perfectly nice.
Here you can see
Why cant i just do this?
plt.figure(figsize=(12,4))
plt.subplot(131)
sns.displot(t['Age'], kind="kde", rug = True)
plt.subplot(132)
sns.displot(t['Age'], kind="hist", bins = 25)
plt.subplot(133)
sns.displot(t['Age'], kind="ecdf")
plt.show()
This looks terrible
How it looks... it seems like they are stuck in the left border
Is it possible to do that without this oo notation?
fig, (ax1, ax2, ax3) = plt.subplots(1,3)
sns.displot(..., ax=ax1)
sns.displot(..., ax=ax2)
...
okok, in consequence of a short but very enlightening study of the seaborn api i get to a conclusion:
displot() is very flexible and you can do many kinds of graphs, which have interestingly each its own functions.
you can do something like this:
plt.figure(figsize=(16,4))
plt.subplot(141)
sns.kdeplot(t['Age'])
plt.subplot(142)
sns.histplot(t['Age'])
plt.subplot(143)
sns.ecdfplot(t['Age'])
plt.subplot(144)
sns.rugplot(t['Age'])
plt.show()
to avoid OO-Style.
Result
But in this case its not that easy to get the rugplot andd the kde plot to the same axes. When you try:
plt.figure(figsize=(12,4))
plt.subplot(131)
sns.kdeplot(t['Age'])
plt.subplot(132)
sns.histplot(t['Age'])
plt.subplot(133)
sns.ecdfplot(t['Age'])
plt.subplot(131)
sns.rugplot(t['Age'])
plt.show()
You get this warning:
So you shouldnt use it because of this warning.
If you want to make it look beautiful you need more controol and OO-Style is probably best solution:
fig, axes = plt.subplots(1,3, figsize=(12,4))
sns.kdeplot(t['Age'], ax = axes[0])
sns.histplot(t['Age'], ax = axes[1])
sns.ecdfplot(t['Age'], ax = axes[2])
sns.rugplot(t['Age'], ax = axes[0])
plt.show()
Very nice

How to sharex and sharey axis in for loop

I'm trying to share the x-axis and y-axis of my sumplots, I've tried using the sharey and sharex several different ways but haven't gotten the correct result.
ax0 = plt.subplot(4,1,1)
for i in range(4):
plt.subplot(4,1,i+1,sharex = ax0)
plt.plot(wavelength[i],flux)
plt.xlim([-1000,1000])
plt.ylim([0,1.5])
plt.subplots_adjust(wspace=0, hspace=0)
plt.show()
If I understood you correctly, want to have four stacked plots, sharing the x-axis and the y-axis. This you can do with plt.subplots and the keywords sharex=True and sharey=True. See example below:
import numpy as np
import matplotlib.pyplot as plt
fig, axlist = plt.subplots(4, 1, sharex=True, sharey=True)
for ax in axlist:
ax.plot(np.random.random(100))
plt.show()

wrong y axis range using matplotlib subplots and seaborn

I'm playing with seaborn for the first time, trying to plot different columns of a pandas dataframe on different plots using matplotlib subplots. The simple code below produces the expected figure but the last plot does not have a proper y range (it seems linked to the full range of values in the dataframe).
Does anyone have an idea why this happens and how to prevent it? Thanks.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pds
import seaborn as sns
X = np.arange(0,10)
df = pds.DataFrame({'X': X, 'Y1': 4*X, 'Y2': X/2., 'Y3': X+3, 'Y4': X-7})
fig, axes = plt.subplots(ncols=2, nrows=2)
ax1, ax2, ax3, ax4 = axes.ravel()
sns.set(style="ticks")
sns.despine(fig=fig)
sns.regplot(x='X', y='Y1', data=df, fit_reg=False, ax=ax1)
sns.regplot(x='X', y='Y2', data=df, fit_reg=False, ax=ax2)
sns.regplot(x='X', y='Y3', data=df, fit_reg=False, ax=ax3)
sns.regplot(x='X', y='Y4', data=df, fit_reg=False, ax=ax4)
plt.show()
Update: I modified the above code with:
fig, axes = plt.subplots(ncols=2, nrows=3)
ax1, ax2, ax3, ax4, ax5, ax6 = axes.ravel()
If I plot data on any axis but the last one I obtain what I'm looking for:
Of course I don't want the empty frames. All plots present the data with a similar visual aspect.
When data is plotted on the last axis, it gets a y range that is too wide like in the first example. Only the last axis seems to have this problem. Any clue?
If you want the scales to be the same on all axes you could create subplots with this command:
fig, axes = plt.subplots(ncols=2, nrows=2, sharey=True, sharex=True)
Which will make all plots to share relevant axis:
If you want manually to change the limits of that particular ax, you could add this line at the end of plotting commands:
ax4.set_ylim(top=5)
# or for both limits like this:
# ax4.set_ylim([-2, 5])
Which will give something like this:

How to use ax with Pandas and Matplotlib

I have a very basic question. I am using a pandas dataframe to make this plot, but I want to add highlighting around certain dates.
In[122]:
df1_99.plot(x='date', y='units', ylim=[0,11], figsize=[12,12])
Out[122]:
I found this code on stackoverflow to add highlighting.
fig, ax = plt.subplots()
ax.plot_date(t, y, 'b-')
ax.axvspan(*mdates.datestr2num(['10/27/2011', '11/2/2011']), color='red', alpha=0.5)
fig.autofmt_xdate()
plt.show()
My question is how can I use ax.avxspan with my current code? Or do I need to convert my x='date', and y='units' to numpy arrays and use the format as in the code above?
pandas.DataFrame.plot will return the matplotlib AxesSubplot object.
ax = df1_99.plot(x='date', y='units', ylim=[0,11], figsize=[12,12])
ax.axvspan(*mdates.datestr2num(['10/27/2011', '11/2/2011']), color='red', alpha=0.5)
plt.show()
If you want to create an ax object in advance, you can pass it into plot as below
fig, ax = plt.subplots()
df1_99.plot(x='date', y='units', ylim=[0,11], figsize=[12,12], ax=ax)
ax.axvspan(*mdates.datestr2num(['10/27/2011', '11/2/2011']), color='red', alpha=0.5)
plt.show()
Finally, you can usually get the current figure and axes objects using the following functions
fig = plt.gcf()
ax = plt.gca()

Categories