Fitting 3 subplots on the same figure - python

I am trying to plot 3 subplots on the same figure and for some reason the code I have is not working. The first two appear on the same figure, but the last one doesn't. Can someone help me out:
fig = plt.figure(0, figsize = (12,10))
fig.add_subplot(221)
bike_gender.plot(kind='bar',title='Trip Duration by Gender', figsize= (9,7))
bar_plot.set_ylabel('Trip duration')
bar_plot.set_xlabel('Gender')
bar_plot.xaxis.set_ticklabels(['Men', 'Women', 'Unknown'])
bar_plot.text (0, 400000, 'Men = 647,466', bbox=dict(facecolor='red', alpha=0.5))
bar_plot.text (1, 400000, 'Women = 202,136', bbox=dict(facecolor='red', alpha=0.5))
bar_plot.text (2, 400000, 'Unknown = 119,240', bbox=dict(facecolor='red', alpha=0.5))
fig.add_subplot(222)
labels = 'Subscriber \n (849,778)', 'Customer \n (119,064)'
pie_chart = bike_user.plot(kind='pie', title= 'Breakdown of usertype', labels = labels, autopct='%1.1f%%', figsize=(9,7))
fig.add_subplot(212)
frequencies.plot(kind='bar',color=['blue','yellow','green'], figsize=(12, 4), stacked=True)
plt.show()

An alternative way is to use gridspec
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
data = pd.DataFrame(np.random.rand(10,2))
gs = gridspec.GridSpec(2,2)
ax1=fig.add_subplot(gs[0,0])
ax2=fig.add_subplot(gs[0,1])
ax3=fig.add_subplot(gs[1,:])
data.plot(ax = ax1)
data.plot(ax = ax2)
data.plot(ax = ax3)
plt.show()

The last plot should actually appears on the figure, but behind the second one.
It's because your third subplot is in a grid whose shape differs from what you already use. You first 2 plots are on a 2x2 grid (add_subplot(22.)) while the last one is on a 2x1 grid (add_subplot(21.)).
As a quick fix, you can try for your last plot:
fig.add_subplot(223)
And it should work.
However, you seems to want to make plot with pandas and display them in a specific axes of a figure with subplots. To do so you should use:
fig, ax = plt.subplots(2,2, figsize=(12,10))
bike_gender.plot(kind="bar", ax=ax[0], title='Trip Duration by Gender')
bike_user.plot(kind='pie', ax=ax[1], title= 'Breakdown of usertype')
frequencies.plot(kind='bar', ax=ax[2], color=['blue','yellow','green'], stacked=True)
HTH

Related

How can I draw 2 subplots into same track?

