matplotlib - how to show entire scales in figure - matplotlib

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

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

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

adjust matplotlib subplot axis + labels after applying tight_layout

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

matplotlib messes up the X-axis if first or last y value is NaN/None. Is this normal?

After subplot.plot([1, 2, 3], [8, 9, 10]), subplot.axis() returns an x-axis that goes roughly from 1 to 3.
But after subplot.plot([1, 2, 3], [None, None, None]), x goes from 0 to 1.
After subplot.plot([1, 2, 3], [8, 9, None]), it goes from 1 to 2.
Is this normal? What should I do to get a correct chart in such a case? (for example, an empty chart spanning 1 to 3 if all None).
#!/usr/bin/env python3
import matplotlib
matplotlib.use("AGG")
import matplotlib.pyplot as plt
def create_plot(ydata):
fig = plt.figure()
subplot = fig.add_subplot(1, 1, 1)
subplot.scatter([1, 2, 3], ydata)
x1, x2, y1, y2 = subplot.axis()
print(f"X axis goes from {x1} to {x2} when ydata={ydata}")
create_plot([8, 9, 10])
create_plot([None, None, None])
create_plot([8, 9, None])
Yes, it's normal.
In case ax.plot([1, 2, 3], [None, None, None]) there is no data to plot, hence the axes does not autoscale and stays at the default [0,1] view limits.
In case ax.plot([1, 2, 3], [8, 9, None]), the only data to show are (1,8) and (2,9). Hence the x axis range is 1 to 2.
If you want to get the same x-axis limits with or without data, you can update the data limits
ax.update_datalim(np.c_[xdata,[0]*len(xdata)], updatey=False)
ax.autoscale()
Complete example:
import numpy as np
import matplotlib.pyplot as plt
def create_plot(ydata):
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
xdata = [1, 2, 3]
ax.scatter(xdata, ydata)
ax.update_datalim(np.c_[xdata,[0]*len(xdata)], updatey=False)
ax.autoscale()
x1, x2, y1, y2 = ax.axis()
print(f"X axis goes from {x1} to {x2} when ydata={ydata}")
create_plot([8, 9, 10])
create_plot([None, None, None])
create_plot([8, 9, None])
plt.show()
IIUC, this is normal as plt will ignore None data. To change the limit, you could set the limit of xaxis:
def create_plot(ydata):
xvals = [1,2,3]
fig = plt.figure()
subplot = fig.add_subplot(1, 1, 1)
subplot.scatter(xvals, ydata)
# set the limit
subplot.set_xlim(min(xvals), max(xvals))
x1, x2, y1, y2 = subplot.axis()
print(f"X axis goes from {x1} to {x2} when ydata={ydata}")

Scatter plot in matplotlib not updating xlim and ylim

Given the below code I would expect the x-axis to be between 0 and 3 with some margins added.
Instead it is much larger. I would expect the call to scatter to automatically update x-axis limits.
I could set the xlim and ylim my self but would like them to be set automatically. What am I doing wrong?
import matplotlib.pyplot as plt
if __name__ == '__main__':
fig = plt.figure()
ax = fig.add_subplot(111)
x = [0, 4000, 8000, 100000]
y = [0, 10, 100, 150]
ax.scatter(x, y)
x = [0, 1, 2, 3]
y = x
ax.clear()
ax.scatter(x, y)
plt.show()
You can clear the figure, and open a new subplot, than the axes will be adjusted as you wanted.
fig = plt.figure()
ax = fig.add_subplot(111)
x = [0, 4000, 8000, 100000]
y = [0, 10, 100, 150]
ax.scatter(x, y)
plt.clf()
ax = fig.add_subplot(111)
x = [0, 1, 2, 3]
y = x
ax.scatter(x, y)
plt.show()
Edit: In this version figure is not closed, just cleared with the clf function.
It is a feature that scatter does not automatically re-limit the graph as in many cases that would be undesirable. See Axes.autoscale and Axes.relim
ax.relim() # might not be needed
ax.autoscale()
should do what you want.
Here is a way of making another scatter plot without needing to clear the figure.
I basically update offests of PathCollection returned by axes.scatter() and add the collection back to the axes. Of course, the axes has to be cleared first. One thing I notice is that I have to manually set the margins.
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
x = [0, 4000, 8000, 100000]
y = [0, 10, 100, 150]
scat = ax.scatter(x, y)
x = [0, 1, 2, 3]
y = x
ax.clear()
corners = (min(x), min(y)), (max(x), max(y))
ax.update_datalim(corners)
ax.margins(0.05, 0.05)
ax.autoscale_view()
scat.set_offsets(np.vstack((x,y)).transpose())
ax.add_collection(scat)
plt.show()
If you comment out the first scatter, everything will be fine