adjust matplotlib subplot axis + labels after applying tight_layout - matplotlib

I am creating this subplot using the grid. The code and output is given below. when I am trying to apply plt.tight_layout() function to adjust labels it did not work fine.
def annotate_axes(fig):
for i, ax in enumerate(fig.axes):
ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center")
ax.tick_params(labelbottom=False, labelleft=False)
ax.set_xlabel('Episode', fontsize=8)
ax.set_ylabel('LPS',fontsize=8)
ax.set_title("Learning Rate=0.9", fontsize=8)
fig = plt.figure()
ax1 = plt.subplot2grid((12, 8), (0, 0), colspan=4,rowspan=4)
ax2 = plt.subplot2grid((12, 8), (0, 4), colspan=4,rowspan=4)
ax3 = plt.subplot2grid((12, 8), (4, 1),rowspan=2,colspan=2)
ax4 = plt.subplot2grid((12, 8), (4, 5),rowspan=2,colspan=2)
ax5 = plt.subplot2grid((12, 8), (6, 2), colspan=4,rowspan=4)
ax6 = plt.subplot2grid((12, 8), (10, 0), colspan=2,rowspan=2)
annotate_axes(fig)
plt.tight_layout()
plt.savefig("Plot.png")
plt.show()

import matplotlib.pyplot as plt
def annotate_axes(fig):
for i, ax in enumerate(fig.axes):
ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center")
ax.tick_params(labelbottom=False, labelleft=False)
ax.set_xlabel('Episode', fontsize=8)
ax.set_ylabel('LPS',fontsize=8)
ax.set_title("Learning Rate=0.9", fontsize=8)
fig = plt.figure(constrained_layout=True)
gs = fig.add_gridspec(12, 8)
ax1 = fig.add_subplot(gs[0:4, 0:4])
ax2 = fig.add_subplot(gs[0:4, 4:8])
ax3 = fig.add_subplot(gs[4:6, 1:3])
ax4 = fig.add_subplot(gs[4:6, 5:7])
ax5 = fig.add_subplot(gs[6:10, 2:6])
ax6 = fig.add_subplot(gs[10:12, 0:2])
annotate_axes(fig)
plt.savefig("Plot.png")
plt.show()

Related

Subplots not taking arguments

I'm, trying to do a 3x9 subplots with a contourf from 3 lists, but when I plotted it it only apply the plot options (ylim, axis scaled, no axis tick) to the last plot, how can I instead apply to all the plots?
Furthermore all the plots results one on top of each other as illustrated in the pic below, how can I spaced them properly?
fig, axes = plt.subplots(3, 9)
for j in range(len(axes[0])):
levels = np.linspace(v_min, v_max, 21)
for i in range(1, 19, 2):
axes[0][j].contourf(V_avg[i], levels=levels, cmap=rgb_V)
np.linspace(v_min, v_max, 11)
for i in range(2, 20, 2):
axes[1][j].contourf(V_avg[i], levels=levels, cmap=rgb_V)
np.linspace(v_min, v_max, 11)
levels = np.linspace(v_min_d_avg, v_max_d_avg, 21)
for i in range(0, 9):
axes[2][j].contourf(V_avg_dud[i], levels=levels, cmap=rgb_D_V)
np.linspace(v_min_d_avg, v_max_d_avg, 11)
plt.xticks([])
plt.yticks([])
plt.axis('scaled')
plt.ylim([15, 90])
plt.savefig("aaa", dpi=300, bbox_inches='tight')
plt.show()
Thanks in advance.
You can use axes.flatten() to loop through the subplots.
Here is a simple example:
import numpy as np
import matplotlib.pyplot as plt
fig, axes = plt.subplots(3, 9, sharex=True, sharey=True)
for ax in axes.flatten():
x = np.random.randint(1, high=10, size=10)
y = np.random.randint(1, high=10, size=10)
ax.scatter(x, y)
plt.show()
Which produces this:
You don't give an example data set format, but here is an example where your data are in a dictionary:
# Build example dataset
keys = ["A", "B", "C", "D"]
data_dict = {}
for key in keys:
data_dict[key] = [
np.random.randint(1, high=10, size=10).tolist(),
np.random.randint(1, high=10, size=10).tolist(),
]
# Loop through dictionary for plotting
fig, axes = plt.subplots(2, 2, sharex=True, sharey=True)
axes = axes.flatten()
for index, (key, value) in enumerate(data_dict.items()):
x, y = value[0], value[1]
axes[index].scatter(x, y)
axes[index].set_title(key)
plt.show()

matplotlib - how to show entire scales in figure

Expected to see entire range of axis from -3 to 3 as the axes scales have been set to (-3, 3).
Please advise how I can show from -3 to 3 in both X and Y axes.
cowers = np.array([
[-3.0, -1.0],
[-3.0, -2.0],
[-2.0, -2.0],
[-3.0, -3.0]
])
cowers
fig, ax = plt.subplots()
ax.axis('equal')
ax.set_xticks(np.linspace(-3, 3, 7))
ax.set_yticks(np.linspace(-3, 3, 7))
ax.set_xlim(-3, 3)
ax.set_ylim(-3, 3)
ax.scatter(x=cowers[:, 0], y=cowers[:, 1])
ax.tick_params(axis='x', colors='red')
ax.tick_params(axis='y', colors='blue')
ax.grid()
Apparently the scale is automatically adjusted.
angle = np.linspace(0, 2 * np.pi, 100)
fig, ax = plt.subplots()
# For the same scaling
# https://matplotlib.org/stable/gallery/subplots_axes_and_figures/axis_equal_demo.html
ax.axis('equal')
ax.set_xticks(np.linspace(-3, 3, 7))
ax.set_yticks(np.linspace(-3, 3, 7))
ax.set_xlim(-3, 3)
ax.set_ylim(-3, 3)
ax.scatter(x=cowers[:, 0], y=cowers[:, 1])
ax.plot(2 * np.cos(angle), 2 * np.sin(angle))
ax.tick_params(axis='x', colors='red')
ax.tick_params(axis='y', colors='blue')
ax.grid()
Adding figsize parameter to plt.subplots() made the entire axis range showing up. However still not sure why it is required.
# fig, ax = plt.subplots()
fig, ax = plt.subplots(figsize=(6, 6))
ax.axis('equal')
ax.set_xticks(np.linspace(-3, 3, 7), minor=True)
ax.set_yticks(np.linspace(-3, 3, 7), minor=True)
ax.set_xlim(-3, 3)
ax.set_ylim(-3, 3)
ax.tick_params(axis='x', colors='red')
ax.tick_params(axis='y', colors='blue')
ax.scatter(x=cow[:, 0], y=cow[:, 1])
ax.grid()
ax.legend()