As you can see I'm trying to draw line graphs which gets its data from the dataframe that I created. I want users to see these drawings in the same page. In other words I want to get it as a single output. How can I do it? Thanks.
import matplotlib.pyplot as plt
import pandas as pd
ax1 = plt.subplots(1,1, figsize=(15,5))
ax1 = df2['Su Seviyesi (m)'].plot(use_index= True)
ax1 = df2['KUYU KOTU (m)'].plot(use_index= True, label="KUYU KOTU")
plt.legend(ncol=3, loc="lower left")
ax1.set(xlabel='Tarih', ylabel='Su Seviyesi (m)')
ax1.get_ygridlines()
ax1.get_yticklines(minor=False)
ax2 = plt.subplots(1,1 ,figsize=(15,5))
ax2 = df2['NaHCO3'].plot(use_index= True, grid=True)
ax2 = df2['TA'].plot(use_index= True, grid=True)
ax2 = df2['Na2CO3'].plot(use_index= True, grid=True)
ax2.get_ygridlines()
ax2.get_yticklines(minor=False)
plt.legend(ncol=3, loc="upper right")
plt.grid()
Output :
Output Expectation :
This is what I think you are trying to do.
import matplotlib.pyplot as plt
import pandas as pd
# Note 1: Subplots returns axes objects, unlike `plt.subplot`
# which works more like the Matlab subplot command and needs
# to be called repeatedly to activate each axis
# Note 2: We need a figsize that is twice as high as one axis
# Note 3: For plots like this it helps to share an x axis
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(15,10), sharex=True)
# Note 4: Here I am passing through the target axis.
# No need to capture the output here
df2['Su Seviyesi (m)'].plot(ax=ax1, use_index=True)
df2['KUYU KOTU (m)'].plot(ax=ax1, use_index=True, label="KUYU KOTU")
ax1.legend(ncol=3, loc="lower left")
ax1.set(xlabel='Tarih', ylabel='Su Seviyesi (m)')
# Note 5: We can easily plot multiple lines with one call to .plot
# if we just select the right columns.
df2[['NaHCO3', 'TA', 'Na2CO3']].plot(ax=ax2, use_index=True, grid=True)
ax2.legend(ncol=3, loc="upper right")
I solved the problem like this. Thanks for your anwers.
import matplotlib.pyplot as plt
import pandas as pd
fig, (ax1, ax2) = plt.subplots(2, figsize=(15,10))
fig.suptitle('{} Kuyusu Verileri'.format(e1_string))
ax1.plot(df2['NUMUNE'], df2['Su Seviyesi (m)'], label= 'Su Seviyesi (m)')
ax1.plot(df2['NUMUNE'], df2['KUYU KOTU (m)'], label= 'KUYU KOTU (m)')
ax1.get_ygridlines()
ax1.get_yticklines(minor=False)
ax1.legend(loc="upper right")
ax1.grid()
ax2.plot(df2['NUMUNE'], df2['NaHCO3'], label = '% NaHCO3' )
ax2.plot(df2['NUMUNE'], df2['Na2CO3'], label = '% Na2CO3' )
ax2.plot(df2['NUMUNE'], df2['TA'], label = '% TA' )
ax2.get_ygridlines()
ax2.get_yticklines(minor=False)
ax2.legend(loc="upper right")
ax2.grid()

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

Histogram with Boxplot above in Python

Hi I wanted to draw a histogram with a boxplot appearing the top of the histogram showing the Q1,Q2 and Q3 as well as the outliers. Example phone is below. (I am using Python and Pandas)
I have checked several examples using matplotlib.pyplot but hardly came out with a good example. And I also wanted to have the histogram curve appearing like in the image below.
I also tried seaborn and it provided me the shape line along with the histogram but didnt find a way to incorporate with boxpot above it.
can anyone help me with this to have this on matplotlib.pyplot or using pyplot
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(style="ticks")
x = np.random.randn(100)
f, (ax_box, ax_hist) = plt.subplots(2, sharex=True,
gridspec_kw={"height_ratios": (.15, .85)})
sns.boxplot(x, ax=ax_box)
sns.distplot(x, ax=ax_hist)
ax_box.set(yticks=[])
sns.despine(ax=ax_hist)
sns.despine(ax=ax_box, left=True)
From seaborn v0.11.2, sns.distplot is deprecated. Use sns.histplot for axes-level plots instead.
np.random.seed(2022)
x = np.random.randn(100)
f, (ax_box, ax_hist) = plt.subplots(2, sharex=True, gridspec_kw={"height_ratios": (.15, .85)})
sns.boxplot(x=x, ax=ax_box)
sns.histplot(x=x, bins=12, kde=True, stat='density', ax=ax_hist)
ax_box.set(yticks=[])
sns.despine(ax=ax_hist)
sns.despine(ax=ax_box, left=True)
Solution using only matplotlib, just because:
# start the plot: 2 rows, because we want the boxplot on the first row
# and the hist on the second
fig, ax = plt.subplots(
2, figsize=(7, 5), sharex=True,
gridspec_kw={"height_ratios": (.3, .7)} # the boxplot gets 30% of the vertical space
)
# the boxplot
ax[0].boxplot(data, vert=False)
# removing borders
ax[0].spines['top'].set_visible(False)
ax[0].spines['right'].set_visible(False)
ax[0].spines['left'].set_visible(False)
# the histogram
ax[1].hist(data)
# and we are good to go
plt.show()
Expanding on the answer from #mwaskom, I made a little adaptable function.
import seaborn as sns
def histogram_boxplot(data, xlabel = None, title = None, font_scale=2, figsize=(9,8), bins = None):
""" Boxplot and histogram combined
data: 1-d data array
xlabel: xlabel
title: title
font_scale: the scale of the font (default 2)
figsize: size of fig (default (9,8))
bins: number of bins (default None / auto)
example use: histogram_boxplot(np.random.rand(100), bins = 20, title="Fancy plot")
"""
sns.set(font_scale=font_scale)
f2, (ax_box2, ax_hist2) = plt.subplots(2, sharex=True, gridspec_kw={"height_ratios": (.15, .85)}, figsize=figsize)
sns.boxplot(data, ax=ax_box2)
sns.distplot(data, ax=ax_hist2, bins=bins) if bins else sns.distplot(data, ax=ax_hist2)
if xlabel: ax_hist2.set(xlabel=xlabel)
if title: ax_box2.set(title=title)
plt.show()
histogram_boxplot(np.random.randn(100), bins = 20, title="Fancy plot", xlabel="Some values")
Image
def histogram_boxplot(feature, figsize=(15,10), bins=None):
f,(ax_box,ax_hist)=plt.subplots(nrows=2,sharex=True, gridspec_kw={'height_ratios':(.25,.75)},figsize=figsize)
sns.distplot(feature,kde=False,ax=ax_hist,bins=bins)
sns.boxplot(feature,ax=ax_box, color='Red')
ax_hist.axvline(np.mean(feature),color='g',linestyle='-')
ax_hist.axvline(np.median(feature),color='y',linestyle='--')

