Let's see a contrived example of 2 matplotlib.pyplot functions returning a plot, which then may be accessed through plt.gcf() or plt.gca() methods:
x = np.linspace(-5, 5, 11)
y = x
y_2 = x * x
plt.plot(x,y)
fig_1 = plt.gcf()
ax_1 = plt.gca()
#plt.close()
plt.plot(x,y_2)
fig_2 = plt.gcf()
ax_2 = plt.gca()
#plt.close()
How would I nicely draw fig_1 and fig_2 objects alongside through e.g. plt.subplots(1,2) (given x, y, y_2 are not accessable)
Use the add_subplot method of the Figure object to draw the two plots alongside.
Try this:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-5, 5, 11)
y = x
y_2 = x * x
fig, axs = plt.subplots(1, 2) # create a figure with subplots
axs[0].plot(x, y) # first figure
axs[1].plot(x, y_2) # second figure
plt.show()
if no given given x, y, y_2:
fig, axs = plt.subplots(1, 2)
axs[0].plot(x, y)
axs[1].plot(x, y_2)
plt.show()
Related
I am trying to plot x vs y data and trying to see the variation of x and y with respect to z using a colorbar.
x = [1,2,3,4,5]
x_err = [0.1,0.2,0.3,0.4,0.5]
y = [5,6,7,8,9]
y_err = [0.5,0.6,0.7,0.8,0.9]
z = [3,4,5,6,7]
fig, ax = plt.subplots()
ax.errorbar(x, y, x_err, y_err, fmt='*', elinewidth = 0.9, ecolor='black')
scatter = ax.scatter(x, y, c=z, s=5)
cbar = fig.colorbar(scatter,cmap='viridis')
cbar.set_label('z')
I need the errorbar to have the same color as that of the datapoint.
You could compute the ecolor from the same cmap. Not sure there aren't any solution to do that for you, but it doesn't cost much
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
x = [1,2,3,4,5]
x_err = [0.1,0.2,0.3,0.4,0.5]
y = [5,6,7,8,9]
y_err = [0.5,0.6,0.7,0.8,0.9]
z = [3,4,5,6,7]
fig, ax = plt.subplots()
# Rest of your code is yours. Only this line is added (and next line modified to use this "col" as ecolor
col=cm.viridis((np.array(z)-min(z))/(max(z)-min(z))) # RGBA colors from z
ax.errorbar(x, y, x_err, y_err, ecolor=col, fmt='*', elinewidth = 0.9)
scatter = ax.scatter(x, y, c=z, s=5)
cbar = fig.colorbar(scatter,cmap='viridis')
cbar.set_label('z')
plt.show()
Result
I want to plot a curve over a background image with the x and y axis in logscale. However, when I try to do so, the image is stretched by the logscale. I obtain this figure
This is the code I wrote.
import numpy as np
import matplotlib.pyplot as plt
x = np.random.uniform(low=0, high=10**6, size=(100,))
y = np.random.uniform(low=10**(-14), high=10**(-10), size=(100,))
x.sort()
y.sort()
xm = len(x)
ym = len(y)
img = plt.imread("quiverplot.png")
fig, ax2 = plt.subplots()
plt.plot(x, y)
ax2.set_xscale('log')
ax2.set_yscale('log')
ax1 = ax2.twinx()
img = ax1.imshow(img, zorder=0, extent=[x[0], x[xm-1], y[0], y[ym-1]], aspect='auto')
fig.tight_layout()
plt.show()
Thanks for any advices you can give me.
Don't use twinx(), but create a new axes with matplotlib.pyplot.axes().
You can do like this controlling the frame(background), x/y axis, and z-order.
fig, ax2 = plt.subplots()
ax2.plot(x, y)
ax2.set_xscale('log')
ax2.set_yscale('log')
ax2.set_frame_on(False)
ax2.zorder = 1
ax1 = plt.axes(ax2.get_position(True))
ax1.set_frame_on(False)
ax1.set_axis_off()
ax1.imshow(img, extent=[x[0], x[xm-1], y[0], y[ym-1]], aspect='auto')
...
It will be simpler if you change the order of plotting like this.
fig, ax2 = plt.subplots()
ax2.imshow(img, extent=[x[0], x[xm-1], y[0], y[ym-1]], aspect='auto')
ax2.set_axis_off()
ax1 = plt.axes(ax2.get_position(True))
ax1.set_frame_on(False)
ax1.set_xscale('log')
ax1.set_yscale('log')
ax1.plot(x, y)
...
This question already has answers here:
show origin axis (x,y) in matplotlib plot
(3 answers)
Closed 2 years ago.
So I am working on a program that displays the graph of a function over an interval, and the plot size is automatically handled by matplotlib. The only thing is, it resizes without showing x=0 and y=0 cartesian axes. Everything I tried so far, like plt.subplot(), only affects the axes that show at the bottom and left, not the cartesian axes. Is there a way to add the axes in?
Here is some example code:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-2, 1, 100)
f = lambda x: x**2 - 1
plt.plot(x, f(x))
plt.show()
The graph that comes from this looks like this:
which does not show the cartesian axes. Is there a way to add this in, maybe by adding lines at x=0 and y=0?
You can set the spine axis to be in a custom position, like the origin:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-2,1,100)
y = x**2
fig, ax = plt.subplots(1, figsize=(6, 4))
ax.plot(x, y)
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.set(ylim=(-1, 4))
Otherwise, you can add a vertical and a horizontal line:
fig, ax = plt.subplots(1, figsize=(6, 4))
ax.plot(x, y)
ax.axhline(0, color='black')
ax.axvline(0, color='black')
You can do it by drawing arrows:
import matplotlib.pyplot as plt
import numpy as np
from pylab import *
x = np.linspace(-2, 1, 100)
f = lambda x: x**2 - 1
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_aspect('equal')
plt.plot(x, f(x))
l,r = ax.get_xlim()
lo,hi = ax.get_ylim()
arrow( l-1, 0, r-l+2, 0, length_includes_head = False, head_width = 0.2 )
arrow( 0, lo-1, 0, hi-lo+2, length_includes_head = True, head_width = 0.2 )
plt.show()
Hi I am trying to create:
horizontally stacked plots
Have secondary axis on both plots
Have different scales on axis - unfortunately, both my Y axis currently have the same scale per subplot... :(
Current code:
# Create axes
fig, (ax1, ax2) = plt.subplots(1, 2)
fig.suptitle("XYZ")
fig.set_figheight(5)
fig.set_figwidth(15)
# First graph
ax1.scatter(
df_PTA_clip_pstar["start_time"],
df_PTA_clip_pstar["pstar"],
s=5,
c="black",
label="P*",
)
plt.ylabel("P*")
ax1.scatter(df_PTA_clipkh["start_time"], df_PTA_clipkh["kh"], s=2, c="cyan", label="Kh")
ax1.secondary_yaxis("right")
plt.ylabel("Kh")
# Second graph - will add the correct data to this once first graph fixed
ax2.scatter(x, y, s=5, c="Red", label="P*")
ax2.scatter(x, z, s=5, c="Green", label="Kh")
ax2.secondary_yaxis("right")
plt.tight_layout()
plt.legend()
plt.show()
Current progress:
You can use .twinx() method on each ax object so you can have two plots on the same ax object sharing x-axis:
import matplotlib.pyplot as plt
import numpy as np
# Create axes
fig, (ax1, ax2) = plt.subplots(1, 2)
## First subplot
x = np.random.random_sample(100)
y = np.random.random_sample(100)
ax1.set_xlim(0, 2)
ax1.scatter(x, y,
s=5,
c="black")
ax11 = ax1.twinx()
x = 1 + x
y = 1 + np.random.random_sample(100)
ax11.scatter(x, y,
s=5,
c="red")
## Second subplot
x = 2 * np.random.random_sample(100) - 1
y = np.random.random_sample(100)
ax2.set_xlim(-1, 2)
ax2.scatter(x, y,
s=5,
c="blue")
ax21 = ax2.twinx()
x = 1 + x
y = 10 + np.random.random_sample(100)
ax21.scatter(x, y,
s=5,
c="orange")
plt.show()
In the reference, they are described as:
axis('equal')
changes limits of x or y axis so that equal increments of x and y have the same length; a circle is
circular.:
axis('scaled')
achieves the same result by changing the dimensions of the plot box instead of the axis data limits.:
But I did not understand the part 'by changing the dimensions of the plot box'.
So I compared directly
import numpy as np
import matplotlib.pyplot as plt
plt.close('all')
x = np.array(np.linspace(-np.pi, np.pi))
y = np.sin(x)
ax1 = plt.subplot(2, 1, 1)
ax1 = plt.plot(x, y)
plt.axis('scaled')
ax1 = plt.subplot(2, 1, 2)
plt.plot(x, y)
plt.axis('equal')
There is only a slight difference that the width is shorter when plotted with plt.axis('scaled').
How can I know the difference better?
I think the difference becomes more apparent, if you use different data.
import numpy as np
import matplotlib.pyplot as plt
x = np.array(np.linspace(-np.pi, np.pi))
y = np.sin(x)*np.pi
ax1 = plt.subplot(2, 1, 1)
ax1 = plt.plot(x, y)
plt.axis('scaled')
ax1 = plt.subplot(2, 1, 2)
plt.plot(x, y)
plt.axis('equal')
plt.show()
So the difference is if the axes around the plot are changed according to the aspect, or if they stay the same as in a usual subplot and are scaled such, that the aspect of the plot data is equal.