共享不同大小的子图轴的缩放比例(不共享轴)
Share scaling of differntly sized subplots' axes (not sharing axes)
使用 matplotlib,我想用相同的 x 轴刻度绘制两个图,但我想显示不同大小的部分。我怎样才能做到这一点?
到目前为止,我可以使用 GridSpec 绘制不同大小的子图或共享 x 轴的相同大小的子图。当我同时尝试两者时,较小的子图具有相同的轴但缩放比例较小,而我想要相同的缩放比例和不同的轴,因此共享轴可能是一个错误的想法。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
x=np.linspace(0,10,100)
y=np.sin(x)
x2=np.linspace(0,5,60)
y2=np.cos(x2)
fig=plt.figure()
gs=GridSpec(2,3)
ax1 = fig.add_subplot(gs[0, :])
ax1.plot(x,y)
ax2 = fig.add_subplot(gs[1,:-1])
#using sharex=ax1 here decreases the scaling of ax2 too much
ax2.plot(x2,y2)
plt.show()
我希望 x.axes 具有相同的缩放比例,即相同的 x 值始终恰好彼此重叠,this should give you an idea. The smaller plot's frame could be expanded or fit the plot, that doesn't matter. As it is now,比例不匹配。
提前致谢。
这个还是有点粗糙。我敢肯定有一种稍微更优雅的方法可以做到这一点,但是您可以在 ax2
的轴坐标和 [= 的数据坐标之间创建自定义 transformation
(参见 Transformations Tutorial) 14=]。也就是说,你计算ax2
的左右两边对应位置的data-value(根据ax1
)是多少,然后调整xlim
13=]相应地。
这里有一个演示,表明即使第二个子图与第一个子图没有以任何特定方式对齐,它也能正常工作。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
x=np.linspace(0,25,100)
y=np.sin(x)
x2=np.linspace(10,30,60)
y2=np.cos(x2)
fig=plt.figure()
gs=GridSpec(2,6)
ax1 = fig.add_subplot(gs[0, :])
ax1.plot(x,y)
ax2 = fig.add_subplot(gs[1,3:-1])
ax2.plot(x2,y2)
# here is where the magic happens
trans = ax2.transAxes + ax1.transData.inverted()
((xmin,_),(xmax,_)) = trans.transform([[0,1],[1,1]])
ax2.set_xlim(xmin,xmax)
# for demonstration, show that the vertical lines end up aligned
for ax in [ax1,ax2]:
for pos in [15,20]:
ax.axvline(pos)
plt.show()
编辑:一种可能的改进是在the xlim_changed
event callback中进行转换。这样,即使在第一个轴中 zooming/panning 时,轴也会保持同步。
如您所述,tight_layout()
也存在一个小问题,但可以通过直接调用回调函数轻松解决。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
def on_xlim_changed(event):
# here is where the magic happens
trans = ax2.transAxes + ax1.transData.inverted()
((xmin, _), (xmax, _)) = trans.transform([[0, 1], [1, 1]])
ax2.set_xlim(xmin, xmax)
x = np.linspace(0, 25, 100)
y = np.sin(x)
x2 = np.linspace(10, 30, 60)
y2 = np.cos(x2)
fig = plt.figure()
gs = GridSpec(2, 6)
ax1 = fig.add_subplot(gs[0, :])
ax1.plot(x, y)
ax2 = fig.add_subplot(gs[1, 3:-1])
ax2.plot(x2, y2)
# for demonstration, show that the vertical lines end up aligned
for ax in [ax1, ax2]:
for pos in [15, 20]:
ax.axvline(pos)
# tight_layout() messes up the axes xlim
# but can be fixed by calling on_xlim_changed()
fig.tight_layout()
on_xlim_changed(None)
ax1.callbacks.connect('xlim_changed', on_xlim_changed)
plt.show()
我建议根据ax1的限制设置第二个轴的限制。
试试这个!
ax2 = fig.add_subplot(gs[1,:-1])
ax2.plot(x2,y2)
lb, ub = ax1.get_xlim()
# Default margin is 0.05, which would be used for auto-scaling, hence reduce that here
# Set lower bound and upper bound based on the grid size, which you choose for second plot
ax2.set_xlim(lb, ub *(2/3) -0.5)
plt.show()
使用 matplotlib,我想用相同的 x 轴刻度绘制两个图,但我想显示不同大小的部分。我怎样才能做到这一点?
到目前为止,我可以使用 GridSpec 绘制不同大小的子图或共享 x 轴的相同大小的子图。当我同时尝试两者时,较小的子图具有相同的轴但缩放比例较小,而我想要相同的缩放比例和不同的轴,因此共享轴可能是一个错误的想法。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
x=np.linspace(0,10,100)
y=np.sin(x)
x2=np.linspace(0,5,60)
y2=np.cos(x2)
fig=plt.figure()
gs=GridSpec(2,3)
ax1 = fig.add_subplot(gs[0, :])
ax1.plot(x,y)
ax2 = fig.add_subplot(gs[1,:-1])
#using sharex=ax1 here decreases the scaling of ax2 too much
ax2.plot(x2,y2)
plt.show()
我希望 x.axes 具有相同的缩放比例,即相同的 x 值始终恰好彼此重叠,this should give you an idea. The smaller plot's frame could be expanded or fit the plot, that doesn't matter. As it is now,比例不匹配。
提前致谢。
这个还是有点粗糙。我敢肯定有一种稍微更优雅的方法可以做到这一点,但是您可以在 ax2
的轴坐标和 [= 的数据坐标之间创建自定义 transformation
(参见 Transformations Tutorial) 14=]。也就是说,你计算ax2
的左右两边对应位置的data-value(根据ax1
)是多少,然后调整xlim
13=]相应地。
这里有一个演示,表明即使第二个子图与第一个子图没有以任何特定方式对齐,它也能正常工作。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
x=np.linspace(0,25,100)
y=np.sin(x)
x2=np.linspace(10,30,60)
y2=np.cos(x2)
fig=plt.figure()
gs=GridSpec(2,6)
ax1 = fig.add_subplot(gs[0, :])
ax1.plot(x,y)
ax2 = fig.add_subplot(gs[1,3:-1])
ax2.plot(x2,y2)
# here is where the magic happens
trans = ax2.transAxes + ax1.transData.inverted()
((xmin,_),(xmax,_)) = trans.transform([[0,1],[1,1]])
ax2.set_xlim(xmin,xmax)
# for demonstration, show that the vertical lines end up aligned
for ax in [ax1,ax2]:
for pos in [15,20]:
ax.axvline(pos)
plt.show()
编辑:一种可能的改进是在the xlim_changed
event callback中进行转换。这样,即使在第一个轴中 zooming/panning 时,轴也会保持同步。
如您所述,tight_layout()
也存在一个小问题,但可以通过直接调用回调函数轻松解决。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
def on_xlim_changed(event):
# here is where the magic happens
trans = ax2.transAxes + ax1.transData.inverted()
((xmin, _), (xmax, _)) = trans.transform([[0, 1], [1, 1]])
ax2.set_xlim(xmin, xmax)
x = np.linspace(0, 25, 100)
y = np.sin(x)
x2 = np.linspace(10, 30, 60)
y2 = np.cos(x2)
fig = plt.figure()
gs = GridSpec(2, 6)
ax1 = fig.add_subplot(gs[0, :])
ax1.plot(x, y)
ax2 = fig.add_subplot(gs[1, 3:-1])
ax2.plot(x2, y2)
# for demonstration, show that the vertical lines end up aligned
for ax in [ax1, ax2]:
for pos in [15, 20]:
ax.axvline(pos)
# tight_layout() messes up the axes xlim
# but can be fixed by calling on_xlim_changed()
fig.tight_layout()
on_xlim_changed(None)
ax1.callbacks.connect('xlim_changed', on_xlim_changed)
plt.show()
我建议根据ax1的限制设置第二个轴的限制。
试试这个!
ax2 = fig.add_subplot(gs[1,:-1])
ax2.plot(x2,y2)
lb, ub = ax1.get_xlim()
# Default margin is 0.05, which would be used for auto-scaling, hence reduce that here
# Set lower bound and upper bound based on the grid size, which you choose for second plot
ax2.set_xlim(lb, ub *(2/3) -0.5)
plt.show()