This article describes how to generate interactive plots by using the .widgets
package from the matplotlib library. As can be inferred from the name, the .widgets
package allows creating different types of interactive buttons, which can be used for modifying what is displayed in a matplotlib graph.
In particular, this article will focus on the creation of a Slider button that will be then used for changing the type of Spline curve interpolating the original plot. In this way, it will be possible to evaluate in real time, the effect of changing some of the spline parameters on the fit.
But let’s start with the end in mind: here’s the code you’re going to explore and the resulting plot:
import numpy as np from scipy.interpolate import UnivariateSpline import matplotlib.pyplot as plt from matplotlib.widgets import Slider # Initial x and y arrays x = np.linspace(0, 10, 30) y = np.sin(0.5*x)*np.sin(x*np.random.randn(30)) # Spline interpolation spline = UnivariateSpline(x, y, s = 6) x_spline = np.linspace(0, 10, 1000) y_spline = spline(x_spline) # Plotting fig = plt.figure() plt.subplots_adjust(bottom=0.25) ax = fig.subplots() p = ax.plot(x,y) p, = ax.plot(x_spline, y_spline, 'g') # Defining the Slider button # xposition, yposition, width and height ax_slide = plt.axes([0.25, 0.1, 0.65, 0.03]) # Properties of the slider s_factor = Slider(ax_slide, 'Smoothing factor', 0.1, 6, valinit=6, valstep=0.2) # Updating the plot def update(val): current_v = s_factor.val spline = UnivariateSpline(x, y, s = current_v) p.set_ydata(spline(x_spline)) #redrawing the figure fig.canvas.draw() # Calling the function "update" when the value of the slider is changed s_factor.on_changed(update) plt.show()
The output is an interactive Python plot window that allows you to control the graph with a slider:
You can try running it in your browser in the following interactive Jupyter notebook, I’ve created for you:
Let’s dive into the code and explore it step-by-step.
Importing Libraries
- First of all, we start by importing all the packages that will be used within this example. We will use Numpy for defining the initial function and
UnivariateSpline
, from theScipy.interpolate
package, for creating the spline curve which will interpolate the initial function. - After that, we need to import
matplotlib.pyplot
for plotting. - Finally, we import the package Slider, from the
matplotlib.widgets
library, this will allow us to interactively modify the already plotted spline curve.
The following code-lines describe the importation of the above-mentioned packages.
import numpy as np from scipy.interpolate import UnivariateSpline import matplotlib.pyplot as plt from matplotlib.widgets import Slider
Defining the initial function that will be fitted by the spline
To define the initial function, we create two arrays βxβ and βyβ which contain the data points describing the function.
The βxβ array is defined by exploiting the .linspace()
function from Numpy; in particular we initialize an array of 30 numbers from 0 to 10.
The βyβ array is described by a more complex function, in order to make the spline approximation trickier and hence be able to appreciate the effect of changing the spline defining parameters. As you can see in the following code-lines, the βyβ array is defined by the combination of the .sin()
and .random.randn()
functions, both belonging to the Numpy library.
#initial x and y arrays x = np.linspace(0, 10, 30) y = np.sin(0.5*x)*np.sin(x*np.random.randn(30))
Creation of the Spline Curve
We proceed further with the generation of the spline curve that should fit the initial function.
- The ensemble of functions describing the spline is assigned to the variable βsplineβ.
- The function that is used for generating the spline interpolation is
.UnivariateSpline()
, from theScipy.interpolate
library.
Related Tutorial: If you are interested in spline curves and their implementation in Python, here you can find a dedicated article.
The mandatory inputs of the .UnivariateSplin
e function are the βxβ and βyβ arrays, we then specify the smoothing factor, a parameter that defines the accuracy of the spline interpolation; it basically tells the function when to stop the interpolation process, based on the difference between the real values and the interpolated ones.
For the first spline, we insert β6β as the initial value for the smoothing factor. After calling the spline function, we define the x and the y arrays that contain the points describing the spline curve, called x_spline
and y_spline
, respectively.
#Spline interpolation spline = UnivariateSpline(x, y, s = 6) x_spline = np.linspace(0, 10, 1000) y_spline = spline(x_spline)
Plotting
The next step involves plotting the initial function and the spline curve that we have just defined. We move the window in which will be displayed the plot a little bit upward by exploiting the command plt.subplots_adjust(bottom=0.25)
in which we have to specify the space that we want to keep blank along the borders; this time we just want some space in the lower part of the window, in order to be able to add the slider.
The last important thing regarding this step is to add β,β after the variable in which we store the plot (βpβ); this enables us to unpack the single value into βpβ and hence gives the possibility to act on it.
The following code-lines explain how to plot the initial function and the spline curve.
#Plotting fig = plt.figure() plt.subplots_adjust(bottom = 0.25) ax = fig.subplots() p = ax.plot(x,y) p, = ax.plot(x_spline, y_spline, 'g')
We do not add the βplt.show()
β command since we still have to include the definition of the Slider.
How to Introduce the Slider Button into the Plot Window
Once we managed to generate the function, the spline curve and to plot them, we can now proceed to the creation of the Slider button. The first thing that should be done is the definition of the space in which the button will be displayed within the plotting window.
To this purpose, we first create the space that will be dedicated to the slider by using the matlplotlib function .axes()
which adds an axes to the current figure (additional documentation here).
As input of this function, we insert a list of values, these values represent the horizontal and vertical position of the slider, its width and height, respectively.
#Defining the Slider button ax_slide = plt.axes([0.25, 0.1, 0.65, 0.03]) #xposition, yposition, width and height
After having created the space for the slider, we now have to specify the characteristics of the button. We do this by exploiting the appropriate function, Slider
, in which we specify multiple properties related to the button.
The first input specifies the location in which the slider will be located, we add βax_slide
β which is the variable referred to the space just created in the previous step. After that, we can specify the label that will appear next to the slider (we use βSmoothing factor
β), the minimum and maximum values, the initial value and the unit increment.
You can find a comprehensive description of all these parameters here: https://matplotlib.org/3.3.3/api/widgets_api.html.
#Properties of the slider s_factor = Slider(ax_slide, 'Smoothing factor', 0.1, 6, valinit=6, valstep=0.2)
Table 1 summarizes the parameters used when calling the βSliderβ function.
Slider function | ||
Syntax: | Slider | |
Parameters: | ax | Axes defining the space in which the slider will be located |
label | Label that appears on the slider button | |
valmin | Minimum value of the slider | |
valmax | Maximum value of the slider | |
valinit | Initial value of the slider | |
valstep | Step increment of the slider | |
Return Value | None |
Table 1: definition of the Slider function and its parameters.
Updating Plot on Changing Slider Value
At this point, we have created the slider, if we plot it, we are already able to modify its value but our actions will not generate any modification in the plot; this is because we still have to relate the values within the slider to the ones that are plotted in the figure.
To accomplish this task, we need to define a function that contains the list of actions that will be taken whenever the value of the slider gets changed. The function will be called βupdateβ and will accept as input only one numerical value, corresponding to the value selected on the slider. Within this function, we create a local variable βcurrent_v
β in which we store the value of the slider by applying the method β.val
β to the Slider that we previously created (βs_factor
β).
Now that we have stored the updated value of the slider, we have to repeat the spline interpolation step, in order to update the spline curve; in this call, we insert βcurrent_v
β as the value for the new smoothing factor.
In this way, each time the slider will be changed, the function will repeat the spline interpolation by using the new value indicated on the slider, as the new smoothing factor. We then set the new values on the plot by the command .set_ydata()
applied to the variable describing the plot (βp
β). The final step is to redraw the current figure with the updated data, this is accomplished by the matplotlib function .draw()
Related: Here you find the official documentation: https://matplotlib.org/3.3.3/api/_as_gen/matplotlib.pyplot.draw.html
#Updating the plot def update(val): current_v = s_factor.val spline = UnivariateSpline(x, y, s = current_v) p.set_ydata(spline(x_spline)) fig.canvas.draw() #redrawing the figure
The very last thing that should be specified is the event that will trigger the call of the βupdateβ function.
We want the plot to be updated every time the value of the slider is changed; we can do this by exploiting the method .on_changed()
, applied to the variable βs_factor
β, which refers to the slider.
As input of this command we have to specify what to do when the value of the slider gets changed; as said before, we want the function βupdateβ to be run at each modification of the slider, in order to iterate the spline interpolation procedure.
After this, we can finally type βplt.show()
β to plot the graph and to start playing with our slider button! As you may notice, the more we decrease the smoothing factor, the better the spline interpolation.
#calling the function "update" when the value of the slider is changed s_factor.on_changed(update) plt.show()
The following GIF displays the final result for this example.