6
\$\begingroup\$

I am trying to code a sin wave with 5 sliders: frequency, amplitude, phase change, number of data points, and time. I am currently trying to link my phase change slider with my graph so that it updates it when I move the slider. I realize that my code is probably quite messy and could be more concise but I can adjust that later.

I think adding a phase change slider and length of time the function is plotted for would be good too, like the frequency and amplitude sliders (which do work).

For those who aren't familiar with the physics terms: amplitude: height of the wave (in y-axis)

  • frequency: number of times a wave passes a certain point per unit time. 1 Hertz = 1 wave passing per second
  • Phase difference: the change in the starting position of the current wave where amplitude = 0 at t = 0. A 90-degree phase change would shift the function the left or right, then representing a cos function rather than sine.

Any advice for my current code would be much appreciated!

My code so far:

import tkinter
import numpy as np
from scipy import signal
from scipy.fft import fft, ifft as sc
from matplotlib import pyplot as p, animation
# Implement the default Matplotlib key bindings.
from matplotlib.backend_bases import key_press_handler
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
from matplotlib.widgets import Slider

root = tkinter.Tk()
root.wm_title("Embedding in Tk")
fig = Figure(figsize=(6, 5), dpi=100)
t = np.linspace(0, 5, 200)
f = 1
time = np.linspace(0, 100, 101)
y = np.sin(f*t)

fig.subplots_adjust(left=0.15, bottom=0.45)  # Adjust subplots region leaving room for the sliders 
and buttons

canvas = FigureCanvasTkAgg(fig, master=root)  # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)

toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)


def on_key_press(event):
    print("you pressed {}".format(event.key))
    key_press_handler(event, canvas, toolbar)


canvas.mpl_connect("key_press_event", on_key_press)


def _quit():
    root.quit()  # stops mainloop
    root.destroy()


button = tkinter.Button(master=root, text="Quit", command=_quit)
button.pack(side=tkinter.BOTTOM)

# Amplitude slider
initiala = 1  # starting value of amplitude on graph
asliderax = fig.add_axes([0.25, 0.15, 0.65, 0.03])  # setting amplitude slider position
aslider = Slider(asliderax, 'Amp', 0.1, 10.0, valinit=initiala)  # setting amplitude slider values

# Frequency slider
initialf = 1  # starting value of frequency on graph
fsliderax = fig.add_axes([0.25, 0.1, 0.65, 0.03])  # setting frequency slider position
fslider = Slider(fsliderax, 'Freq', 0.1, 3.0, valinit=initialf)  # setting frequency slider values

# Time slider
initialt = 1  # starting value of time on graph
tsliderax = fig.add_axes([0.25, 0.2, 0.65, 0.03])  # setting time slider position
tslider = Slider(tsliderax, 'Time', 0.1, 100.0, valinit=initialt)  # setting time slider values

# Number of Points slider
initialp = 99  # starting value of number of points on graph
psliderax = fig.add_axes([0.25, 0.25, 0.65, 0.03])  # setting points slider position
pslider = Slider(psliderax, 'Points', 3, 30.0, valinit=initialp)  # setting frequency points values

# Phase slider
initialph = 0  # starting value of number of points on graph
phsliderax = fig.add_axes([0.25, 0.3, 0.65, 0.03])  # setting points slider position
phslider = Slider(phsliderax, 'Phase Change', 0, np.pi*2, valinit=initialph)  # setting frequency 
points values


def update(val):
    amp = aslider.val
    freq = fslider.val
    t = np.linspace(0, 5, 200)
    y.set_ydata(amp*np.sin(2*np.pi*freq*t))


fslider.on_changed(update)
aslider.on_changed(update)
tslider.on_changed(update)
pslider.on_changed(update)


tkinter.mainloop()
New contributor
CMTT is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
\$\endgroup\$
  • \$\begingroup\$ About this: I can't quite think how to add the phase change slider like the frequency and amplitude sliders - Code Review cannot help you. We review code that is working. Given that your code is "mostly working", if you edit your question to focus on review, it will be on-topic; but any emphasis on fixing your slider problem will keep it off-topic. For that problem you're best off asking Stack Overflow. \$\endgroup\$ – Reinderien Oct 18 at 17:03
  • \$\begingroup\$ @Reinderien So if I ask 'How can this code be developed/improved' or something similar and more specific then this would be on-topic? Just want to check I understand you correctly. Apologies if I misunderstood you \$\endgroup\$ – CMTT Oct 18 at 19:11
  • \$\begingroup\$ Exactly right 😊 \$\endgroup\$ – Reinderien Oct 18 at 19:17
  • 3
    \$\begingroup\$ Can you also put in some links and images showing current app, and reference to the phase, amplitude relations etc. It has been years since I studied physics \$\endgroup\$ – hjpotter92 Oct 18 at 20:41
  • 2
    \$\begingroup\$ @pacmaninbw just a note, "realise" is also correct :) merriam-webster.com/words-at-play/realize-vs-realise-difference \$\endgroup\$ – hjpotter92 Oct 20 at 6:36
0
\$\begingroup\$

Seems to me you just need to add the phase to the angle in update().

def update(val):
    amp = aslider.val
    freq = fslider.val
    phase = phslider.val
    t = np.linspace(0, 5, 200)

    y.set_ydata(amp*np.sin(2*np.pi*freq*t + phase))  # << add phase here


fslider.on_changed(update)
aslider.on_changed(update)
tslider.on_changed(update)
pslider.on_changed(update)
phslider.on_changed(update)  # update on slider change
| improve this answer | |
\$\endgroup\$

Your Answer

CMTT is a new contributor. Be nice, and check out our Code of Conduct.

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.