1

I want to find the two roots of a quadratic equation ax^2 + bx + c =0 and plot them against coefficient c while keeping a as a changeable parameter. To change a and see what happens to the plots with varying the parameter, I would like to create a Silder for a from Python's Matplotlib module.

I have the following, however, it doesn't seem to be working.

# Solve the quadratic equation ax**2 + bx + c = 0 from matplotlib.widgets import Slider # import the Slider widget import numpy as np import matplotlib.pyplot as plt import cmath a_min = -2 a_max = 2 a_init = -2 fig = plt.figure(figsize=(8,3)) # Slider layout slider_ax = plt.axes([0.1, 0.05, 0.8, 0.05]) b = 10 def sol1(a,b,c): d = (b**2) - (4*a*c) # Discriminant return (-b-np.sqrt(d))/(2*a) def sol2(a,b,c): d = (b**2) - (4*a*c) # Discriminant return (-b+np.sqrt(d))/(2*a) for c in np.linspace(-2, 2, 11): print('c=',c,' sol1=',sol1(a_init,b,c),' sol2=',sol2(a_init,b,c)) # Plot with initial parameter value #plt.axes(func_ax) plt.xlabel('$c$') plt.title('Roots of $ax^2 + bx + c = 0$') plot1, = plt.plot(c, sol1(a_init,b,c), 'r') plot2, = plt.plot(c, sol2(a_init,b,c), 'b') # Create a slider a_slider = Slider(slider_ax, # the axes object containing the slider '$a$', # the name of the slider parameter a_min, # minimal value of the parameter a_max, # maximal value of the parameter valinit=a_init # initial value of the parameter ) # Update function def update(a): plot1.set_ydata(sol1(a,b,c)) plot2.set_ydata(sol2(a,b,c)) fig.canvas.draw_idle() # redraw the plot # Execute when parameter gets updated a_slider.on_changed(update) plt.show() 

Any help?

1 Answer 1

2

I made a couple of modifications to your code to make the slider work:

  • First, plot1 and plot2 are defined in a loop in your code. This means that they are deleted and created again at each iteration. Instead, it makes more sense to compute all the variables you want to plot and then plot them outside the loop. This is performed in the update_sols function.
  • Second, I changed the update function of your slider. The variable updated by the slider should be accessed by using a_slider.val (see an example here).
  • Finally, to make sure that you can see everything that you want to plot, you need to update the y limits of your plot each time you move your slider.

Overall, the updated code looks like that:

from matplotlib.widgets import Slider import numpy as np import matplotlib.pyplot as plt import cmath #Initial values a_min = -2 a_max = 2 a_init = -2 b = 10 c_list=np.linspace(-2, 2, 11) fig, ax = plt.subplots() plt.subplots_adjust(left=0.25, bottom=0.25) # Slider layout slider_ax = plt.axes([0.25, 0.1, 0.65, 0.03]) def sol1(a,b,c): d = (b**2) - (4*a*c) # Discriminant return (-b-np.sqrt(d))/(2*a) def sol2(a,b,c): d = (b**2) - (4*a*c) # Discriminant return (-b+np.sqrt(d))/(2*a) #Function to update solutions after modifying c def update_sols(a): res1=[] res2=[] for c in c_list: res1.append(sol1(a,b,c)) res2.append(sol2(a,b,c)) return res1,res2 #Initialising plot with solutions for a_init sols1,sols2=update_sols(a_init) plot1,=ax.plot(c_list, sols1, 'r') plot2,=ax.plot(c_list, sols2, 'b') ax.set_xlabel('$c$') ax.set_title('Roots of $ax^2 + bx + c = 0$') # Create a slider a_slider = Slider(ax=slider_ax,label='$a$',valmin=a_min,valmax=a_max,valinit=a_init) # Update function def update(val): #updating y data sols1,sols2=update_sols(a_slider.val) plot1.set_ydata(sols1) plot2.set_ydata(sols2) #updating y limits sols1_abs=np.abs(sols1) sols2_abs=np.abs(sols2) max_ylim=np.amax(np.concatenate((sols1_abs,sols2_abs))) ax.set_ylim([-1.1*max_ylim,1.1*max_ylim]) fig.canvas.draw_idle() # redraw the plot # Execute when parameter gets updated a_slider.on_changed(update) plt.show() 

And the output looks like that:

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.