В вашем примере происходит смешивание очень разных API. Панель предназначена для упрощения некоторых API-интерфейсов Bokeh, поэтому многое из того, что вы здесь делаете, не нужно. Тем не менее, я предоставлю несколько версий, которые либо используют только компоненты Panel, либо объединяют компоненты Panel и bokeh.
Для начала вот как я мог бы написать этот пример, используя просто Panel:
import numpy as np
import panel as pn
import holoviews as hv
pn.extension()
start, end = 0, np.pi*2
slider = pn.widgets.FloatSlider(start=start, end=end, value=start, step=0.2, name="Phase")
@pn.depends(phase=slider.param.value)
def sine(phase):
xs = np.linspace(0, np.pi*4)
return hv.Curve((xs, np.sin(xs+phase))).opts(width=800)
dmap = hv.DynamicMap(sine)
row = pn.Row(dmap, slider)
# Show in notebook
row.app('localhost:8888')
# Open a server
row.show()
# To deploy this using `panel serve` or `bokeh serve`
row.servable()
В вашем примере вы вместо этого используете различные компоненты боке, это также возможно и может быть желательно, если у вас уже есть код боке.
import numpy as np
import holoviews as hv
import panel as pn
from bokeh.models import Slider, Button
# Create the holoviews app again
def sine(phase):
xs = np.linspace(0, np.pi*4)
return hv.Curve((xs, np.sin(xs+phase))).opts(width=800)
stream = hv.streams.Stream.define('Phase', phase=0.)()
dmap = hv.DynamicMap(sine, streams=[stream])
def slider_update(attrname, old, new):
# Notify the HoloViews stream of the slider update
stream.event(phase=new)
start, end = 0, np.pi*2
slider = Slider(start=start, end=end, value=start, step=0.2, title="Phase")
slider.on_change('value', slider_update)
graph = pn.Row(dmap, slider)
# Show in notebook
row.app('localhost:8888')
# Open a server
row.show()
# To deploy this using `panel serve` or `bokeh serve`
row.servable()
Если вы хотите обслуживать эти приложения нескольким людям, я определенно рекомендую использовать panel serve
, но если вы действительно хотите создать скрипт, который вы можете запустить с python script.py
, вы должны сделать это:
def app():
start, end = 0, np.pi*2
slider = pn.widgets.FloatSlider(start=start, end=end, value=start, step=0.2, name="Phase")
@pn.depends(phase=slider.param.value)
def sine(phase):
xs = np.linspace(0, np.pi*4)
return hv.Curve((xs, np.sin(xs+phase))).opts(width=800)
dmap = hv.DynamicMap(sine)
return pn.Row(dmap, slider)
pn.serve({'/': app})
Для этого требуется последняя версия Panel, но она гарантируется, даже если вы запустите приложение в виде сценария, в котором каждый пользователь получает новый экземпляр приложения, который не разделяет состояние со всеми остальными.