2

当前版本的 matplotlib 不再允许,我应该如何做与答案box-forced相同的事情?

我正在使用 matplotlib 3.1.0。在我用函数在同一个图上绘制另一组数据后twinx(),我想将实际绘图区域的纵横比更改为 1。

通常我这样做,它适用于非双轴

ratio = 1
xleft, xright = ax.get_xlim()
ybottom, ytop = ax.get_ylim()
ax.set_aspect(abs((xright - xleft) / (ybottom - ytop)) * ratio)

对于 twinx 轴,上面的代码不起作用,但也不会引发任何错误。
然后我在这里找到了答案

该代码基本上使用相同的方法将纵横比设置为1,只是带有box-forced选项。

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 1.6, 50) + 50.0

fig, ax = plt.subplots()
ax2 = ax.twinx()

XLIM = [50.0, 51.6]
YLIM = [0.0, 1.1, 0.0, 11.0]

ax.plot(x, np.sin(x - 50.0), 'b')
ax2.plot(x, np.cos(x - 50.0) * 10., 'r')

# set aspect to 1
ax.set(adjustable='box-forced',
       xlim=XLIM, ylim=YLIM[:2],
       xticks=np.arange(XLIM[0], XLIM[1], 0.2),
       yticks=np.arange(YLIM[0], YLIM[1] + 0.1, 0.1)[:-1],
       aspect=(XLIM[1] - XLIM[0]) / (YLIM[1] - YLIM[0]))

ax2.set(adjustable='box-forced',
        ylim=YLIM[2:],
        yticks=np.arange(YLIM[2], YLIM[3] + 1.0, 1.0),
        aspect=(XLIM[1] - XLIM[0]) / (YLIM[3] - YLIM[2]))

ax.grid(True, which='major', linestyle='solid')

plt.show()

我的python中的这段代码不起作用,引发

ValueError: 'box-forced' is not a valid value for adjustable; supported values are 'box', 'datalim'

如果我将其更改为'box',它会给

RuntimeError: Adjustable 'box' is not allowed in a twinned Axes.  Use 'datalim' instead.

我不确定从何时box-forced删除。现在我们应该如何以“盒子”的方式设置纵横比?

谢谢!

供参考:matplotlib.axes.Axes.set_adjustable

4

2 回答 2

2

正如我刚刚评论了一个相应的 matplotlib 问题,

matplotlib 中的“方面”总是指数据,而不是轴框。因此,设置双轴或共享轴的纵横比并让框可调整实际上只有在比例相同或不同偏移量(与任何其他线性或非线性函数相反)时才有意义。Matplotlib 不会对此进行任何检查,因此在这种情况下它不允许可调='box'。

在我看来,在这里使用方面只是为轴框获得固定比率的一种解决方法。到目前为止,Matplotlib 没有为此提供任何清晰的代码路径,但可以通过调整 subplot 参数来强制轴框进入方形空间

import numpy as np
import matplotlib.pyplot as plt

def squarify(fig):
    w, h = fig.get_size_inches()
    if w > h:
        t = fig.subplotpars.top
        b = fig.subplotpars.bottom
        axs = h*(t-b)
        l = (1.-axs/w)/2
        fig.subplots_adjust(left=l, right=1-l)
    else:
        t = fig.subplotpars.right
        b = fig.subplotpars.left
        axs = w*(t-b)
        l = (1.-axs/h)/2
        fig.subplots_adjust(bottom=l, top=1-l)


x = np.linspace(0,1.6,50) + 50.0

fig, ax = plt.subplots()
ax2 = ax.twinx()

ax.set(xlim = [50.0, 51.6], ylim = [0.0, 1.1])
ax2.set(ylim = [0.0, 11.0])

ax.plot(x,np.sin(x-50.0),'b')
ax2.plot(x,np.cos(x-50.0)*10.,'r')

ax.grid(True, which='major',linestyle='solid')

squarify(fig)
fig.canvas.mpl_connect("resize_event", lambda evt: squarify(fig))

plt.show()

另请参阅此答案以获取多个子图。

如果您想使用mpl_toolkits并弄脏手,那么此答案将是一个不错的选择。

于 2019-07-27T00:49:38.070 回答
1

感谢@ImportanceOfBeingErnest,但为了在几个子图中进行这项工作,我发现了另一种受您的回答启发的方法:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import Divider, Size
from mpl_toolkits.axes_grid1.axes_divider import AxesDivider

def make_patch_spines_invisible(ax):
    ax.set_frame_on(True)
    ax.patch.set_visible(False)
    for sp in ax.spines.values():
        sp.set_visible(False)

def demo_fixed_size_axes():
    fig, axs = plt.subplots(1, 2, figsize=(12, 9))
    axs[0].plot([1, 2, 3])
    axs[1].plot([1, 2, 3.5])
    ax3 = axs[1].twinx()
    ax3.plot([1, 2, 3], [1, 25, 30])

    axs[1].spines['right'].set_visible(False)
    make_patch_spines_invisible(ax4Alt)
    ax4Alt.spines['right'].set_visible(True)

    for ax in fig.get_axes():
        figPos = AxesDivider(ax).get_position()
        h = [Size.Fixed(4)] # has to be fixed
        v = h

        divider = Divider(fig, figPos, h, v, aspect=False)

        ax.set_axes_locator(divider.new_locator(nx=0, ny=0))


if __name__ == "__main__":
    demo_fixed_size_axes()

    plt.show()

缺点是必须决定以英寸为单位使用哪种尺寸。虽然我不完全理解我的代码......

于 2019-07-28T20:58:09.290 回答