How to highlight selected panels in matplotlib? Tight layout ignored added patched

I want to highlight some panels of my figure, but the command tight_layout() will misalign the added rectangle with the aimed panel.
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
fig, axs = plt.subplots(3, 3, figsize=(5, 5), sharex=True, sharey=True,
gridspec_kw={'hspace': 0, 'wspace': 0})
axs = axs.flatten()
ax = axs[4]
chartBox = ax.get_position()
x0, y0, x1, y1, w, h = chartBox.x0, chartBox.y0, chartBox.x1, chartBox.y1, chartBox.width, chartBox.height
fig.patches.extend([plt.Rectangle((x0, y0),
w, h,
fc ='none',
transform=fig.transFigure,
figure=fig,
ec ='r',
lw = 4)])
plt.tight_layout()
plt.show()
mport matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
fig, axs = plt.subplots(3, 3, figsize=(5, 5), sharex=True, sharey=True,
gridspec_kw={'hspace': 0, 'wspace': 0})
ax = axs[1, 1]
fig.patches.extend([plt.Rectangle((0, 0),
1, 1,
fc ='none',
transform=ax.transAxes,
figure=fig,
ec ='r',
lw = 4)])
plt.show()
Gives you exactly what you want.
One of the solutions with minimum change of the above code is to provoke tight_layout() earlier than plotting the patch.
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
fig, axs = plt.subplots(3, 3, figsize=(5, 5), sharex=True, sharey=True,
gridspec_kw={'hspace': 0, 'wspace': 0})
axs = axs.flatten()
plt.tight_layout()
ax = axs[4]
chartBox = ax.get_position()
x0, y0, x1, y1, w, h = chartBox.x0, chartBox.y0, chartBox.x1, chartBox.y1, chartBox.width, chartBox.height
fig.patches.extend([plt.Rectangle((x0, y0),
w, h,
fc ='none',
transform=fig.transFigure,
figure=fig,
ec ='r',
lw = 4)])
plt.show()

PyPlot: hide axes but keep axis labels

I have the following code:
import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 4)
for n, ax in enumerate(axs):
ax.plot([1, 2], [1, 2])
ax.set_xticks([])
ax.set_yticks([])
ax.set_xlabel(n)
plt.show()
...which displays this:
What I want is to hide the black boxes but keep the labels. I've tried adding ax.set_axis_off() but that removes the labels as well:
How can I do this?
Just change the color of spines to None:
fig, axs = plt.subplots(1, 4)
for n, ax in enumerate(axs):
ax.plot([1, 2], [1, 2])
ax.set_xticks([])
ax.set_yticks([])
ax.set_xlabel(n)
plt.setp(ax.spines.values(), color=None)
plt.show()

Label is Missing from matplotlib legend

I'm plotting subplots with matplotlib and the legend does not show up for some plots.
In this example, the scatter plot legend does not show up.
import numpy as np
import matplotlib
from matplotlib import pyplot as plt
from matplotlib.legend_handler import HandlerLine2D
from matplotlib.patches import Rectangle, Circle
fig = plt.figure()
plt.cla()
plt.clf()
x = np.arange(5) + 1
y = np.full(5, 10)
fig, subplots = plt.subplots(2, sharex=False, sharey=False)
subplots[0].bar(x, y, color='r', alpha=0.5, label='a')
scat = subplots[0].scatter(x, y-1, color='g', label='c')
subplots[0].set_yscale('log')
subplots[1].bar(x, y, color='r', alpha=0.5, label='a')
x = [2, 3]
y = [4, 4]
subplots[1].bar(x, y, color='b', alpha=1, label='b')
subplots[1].set_yscale('log')
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), handler_map={scat: HandlerLine2D(numpoints=4)})
plt.show()
Here is what I tried as a workaround:
p1 = Rectangle((0, 0), 1, 1, fc="r", alpha=0.5)
p2 = Rectangle((0, 0), 1, 1, fc="b")
p3 = Circle((0, 0), 1, fc="g")
legend([p1, p2, p3], ['a', 'b', 'c'], loc='center left', bbox_to_anchor=(1, 0.5))
I really prefer to fix this without the workaround so if anyone knows how to fix it please let me know.
Also, an issue with the workaround is that the Circle object still appears as a bar on the legend.
plt.legend starts with a gca() (which returns the current axes):
# from pyplot.py:
def legend(*args, **kwargs):
ret = gca().legend(*args, **kwargs)
So calling plt.legend will only get you a legend on your last subplot. But it is also possible to call e.g. ax.legend(), or in your case subplots[0].legend(). Adding that to the end of your code gives me a legend for both subplots.
Sample:
for subplot in subplots:
subplot.legend(loc='center left', bbox_to_anchor=(1, 0.5))