Je me prépare à utiliser le bokeh pour une implémentation interactive en ligne de certains modèles python que j'ai écrits).
L'étape 1 consiste à comprendre quelques exemples interactifs de base, mais je ne peux pas obtenir les exemples d'introduction exécutés de manière INTERACTIVE dans un cahier Jupyter. J'espère que quelqu'un pourra corriger ma mauvaise compréhension de ce qui est un copier-coller du propre code d'exemple de bokeh.
Je suis conscient que la documentation de Bokeh n'est pas parfaite (j'ai corrigé une référence obsolète à bokeh.plotting.show
plutôt que io.show
), mais je pense que la structure de base que j'utilise devrait être proche de la corriger.
le code est basé sur: https://github.com/bokeh/bokeh/blob/master/examples/app/sliders.py
https://docs.bokeh.org/en/latest/docs/user_guide/notebook.html
############ START BOILERPLATE ############
#### Interactivity -- BOKEH
import bokeh.plotting.figure as bk_figure
from bokeh.io import curdoc, show
from bokeh.layouts import row, widgetbox
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Slider, TextInput
from bokeh.io import output_notebook # enables plot interface in J notebook
# init bokeh
output_notebook()
############ END BOILERPLATE ############
# Set up data
N = 200
x = np.linspace(0, 4*np.pi, N)
y = np.sin(x)
source = ColumnDataSource(data=dict(x=x, y=y))
# Set up plot
plot = bk_figure(plot_height=400, plot_width=400, title="my sine wave",
tools="crosshair,pan,reset,save,wheel_zoom",
x_range=[0, 4*np.pi], y_range=[-2.5, 2.5])
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)
# Set up widgets
text = TextInput(title="title", value='my sine wave')
offset = Slider(title="offset", value=0.0, start=-5.0, end=5.0, step=0.1)
amplitude = Slider(title="amplitude", value=1.0, start=-5.0, end=5.0, step=0.1)
phase = Slider(title="phase", value=0.0, start=0.0, end=2*np.pi)
freq = Slider(title="frequency", value=1.0, start=0.1, end=5.1, step=0.1)
# Set up callbacks
def update_title(attrname, old, new):
plot.title.text = text.value
text.on_change('value', update_title)
def update_data(attrname, old, new):
# Get the current slider values
a = amplitude.value
b = offset.value
w = phase.value
k = freq.value
# Generate the new curve
x = np.linspace(0, 4*np.pi, N)
y = a*np.sin(k*x + w) + b
source.data = dict(x=x, y=y)
### I thought I might need a show() here, but it doesn't make a difference if I add one
# show(layout)
for w in [offset, amplitude, phase, freq]:
w.on_change('value', update_data)
# Set up layouts and add to document
inputs = widgetbox(text, offset, amplitude, phase, freq)
layout = row(plot,
widgetbox(text, offset, amplitude, phase, freq))
curdoc().add_root(row(inputs, layout, width=800))
curdoc().title = "Sliders"
show(layout)
Je génère un tracé comme ci-dessous, mais la figure ne se met pas à jour lorsque les curseurs sont déplacés (ni lorsque le texte du titre est mis à jour)
Merci beaucoup pour toutes suggestions.
PS. J'essaie de garder ce code aussi près que possible de quelque chose que je peux implémenter avec des fichiers .py sur un serveur, évitant ainsi les solutions de contournement spécifiques à jupyter comme Push_notebook
.
Je suis d'accord (en tant qu'utilisateur) que les documents pourraient être meilleurs à ce sujet. J'ai dû chercher beaucoup pour trouver la procédure, mais quand vous la trouvez, ce n'est pas si difficile! J'ai modifié votre code, vous pouvez l'exécuter dans le cahier Jupyter.
L'astuce est:
from bokeh.application import Application
from bokeh.application.handlers import FunctionHandler
.
.
<your code here>
.
.
#add server-related code inside this modify_doc function
def modify_doc(doc): #use doc as you use curdoc() in bokeh server
doc.add_root(<your_layout>)
doc.on_change(...)
doc.add_periodic_callback(...)
handler = FunctionHandler(modify_doc)
app = Application(handler)
show(app)
et la version modifiée de votre code:
############ START BOILERPLATE ############
#### Interactivity -- BOKEH
import bokeh.plotting.figure as bk_figure
from bokeh.io import curdoc, show
from bokeh.layouts import row, widgetbox
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Slider, TextInput
from bokeh.io import output_notebook # enables plot interface in J notebook
import numpy as np
# init bokeh
from bokeh.application import Application
from bokeh.application.handlers import FunctionHandler
output_notebook()
############ END BOILERPLATE ############
# Set up data
N = 200
x = np.linspace(0, 4*np.pi, N)
y = np.sin(x)
source = ColumnDataSource(data=dict(x=x, y=y))
# Set up plot
plot = bk_figure(plot_height=400, plot_width=400, title="my sine wave",
tools="crosshair,pan,reset,save,wheel_zoom",
x_range=[0, 4*np.pi], y_range=[-2.5, 2.5])
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)
# Set up widgets
text = TextInput(title="title", value='my sine wave')
offset = Slider(title="offset", value=0.0, start=-5.0, end=5.0, step=0.1)
amplitude = Slider(title="amplitude", value=1.0, start=-5.0, end=5.0, step=0.1)
phase = Slider(title="phase", value=0.0, start=0.0, end=2*np.pi)
freq = Slider(title="frequency", value=1.0, start=0.1, end=5.1, step=0.1)
# Set up callbacks
def update_title(attrname, old, new):
plot.title.text = text.value
def update_data(attrname, old, new):
# Get the current slider values
a = amplitude.value
b = offset.value
w = phase.value
k = freq.value
# Generate the new curve
x = np.linspace(0, 4*np.pi, N)
y = a*np.sin(k*x + w) + b
source.data = dict(x=x, y=y)
### I thought I might need a show() here, but it doesn't make a difference if I add one
# show(layout)
for w in [offset, amplitude, phase, freq]:
w.on_change('value', update_data)
# Set up layouts and add to document
inputs = widgetbox(text, offset, amplitude, phase, freq)
layout = row(plot,
widgetbox(text, offset, amplitude, phase, freq))
def modify_doc(doc):
doc.add_root(row(layout, width=800))
doc.title = "Sliders"
text.on_change('value', update_title)
handler = FunctionHandler(modify_doc)
app = Application(handler)
show(app)