Dynamically change y limit

Here is the code:

#!/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()

      

When the amplitude / frequency of the wave in the 1st section is changed with the slider, it also changes the amplitude / frequency of the wave in the 2nd section (it doubles the amplitude in the 2nd section). The problem is that the amplitude of the 1st section is greater than 3. In this case, it simply does not fit the second section. Because it has a range y

of -6 to 6. y limit is not enough

Three questions:

  • Where do the numbers -6 and 6 come from? I have not installed them.
  • How can the constraint y be changed dynamically in the 2nd section? I can install it for example, ax[1].set_ylim([-20, 20])

    but I want something more general. Suppose the 2nd plot can have a value y

    greater than 20 (this could be the result of some complex calculation that is not known when plotting the plot). Basically, when the amplitude of the 1st graph is small, y

    the 2nd graph should decrease and when the amplitude is large, it y

    should expand.
  • Can I leave the second section blank until I change the amplitude / frequency of the 1st section. In other words, it could be as well (please show both cases, one where the second plot already exists and the other if it hasn't reached), without creating a second plot first using the following line:line1, = ax[1].plot(t,s, lw=2, color='green', label="green")

+3


source to share


1 answer


EDIT: User hitzg has provided some useful improvements to the original answer in the comments - I've taken these and generally made the answer deeper and more general.


I'll take questions one by one

  • Where did 6 and -6 come from?

This is matplotlib's best guess based on the data you plotted on the axis initially. If you do not provide any values, they will match the axis limits as much as possible.

For those with a deeper interest - these are the lines of code where matplotlib automatically scales the axes by default if no scales are given, with this line actually applying the automatic scaling.

  1. How can the constraint y be changed dynamically in the 2nd section? I

You're almost there. In update1()

add ax[1].autoscale_view()

, which, since you added new data, must precede ax[1].relim()

. This will allow matplotlib to auto-scale the axes according to the values โ€‹โ€‹of any data you have drawn on them, and is a general solution. If you need "manual" but dynamic control of the axes yourself, see my initial suggestion below.

NB In the original version, I suggested just writing ax[1].set_ylim(-2.2*amp,2.2*amp)

or something similar, where there 2.2

was an arbitrary factor: the sine wave amplitude limits given by the slider plus a few bits ( 0.2

)

  1. Can I leave the second section blank until I change the amplitude / frequency of the 1st section?


Yes. One way is to replace

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

      

from

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

      

This creates a line object for the axes that you can update, but which have no data at first. Notabene Originally I suggested using 0,0

instead [],[]

, but that would overlay the dot at 0,0, which may not be consistent with your goals.

And then in update1()

place

line1.set_xdata(t)

      

Final code for function 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()

      

+3


source







All Articles