官术网_书友最值得收藏!

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...

  1. 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
  2. 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))
  3. 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.

  4. 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
  5. Now, we create the buttons. There are several steps. First, we instantiate a ButtonWidget object for each note. Then, we specify a callback() 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)
  6. 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]
  7. 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 the hbox 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...

See also

  • The Creating a custom JavaScript widget in the notebook – a spreadsheet editor for pandas recipe
主站蜘蛛池模板: 买车| 江永县| 尉氏县| 天柱县| 民丰县| 黑水县| 宿松县| 合水县| 兴安县| 凉城县| 民乐县| 宜昌市| 沂水县| 井陉县| 开阳县| 舟山市| 明光市| 固安县| 蓬莱市| 通海县| 安新县| 沙洋县| 罗田县| 娄底市| 稻城县| 自治县| 玉龙| 淮南市| 周宁县| 青阳县| 富裕县| 东至县| 建德市| 郁南县| 叙永县| 广汉市| 龙门县| 东明县| 仙桃市| 洞头县| 诏安县|