Insert a pandas DataFrame plot into a matplotlib subplot - python

I have created a plot with 4 subplots and each subplot will show a different type of analyses on some infrasound data. This the code I have used to create the subplots:
gs = gridspec.GridSpec(2, 2, width_ratios=[1,1], height_ratios=[1,1])
ax1 = plt.subplot(gs[0])
ax2 = plt.subplot(gs[1])
ax3 = plt.subplot(gs[2])
ax4 = plt.subplot(gs[3])
So far I have been able to input what I have wanted into the subplots, but I want to be able to input a pandas DataFrame plot into ax3 and I can't seem to do it. I have already written the pandas program and was just going to insert it into the larger script so it was shown in the subplot.
This is the line of code that is used to plot the pandas DataFrame plot:
df.plot(subplots=True, sharey=True, ylim=(0,(y_max*1.5)))

When plotting using pandas.Dataframe.plot you can choose the Axes object you would like to plot to with the keyword argument ax as shown below:
gs = gridspec.GridSpec(2, 2, width_ratios=[1,1], height_ratios=[1,1])
ax1 = plt.subplot(gs[0])
ax2 = plt.subplot(gs[1])
ax3 = plt.subplot(gs[2])
ax4 = plt.subplot(gs[3])
# ...some other code that defines df...
df.plot(ax=ax3)
This will add your data to the ax3 object. Note that this will plot all of your columns into that one subplot, if you want one particular column then you could do df['my_col_name'].plot(ax=ax3).

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 do I remove labels from one axis in a subplot?

I am using Python 3.9 on MacOS. Shortly, I have to make a plot with 4 subplots, and they share axis. The code looks like this:
#take some data
gs = gridspec.GridSpec(2, 2, height_ratios = [3, 1])
ax0 = plt.subplot(gs[0])
#plot data, make legend, etc.
ax2 = plt.subplot(gs[2], sharex = ax0)
#plot data, make legend, etc.
#take more data
ax1 = plt.subplot(gs[1], sharey = ax0)
#plot data, make legend, etc.
ax3 = plt.subplot(gs[3], sharex = ax1, sharey = ax2)
#plot data, make legend, etc.
plt.show()
As you can see, some plots share an axis with each other. The problem is that on the x-axis everything is fine, while it is not on the y-axis (see picture). Getting to the point: how can I remove the numbers on the vertical axis of the right plot but not on the left? I've seen many posts in which the problem was solved with things like
ax.set_yticklabels([])
but that removes the numbers from the left plot as well.
Try this:
ax1.tick_params('y', labelleft=False)

Subplotting subplots

