- IPython Interactive Computing and Visualization Cookbook
- Cyrille Rossant
- 700字
- 2021-08-05 17:57:28
Using interactive widgets – a piano in the notebook
Starting with IPython 2.0, we can put interactive widgets in notebooks to create rich GUI applications that interact with our Python kernel. IPython comes with a rich set of graphical controls such as buttons, sliders, and drop-down menus. We have full control of their placement and appearance. We can combine different widgets to form complex layouts. We can even create our own interactive widgets from scratch as we will see in the next recipe, Creating a custom Javascript widget in the notebook – a spreadsheet editor for pandas.
In this recipe, we will show many possibilities offered by the interactive widget API in IPython 2.0+. We will create a very basic piano in the notebook.
Getting ready
You need to download the Piano dataset from the book's website (http://ipython-books.github.io). This dataset contains synthetic sounds of piano notes obtained on archive.org
(CC0 1.0 Universal license). It is available at https://archive.org/details/SynthesizedPianoNotes.
How to do it...
- Let's import a few modules as follows:
In [1]: import numpy as np import os from IPython.display import (Audio, display, clear_output) from IPython.html import widgets from functools import partial
- To create a piano, we will draw one button per note. The corresponding note plays when the user clicks on the button. This is implemented by displaying an
<audio>
element as follows:In [2]: dir = 'data/synth' In [3]: # This is the list of notes. notes = 'C,C#,D,D#,E,F,F#,G,G#,A,A#,B,C'.split(',') In [4]: def play(note, octave=0): """This function displays an HTML Audio element that plays automatically when it appears.""" f = os.path.join(dir, "piano_{i}.mp3".format(i=note+12*octave)) clear_output() display(Audio(filename=f, autoplay=True))
- We are going to place all buttons within a container widget. In IPython 2.0, widgets can be organized hierarchically. One common use case is to organize several widgets in a given layout. Here,
piano
will contain 12 buttons for the 12 notes:In [5]: piano = widgets.ContainerWidget()
Note
The API for creating container widgets such as horizontal or vertical boxes has changed in IPython 3.0. Refer to IPython's documentation for more details.
- We create our first widget: a slider control that specifies the octave (0 or 1 here):
In [6]: octave_slider = widgets.IntSliderWidget() octave_slider.max = 1 octave_slider
- Now, we create the buttons. There are several steps. First, we instantiate a
ButtonWidget
object for each note. Then, we specify acallback()
function that plays the corresponding note (given by an index) at a given octave (given by the current value of the octave slider). Finally, we set the CSS of each button, notably the white or black color.In [7]: buttons = [] for i, note in enumerate(notes): button = widgets.ButtonWidget(description=note) def on_button_clicked(i, _): play(i+1, octave_slider.value) button.on_click(partial(on_button_clicked, i)) button.set_css({ 'width': '30px', 'height': '60px', 'padding': '0', 'color': ('black', 'white')['#' in note], 'background': ('white', 'black')['#' in note], 'border': '1px solid black', 'float': 'left'}) buttons.append(button)
- Finally, we arrange all widgets within the containers. The
piano
container contains the buttons, and the main container (container
) contains the slider and the piano. This can be implemented:In [8]: piano.children = buttons In [9]: container = widgets.ContainerWidget() container.children = [octave_slider, piano]
- By default, widgets are organized vertically within a container. Here, the octave slider will be above the piano. Within the piano, we want all notes to be arranged horizontally. We do this by replacing the default
vbox
CSS class by thehbox
class. The following screenshot shows the piano in the IPython notebook:In [10]: display(container) piano.remove_class('vbox') piano.add_class('hbox')
How it works...
The IPython widgets are represented by rich objects that are shared between the Python kernel and the browser. A widget contains special attributes called trait attributes. For example, the value
trait attribute of SliderWidget
is dynamically and automatically linked to the value that is selected by the user in the notebook's slider.
This link is bidirectional. Changing this attribute in Python updates the slider in the notebook.
The placement of the widgets is controlled by container widgets and with CSS classes. You will find more information in the documentation.
This architecture enables the creation of rich graphical applications in the notebook that are backed by Python code.
There's more...
- Widget examples at http://nbviewer.ipython.org/github/ipython/ipython/blob/master/examples/Interactive%20Widgets/Index.ipynb
See also
- The Creating a custom JavaScript widget in the notebook – a spreadsheet editor for pandas recipe