I'm trying to use a horizontal slider to change the xlim of my plot. But first, I can't figure out how to get the slider to update using the on_changed() method. I don't have a strong understanding of how classes, and objects interact with each other.
I'm using this slider example as a template:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons
fig, ax = plt.subplots()
plt.subplots_adjust(left=0.25, bottom=0.25)
t = np.arange(0.0, 1.0, 0.001)
a0 = 5
f0 = 3
delta_f = 5.0
s = a0 * np.sin(2 * np.pi * f0 * t)
l, = plt.plot(t, s, lw=2)
ax.margins(x=0)
axcolor = 'lightgoldenrodyellow'
axfreq = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor=axcolor)
axamp = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor=axcolor)
sfreq = Slider(axfreq, 'Freq', 0.1, 30.0, valinit=f0, valstep=delta_f)
samp = Slider(axamp, 'Amp', 0.1, 10.0, valinit=a0)
def update(val):
amp = samp.val
freq = sfreq.val
l.set_ydata(amp*np.sin(2*np.pi*freq*t))
fig.canvas.draw_idle()
sfreq.on_changed(update)
samp.on_changed(update)
resetax = plt.axes([0.8, 0.025, 0.1, 0.04])
button = Button(resetax, 'Reset', color=axcolor, hovercolor='0.975')
def reset(event):
sfreq.reset()
samp.reset()
button.on_clicked(reset)
rax = plt.axes([0.025, 0.5, 0.15, 0.15], facecolor=axcolor)
radio = RadioButtons(rax, ('red', 'blue', 'green'), active=0)
def colorfunc(label):
l.set_color(label)
fig.canvas.draw_idle()
radio.on_clicked(colorfunc)
plt.show()
The part that I'm having trouble implementing in my app is:
sfreq.on_changed(update)
samp.on_changed(update)
It works fine if you're opening a plot using plt.show(), but if you're packing it into a canvas like I'm doing below, it stops working. Any ideas why?
Here is the code for my app: UPDATE: I simplified the code to focus on the problem.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import(FigureCanvasTkAgg, NavigationToolbar2Tk)
from tkinter import *
import tkinter as tk
global running
running = True
global graph_exists
graph_exists = False
class MyApp:
def __init__(self, parent):
self.myParent = parent ###remember my parent, the root
self.sfreq = 0
self.samp = 0
def run(self):
self.fig, self.ax = plt.subplots()
plt.subplots_adjust(left=0.25, bottom=0.25)
self.t = np.arange(0.0, 1.0, 0.001)
a0 = 5
f0 = 3
delta_f = 5.0
s = a0 * np.sin(2 * np.pi * f0 * self.t)
self.l, = plt.plot(self.t, s, lw=2)
self.ax.margins(x=0)
axcolor = 'lightgoldenrodyellow'
axfreq = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor=axcolor)
axamp = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor=axcolor)
self.sfreq = Slider(axfreq, 'Freq', 0.1, 30.0, valinit=f0, valstep=delta_f)
self.samp = Slider(axamp, 'Amp', 0.1, 10.0, valinit=a0)
canvas = FigureCanvasTkAgg(self.fig, root)
canvas.draw()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
graph_exists = True
def update(self, val):
amp = self.samp.val
freq = self.sfreq.val
self.l.set_ydata(amp*np.sin(2*np.pi*freq*self.t))
self.fig.canvas.draw_idle()
if graph_exists:
self.sfreq.on_changed(update)
self.samp.on_changed(update)
#Run the event loop
root = tk.Tk()
myapp = MyApp(root)
myapp.run()
root.mainloop()
The problem with your code is the method update
is never called... You need to put the part if graph_exists
into the run
method. Besides, as suggested in the post @acw1668 shared, you also need to add the figure into canvas before plotting.
Try the code below
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import(FigureCanvasTkAgg, NavigationToolbar2Tk)
from tkinter import *
import tkinter as tk
global running
running = True
global graph_exists
graph_exists = False
class MyApp:
def __init__(self, parent):
self.myParent = parent ###remember my parent, the root
self.sfreq = 0
self.samp = 0
def run(self):
self.fig, self.ax = plt.subplots()
canvas = FigureCanvasTkAgg(self.fig, root)
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
plt.subplots_adjust(left=0.25, bottom=0.25)
self.t = np.arange(0.0, 1.0, 0.001)
a0 = 5
f0 = 3
delta_f = 5.0
s = a0 * np.sin(2 * np.pi * f0 * self.t)
self.l, = plt.plot(self.t, s, lw=2)
self.ax.margins(x=0)
axcolor = 'lightgoldenrodyellow'
axfreq = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor=axcolor)
axamp = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor=axcolor)
self.sfreq = Slider(axfreq, 'Freq', 0.1, 30.0, valinit=f0, valstep=delta_f)
self.samp = Slider(axamp, 'Amp', 0.1, 10.0, valinit=a0)
graph_exists = True
if graph_exists:
self.sfreq.on_changed(self.update)
self.samp.on_changed(self.update)
def update(self, val):
print('inside update')
amp = self.samp.val
freq = self.sfreq.val
self.l.set_ydata(amp*np.sin(2*np.pi*freq*self.t))
self.fig.canvas.draw_idle()
#Run the event loop
root = tk.Tk()
myapp = MyApp(root)
myapp.run()
root.mainloop()