Share scaling of differntly sized subplots' axes (not sharing axes)

老子叫甜甜 提交于 2020-12-13 05:46:29

问题


With matplotlib, I want to plot two graphs with the same x-axis scale, but I want to show different sized sections. How can I accomplish that?

So far I can plot differently sized subplots with GridSpec or same sized ones who share the x-axis. When I try both at once, the smaller subplot has the same axis but smaller scaled, while I want the same scaling and a different axis, so sharing the axis might be a wrong idea.

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

I want the x.axes to have the same scaling, i.e. the same x values are always exactly on top of each other, 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, the scales don't match.

Thanks in advance.


回答1:


This is still a bit rough. I'm sure there's a slightly more elegant way to do this, but you can create a custom transformation (see Transformations Tutorial) between the Axes coordinates of ax2 and the data coordinates of ax1. In other word, your calculating what is the data-value (according to ax1) at the position corresponding to the left and right edges of ax2, and then adjust the xlim of ax2 accordingly.

Here is a demonstration showing that it works even if the second subplot is not aligned in any particular way with the first.

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

EDIT: One possible refinement would be to do the transform in the xlim_changed event callback. That way, the axes stay in sync even when zooming/panning in the first axes.

There is also a slight issue with tight_layout() as you noted, but that is easily fixed by calling the callback function directly.

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



回答2:


I suggest setting limits of the second axis based on the limits of ax1.

Try this!

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



来源:https://stackoverflow.com/questions/54040731/share-scaling-of-differntly-sized-subplots-axes-not-sharing-axes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!