Using TapTool to draw underlying data in another plot.

Hi all,

Thank you for bokeh - it’s looking great and I’ve just started using it.
I’ve run into some trouble trying to make TapTool in one plot draw underlying data in another plot, i.e. the data points
in the first plot are all parameters from regression analysis and if one of those are “off” it would be useful to be able to
plot the data from the regression in another plot by clicking on the outlier.

Has anyone here done something similar already? Any help would be greatly appreciated.

Here is how far I got (using bokeh serve):
import numpy as np

from bokeh.io import curdoc
from bokeh.plotting import Figure, gridplot
from bokeh.models import ColumnDataSource, TapTool, CustomJS

Generate some fake data with noise to work with

xdata, ydata = ,
for xend, num_x, intercept, slope in zip([13,17,14], [23,27,14], [5, 9, 7], [2, 3, 5]):
xdata.append(np.linspace(0, xend, num_x))
ydata.append(intercept + slope*xdata[-1] + np.random.random(num_x))

Simulate data analysis: fitting 1st order polynomials: y = a + b*x

fits =
for x, y in zip(xdata, ydata):
fits.append(np.polyfit(x, y, 1))

source = ColumnDataSource(data={‘a’: , ‘b’: })
source.data[‘a’] = [f[1] for f in fits]
source.data[‘b’] = [f[0] for f in fits]

top = Figure(plot_height=600, plot_width=800, tools=‘tap’, title=‘y = a + b*x’)
top.xaxis.axis_label = ‘a’
top.yaxis.axis_label = ‘b’
cr = top.circle(x=‘a’, y=‘b’, source=source)

bottom = Figure(plot_height=600, plot_width=800, title=‘Data for respective fit’)
bottom.xaxis.axis_label = ‘x’
bottom.yaxis.axis_label = ‘y’
source0 = ColumnDataSource(data={‘xdat’: , ‘ydat’: })
source0.data[‘xdat’] = xdata[0]
source0.data[‘ydat’] = ydata[0]
serie = bottom.circle(x=‘xdat’, y=‘ydat’, source=source0)

