Это все еще немного грубо. Я уверен, что есть немного более элегантный способ сделать это, но вы можете создать пользовательский transformation
(см. Руководство по трансформациям ) между координатами осей ax2
и координатами данных ax1
, Другими словами, вы вычисляете, каково значение данных (согласно ax1
) в позиции, соответствующей левому и правому краям ax2
, и затем корректируйте xlim
из ax2
соответственно.
Вот демонстрация, показывающая, что он работает, даже если второй подзаговор никак не выровнен с первым.
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()
РЕДАКТИРОВАТЬ : Одним из возможных уточнений было бы преобразование в обратном вызове xlim_changed
. Таким образом, оси остаются синхронизированными даже при масштабировании / панорамировании по первым осям.
Существует также небольшая проблема с 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()