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.
Related
I can remove the ticks with
ax.set_xticks([])
ax.set_yticks([])
but this removes the labels as well. Any way I can plot the tick labels but not the ticks and the spine
You can set the tick length to 0 using tick_params (http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.tick_params):
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([1],[1])
ax.tick_params(axis=u'both', which=u'both',length=0)
plt.show()
Thanks for your answers #julien-spronck and #cmidi.
As a note, I had to use both methods to make it work:
import numpy as np
import matplotlib.pyplot as plt
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(11, 3))
data = np.random.random((4, 4))
ax1.imshow(data)
ax1.set(title='Bad', ylabel='$A_y$')
# plt.setp(ax1.get_xticklabels(), visible=False)
# plt.setp(ax1.get_yticklabels(), visible=False)
ax1.tick_params(axis='both', which='both', length=0)
ax2.imshow(data)
ax2.set(title='Somewhat OK', ylabel='$B_y$')
plt.setp(ax2.get_xticklabels(), visible=False)
plt.setp(ax2.get_yticklabels(), visible=False)
# ax2.tick_params(axis='both', which='both', length=0)
ax3.imshow(data)
ax3.set(title='Nice', ylabel='$C_y$')
plt.setp(ax3.get_xticklabels(), visible=False)
plt.setp(ax3.get_yticklabels(), visible=False)
ax3.tick_params(axis='both', which='both', length=0)
plt.show()
While attending a coursera course on Python, this was a question.
Below is the given solution, which I think is more readable and intuitive.
ax.tick_params(top=False,
bottom=False,
left=False,
right=False,
labelleft=True,
labelbottom=True)
This worked for me:
plt.tick_params(axis='both', labelsize=0, length = 0)
matplotlib.pyplot.setp(*args, **kwargs) is used to set properties of an artist object. You can use this in addition to get_xticklabels() to make it invisible.
something on the lines of the following
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(2,1,1)
ax.set_xlabel("X-Label",fontsize=10,color='red')
plt.setp(ax.get_xticklabels(),visible=False)
Below is the reference page
http://matplotlib.org/api/pyplot_api.html
You can set the yaxis and xaxis set_ticks_position properties so they just show on the left and bottom sides, respectively.
ax.yaxis.set_ticks_position('left')
ax.xaxis.set_ticks_position('bottom')
Furthermore, you can hide the spines as well by setting the set_visible property of the specific spine to False.
axes[i].spines['right'].set_visible(False)
axes[i].spines['top'].set_visible(False)
This Worked out pretty well for me! try it out
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
languages =['Python', 'SQL', 'Java', 'C++', 'JavaScript']
pos = np.arange(len(languages))
popularity = [56, 39, 34, 34, 29]
plt.bar(pos, popularity, align='center')
plt.xticks(pos, languages)
plt.ylabel('% Popularity')
plt.title('Top 5 Languages for Math & Data \nby % popularity on Stack Overflow',
alpha=0.8)
# remove all the ticks (both axes),
plt.tick_params(top='off', bottom='off', left='off', right='off', labelleft='off',
labelbottom='on')
plt.show()
Currently came across the same issue, solved as follows on version 3.3.3:
# My matplotlib ver: 3.3.3
ax.tick_params(tick1On=False) # "for left and bottom ticks"
ax.tick_params(tick2On=False) # "for right and top ticks, which are off by default"
Example:
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])
ax.tick_params(tick1On=False)
plt.show()
Output:
Assuming that you want to remove some ticks on the Y axes and only show the yticks that correspond to the ticks that have values higher than 0 you can do the following:
from import matplotlib.pyplot as plt
fig, ax = plt.subplots()
# yticks and yticks labels
yTicks = list(range(26))
yTicks = [yTick if yTick % 5 == 0 else 0 for yTick in yTicks]
yTickLabels = [str(yTick) if yTick % 5 == 0 else '' for yTick in yTicks]
Then you set up your axis object's Y axes as follow:
ax.yaxis.grid(True)
ax.set_yticks(yTicks)
ax.set_yticklabels(yTickLabels, fontsize=6)
fig.savefig('temp.png')
plt.close()
And you'll get a plot like this:
I have tried the following:
d = [1,2,3,4,5,6,7,8,9]
f = [0,1,0,0,1,0,1,1,0]
fig = plt.figure()
fig.set_size_inches(30,10)
ax1 = fig.add_subplot(211)
line1 = ax1.plot(d,marker='.',color='b',label="1 row")
ax2 = fig.add_subplot(212)
line1 = ax2.plot(f,marker='.',color='b',label="1 row")
ax1.grid()
ax2.grid()
plt.show()
I got the following output :
But I was expecting the following output:
How I can get the grids across the two plots?
There is no built-in option to create inter-subplot grids. In this case I'd say an easy option is to create a third axes in the background with the same grid in x direction, such that the gridline can be seen in between the two subplots.
import matplotlib.pyplot as plt
d = [1,2,3,4,5,6,7,8,9]
f = [0,1,0,0,1,0,1,1,0]
fig, (ax1,ax2) = plt.subplots(nrows=2, sharex=True)
ax3 = fig.add_subplot(111, zorder=-1)
for _, spine in ax3.spines.items():
spine.set_visible(False)
ax3.tick_params(labelleft=False, labelbottom=False, left=False, right=False )
ax3.get_shared_x_axes().join(ax3,ax1)
ax3.grid(axis="x")
line1 = ax1.plot(d, marker='.', color='b', label="1 row")
line1 = ax2.plot(f, marker='.', color='b', label="1 row")
ax1.grid()
ax2.grid()
plt.show()
Here is my solution:
import matplotlib.pyplot as plt
x1 = [1,2,3,4,5,6,7,8,9]
x2= [0,1,0,0,1,0,1,1,0]
x3= range(-10,0)
# frameon=False removes frames
# fig, (ax1,ax2, ax3) = plt.subplots(nrows=3, sharex=True, subplot_kw=dict(frameon=False))
fig, (ax1,ax2, ax3) = plt.subplots(nrows=3, sharex=True)
# remove vertical gap between subplots
plt.subplots_adjust(hspace=.0)
ax1.grid()
ax2.grid()
ax3.grid()
ax1.plot(x1)
ax2.plot(x2)
ax3.plot(x3)
Without frames subplot_kw=dict(frameon=False):
An option is to create a single plot then just offset the data. So one set plots above the other.
I'm new to programming and currently stuck on this: I create 4 different plots using a for loop and I want to assign each plot to a different subplot. Basically, I want 4 plots in a 2x2 grid so I can compare my data. Anyone knows how I can achieve this? My approach was to create a list of subplots and then assign every plot to a subplot using a nested plot:
import matplotlib.pyplot as plt
import numpy as np
def load_file(filename):
return np.loadtxt(filename, delimiter=',', usecols=(0, 1), unpack=True, skiprows=1)
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
ax_list=[ax1, ax2, ax3, ax4]
for i,filename in enumerate(file_list):
for p in ax_list:
x,y = load_file(filename)
plt.plot(x,y,
label=l, #I assign labels from a list beforehand, as well as colors
color=c,
linewidth=0.5,
ls='-',
)
p.plot()
The problem is, all plots are assigned to only one subplot and I don't know how to correct this. I'd appreciate any help!
I guess what you want is to show different data on all 4 plots, hence use a single loop. Make sure to use the axes plotting method, not plt.plot as the latter would always plot in the last subplot.
import matplotlib.pyplot as plt
import numpy as np
def load_file(filename):
return np.loadtxt(filename, delimiter=',', usecols=(0, 1), unpack=True, skiprows=1)
fig, ax_list = plt.subplots(2,2)
for i,(filename,ax) in enumerate(zip(file_list, ax_list.flatten())):
x,y = load_file(filename)
ax.plot(x,y, linewidth=0.5,ls='-' )
plt.show()
You don't need to loop over filenames and plots, only need to select the next plot in the list.
for i, filename in enumerate(file_list):
p = ax_list[i]:
x,y = load_file(filename)
p.plot(x, y,
label=l, #I assign labels from a list beforehand, as well as colors
color=c,
linewidth=0.5,
ls='-')
plt.plot()
You can also replace
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
ax_list=[ax1, ax2, ax3, ax4]
with just
fig, ax_list = plt.subplots(2, 2)
ax_list = ax_list.flatten()
To get a simple 2x2 grid.
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
This solution to another thread suggests using gridspec.GridSpec instead of plt.subplots. However, when I share axes between subplots, I usually use a syntax like the following
fig, axes = plt.subplots(N, 1, sharex='col', sharey=True, figsize=(3,18))
How can I specify sharex and sharey when I use GridSpec ?
First off, there's an easier workaround for your original problem, as long as you're okay with being slightly imprecise. Just reset the top extent of the subplots to the default after calling tight_layout:
fig, axes = plt.subplots(ncols=2, sharey=True)
plt.setp(axes, title='Test')
fig.suptitle('An overall title', size=20)
fig.tight_layout()
fig.subplots_adjust(top=0.9)
plt.show()
However, to answer your question, you'll need to create the subplots at a slightly lower level to use gridspec. If you want to replicate the hiding of shared axes like subplots does, you'll need to do that manually, by using the sharey argument to Figure.add_subplot and hiding the duplicated ticks with plt.setp(ax.get_yticklabels(), visible=False).
As an example:
import matplotlib.pyplot as plt
from matplotlib import gridspec
fig = plt.figure()
gs = gridspec.GridSpec(1,2)
ax1 = fig.add_subplot(gs[0])
ax2 = fig.add_subplot(gs[1], sharey=ax1)
plt.setp(ax2.get_yticklabels(), visible=False)
plt.setp([ax1, ax2], title='Test')
fig.suptitle('An overall title', size=20)
gs.tight_layout(fig, rect=[0, 0, 1, 0.97])
plt.show()
Both Joe's choices gave me some problems: the former, related with direct use of figure.tight_layout instead of figure.set_tight_layout() and, the latter, with some backends (UserWarning: tight_layout : falling back to Agg renderer). But Joe's answer definitely cleared my way toward another compact alternative. This is the result for a problem close to the OP's one:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=2, ncols=1, sharex='col', sharey=True,
gridspec_kw={'height_ratios': [2, 1]},
figsize=(4, 7))
fig.set_tight_layout({'rect': [0, 0, 1, 0.95], 'pad': 1.5, 'h_pad': 1.5})
plt.setp(axes, title='Test')
fig.suptitle('An overall title', size=20)
plt.show()
I made a function where you input a list or array of axes and it shares x or y along the rows and cols as specified. Not fully tested but here's the gist of it:
def share_axes(subplot_array, sharex, sharey, delete_row_ticklabels = 1, delete_col_ticklabels = 1):
shape = np.array(subplot_array).shape
if len(shape) == 1:
for i, ax in enumerate(subplot_array):
if sharex:
ax.get_shared_x_axes().join(ax, subplot_array[0])
if delete_row_ticklabels and not(i==len(subplot_array)-1):
ax.set_xticklabels([])
if sharey:
ax.get_shared_x_axes().join(ax, subplot_array[0])
if delete_col_ticklabels and not(i==0):
ax.set_yticklabels([])
elif len(shape) == 2:
for i in range(shape[0]):
for j in range(shape[1]):
ax = subplot_array[i,j]
if sharex in ('rows', 'both'):
ax.get_shared_x_axes().join(ax, subplot_array[-1,j])
if delete_row_ticklabels and not(i==shape[0]-1):
ax.set_xticklabels([])
if sharey in ('rows', 'both'):
ax.get_shared_y_axes().join(ax, subplot_array[-1,j])
if sharex in ('cols', 'both'):
ax.get_shared_x_axes().join(ax, subplot_array[i,0])
if sharey in ('cols', 'both'):
if delete_col_ticklabels and not(j==0):
ax.set_yticklabels([])
ax.get_shared_y_axes().join(ax, subplot_array[i,0])