动态更改 y 轴限制

4
这里是代码:
#!/usr/bin/python
import numpy as np
import matplotlib.pyplot  as plt
from   matplotlib.widgets import Slider
########################################
t = np.arange(0.0, 1.0, 0.001)
a0 = 5
f0 = 3
s = a0*np.sin(2*np.pi*f0*t)
########################################
plt.close('all')
fig, ax = plt.subplots(nrows=2, ncols=1)
plt.subplots_adjust(bottom=0.30)
########################################
line0, = ax[0].plot(t,s, lw=2, color='red',   label="red")
# IS THIS LINE NECESSARY
line1, = ax[1].plot(t,s, lw=2, color='green', label="green")
########################################
ax[0].set_xlim([0, 1])
ax[0].set_ylim([-10, 10])
########################################
axcolor = 'lightgoldenrodyellow'
left   = 0.25
bottom = 0.20
width  = 0.65
# DIFFERENT SCALE
# height = fig.get_size_inches()[1] * 0.1
height = 0.03
vgap   = 0.02
print "fig height %s" % fig.get_size_inches()[1]

f1  = plt.axes([left, bottom-0*(height+vgap), width, height], axisbg=axcolor)
a1  = plt.axes([left, bottom-1*(height+vgap), width, height], axisbg=axcolor)

sf1 = Slider(f1, 'Freq1', 0.1, 30.0, valinit=f0)
sa1 = Slider(a1, 'Amp1',  0.1, 10.0, valinit=a0)
########################################
def update1(val):
    amp  = sa1.val
    freq = sf1.val

    line0.set_ydata(amp*np.sin(2*np.pi*freq*t))
    line1.set_ydata(2*amp*np.sin(2*np.pi*freq*t))

sf1.on_changed(update1)
sa1.on_changed(update1)

plt.show()

当第一个图表中的波的振幅/频率通过滑块改变时,它也会改变第二个图表中波的振幅/频率(在第二个图表中振幅加倍)。问题是当第一个图表的振幅超过3时。在这种情况下,它根本不适合第二个图表。因为它具有从-6到6的y范围。
三个问题:
1. -6和6的数字来自哪里?我没有设置它们。 2. 如何动态更改第二个图表的y限制?我可以使用ax[1].set_ylim([-20,20])进行设置,但我想要更通用的东西。假设第二个图表的y值可以超过20(这可能是一些未知的复杂计算的结果,在绘图期间不知道)。基本上,当第一个图表的振幅很小的时候,第二个图表的y应该缩小,当振幅很大时,y应该扩展。 3. 我可以在改变第一个图表的振幅/频率之前将第二个图表留空吗?换句话说,是否可以在不首先创建第二个图表的情况下实现这一点(请显示两种情况,一种是第二个图表已经存在,另一种是不存在): line1,= ax [1]。plot(t,s,lw = 2,color ='green',label ="green")
1个回答

4

编辑:用户hitzg评论中提供了一些有用的改进意见,我将这些意见融合到答案中,使其更加深入和通用。


我将逐个回答这些问题。

  1. 6和-6是从哪里来的?

这是matplotlib根据你最初在轴上绘制的数据所做出的最佳猜测。如果没有指定任何值,它会尽可能地拟合轴限制。

对于那些更深入的了解 - 这些代码行是matplotlib默认情况下自动缩放轴的位置,如果没有指定比例,则使用这行代码实际应用自动缩放。

  1. 如何在第二个图中动态更改y限制?

你已经接近成功了。在update1()中,加入ax[1].autoscale_view(),由于添加了新数据,必须先执行ax[1].relim()。这将让matplotlib自动调整轴以适应你绘制的任何数据值,并且是一种通用的解决方案。如果你需要自己控制轴的“手动”但是动态的方式,请参见下面我的原始建议。

N.B.在原始版本中,我建议简单地编写ax[1].set_ylim(-2.2*amp,2.2*amp)或类似的内容,其中2.2是一个任意因子:正弦波振幅的极限由滑块设置加上一点点(0.2

  1. 我可以在更改第一个图的振幅/频率之前保留第二个图为空吗?

可以。一种方法是替换

line1, = ax[1].plot(t,s, lw=2, color='green', label="green")

使用

line1, = ax[1].plot([],[], lw=2, color='green', label="green")

这将在框图上创建一条对象,您可以更新它,但最初没有数据。请注意,我最初建议使用0,0代替[],[],但这将在0,0处绘制一个点,这可能不适合您的目的。

然后在update1()中输入:

line1.set_xdata(t)

update1()函数的最终代码

def update1(val):
    amp  = sa1.val
    freq = sf1.val

    line0.set_ydata(amp*np.sin(2*np.pi*freq*t))
    line1.set_xdata(t)
    line1.set_ydata(2*amp*np.sin(2*np.pi*freq*t))
    ax[1].relim()
    ax[1].autoscale_view()

1
我有两个改进建议: 1) 使用 ax[1].plot([], []),因为这样确实会创建一个空的 Line2D 对象。如果传递 (0,0),则在设置标记时会可见。2) Matplotlib 使用两个函数自动计算轴限制:ax.relim() 计算限制,ax.autoscale_view() 应用它们。ax.plot 也使用了这两个函数。因此,您可以使用这些函数来调整轴限制,而不是仅在这个特定的例子中使用 ax[1].set_ylim(-2*amp, 2*amp),因为这种方法只对特定情况有效。 - hitzg
1
两个不错的建议,谢谢。一旦我坐在电脑前,我就会将它们合并到我的工作中去。 - J Richard Snape

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接