How to make a title for this multi-axis matplotlib plot? - python

This function:
def plotGrid(ax, grid, text=''):
ax.imshow(grid, cmap=cmap, norm=Normalize(vmin=0, vmax=9))
ax.grid(True, which='both', color='lightgrey', linewidth=0.5)
ax.set_yticks([x-0.5 for x in range(1+len(grid))])
ax.set_xticks([x-0.5 for x in range(1+len(grid[0]))])
ax.set_xticklabels([])
ax.set_yticklabels([])
ax.set_title(text)
def plotTaskGrids(task):
nTrain = len(task['train'])
fig, ax = plt.subplots(2, nTrain, figsize=(3*nTrain, 3*2))
for i in range(nTrain):
plotGrid(ax[0, i], task['train'][i]['input'], 'train input')
plotGrid(ax[1, i], task['train'][i]['output'], 'train output')
plt.tight_layout()
plt.title('title')
plt.show()
displays this window:
I would like to replace Figure 1 in the window title with title, but plt.title('title') doesn't accomplish that, instead it changes one of the subtitles. What is the solution?

Perhaps you could try adding num="title" when calling plt.subplots?
fig, ax = plt.subplots(2, nTrain, figsize=(3*nTrain, 3*2), num="title")
This should get passed to the plt.figure call within the subplots call.

Related

How to have text placed onto negative y point in subplot

I want to plot some data I have (square wave signals) in a subplot but I want to remove the axis for better visualization. This results in not having a ylabel. I thought I could add a simple text() so I could manually insert the text I want, but I can't seem to be able to use negative values for the y axis (as I could without a subplot). The code I thought would work was:
fig, (ax1, ax2, ax3, ax4, ax5, ax6)= plt.subplots(6,1)
#plot
ax1.plot(PathClockGeneration_4.q2bar_x,PathClockGeneration_4.clk_y, linewidth=2, color='black')
ax2.plot(PathClockGeneration_4.q2bar_x,PathClockGeneration_4.clkbar_y, linewidth=2, color='black')
ax3.plot(PathClockGeneration_4.q2bar_x,PathClockGeneration_4.q1_y, linewidth=2, color='C0')
ax4.plot(PathClockGeneration_4.q2bar_x,PathClockGeneration_4.q2_y, linewidth=2, color='C1')
ax5.plot(PathClockGeneration_4.q2bar_x,PathClockGeneration_4.q1bar_y, linewidth=2, color='C2')
ax6.plot(PathClockGeneration_4.q2bar_x,PathClockGeneration_4.q2bar_y, linewidth=2, color='C3')
#axis
ax1.axis('off')
ax2.axis('off')
ax3.axis('off')
ax4.axis('off')
ax5.axis('off')
ax6.axis('off')
#text
ax1.text(-1.5, 2, 'MyText')
If i try the last line as ax1.text(0, 2, 'MyText') it works fine, but the placement of the text is not the one I want. I suppose this comes from the size my plot is allowed to have and I would need to change it, how to do so?
EDIT
This is what I obtain hiding the axis manually (which can allow me to insert a ylabel). This is what I really want as plot obtained from the coded posted above by commenting ax1.text(-1.5, 2, 'MyText')
You can use fig instead of the ax1 to place your text. The arguments 0.05, 0.6 are the x and y coordinates in relative scale. You can choose them as per your taste.
Complete answer
import numpy as np
import matplotlib.pyplot as plt
fig, (ax1, ax2, ax3, ax4, ax5, ax6) = plt.subplots(6,1)
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)
ax1.plot(x, y, linewidth=2, color='black')
ax2.plot(x, y, linewidth=2, color='black')
ax3.plot(x, y, linewidth=2, color='C0')
ax4.plot(x, y, linewidth=2, color='C1')
ax5.plot(x, y, linewidth=2, color='C2')
ax6.plot(x, y, linewidth=2, color='C3')
# Hiding axis
for ax in [ax1, ax2, ax3, ax4, ax5, ax6]:
ax.axis('off')
fig.text(0.05, 0.6, 'MyText', rotation=90, fontsize=20)
plt.show()

How to Return a MatPlotLib Figure with its corresponding Legend

I'm trying to define a function which returns a pre-styled figure with certain grid, style, width and other properties. However, when I return the fig and its axes, the legend is missing. Here's a simplified example:
def getfig():
plt.style.use('default')
fig, axs = plt.subplots(1, 1, figsize=(1,1), sharey=False)
if issubclass(type(axs),mpl.axes.SubplotBase):
axs=[axs]
for ax in axs:
ax.grid(color='grey', axis='both', linestyle='-.', linewidth=0.4)
ax.legend(loc=9, bbox_to_anchor=(0.5, -0.3), ncol=2)
return fig,axs
fig,axs=getfig()
axs[0].plot(range(10), label="label")
What am I missing?
Thanks!
UPDATE:
This is what I'm using so far but I think there really should be a way to force all future legends associated to a figure to have a certain style.
def fig_new(rows=1,columns=1,figsize=(1,1)):
plt.style.use('default')
fig, axs = plt.subplots(rows,columns, figsize=figsize, sharey=False)
if issubclass(type(axs),mpl.axes.SubplotBase):
axs=[axs]
for ax in axs:
ax.grid(color='grey', axis='both', linestyle='-.', linewidth=0.4)
return fig,axs
def fig_leg(fig):
for ax in fig.get_axes():
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.3), ncol=5)
fig,axs=fig_new()
axs[0].plot(range(10), label="label")
fig_leg(fig)
You need to call the legend after an artist with a label is plotted to the axes.
An option is to let the function return the arguments to use for the legend afterwards.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
def getfig():
plt.style.use('default')
fig, axs = plt.subplots(1, 1, figsize=(1,1), sharey=False)
if issubclass(type(axs),mpl.axes.SubplotBase):
axs=np.array([axs])
legendkw = []
for ax in axs:
ax.grid(color='grey', axis='both', linestyle='-.', linewidth=0.4)
legendkw.append(dict(loc=9, bbox_to_anchor=(0.5, -0.3), ncol=2))
return fig,axs,legendkw
fig,axs,kw=getfig()
axs[0].plot(range(10), label="label")
for i,ax in enumerate(axs.flat):
ax.legend(**kw[i])
plt.show()

