Right, so here are a couple of more examples:
This is an example using ipywidgets.widgets.interactive_output - to me it looks as sluggish as the previous solution:
import bokeh.plotting as bplt
from jupyter_bokeh.widgets import BokehModel
import bokeh.io
import numpy as np
import pandas as pd
import requests
import random
from ipywidgets import widgets, Layout
from IPython.display import display
# for the ipython notebook
bplt.output_notebook()
CSSNAMESLINK="https://gist.githubusercontent.com/ek/913fe6905da054977ab9ebc00fc43470/raw/4294f90b9dee884a1146e40e7fc57ada62eb82a0/html-color-names-keywords-list.txt"
css_response = requests.get(CSSNAMESLINK)
cssnames = css_response.text.split()
# generate simulated data
numvals = 1000 # 10000
#numvals = 10
xcol = np.arange(0, numvals, 1)
df = pd.DataFrame(dtype=np.int64)
for iser in range(0, 3):
for ix in xcol:
irow = iser*len(xcol)+ix
df.at[irow, 0] = int(iser)
df.at[irow, 1] = int(ix)
df.at[irow, 2] = int( ix*(iser+2)*0.3 )
df = df.rename(columns={0: "ser", 1: "xcol", 2: "ycol"})
df = df.astype(np.int64) # without this, getting floats
# prepare plot
datachans = df["ser"].unique()
mycolors = random.sample(cssnames, len(datachans))
print(mycolors)
myfig = bplt.figure(plot_height=300, tools="pan,wheel_zoom,box_zoom,hover,reset", sizing_mode="stretch_width")
traces_l = []
for ichan in datachans:
# use .circle here instead of .line, as it meeds more drawing/is more sluggish
line = myfig.circle([0,0], [0,0], line_width=2, line_color=mycolors[ichan])
traces_l.append(line)
myfig.x_range.start = 0 ; myfig.x_range.end = numvals
myfig.y_range.start = 0 ; myfig.y_range.end = numvals
the_slider = widgets.IntSlider(min=0, max=len(datachans), description='Test:')
myfig_model = BokehModel(myfig)
the_ui = widgets.VBox([the_slider, myfig_model])
def update_plot(newval):
final_newval = newval*0.1*numvals
for ichan in datachans:
this_ch_data = df[df["ser"]==ichan]
traces_l[ichan].data_source.data={ 'x': this_ch_data["xcol"].values, 'y': this_ch_data["ycol"].values+final_newval }
bokeh.io.push_notebook()
out = widgets.interactive_output(update_plot, {'newval': the_slider})
display(the_ui)
on_slider_change({'type': 'change', 'name': 'value', 'new': 0 }) # initial call
And here is one, that uses bokeh.io.push_notebook
and notebook_handle=True
- it seems much faster/more responsive – regardless if the_slider.observe
is used, or if widgets.interactive_output
is used.
import bokeh.plotting as bplt
from jupyter_bokeh.widgets import BokehModel
import bokeh.io
import numpy as np
import pandas as pd
import requests
import random
from ipywidgets import widgets, Layout
from IPython.display import display
# for the ipython notebook
bplt.output_notebook()
CSSNAMESLINK="https://gist.githubusercontent.com/ek/913fe6905da054977ab9ebc00fc43470/raw/4294f90b9dee884a1146e40e7fc57ada62eb82a0/html-color-names-keywords-list.txt"
css_response = requests.get(CSSNAMESLINK)
cssnames = css_response.text.split()
# generate simulated data
numvals = 1000 # 10000
#numvals = 10
xcol = np.arange(0, numvals, 1)
df = pd.DataFrame(dtype=np.int64)
for iser in range(0, 3):
for ix in xcol:
irow = iser*len(xcol)+ix
df.at[irow, 0] = int(iser)
df.at[irow, 1] = int(ix)
df.at[irow, 2] = int( ix*(iser+2)*0.3 )
df = df.rename(columns={0: "ser", 1: "xcol", 2: "ycol"})
df = df.astype(np.int64) # without this, getting floats
# prepare plot
datachans = df["ser"].unique()
mycolors = random.sample(cssnames, len(datachans))
print(mycolors)
myfig = bplt.figure(plot_height=300, tools="pan,wheel_zoom,box_zoom,hover,reset", sizing_mode="stretch_width")
traces_l = []
for ichan in datachans:
# use .circle here instead of .line, as it meeds more drawing/is more sluggish
line = myfig.circle([0,0], [0,0], line_width=2, line_color=mycolors[ichan])
traces_l.append(line)
myfig.x_range.start = 0 ; myfig.x_range.end = numvals
myfig.y_range.start = 0 ; myfig.y_range.end = numvals
the_slider = widgets.IntSlider(min=0, max=len(datachans), description='Test:')
the_ui = widgets.VBox([the_slider])
def update_plot(newval):
final_newval = newval*0.1*numvals
for ichan in datachans:
this_ch_data = df[df["ser"]==ichan]
traces_l[ichan].data_source.data={ 'x': this_ch_data["xcol"].values, 'y': this_ch_data["ycol"].values+final_newval }
bokeh.io.push_notebook(handle=nbhandle)
def on_slider_change(change):
if change['type'] == 'change' and change['name'] == 'value': # prevent multiple hits upon single value change
update_plot(change['new'])
the_slider.observe(on_slider_change)
nbhandle = bokeh.io.show(myfig, notebook_handle=True)
display(the_ui)
the_slider.value = 1 # initial call
EDIT: also discovered, that this works:
import bokeh.plotting as bplt
from jupyter_bokeh.widgets import BokehModel
import bokeh.io
from bokeh.io.notebook import run_notebook_hook
from bokeh.io.state import curstate
....
state = curstate()
nbhandle = run_notebook_hook(state.notebook_type, 'doc', myfig, state, notebook_handle=True)
myfig_model = BokehModel(nbhandle._doc.roots[0])
the_ui = widgets.VBox([the_slider, myfig_model])
display(the_ui)
… however, unfortunately, the call to run_notebook_hook
also draws the plot, so then the last display(the_ui)
will draw a second plot - otherwise, this could have made BokehModel
for ipywidgets work with push_notebook
without problems (actually, it does work, its just that two graphs are needlessly updated)