How to use ax with Pandas and Matplotlib - python

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

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

Plots different columns of different dataframe in one plot as scatter plot

I am trying to plot different columns (longitude & latitude ) from different dataframes in one plot. But they are being plotted in different figures separately.
Here is the code I am using
fig,ax=plt.subplots()
cells_final.plot.scatter(x='lon',y='lat')
data_rupture.plot.scatter(x='Longitude',y='Latitude',color='red')
plt.show()
How can I plot this in one single figure?
Use the axes instance (ax) created by
fig, ax = plt.subplots()
And pass it as the ax parameter of pandas.DataFrame.plot,
fig,ax=plt.subplots()
cells_final.plot.scatter(x='lon',y='lat', ax=ax)
data_rupture.plot.scatter(x='Longitude',y='Latitude',color='red', ax=ax)
plt.show()
Or if you'd rather have the plots on different subplots in the same figure you can create multiple axes
fig, (ax1, ax2) = plt.subplots(1, 2)
cells_final.plot.scatter(x='lon',y='lat', ax=ax1)
data_rupture.plot.scatter(x='Longitude',y='Latitude',color='red', ax=ax2)
plt.show()
You need specify the axis:
fig,ax=plt.subplots(1,2, figsize=(12, 8))
cells_final.plot.scatter(x='lon',y='lat', ax=ax=[0])
data_rupture.plot.scatter(x='Longitude',y='Latitude',color='red', ax=ax[1])
plt.show()
Thanks #William Miller.......!

Is there a restriction on catplot with subplot?

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

ax.set_xlabel and ax.set_ylabel not working with pandas plot

I have found similar questions previously, but I haven't managed to find an answer that has worked for me.
I am plotting directly from my data frame and would like to label my axis. This is the code I am using:
fig,ax = plt.subplots()
ax = plt.gca()
ax.set_xlabel("Time (s)")
ax.set_ylabel("Normalised Vertical Acceleration")
data.plot(kind='line', x='time', y='accel_y', ax=ax)
The graph generated only has "cycle" as the x-axis label and no y-axis label. Is there something that I'm doing wrong? Or is there a better method?
Thanks in advance.
Edited answer: Based on your updated question
You don't need additionally ax = plt.gca(). Then, first plot the data and then set the axis labels
fig, ax = plt.subplots()
data.plot(kind='line', x='time', y='accel_y', ax=ax)
ax.set_xlabel("Time (s)")
ax.set_ylabel("Normalised Vertical Acceleration")
#Sheldore's answer didn't work for me.
Instead, we need to use the inbuild function parameter:
fig, ax = plt.subplots()
data.plot(kind='line', x='time', y='accel_y', ax=ax,
ylabel="Normalised Vertical Acceleration",
xlabel="Time (s)")
I would report this as a bug to Pandas, which might be version-specific.

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:

Categories