Testing ipywidgets and Music21

These are tests of widgets within Music21

import ipywidgets as widgets
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
@widgets.interact
def f(x=5):
    print(x)
 interactive(children=(IntSlider(value=5, description='x', max=15, min=-5), Output()), _dom_classes=('widget-in…
@widgets.interact(x=(0, 5))
def ff(x=5):
    print(x)
 interactive(children=(IntSlider(value=5, description='x', max=5), Output()), _dom_classes=('widget-interact',)…
@widgets.interact_manual(
    color=['blue', 'red', 'green'], lw=(1.0, 10.0))
def plot(freq=1.0, color='blue', lw=2, grid=True):
    t = np.linspace(-1.0, 1.0, 1000)
    fig, ax = plt.subplots(1, 1, figsize=(8, 6))
    ax.plot(t, np.sin(2 * np.pi * freq * t),
            lw=lw, color=color)
    ax.grid(grid)
 interactive(children=(FloatSlider(value=1.0, description='freq', max=3.0, min=-1.0), Dropdown(description='col…
freq_slider = widgets.FloatSlider(
    value=2.0,
    min=1.0,
    max=10.0,
    step=0.1,
    description='Frequency:',
    readout_format='.1f',
)
freq_slider
 FloatSlider(value=2.0, description='Frequency:', max=10.0, min=1.0, readout_format='.1f')

Create a Custom Widget

Older Jupyter provided require/define from RequireJS which gave access to Jupyter widgets. This is no longer the case, so we first need to install anywidget (since it’s not part of the music21 ecosystem):

%pip install anywidget
 Collecting anywidget
   Downloading anywidget-0.11.0-py3-none-any.whl.metadata (8.9 kB)
 Requirement already satisfied: ipywidgets>=7.6.0 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from anywidget) (8.1.8)
 Collecting psygnal>=0.8.1 (from anywidget)
   Downloading psygnal-0.15.1-cp313-cp313-macosx_11_0_arm64.whl.metadata (6.1 kB)
 Requirement already satisfied: typing-extensions>=4.2.0 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from anywidget) (4.14.0)
 Requirement already satisfied: comm>=0.1.3 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from ipywidgets>=7.6.0->anywidget) (0.2.3)
 Requirement already satisfied: ipython>=6.1.0 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from ipywidgets>=7.6.0->anywidget) (9.3.0)
 Requirement already satisfied: traitlets>=4.3.1 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from ipywidgets>=7.6.0->anywidget) (5.14.3)
 Requirement already satisfied: widgetsnbextension~=4.0.14 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from ipywidgets>=7.6.0->anywidget) (4.0.15)
 Requirement already satisfied: jupyterlab_widgets~=3.0.15 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from ipywidgets>=7.6.0->anywidget) (3.0.16)
 Requirement already satisfied: decorator in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (5.2.1)
 Requirement already satisfied: ipython-pygments-lexers in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (1.1.1)
 Requirement already satisfied: jedi>=0.16 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (0.19.2)
 Requirement already satisfied: matplotlib-inline in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (0.1.7)
 Requirement already satisfied: pexpect>4.3 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (4.9.0)
 Requirement already satisfied: prompt_toolkit<3.1.0,>=3.0.41 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (3.0.51)
 Requirement already satisfied: pygments>=2.4.0 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (2.19.1)
 Requirement already satisfied: stack_data in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (0.6.3)
 Requirement already satisfied: wcwidth in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from prompt_toolkit<3.1.0,>=3.0.41->ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (0.2.13)
 Requirement already satisfied: parso<0.9.0,>=0.8.4 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from jedi>=0.16->ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (0.8.4)
 Requirement already satisfied: ptyprocess>=0.5 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from pexpect>4.3->ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (0.7.0)
 Requirement already satisfied: executing>=1.2.0 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from stack_data->ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (2.2.0)
 Requirement already satisfied: asttokens>=2.1.0 in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from stack_data->ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (3.0.0)
 Requirement already satisfied: pure-eval in /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages (from stack_data->ipython>=6.1.0->ipywidgets>=7.6.0->anywidget) (0.2.3)
 Downloading anywidget-0.11.0-py3-none-any.whl (317 kB)
 Downloading psygnal-0.15.1-cp313-cp313-macosx_11_0_arm64.whl (574 kB)
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 574.8/574.8 kB 10.5 MB/s  0:00:00
 [?25hInstalling collected packages: psygnal, anywidget
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2/2 [anywidget]
 Successfully installed anywidget-0.11.0 psygnal-0.15.1

 [notice] A new release of pip is available: 25.2 -> 26.1.1
 [notice] To update, run: pip install --upgrade pip
 Note: you may need to restart the kernel to use updated packages.

Now create a button that synchronizes Counter value with JS value

import anywidget
import traitlets


class Counter(anywidget.AnyWidget):
    _esm = r'''
    export function render({ model, el }) {
        const bm = document.createElement('button');
        bm.textContent = '-';

        const bp = document.createElement('button');
        bp.textContent = '+';

        const span = document.createElement('span');
        span.style.marginLeft = '10px';
        span.style.marginRight = '10px';

        const set_span = () => {
            span.textContent = String(model.get('value'));
        };

        bm.addEventListener('click', () => {
            const x = model.get('value');
            model.set('value', x - 1);
            model.save_changes();
        });

        bp.addEventListener('click', () => {
            const x = model.get('value');
            model.set('value', x + 1);
            model.save_changes();
        });

        model.on('change:value', set_span);

        el.appendChild(bm);
        el.appendChild(span);
        el.appendChild(bp);

        set_span();
    }
    '''
    value = traitlets.Int(0).tag(sync=True)


c = Counter()
c
 <__main__.Counter object at 0x10aa09940>

This number here will change (when reevaluated) with Counter’s value changing above

c.value
 0
def a_w(min=0, max=100):
    @widgets.interact(x=(min,max))
    def f(x=50):
        print(x)
a_w(20, 60)
 interactive(children=(IntSlider(value=50, description='x', max=60, min=20), Output()), _dom_classes=('widget-i…
def a_w(min=0, max=100):
    @widgets.interact(x=(min,max))
    def f(x=(min+max)//2):
        print(x)
a_w(10, 20)
 interactive(children=(IntSlider(value=15, description='x', max=20, min=10), Output()), _dom_classes=('widget-i…