I am creating two plots using matplotlib, each of them is a subplot showing two metrics on the same axis.
I'm trying to run them so they show as two charts but in one graphic, so that when I save the graphic I see both plots. At the moment, running the second plot overwrites the first in memory so I can only ever save the second.
How can I plot them together?
My code is below.
plot1 = plt.figure()
fig,ax1 = plt.subplots()
ax1.plot(dfSat['time'],dfSat['wind_at_altitude'], 'b-', label = "speed", linewidth = 5.0)
plt.title('Wind Speeds - Saturday - {}'.format(windloc))
plt.xlabel('Time of day')
plt.ylabel('Wind speed (mph)')
ax1.plot(dfSat['time'],dfSat['gust_at_altitude'], 'r-', label = "gust", linewidth = 5.0)
plt.legend(loc="upper right")
ax1.text(0.05, 0.95, calcmeassat, transform=ax1.transAxes, fontsize=30,
verticalalignment='top')
plt.ylim((0,100))
plot2 = plt.figure()
fig,ax2 = plt.subplots()
ax2.plot(dfSun['time'],dfSun['wind_at_altitude'], 'b-', label = "speed", linewidth = 5.0)
plt.title('Wind Speeds - Sunday - {}'.format(windloc))
plt.xlabel('Time of day')
plt.ylabel('Wind speed (mph)')
ax2.plot(dfSun['time'],dfSun['gust_at_altitude'], 'r-', label = "gust", linewidth = 5.0)
plt.legend(loc="upper right")
ax2.text(0.05, 0.95, calcmeassun, transform=ax2.transAxes, fontsize=30,
verticalalignment='top')
plt.ylim((0,100))
As mentioned, in your case you only need one level of subplots, e.g., nrows=1, ncols=2.
However, in matplotlib 3.4+ there is such a thing as "subplotting subplots" called subfigures, which makes it easier to implement nested layouts, e.g.:
How to create row titles for subplots
How to share colorbars within some subplots
How to share xlabels within some subplots
Subplots
For your simpler use case, create 1x2 subplots with ax1 on the left and ax2 on the right:
# create 1x2 subplots
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(16, 4))
# plot saturdays on the left
dfSat.plot(ax=ax1, x='date', y='temp_min')
dfSat.plot(ax=ax1, x='date', y='temp_max')
ax1.set_ylim(-20, 50)
ax1.set_title('Saturdays')
# plot sundays on the right
dfSun.plot(ax=ax2, x='date', y='temp_min')
dfSun.plot(ax=ax2, x='date', y='temp_max')
ax2.set_ylim(-20, 50)
ax2.set_title('Sundays')
Subfigures
Say you want something more complicated like having the left side show 2012 with its own suptitle and right side to show 2015 with its own suptitle.
Create 1x2 subfigures (left subfig_l and right subfig_r) with 2x1 subplots on the left (top ax_lt and bottom ax_lb) and 2x1 subplots on the right (top ax_rt and bottom ax_rb):
# create 1x2 subfigures
fig = plt.figure(constrained_layout=True, figsize=(12, 5))
(subfig_l, subfig_r) = fig.subfigures(nrows=1, ncols=2, wspace=0.07)
# create top/box axes in left subfig
(ax_lt, ax_lb) = subfig_l.subplots(nrows=2, ncols=1)
# plot 2012 saturdays on left-top axes
dfSat12 = dfSat.loc[dfSat['date'].dt.year.eq(2012)]
dfSat12.plot(ax=ax_lt, x='date', y='temp_min')
dfSat12.plot(ax=ax_lt, x='date', y='temp_max')
ax_lt.set_ylim(-20, 50)
ax_lt.set_ylabel('Saturdays')
# plot 2012 sundays on left-top axes
dfSun12 = dfSun.loc[dfSun['date'].dt.year.eq(2012)]
dfSun12.plot(ax=ax_lb, x='date', y='temp_min')
dfSun12.plot(ax=ax_lb, x='date', y='temp_max')
ax_lb.set_ylim(-20, 50)
ax_lb.set_ylabel('Sundays')
# set suptitle for left subfig
subfig_l.suptitle('2012', size='x-large', weight='bold')
# create top/box axes in right subfig
(ax_rt, ax_rb) = subfig_r.subplots(nrows=2, ncols=1)
# plot 2015 saturdays on left-top axes
dfSat15 = dfSat.loc[dfSat['date'].dt.year.eq(2015)]
dfSat15.plot(ax=ax_rt, x='date', y='temp_min')
dfSat15.plot(ax=ax_rt, x='date', y='temp_max')
ax_rt.set_ylim(-20, 50)
ax_rt.set_ylabel('Saturdays')
# plot 2015 sundays on left-top axes
dfSun15 = dfSun.loc[dfSun['date'].dt.year.eq(2015)]
dfSun15.plot(ax=ax_rb, x='date', y='temp_min')
dfSun15.plot(ax=ax_rb, x='date', y='temp_max')
ax_rb.set_ylim(-20, 50)
ax_rb.set_ylabel('Sundays')
# set suptitle for right subfig
subfig_r.suptitle('2015', size='x-large', weight='bold')
Sample data for reference:
import pandas as pd
from vega_datasets import data
df = data.seattle_weather()
df['date'] = pd.to_datetime(df['date'])
dfSat = df.loc[df['date'].dt.weekday.eq(5)]
dfSun = df.loc[df['date'].dt.weekday.eq(6)]
It doesn't work like that. Subplots are what they are called; plots inside a main plot.
That means if you need two subplots; then you need one plot containing two subplots in it.
# figure object NOT plot object
# useful when you want only one plot NO subplots
fig = plt.figure()
# 2 subplots inside 1 plot
# 1 row, 2 columns
fig, [ax1, ax2] = plt.subplots(1, 2)
# then call plotting method on each axis object to
# create plot on that subplot
sns.histplot(...., ax=ax1)
sns.violinplot(..., ax=ax2)
# or using matplotlib like this
ax1.plot()
ax2.plot()
Learn more about subplots

how to create multiple one plot that contains all my plots