taptool = top.select(type=TapTool)
taptool.callback = CustomJS(args=dict(bottom=bottom), code="""
var flag = cb_obj.get(‘selected’)[‘0d’].flag;
var index = cb_obj.get(‘selected’)[‘0d’].indices[0];
alert(“magic goes here”);
“”")

p = gridplot([[top], [bottom]])
curdoc().add_root(p)

``

So the second plot is static and shows the underlying data for the first data point in the upper plot.
What I would like to do s to update the data in bottom, (do I need to pass multiple ColumnDataSources? or can they be N-dimensional?)

Best regards,
Björn Dahlgren

Hi Bjorn,

Here is an example in the User's Guide that demonstrates updating a different glyph's data source based on a hover selection:
  
  Interaction — Bokeh 3.3.2 Documentation

That's not exactly the same thing, but it should translate fairly directly straight to the TapTool callback case.

Thanks,

Bryan

···

On Mar 1, 2016, at 6:10 PM, Björn Dahlgren <[email protected]> wrote:

Hi all,

Thank you for bokeh - it's looking great and I've just started using it.
I've run into some trouble trying to make TapTool in one plot draw underlying data in another plot, i.e. the data points
in the first plot are all parameters from regression analysis and if one of those are "off" it would be useful to be able to
plot the data from the regression in another plot by clicking on the outlier.

Has anyone here done something similar already? Any help would be greatly appreciated.

Here is how far I got (using bokeh serve):
import numpy as np

from bokeh.io import curdoc
from bokeh.plotting import Figure, gridplot
from bokeh.models import ColumnDataSource, TapTool, CustomJS

# Generate some fake data with noise to work with
xdata, ydata = ,
for xend, num_x, intercept, slope in zip([13,17,14], [23,27,14], [5, 9, 7], [2, 3, 5]):
    xdata.append(np.linspace(0, xend, num_x))
    ydata.append(intercept + slope*xdata[-1] + np.random.random(num_x))

# Simulate data analysis: fitting 1st order polynomials: y = a + b*x
fits =
for x, y in zip(xdata, ydata):
    fits.append(np.polyfit(x, y, 1))

source = ColumnDataSource(data={'a': , 'b': })
source.data['a'] = [f[1] for f in fits]
source.data['b'] = [f[0] for f in fits]

top = Figure(plot_height=600, plot_width=800, tools='tap', title='y = a + b*x')
top.xaxis.axis_label = 'a'
top.yaxis.axis_label = 'b'
cr = top.circle(x='a', y='b', source=source)

bottom = Figure(plot_height=600, plot_width=800, title='Data for respective fit')
bottom.xaxis.axis_label = 'x'
bottom.yaxis.axis_label = 'y'
source0 = ColumnDataSource(data={'xdat': , 'ydat': })
source0.data['xdat'] = xdata[0]
source0.data['ydat'] = ydata[0]
serie = bottom.circle(x='xdat', y='ydat', source=source0)

taptool = top.select(type=TapTool)
taptool.callback = CustomJS(args=dict(bottom=bottom), code="""
        var flag = cb_obj.get('selected')['0d'].flag;
        var index = cb_obj.get('selected')['0d'].indices[0];
        alert("magic goes here");
""")

p = gridplot([[top], [bottom]])
curdoc().add_root(p)

So the second plot is static and shows the underlying data for the first data point in the upper plot.
What I would like to do s to update the data in bottom, (do I need to pass multiple ColumnDataSources? or can they be N-dimensional?)

Best regards,
Björn Dahlgren

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/473e23d7-0443-4277-a7eb-609cb812b99c%40continuum.io\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

Hi Bjorn,

Just wondering if you were ever able to solve this issue and could post updated code to the synthetic data you provided above. I am having the same issue as you are.

Thank you

···

On Tuesday, March 1, 2016 at 7:10:01 PM UTC-5, Björn Dahlgren wrote:

Hi all,

Thank you for bokeh - it’s looking great and I’ve just started using it.
I’ve run into some trouble trying to make TapTool in one plot draw underlying data in another plot, i.e. the data points
in the first plot are all parameters from regression analysis and if one of those are “off” it would be useful to be able to
plot the data from the regression in another plot by clicking on the outlier.

Has anyone here done something similar already? Any help would be greatly appreciated.

Here is how far I got (using bokeh serve):
import numpy as np

from bokeh.io import curdoc
from bokeh.plotting import Figure, gridplot
from bokeh.models import ColumnDataSource, TapTool, CustomJS

Generate some fake data with noise to work with

xdata, ydata = ,
for xend, num_x, intercept, slope in zip([13,17,14], [23,27,14], [5, 9, 7], [2, 3, 5]):
xdata.append(np.linspace(0, xend, num_x))
ydata.append(intercept + slope*xdata[-1] + np.random.random(num_x))

Simulate data analysis: fitting 1st order polynomials: y = a + b*x

fits =
for x, y in zip(xdata, ydata):
fits.append(np.polyfit(x, y, 1))

source = ColumnDataSource(data={‘a’: , ‘b’: })
source.data[‘a’] = [f[1] for f in fits]
source.data[‘b’] = [f[0] for f in fits]

top = Figure(plot_height=600, plot_width=800, tools=‘tap’, title=‘y = a + b*x’)
top.xaxis.axis_label = ‘a’
top.yaxis.axis_label = ‘b’
cr = top.circle(x=‘a’, y=‘b’, source=source)

bottom = Figure(plot_height=600, plot_width=800, title=‘Data for respective fit’)
bottom.xaxis.axis_label = ‘x’
bottom.yaxis.axis_label = ‘y’
source0 = ColumnDataSource(data={‘xdat’: , ‘ydat’: })
source0.data[‘xdat’] = xdata[0]
source0.data[‘ydat’] = ydata[0]
serie = bottom.circle(x=‘xdat’, y=‘ydat’, source=source0)

taptool = top.select(type=TapTool)
taptool.callback = CustomJS(args=dict(bottom=bottom), code=“”"
var flag = cb_obj.get(‘selected’)[‘0d’].flag;
var index = cb_obj.get(‘selected’)[‘0d’].indices[0];
alert(“magic goes here”);
“”")

p = gridplot([[top], [bottom]])
curdoc().add_root(p)

``

So the second plot is static and shows the underlying data for the first data point in the upper plot.
What I would like to do s to update the data in bottom, (do I need to pass multiple ColumnDataSources? or can they be N-dimensional?)

Best regards,
Björn Dahlgren