<jupyter_start><jupyter_text>Javascript callbacksHere is a short demo of interactive Bokeh plot using Javascript callbacks which we are going to discuss in the tutorial. Unfortunately I did not manage to write a guide on this topic, so we will discuss this during the tutorial instead (assuming we have time). For more information please refer to [the documentation on callbacks](https://bokeh.pydata.org/en/latest/docs/user_guide/interaction/callbacks.html).For this section, a basic knowledge of JavaScript is required. It is possible to write a Python code that gets translated to JavaScript ([see here](https://bokeh.pydata.org/en/latest/docs/user_guide/interaction/callbacks.htmlcustomjs-with-a-python-function)) but I found this to be quite limiting. It is also possible to have interactivity using just Python, but this involves running a Bokeh server ([see here](https://bokeh.pydata.org/en/latest/docs/user_guide/server.html)).Our first example comes from the first example in the documentation (with slight modification).<jupyter_code>import numpy as np
from bokeh.layouts import column
from bokeh.models import CustomJS, ColumnDataSource, Slider
from bokeh.plotting import figure, output_notebook, show

output_notebook()

x_1 = np.linspace(0,1,200) # create range from 0 to 1 with 200 intervals for x
y_1 = np.linspace(0,1,200) # create range from 0 to 1 with 200 intervals for y

source_1 = ColumnDataSource(data=dict(x=x_1, y=y_1))

plot_1 = figure(plot_width=400, plot_height=400)
plot_1.line('x', 'y', source=source_1, line_width=3, line_alpha=0.6)

callback_1 = CustomJS(args=dict(source=source_1), code="""
    var data = source.data;
    var f = cb_obj.value
    var x = data['x']
    var y = data['y']
    for (var i = 0; i < x.length; i++) {
        y[i] = Math.pow(x[i], f)
    }
    source.change.emit();
""")

slider_1 = Slider(start=0.1, end=4, value=1, step=.1, title="power")
slider_1.js_on_change('value', callback_1)

layout_1 = column(slider_1, plot_1)

show(layout_1)<jupyter_output><empty_output><jupyter_text>Our second example is a lot more involved. Based on the elements plot in the previous section, we are going to filter the data using javascript.<jupyter_code>import pandas as pd

elements_df = pd.read_csv('../data/elements.csv',
    usecols=[0,1,2,3,12,14,15,16,18],
    nrows=54)
elements = ColumnDataSource.from_df(elements_df)
from bokeh.plotting import figure
from bokeh.io import output_notebook, show, curdoc
from bokeh.models import ColumnDataSource, Div

output_notebook()

source = ColumnDataSource(data=dict(x =[],
                                    y =[],
                                    mp = [],
                                    bp = [],
                                    yr = [],
                                    name = [],
                                   )
                         )

TOOLTIPS = [('name','@name'),
            ('melting point','@{mp}'),
            ('boiling point','@{bp}'),
            ('year discovered','@{yr}'),
           ]

elements_fig = figure(plot_width=900, plot_height=600, 
                         x_range=(1800,1900), y_range=(0,5000),
                         tooltips=TOOLTIPS)
elements_fig.circle(x='x',y='y',source = source, size=20,line_color=None,)
from bokeh.models.callbacks import CustomJS

update = CustomJS(args=dict(source=source, elements=elements),code="""
    var s_name = elements['name']
    var s_yr = elements['year discovered']
    var s_mp = elements['melting point']
    var s_bp = elements['boiling point']
    var s_st = elements['standard state']

    var f = cb_obj.value;
    
    var name=[];
    var x=[];
    var y=[];
    var mp=[];
    var bp=[];
    
    if (f !== 'all'){
        for(var i=0; i<s_name.length;i++){

            if (s_st[i] === f){
                x.push(s_yr[i]);
                y.push(s_bp[i]);
                name.push(s_name[i]);
                mp.push(s_mp[i]);
                bp.push(s_bp[i]);
                
            }
        }
    }
    source.data['x'] = x;
    source.data['y'] = y;
    source.data['name'] = name;
    source.data['mp'] = mp;
    source.data['bp'] = bp;
    source.data['yr'] = x;
    
    console.log(source.data);
    source.change.emit();
""")
from bokeh.models.widgets import Select
from bokeh.layouts import layout, widgetbox

standard_state = list(elements_df['standard state'].unique())
standard_state.append('all')
standard_state

state_selector = Select(title = 'Standard state', options = standard_state, value='all')
#state_selector.js_on_change('value',CustomJS.from_py_func(update2))
state_selector.js_on_change('value',update)

inputs = widgetbox(state_selector)

main_layout = layout(inputs,elements_fig)
show(main_layout)
print(source)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12761944677284157, 'fraction_numerical': 0.019069572506286672, 'mean_word_length': 3.024451939291737, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '286466', 'license': 'MIT', 'n_tokens_mistral': 1567, 'n_tokens_neox': 1491, 'n_words': 386, 'path': 'bokeh_tutorial/3-bokeh-javascript.ipynb', 'repo_name': 'sutantyo/matplotlib_tutorial', 'size': '4772'}