1

Assume the source has 4 columns named time_s, time_min, time_h and y.

source = ColumnDataSource(...) 

Then from those columns initially time_s and y are selected

p = figure(tools=tools, toolbar_location="above")
p.line(x='time_s', y='y', source=source)

In a CustomJS callback codeblock I would like to switch the x-column from time_s to maybe time_min and rerender the plot accordingly. I know how I can explore / access some of the data and objects in general by analysing them in the DevTools-console, but I cannot find the x='time_s' from the p.line object or how it can be accessed.

js = """
// Explore Objects in DevTools Console
console.log(data)
console.log(source)
console.log(plot) 

data = source.data
data['time_s'] = do something to column here ...

if (widget.value === 'xyz') {
    // Looking for something like:
    plot.line.x = data['time_min'] // not working
}

// After data change -> rerender
source.change.emit()

"""
cb = CustomJS(args=dict(src=source, plot=p, widget=mywidget), code=js)
mywidget.js_on_change('value', cb)

So how can this be done?

1
  • I know that I could just recalculate the column from 's' to 'min' and 'h' easily in a mathematical way, but this is a more general question, thx :) Commented Jun 9, 2019 at 23:21

1 Answer 1

2

There are a variety of ways I can imagine doing this. Assuming you can tolerate one column being duplicated in the data source, this is what I would suggest:

import numpy as np

from bokeh.io import show
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, CustomJS, Select
from bokeh.plotting import figure

x = np.linspace(0, 10, 100)
foo = x**2
bar = np.sin(x)

source = ColumnDataSource(data=dict(x=x, y=foo, foo=foo, bar=bar))

plot = figure(plot_height=350)
plot.line(x='x', y='y', source=source)

select = Select(value='foo', options=['foo', 'bar'])
select.js_on_change('value', CustomJS(args=dict(source=source, select=select), code="""
    // make a shallow copy of the current data dict
    const new_data = Object.assign({}, source.data)

    // update the y column in the new data dict from the appropriate other column
    new_data.y = source.data[select.value]

    // set the new data on source, BokehJS will pick this up automatically
    source.data = new_data
"""))

show(column(plot, select))

If duplicating the selected column in to the "y" column is not acceptable, then it is possible to update the glyph, to change what column it points at. That would look something like this:

r = p.line(x='x', y='foo' source=source)

cb = CustomJS(args=dict(r=r, select=select), code="""
    // tell the glyph which field of the source y should refer to
    r.glyph.y.field = select.value

    // manually trigger change event to re-render
    r.glyph.change.emit()
""")
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you @bigreddot, the second example was exactly what I was looking for.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.