How do I animate this graph so that the dot moves and the green line plots over a different range for each element in loop?

I am trying to make this animated so that the dot and the green line move due to the for loop. This code displays 3 different graphs one below the other. The middle graph has no animation section.
x =lag_range
count = 0
plt.ion()
fig, ax = plt.subplots()
for b in x:
plt.subplot(311)
plt.plot(x,pear_corr, color='b', linewidth=1.5, label ='Pearson')
plt.plot(x,spear_corr, color ='r', linewidth=1.5, label='Spearman')
plt.plot(x[count],pear_corr[count],'yo')
plt.legend()
axes = plt.gca()
plt.ylabel('Correlation coefficients')
plt.xlabel('Lag times /days')
axes.set_xlim([min(lag_list),last])
axes.set_ylim(-1,1)
plt.subplot(312)
plt.plot(x,pear_p_values, color='b', linewidth=1.5)
plt.plot(x,spear_p_values, color ='r', linewidth=1.5)
axes = plt.gca()
plt.ylabel('P values')
plt.xlabel('Lag times /days')
axes.set_xlim([min(lag_list),last])
plt.subplot(313)
ax1 = plt.subplot(313)
x_for_p = range(len(x_prices))
ax1.plot(x_for_p, x_prices, color ='grey', linewidth=1.5)
ax1.set_ylabel('Share price', color ='grey')
ax1.tick_params('y', colors='grey')
ax1.set_xlabel('Days')
axes = plt.gca()
axes.set_xlim([min(lag_list),(2*last)])
ax2 = ax1.twinx()
x_for_den = range(b,(b+len(x_prices)))
ax2.plot(x_for_den, y_planes, color='g', linewidth=1.5)
ax2.set_ylabel('Plane density', color='g')
ax2.tick_params('y', colors='g')
count += 1
plt.pause(2)
plt.draw()
cross_corr2_vis(prices, density_p3)
If you could share a working code or just definitions of variables pear_corr, spear_corr, etc., the following code might have not resulted in this simple animation:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
N_points = 1000
x = np.linspace(0,2.*np.pi,N_points)
y = np.sin(x)
fig, ax = plt.subplots()
ax.set_xlim([0,2.*np.pi])
ax.set_ylim([-1,1])
line, = ax.plot( [],[], lw=2, color='g')
sctr = ax.scatter([],[], s=100, color='r')
def animate(i):
line.set_ydata(y[:i+1]) # update
line.set_xdata(x[:i+1])
sctr.set_offsets((x[i],y[i]))
return line,sctr
ani = animation.FuncAnimation(fig, animate, N_points, interval=5, blit=True)
plt.show()

Python: Suplots with secondary-axis

I wrote the following code below to do the following graph:
fig, ax = plt.subplots(figsize=(8, 6))
ax.patch.set_facecolor('white')
ax.plot(df.index, df.X1.values, 'b',
label='NMA', linewidth=1.5)
ax.set_ylabel('Index')
ax2 = ax.twinx()
ax2.plot(df.index, df.Y.values, 'r--',
label='Rate', linewidth=1.5)
ax2.set_ylabel('Rate')
lines = ax.get_lines() + ax2.get_lines()
lgd = ax.legend(lines, [line.get_label() for line in lines],
loc='lower center', ncol=2, bbox_to_anchor=(0.5, -0.15),
frameon=False)
ax.set_title('Economic Rate and Index',
weight='bold')
for i in range(5):
plt.axvspan(Dates['Peak'][i], Dates['Trough'][i],
facecolor='grey', alpha=0.5)
plt.grid(False)
plt.savefig('C:\\test.pdf',
bbox_extra_artists=(lgd,), bbox_inches='tight')
I am having a hard time to reproduce this figure in a subplot (2X2). The only thing I would change in each of the subplots is the blue line (X1 in df... for X2, X3...). How can I have a 2X2 subplot of the above graph? Of Course I would only keep one legend at the bottom of the subplots. Thanks for the help.
The data is here and the "Dates" to reproduce the gray bars here.
This is how you could create a 2x2 raster with twinx each:
import matplotlib.pyplot as plt
fig, ((ax1a, ax2a), (ax3a, ax4a)) = plt.subplots(2, 2)
ax1b = ax1a.twinx()
ax2b = ax2a.twinx()
ax3b = ax3a.twinx()
ax4b = ax4a.twinx()
ax1a.set_ylabel('ax1a')
ax2a.set_ylabel('ax2a')
ax3a.set_ylabel('ax3a')
ax4a.set_ylabel('ax4a')
ax1b.set_ylabel('ax1b')
ax2b.set_ylabel('ax2b')
ax3b.set_ylabel('ax3b')
ax4b.set_ylabel('ax4b')
plt.tight_layout()
plt.show()
Result:

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