Reputation: 8042
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 amplitude/frequency of wave on 1st plot is changed using slider it also changes the amplitude/frequency of wave on 2nd plot (it doubles the amplitude on 2nd plot). Problem is when amplitude of 1st plot is exceeds 3. In that case it simply does not fits in to the 2nd plot. Because it has the y
range from -6 to 6.
Three questions:
ax[1].set_ylim([-20, 20])
but I want something more general. Let's pretend that 2nd plot can have y
value more than 20 (it might be result of some complicated computation which is not known during plotting). Basically when amplitude of 1st plot is small value the y
of 2nd plot should shrink and when amplitude is large y
should expand.line1, = ax[1].plot(t,s, lw=2, color='green', label="green")
Upvotes: 4
Views: 3706
Reputation: 20344
EDIT: User hitzg provided some helpful improvements to the original answer in comments - I've taken these and generally made the answer deeper and more generic.
I'll take the questions one by one
- Where did 6 and -6 come from?
That's matplotlib's best guess, based on the data that you plotted on the axis originally. If you don't specify any values, it will fit the axes limits the best it can.
For those with deeper interest - these lines of code are where matplotlib defaults to auto-scaling the axes if no scales are specified, with this line actually applying the auto scaling.
- How can be the y limit changed dynamically on 2nd plot? I
You're almost there. In update1()
, add ax[1].autoscale_view()
which, as you've added new data, must be preceded by ax[1].relim()
. This will let matplotlib autoscale the axes to suit the values of whatever data you have plotted on them and is a generic solution. If you need 'manual' but dynamic control of the axes yourself, see my original suggestion below.
N.B. In the original version, I suggested simply writing ax[1].set_ylim(-2.2*amp,2.2*amp)
or something similar where 2.2
was an arbitrary factor: the limits of the sine wave amplitude as set by the slider plus a little bit (the 0.2
)
- Can I leave the 2nd plot empty until I change the amplitude/frequency of the 1st plot?
Yes. One way is to replace
line1, = ax[1].plot(t,s, lw=2, color='green', label="green")
with
line1, = ax[1].plot([],[], lw=2, color='green', label="green")
This creates a line object on the axes that you can update, but which initially has no data. N.B. I originally suggested using 0,0
instead of [],[]
, but this would plot a point at 0,0 which might not suit your purposes.
And then in update1()
put
line1.set_xdata(t)
update1()
functiondef 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()
Upvotes: 4