Развертывание документа Bokeh на сервере - PullRequest
0 голосов
/ 28 января 2020

Я следую приведенному ниже примеру кода. В настоящее время он отображает график и связанный с ним ползунок, встроенный в do c, возвращенный функцией "modify_do c" в записной книжке. Тем не менее, я хотел бы развернуть его на своем собственном сервере, чтобы получить GUI, при этом сохраняя возможность запуска обратного вызова при изменении ползунка и обновления графика. Однако, когда я пытаюсь использовать Panel Pyviz для ее развертывания, она просто отображает сообщение «» на всплывающем сервере. Как развернуть do c таким образом, чтобы отображалось изображение?

import numpy as np
import holoviews as hv

from bokeh.io import show, curdoc
from bokeh.layouts import layout
from bokeh.models import Slider, Button

renderer = hv.renderer('bokeh').instance(mode='server')

# 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])

# Define valid function for FunctionHandler
# when deploying as script, simply attach to curdoc
def modify_doc(doc):
    # Create HoloViews plot and attach the document
    hvplot = renderer.get_plot(dmap, doc)

    # Create a slider

    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)

    # Combine the holoviews plot and widgets in a layout
    plot = layout([
    [hvplot.state],
    [slider]], sizing_mode='fixed')

    doc.add_root(plot)
    return doc

# To display in the notebook
show(modify_doc, notebook_url='localhost:8888')

# To display in a script
doc = modify_doc(curdoc()) 

# To deploy to separate server using Panel (attempt, doesn't work. Just displays #"<bokeh.document.document.Document object at 0x00000193EC5FFE80>":

graph = pn.Row (doc)
graph.show()

1 Ответ

0 голосов
/ 01 февраля 2020

В вашем примере происходит смешивание очень разных 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, но она гарантируется, даже если вы запустите приложение в виде сценария, в котором каждый пользователь получает новый экземпляр приложения, который не разделяет состояние со всеми остальными.

...