Skip to content

Instantly share code, notes, and snippets.

@scottire
Last active March 11, 2023 10:42
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save scottire/a8e5b74efca37945c0f1b0670761d568 to your computer and use it in GitHub Desktop.
Save scottire/a8e5b74efca37945c0f1b0670761d568 to your computer and use it in GitHub Desktop.
Interactive and clickable plots using Panel, Holoviz and Bokeh in Jupyter Notebooks
import numpy as np
import panel as pn
import holoviews as hv
hv.extension("bokeh")
# hv.extension('matplotlib')
from holoviews.streams import Stream, Params
from scipy.io import wavfile
from scipy.signal import spectrogram
rate, data = wavfile.read('/filepath.wav')
width = 1000
audio = pn.pane.Audio(data, sample_rate=rate, name='Audio', throttle=500)
time = np.linspace(0, len(data) / rate, num=len(data))
line_plot = hv.Curve((time, data), ["time (s)","amplitude"]).opts(width=width)
f, t, sxx = spectrogram(data, rate)
spec_gram = hv.Image((t, f, np.log10(sxx)), ["time (s)","frequency (hz)"]).opts(width=width)
def interactive_play(x,y,t):
if x is None:
return hv.VLine(t).opts(color='green')
else:
audio.time = x
return hv.VLine(x).opts(color='green')
stream = Params(parameters=[audio.param.time], rename={'time': 't'})
tap = hv.streams.SingleTap(transient=True)
dmap_time = hv.DynamicMap(interactive_play, streams=[stream, tap])
pn.Column( audio, (spec_gram * dmap_time), (line_plot * dmap_time))
@philippjfr
Copy link

philippjfr commented Jun 4, 2020

Minor suggestions for simplification:

  1. You only need either pn.extension or hv.extension, i.e. hv.extension("bokeh") should be sufficient.

  2. You can now use pn.depends or param.depends to declare DynamicMap callbacks:

tap = hv.streams.SingleTap(transient=True)

@pn.depends(x=tap.param.x, y=tap.param.y, t=audio.param.time) 
def interactive_play(x, y, t):
    if x is None:
        return hv.VLine(t).opts(color='green')
    else:
        audio.time = x
        return hv.VLine(x).opts(color='green')

dmap_time = hv.DynamicMap(interactive_play)

@scottire
Copy link
Author

scottire commented Jun 5, 2020

Thanks @philippjfr, I've tried your suggestions and the #2 decorator strangely stops the tap event from working.
I removed audio.param.time to simplify things

This works:

tap = hv.streams.SingleTap(x=0, y=0, transient=True)
def interactive_play(x,y):
    return hv.VLine(x).opts(color='green')
dmap_time = hv.DynamicMap(interactive_play, streams=[tap])

This doesn't:

tap = hv.streams.SingleTap(x=0, y=0, transient=True)
@pn.depends(x=tap.param.x, y=tap.param.y) 
def interactive_play(x,y):
    return hv.VLine(x).opts(color='green')
dmap_time = hv.DynamicMap(interactive_play)

I'm sure there's something obvious I'm missing. Should that above code work or is there something I'm doing wrong?

@philippjfr
Copy link

Hmm, odd, which version of HoloViews do you have?

@scottire
Copy link
Author

scottire commented Jun 5, 2020

which version of HoloViews do you have

import holoviews as hv
hv.__version__
>>> '1.13.2'

@sonal-ssj
Copy link

sonal-ssj commented Feb 26, 2021

Thanks for this wonderful idea and code. I'm able to plot the spectrogram and audio, however the audio doesn't seem to play.
image

Strangely, it works for normal display audio though. I'm using holoviews version '1.14.2a5' and jupyter lab.
Any suggestions?

@VladSkripniuk
Copy link

There is a related issue, pane Audio is broken for np.array waveform input. Downgrading to panel==0.10.3 solved the issue where audio doesn't seem to play for me.

@aqibsaeed
Copy link

I tried this but the vertical line is not sliding as the audio is being played. Any ideas what could be the reason?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment