Синхронизация HoloViews VLine с PyViz Panel audio.time

Я хочу визуализировать в графике HoloViews, где текущий звук находится на графике. Эта строка должна обновляться автоматически при изменении значения pn.pane.Audio.time PyViz (при воспроизведении звука или изменении Audio.time).

Моя попытка:

# Python 3.7 in JupyterLab
import numpy as np
import holoviews as hv  # interactive plots
hv.notebook_extension("bokeh")
import panel as pn
pn.extension()
from holoviews.streams import Stream, param

# create sound
sps = 44100 # Samples per second
duration = 10 # Duration in seconds
modulator_frequency = 2.0
carrier_frequency = 120.0
modulation_index = 2.0

time = np.arange(sps*duration) / sps
modulator = np.sin(2.0 * np.pi * modulator_frequency * time) * modulation_index
carrier = np.sin(2.0 * np.pi * carrier_frequency * time)
waveform = np.sin(2. * np.pi * (carrier_frequency * time + modulator))
waveform_quiet = waveform * 0.3
waveform_int = np.int16(waveform_quiet * 32767)

# PyViz Panel's Audio widget to play sound
audio = pn.pane.Audio(waveform_int, sample_rate=sps)
# generated plotting data
x = np.arange(11.0)
y = np.arange(11.0, 0.0, -1) / 10
y[0::2] *= -1  # alternate positve-negative
# HoloViews line plot
line_plot = hv.Curve((x, y)).opts(width=500)

# should keep track of audio.time; DOES NOT WORK
Time = Stream.define('Time', t=param.Number(default=0.0, doc='A time parameter'))
time = Time(t=audio.time)

# callback to draw line when time value changes
def interactive_play(t):
    return hv.VLine(t).opts(color='green')

# dynamic map plot of line for current audio time
dmap_time = hv.DynamicMap(interactive_play, streams=[time])

# display Audio pane
display(audio)
# combine plot with stream of audio.time
line_plot * dmap_time

Почему это не работает?

Поскольку время установлено как param.Number(), я ожидаю, что это будет отслеживать audio.time. Следовательно, при воспроизведении звука необходимо постоянно вызывать обратный вызов interactive_play(), в результате чего линия перемещается по графику. Этого не происходит, и в строке остается только значение по умолчанию 0,0 (или любое другое значение, которое audio.time имеет во время выполнения кода).

Как мне обновить VLine, чтобы отслеживать audio.time?

Зеленая линия должна соответствовать времени звуковой панели

аудио-синхронизация панели фильмов


person NumesSanguis    schedule 27.11.2019    source источник


Ответы (1)


Поскольку время установлено как param.Number (), я ожидаю, что он будет отслеживать audio.time.

В вашем примере вы никоим образом не связываете объект Panel Audio с потоком. Все, что вы делаете, когда делаете это:

time = Time(t=audio.time)

устанавливает начальное значение вашего Time потока равным текущему значению Audio Pane. audio.time не является ссылкой на параметр, это просто текущее значение этого параметра.

HoloViews DynamicMaps уже довольно давно поддерживает возможность прослушивания параметров других объектов. Есть два основных способа сделать это, сделав что-нибудь вроде этого:

@pn.depends(t=audio.param.time)
def interactive_play(t):
    return hv.VLine(t).opts(color='green')

dmap_time = hv.DynamicMap(interactive_play)

Здесь вы украшаете функцию interactive_play зависимостью от параметра audio.time, поэтому при каждом изменении DynamicMap обновляется. Более явный способ сделать это и что на самом деле происходит внутри:

from holoviews.streams import Params

def interactive_play(t):
    return hv.VLine(t).opts(color='green')

stream = Params(parameters=[audio.param.time], rename={'time': 't'})
dmap_time = hv.DynamicMap(interactive_play, streams=[stream])

Если вам нужно обновить звуковые панели новыми файлами, я настоятельно рекомендую вам сделать это с помощью обратных вызовов вместо постоянного создания новых звуковых панелей с использованием интерактивных или реактивных API. Таким образом, вам также не придется обновлять поток для постоянно меняющихся звуковых панелей.

person philippjfr    schedule 28.11.2019
comment
Работает, спасибо! Обновление существующей звуковой панели действительно звучит лучше. Как мне обновить звук внутри этой панели? Что-то вроде audio.object = waveform_int) (если вы измените некоторые значения для генерации waveform_int), не работает. - person NumesSanguis; 29.11.2019