So first, here is my code:
%matplotlib ipympl
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button
def ODE_r(x, t, params):
r, d1t_r = x
q, m, U_0, w, r_0 = params
derivs = [d1t_r,
-1 * (q / m) * U_0 * np.sin(w * t) * (r / r_0)]
return derivs
def ODE_z(y, t, params):
z, d1t_z = y
q, m, U_0, w, r_0 = params
derivs = [d1t_z,
(q / m) * U_0 * np.sin(w * t) * 2 * (z / r_0)]
return derivs
q = 1 # Mass of particle
q_u = sp.constants.e # Unit in e (C)
m = 1836 # Mass of particle
m_u = sp.constants.m_e # Unit in electron mass (kg)
U_0 = 10 # Amplitude of AC voltage
U_0_u = 1 # Unit in V
w = 4000 # Frequency of AC voltage
w_u = 1 # Unit in Hz
r_0 = 1000 # Geometrical factor
r_0_u = 1 # Unit?
# Initial values in m und m/s
r0 = 2e-6
d1t_r0 = 1e-3
z0 = -1e-6
d1t_z0 = 1e-3
# Define parameters for ODE solver and slider
def params(q, m, U_0, w, r_0):
func = [q*q_u, m*m_u, U_0*U_0_u, w*w_u, r_0]
return func
# Initial values for ODE solver
x0 = [r0, d1t_r0]
y0 = [z0, d1t_z0]
# Time array for solution (in s)
tStop = 0.1
tInc = 0.00005
Zeit = np.arange(0, tStop, tInc)
# Define numeric solution
def r_n(f, v0, t, parameters):
func = sp.integrate.odeint(f, v0, t, args=(parameters,))
return func[:,0]
def z_n(f, v0, t, parameters):
func = sp.integrate.odeint(f, v0, t, args=(parameters,))
return func[:,0]
fig = plt.figure(figsize=(8, 11), dpi=100)
ax = fig.add_subplot(111)
# Adjust the subplots region to leave some space for the sliders and buttons
fig.subplots_adjust(left=0.15, bottom=0.4)
# Draw the initial plot
# The 'line' variable is used for modifying the line later
[line] = ax.plot(r_n(ODE_r, x0, Zeit, params(q, m, U_0, w, r_0)), z_n(ODE_z, y0, Zeit, params(q, m, U_0, w, r_0)),
marker=',',
linestyle='-',
color='#008080',
label='trajectory')
#ax.set_xlim([0, 1])
#ax.set_ylim([-10, 10])
plt.xlabel('r / m')
plt.ylabel('z / m')
plt.title('Particle trajectory in the r - z plane of a Paul trap',
fontsize=12)
# plt.legend(loc='best', fancybox=True, shadow=True)
plt.grid(True)
# Sliders for tweaking the parameters
axis_color = 'lightgoldenrodyellow'
q_slider_ax = fig.add_axes([0.25, 0.3, 0.65, 0.03], facecolor=axis_color)
q_slider = Slider(q_slider_ax, 'q / e', -1, 10, valinit=q, valfmt='%0.0f')
m_slider_ax = fig.add_axes([0.25, 0.25, 0.65, 0.03], facecolor=axis_color)
m_slider = Slider(m_slider_ax, 'm / m_e', 1, 2000, valinit=m, valfmt='%0.0f')
U_slider_ax = fig.add_axes([0.25, 0.2, 0.65, 0.03], facecolor=axis_color)
U_slider = Slider(U_slider_ax, 'U_0 / V', 1, 100, valinit=U_0, valfmt='%0.0f')
w_slider_ax = fig.add_axes([0.25, 0.15, 0.65, 0.03], facecolor=axis_color)
w_slider = Slider(w_slider_ax, 'Freq / Hz', 1, 10000, valinit=w, valfmt='%0.0f')
r_slider_ax = fig.add_axes([0.25, 0.1, 0.65, 0.03], facecolor=axis_color)
r_slider = Slider(r_slider_ax, 'r_0', 1, 10000, valinit=r_0, valfmt='%0.0f')
# Define an action for modifying the line when any slider's value changes
def sliders_on_changed(val):
line.set_xdata(r_n(ODE_r, x0, Zeit, params(q.val, m.val, U_0.val, w.val, r_0.val)))
line.set_ydata(z_n(ODE_z, y0, Zeit, params(q.val, m.val, U_0.val, w.val, r_0.val)))
fig.canvas.draw_idle()
q_slider.on_changed(sliders_on_changed)
m_slider.on_changed(sliders_on_changed)
U_slider.on_changed(sliders_on_changed)
w_slider.on_changed(sliders_on_changed)
r_slider.on_changed(sliders_on_changed)
# Add a button for resetting the parameters
reset_button_ax = fig.add_axes([0.8, 0.05, 0.1, 0.04])
reset_button = Button(reset_button_ax, 'Reset', color=axis_color, hovercolor='0.975')
def reset_button_on_clicked(mouse_event):
q_slider.reset()
w_slider.reset()
reset_button.on_clicked(reset_button_on_clicked)
plt.show()
Background:
I need to plot a particle trajectory in a paul trap by numerically integrating two second order ODEs.
Problem:
Most part of the code is working as intended. The problem occurs by the slider.
I can interact with slider, but plot will not be updated, at least seems like that.
The most possible problems in my opinions are:
- Either the sliders are working, but new plot are out of range. The scale also need to be changed. Is it possible to add an autoscale button just like reset?
- Or the sliders are not working. I am not sure why. Maybe it is related to the numeric integration? Then how may I fix it?
Or the problem is elsewhere? May anyone help me?