Widget

import ipywidgets as ipw
from IPython.display import SVG

from pyabc2.abcjs.widget import ABCJSWidget, interactive

The display widget

Used to display Tunes in the notebook environment. ABCJSWidget supports many of the abcjs render options.

# Nothing (or logo if abcjs hasn't been loaded yet)
ABCJSWidget()
# Nothing
ABCJSWidget()
# Really nothing
ABCJSWidget(hide=True)
# Just logo
ABCJSWidget(logo=True)
# Logo and a bit of music
ABCJSWidget(abc="DEFG E2 CD- | D8 ||", logo=True)
# Slightly more complicated example
ABCJSWidget(abc="K:G\n" + " G,A,B,C DEFG | " * 4, staff_width=500, foreground="teal")
# Adding ABC and modifying parameters after init
w = ABCJSWidget()
w.abc = """\
K: G
G,A,B,C DEFG | ABcd efga | bc'd'e' f'g'a'b' |
"""
w.scale = 0.8
w.staff_width = 550
display(w)
# Dynamic update
# Note both display instances are modified!
w.abc += "| c'"
w

Save the SVG from the display widget

It doesn’t seem to be possible to do this with a single cell, but with two cells we can get to the SVGs (based on experiments in JupyterLab).

w = ABCJSWidget(hide=True)
w.abc = """\
K: G
G,A,B,C DEFG | ABcd efga | bc'd'e' f'g'a'
"""
display(w)
print(w.svgs)  # NOTE: Empty at this point
[]
# NOTE: must run this cell again for `.svgs` to be populated if using restart and run (to selected cell or full)
print(len(w.svgs), "SVG(s)")
for i, s in enumerate(w.svgs):
    display(SVG(s))
0 SVG(s)

Editor

Note

The docs version doesn’t currently provide full interactivity (a running Python kernel is needed, e.g. JupyterLab).

interactive()

Editor example

With a single widget instance, both display instances should update when you change something.

Here, we initialize the widget with some ABC and a few non-default settings.

abc = "K: C\nM: 4/4\nT: The best scale\n" + '"C"' + "CDEF GABc | " * 4

w = interactive(abc, foreground="#808080", staff_width=600)
w
w

Compare to ipywidgets behavior

slider = ipw.FloatSlider(min=200, max=500, value=400)
slider
# We can do this and all display instances change and the slider still shows for this cell
slider.value += 1
slider

Headless

We can also use abcjs in the background via Node.js using pyabc2.abcjs.headless.

from IPython.display import SVG, Image

from pyabc2.abcjs.headless import svg, svg_to
s = svg("CDEF GABc |")
print(s[:100], "...")
SVG(s)
(node:696) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
added 40 packages, and audited 41 packages in 3s

9 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
npm notice
npm notice New minor version of npm available! 11.11.0 -> 11.12.1
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.12.1
npm notice To update run: npm install -g npm@11.12.1
npm notice
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" fill=" ...
../_images/30a48b5a0e01f07848c3e4dfc4d25f8a1039c5c4c693ac2960e4756ac82c0c9b.svg

build() is automatically called if needed. The next time we call svg(), it should be faster.

SVG(svg("A2 B2 C2 D2 |"))
../_images/e7b4de4f27d1b1bc082b43f87875bbd933e3e7a5f9f0b563063d38c881e06f13.svg
try:
    display(Image(data=svg_to(s, "png")))
except RuntimeError:
    print("failed to load cairo")
../_images/443ef7ecc85e48dfe62ceb886e6c509f55c26f3ba9f93bfd77e1a25e6c5ffcec.png