matplotlib: Remove subplot padding when adding tick labels

I have an issue where adding tick labels interferes with my given padding preference between subplots. What I want, is a tight_layout with no padding at all in between, but with some custom ticks along the x-axis. This snippet and resulting figures shows the issue:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig_names = ['fig1']
gs = gridspec.GridSpec(1, len(fig_names))
gs.update(hspace=0.0)
figs = dict()
for fig_name in fig_names:
figs[fig_name] = plt.figure(figsize=(3*len(fig_names),6))
for i in range(0,len(fig_names)):
ax = figs[fig_name].add_subplot(gs[i])
ax.plot([0,1],[0,1], 'r-')
if i != 0:
ax.set_yticks(list())
ax.set_yticklabels(list())
ax.set_xticks(list())
ax.set_xticklabels(list())
for name,fig in figs.items():
fig.text(0.5, 0.03, 'Common xlabel', ha='center', va='center')
gs.tight_layout(fig, h_pad=0.0, w_pad=0.0)
ax = fig.add_subplot(gs[len(fig_names)-1])
ax.legend(('Some plot'), loc=2)
plt.show()
By changing the corresponding lines into:
ax.set_xticks([0.5,1.0])
ax.set_xticklabels(['0.5','1.0'])
...unwanted padding is added to the graphs.
How can I customize the tick text so that the graph plots has no padding, regardless of what tick text I enter? The text may "overlap" with the next subplot.
Perhaps you could simply create the axes with plt.subplots:
import numpy as np
import matplotlib.pyplot as plt
fig, axs = plt.subplots(ncols=2, sharey=True)
for ax in axs:
ax.plot([0,1],[0,1], 'r-')
ax.set_xticks([0.5,1.0])
ax.set_xticklabels(['0.5','1.0'])
axs[-1].legend(('Some plot'), loc=2)
for ax in axs[1:]:
ax.yaxis.set_visible(False)
fig.subplots_adjust(wspace=0)
plt.show()

How to add a title to each subplot