fig = plt.figure()
ax = fig.add_subplot(111)
scatter = ax.scatter(wh1['area'],wh1['rain'],
c=kmeans[0],s=50)
ax.set_title('K-Means Clustering')
ax.set_xlabel('area')
ax.set_ylabel('rain')
plt.colorbar(scatter)
fig = plt.figure()
ax1 = fig.add_subplot(111)
scatter = ax.scatter(wh1['area'],wh1['wind'],
c=kmeans[0],s=50)
ax1.set_title('K-Means Clustering')
ax1.set_xlabel('area')
ax1.set_ylabel('wind')
plt.colorbar(scatter)
plot.show()
this code creates two separate plots, i want to create one plot that contains both of these.i left an image of how the plots appear. Help would be appreciated, thanks
a suggested solution was to avoid plotting twice and using subplots instead, but this causes the 2 graphs to bisect each other any suggested fixes?
fig = plt.figure()
ax = fig.add_subplot(121)
scatter = ax.scatter(wh1['area'],wh1['rain'],
c=kmeans[0],s=50)
ax.set_title('K-Means Clustering')
ax.set_xlabel('area')
ax.set_ylabel('rain')
plt.colorbar(scatter)
ax1 = fig.add_subplot(122)
scatter = ax.scatter(wh1['area'],wh1['wind'],
c=kmeans[0],s=50)
ax1.set_title('K-Means Clustering')
ax1.set_xlabel('area')
ax1.set_ylabel('wind')
plt.colorbar(scatter)
You can use subplots. Instead of making different figures you can call add_subplot on the same figure.
You make a figure by the following code and get a handle to a figure:
fig = plt.figure()
Then you determine the number of rows and columns of plots inside that figure by a number that you pass to the add_subplot function. For example, if you want a layout of one row and two columns the first two digits in the argument is 12 and the third digit determines which cell:
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
So, your code will be like this:
fig = plt.figure()
ax = fig.add_subplot(121)
scatter = ax.scatter(wh1['area'],wh1['rain'],
c=kmeans[0],s=50)
ax.set_title('K-Means Clustering')
ax.set_xlabel('area')
ax.set_ylabel('rain')
plt.colorbar(scatter)
ax1 = fig.add_subplot(122)
scatter = ax1.scatter(wh1['area'],wh1['wind'],
c=kmeans[0],s=50)
ax1.set_title('K-Means Clustering')
ax1.set_xlabel('area')
ax1.set_ylabel('wind')
plt.colorbar(scatter)
plot.show()

Matplotlib several subplots and axes

I am trying to use matplotlib to plot several subplots, each with 2 y-axis (the values are completely different between the two curves, so I have to plot them in different y-axis)
To plot one graph with 2 y-axis I do:
fig, ax1 = plt.subplots(figsize=(16, 10))
ax2 = ax1.twinx()
ax1.plot(line1, 'r')
ax2.plot(line2, 'g')
To plot 2 subplots, one with each curve I do:
plt.subplot(2,1,1)
plt.plot(line1, 'r')
plt.subplot(2,1,2)
plt.plot(line2, 'g')
I can't manage to merge the two methods.
I wanted something like:
fig, ax1 = plt.subplots(figsize=(16, 10))
plt.subplot(2,1,1)
ax2 = ax1.twinx()
ax1.plot(line1, 'r')
ax2.plot(line2, 'g')
plt.subplot(2,1,2)
ax1.plot(line3, 'r')
ax2.plot(line4, 'g')
But this doesn't work, it just shows 2 empty subplots.
How can I do this?
You should create your subplots first, then twin the axes for each subplot. It is easier to use the methods contained in the axis object to do the plotting, rather than the high level plot function calls.
The axes returned by subplots is an array of axes. If you have only 1 column or 1 row, it is a 1-D array, but if both are greater than 1 it is a 2-D array. In the later case, you need to either .ravel() the axes array or iterate over the rows and then axes in each row.
import numpy as np
import matplotlib.pyplot as plt
# create a figure with 4 subplot axes
fig, axes = plt.subplots(2,2, figsize=(8,8))
for ax_row in axes:
for ax in ax_row:
# create a twin of the axis that shares the x-axis
ax2 = ax.twinx()
# plot some data on each axis.
ax.plot(np.arange(50), np.random.randint(-10,10, size=50).cumsum())
ax2.plot(np.arange(50), 100+np.random.randint(-100,100, size=50).cumsum(), 'r-')
plt.tight_layout()
plt.show()

Categories