I have one figure which contains many subplots.
fig = plt.figure(num=None, figsize=(26, 12), dpi=80, facecolor='w', edgecolor='k')
fig.canvas.set_window_title('Window Title')
# Returns the Axes instance
ax = fig.add_subplot(311)
ax2 = fig.add_subplot(312)
ax3 = fig.add_subplot(313)
How do I add titles to the subplots?
fig.suptitle adds a title to all graphs and although ax.set_title() exists, the latter does not add any title to my subplots.
Thank you for your help.
Edit:
Corrected typo about set_title(). Thanks Rutger Kassies
ax.title.set_text('My Plot Title') seems to work too.
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
ax1.title.set_text('First Plot')
ax2.title.set_text('Second Plot')
ax3.title.set_text('Third Plot')
ax4.title.set_text('Fourth Plot')
plt.show()
ax.set_title() should set the titles for separate subplots:
import matplotlib.pyplot as plt
if __name__ == "__main__":
data = [1, 2, 3, 4, 5]
fig = plt.figure()
fig.suptitle("Title for whole figure", fontsize=16)
ax = plt.subplot("211")
ax.set_title("Title for first plot")
ax.plot(data)
ax = plt.subplot("212")
ax.set_title("Title for second plot")
ax.plot(data)
plt.show()
Can you check if this code works for you? Maybe something overwrites them later?
A shorthand answer assuming
import matplotlib.pyplot as plt:
plt.gca().set_title('title')
as in:
plt.subplot(221)
plt.gca().set_title('title')
plt.subplot(222)
etc...
Then there is no need for superfluous variables.
If you want to make it shorter, you could write :
import matplotlib.pyplot as plt
for i in range(4):
plt.subplot(2,2,i+1).set_title(f'Subplot n°{i+1}')
plt.show()
It makes it maybe less clear but you don't need more lines or variables
A solution I tend to use more and more is this one:
import matplotlib.pyplot as plt
fig, axs = plt.subplots(2, 2) # 1
for i, ax in enumerate(axs.ravel()): # 2
ax.set_title("Plot #{}".format(i)) # 3
Create your arbitrary number of axes
axs.ravel() converts your 2-dim object to a 1-dim vector in row-major style
assigns the title to the current axis-object
fig, (ax1, ax2, ax3, ax4) = plt.subplots(nrows=1, ncols=4,figsize=(11, 7))
grid = plt.GridSpec(2, 2, wspace=0.2, hspace=0.5)
ax1 = plt.subplot(grid[0, 0])
ax2 = plt.subplot(grid[0, 1:])
ax3 = plt.subplot(grid[1, :1])
ax4 = plt.subplot(grid[1, 1:])
ax1.title.set_text('First Plot')
ax2.title.set_text('Second Plot')
ax3.title.set_text('Third Plot')
ax4.title.set_text('Fourth Plot')
plt.show()
In case you have multiple images and you want to loop though them and show them 1 by 1 along with titles - this is what you can do. No need to explicitly define ax1, ax2, etc.
The catch is you can define dynamic axes(ax) as in Line 1 of code
and you can set its title inside a loop.
The rows of 2D array is length (len) of axis(ax)
Each row has 2 items i.e. It is list within a list (Point No.2)
set_title can be used to set title, once the proper axes(ax) or subplot is selected.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2, figsize=(6, 8))
for i in range(len(ax)):
for j in range(len(ax[i])):
## ax[i,j].imshow(test_images_gr[0].reshape(28,28))
ax[i,j].set_title('Title-' + str(i) + str(j))
You are able to give every graph a different title and label by Iteration only.
titles = {221: 'First Plot', 222: 'Second Plot', 223: 'Third Plot', 224: 'Fourth Plot'}
fig = plt.figure()
for x in range(221,225):
ax = fig.add_subplot(x)
ax.title.set_text(titles.get(x))
plt.subplots_adjust(left=0.1,
bottom=0.1,
right=0.9,
top=0.9,
wspace=0.4,
hspace=0.4)
plt.show()
Output:
As of matplotlib 3.4.3, the Figure.add_subplot function supports kwargs with title as:
fig.add_subplot(311, title="first")
fig.add_subplot(312, title="second")
For completeness, the requested result can also be achieve without explicit reference to the figure axes as follows:
import matplotlib.pyplot as plt
plt.subplot(221)
plt.title("Title 1")
plt.subplot(222)
plt.title("Title 2")
plt.subplot(223)
plt.title("Title 3")
plt.subplot(224)
plt.title("Title 4")
Use plt.tight_layout() after the last plot if you have issues with overlapping labels.

Categories