Linking two Scatter charts

Cross-posting from Stack Overflow with the link to there, in case there’s an answer, so it can go public. If this is discouraged, please let me know and I won’t do it in the future!

http://stackoverflow.com/questions/41625650/link-two-scatter-charts-in-bokeh

The idea is that I saw that we can link two bokeh plots made using the plotting interface, but didn’t see how to do it using the high level charts. Is it possible to do so? The thing that I’ve done, that doesn’t work, is to add the source keyword argument to the Scatter plot constructor, but that doesn’t link my two plots; neither does feeding the constructors the same Pandas data frame.

What do you mean by “linking” plots? Sharing axes?

If you want them to share their x axis you have to add in s2

x_range = s1.x_range

``

My apologies, I wasn’t clear! Thank you for responding, Sebastien.

So, for linking the two plots’ x-axes, I tried that using the Scatter chart interface:


from bokeh.charts import Scatter

# make data: df_samp

s1 = Scatter(df_samp, x='Elevation', y='Horizontal_Distance_To_Roadways', color='Cover_Type', plot_height=400, plot_width=400, tools=TOOLS)

s2 = Scatter(df_samp, x='Elevation', y='Aspect', color='Cover_Type', plot_height=400, plot_width=400, tools=TOOLS, x_range=s1.x_range)

However, this doesn’t work - the resulting plots do not sync up their x-axes.

OTOH, I was thinking of “brush linking” when I first posted just now. Is this possible with the Scatter charts?

Tried with charts and indeed I couldn’t link the plots either.

I know you want to use charts but in your SO post you say you do that because you like some “automatic” styling like filling in colours with a 3rd column, but you can do that just as easily with bokeh.plotting:

from bokeh.plotting import Figure,output_file

from bokeh.models import Legend, Panel, Tabs, CustomJS, ColumnDataSource, CheckboxGroup, RadioGroup, Button, VBox, PreText

from bokeh.models.widgets import DataTable, TableColumn

from bokeh.layouts import gridplot, widgetbox

from bokeh.resources import CDN

from bokeh.embed import file_html

import random

colour = [ “red”, “blue”, “green”, “yellow”, “purple”, “orange”, “white”, “black” ]

source = ColumnDataSource(data={‘x’:range(10),‘y’:range(10),‘z’:range(10)[::-1],‘colo’:[random.choice(colour) for i in range(10)]})

TOOLS = [“pan,wheel_zoom,box_zoom,undo,redo,reset,box_select,save”]

fig = Figure(plot_height=400,plot_width=400,tools=TOOLS)

fig2 = Figure(plot_height=400,plot_width=400,x_range=fig.x_range)

s1 =

s1.append( fig.scatter(x=‘x’,y=‘y’,source=source) )

s2 =

s2.append( fig2.scatter(x=‘x’,y=‘z’,color=‘colo’,source=source) )

grid = gridplot([[fig,fig2]],toolbar_location=‘left’)

outfile=open(‘chartest.html’,‘w’)

outfile.write(file_html(grid,CDN,‘chartest’))

outfile.close()

``

Sebastien, you’re amazing! I implemented what you suggested, and it works! I uploaded what I’ve done here: https://github.com/ericmjl/iacs2017/blob/master/bokehscatter.py

By the way, if you might have the relevant expertise here… the bokehscatter.py script is modelled off the Bokeh server examples. In it are the two plots. I’m having trouble updating the x-axis on both plots simultaneously; do you happen to know how to make that work as well? What I’ve tried already doesn’t work, in that the plots refuse to re-render. I inspected the JS console, and I see that there’s a RuntimeError, containing the error message ‘Cannot apply patch to [some long string] which is not in the document.’

Maybe also ping Bryan/Sarah for help here?

···

On Thu, Jan 12, 2017 at 9:32 PM, [email protected] wrote:

Tried with charts and indeed I couldn’t link the plots either.

I know you want to use charts but in your SO post you say you do that because you like some “automatic” styling like filling in colours with a 3rd column, but you can do that just as easily with bokeh.plotting:

from bokeh.plotting import Figure,output_file

from bokeh.models import Legend, Panel, Tabs, CustomJS, ColumnDataSource, CheckboxGroup, RadioGroup, Button, VBox, PreText

from bokeh.models.widgets import DataTable, TableColumn

from bokeh.layouts import gridplot, widgetbox

from bokeh.resources import CDN

from bokeh.embed import file_html

import random

colour = [ “red”, “blue”, “green”, “yellow”, “purple”, “orange”, “white”, “black” ]

source = ColumnDataSource(data={‘x’:range(10),‘y’:range(10),‘z’:range(10)[::-1],‘colo’:[random.choice(colour) for i in range(10)]})

TOOLS = [“pan,wheel_zoom,box_zoom,undo,redo,reset,box_select,save”]

fig = Figure(plot_height=400,plot_width=400,tools=TOOLS)

fig2 = Figure(plot_height=400,plot_width=400,x_range=fig.x_range)

s1 =

s1.append( fig.scatter(x=‘x’,y=‘y’,source=source) )

s2 =

s2.append( fig2.scatter(x=‘x’,y=‘z’,color=‘colo’,source=source) )

grid = gridplot([[fig,fig2]],toolbar_location=‘left’)

outfile=open(‘chartest.html’,‘w’)

outfile.write(file_html(grid,CDN,‘chartest’))

outfile.close()

``

You received this message because you are subscribed to a topic in the Google Groups “Bokeh Discussion - Public” group.

To unsubscribe from this topic, visit https://groups.google.com/a/continuum.io/d/topic/bokeh/tOJfoWrz-rs/unsubscribe.

To unsubscribe from this group and all its topics, 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/8de0d8dc-86be-4d54-875d-7051e60f80e5%40continuum.io.

For more options, visit https://groups.google.com/a/continuum.io/d/optout.

Are you trying to replace the entire range objects? If so I think there are some issue that might bump into. Better woudl be to update the start and end properties of the existing ranges, rather than replacing the ranges (at least for the time being).

Thanks,

Bryan

···

On Jan 12, 2017, at 10:24 PM, Eric Ma <[email protected]> wrote:

Sebastien, you're amazing! I implemented what you suggested, and it works! I uploaded what I've done here: https://github.com/ericmjl/iacs2017/blob/master/bokehscatter.py

By the way, if you might have the relevant expertise here... the bokehscatter.py script is modelled off the Bokeh server examples. In it are the two plots. I'm having trouble updating the x-axis on both plots simultaneously; do you happen to know how to make that work as well? What I've tried already doesn't work, in that the plots refuse to re-render. I inspected the JS console, and I see that there's a RuntimeError, containing the error message 'Cannot apply patch to [some long string] which is not in the document.'

Maybe also ping Bryan/Sarah for help here?

On Thu, Jan 12, 2017 at 9:32 PM, <[email protected]> wrote:
Tried with charts and indeed I couldn't link the plots either.

I know you want to use charts but in your SO post you say you do that because you like some "automatic" styling like filling in colours with a 3rd column, but you can do that just as easily with bokeh.plotting:

from bokeh.plotting import Figure,output_file
from bokeh.models import Legend, Panel, Tabs, CustomJS, ColumnDataSource, CheckboxGroup, RadioGroup, Button, VBox, PreText
from bokeh.models.widgets import DataTable, TableColumn
from bokeh.layouts import gridplot, widgetbox
from bokeh.resources import CDN
from bokeh.embed import file_html
import random

colour = [ "red", "blue", "green", "yellow", "purple", "orange", "white", "black" ]

source = ColumnDataSource(data={'x':range(10),'y':range(10),'z':range(10)[::-1],'colo':[random.choice(colour) for i in range(10)]})

TOOLS = ["pan,wheel_zoom,box_zoom,undo,redo,reset,box_select,save"]

fig = Figure(plot_height=400,plot_width=400,tools=TOOLS)
fig2 = Figure(plot_height=400,plot_width=400,x_range=fig.x_range)

s1 =
s1.append( fig.scatter(x='x',y='y',source=source) )
s2 =
s2.append( fig2.scatter(x='x',y='z',color='colo',source=source) )

grid = gridplot([[fig,fig2]],toolbar_location='left')

outfile=open('chartest.html','w')
outfile.write(file_html(grid,CDN,'chartest'))
outfile.close()

--
You received this message because you are subscribed to a topic in the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this topic, visit https://groups.google.com/a/continuum.io/d/topic/bokeh/tOJfoWrz-rs/unsubscribe\.
To unsubscribe from this group and all its topics, 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/8de0d8dc-86be-4d54-875d-7051e60f80e5%40continuum.io\.

For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

--
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/CAK-i%3DxjL9W1Oa9qNGdYgEzYs2pjOVY0B3g63Je9ayP3Hb04xbQ%40mail.gmail.com\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

You are trying to plot a difference x vs y plot each time you select a different x or y value from the dropdown menus.

Are you trying to do something like that? I am not sure how to do that with the bokeh server though.

from bokeh.plotting import Figure, output_file

from bokeh.models import CustomJS, ColumnDataSource, Select

from bokeh.layouts import gridplot

from bokeh.resources import CDN

from bokeh.embed import file_html

from random import random

TOOLS = “pan,wheel_zoom,box_zoom,undo,redo,reset,box_select,save”

iterable = [(‘x’+str(i),[j*(i+1) for j in range(100)]) for i in range(5)]+[(‘y’+str(i),[random()10(i+1) for j in range(100)]) for i in range(10)]

source = ColumnDataSource(data={key:value for key,value in iterable})

fillsource = ColumnDataSource(data={‘x’:source.data[‘x0’],‘y’:source.data[‘y0’],‘z’:source.data[‘y1’]})

fig1 = Figure(plot_height=400,plot_width=400,tools=TOOLS)

fig1.scatter(x=‘x’,y=‘y’,source=fillsource)

fig2 = Figure(plot_height=400,plot_width=400,tools=TOOLS,x_range=fig1.x_range)

fig2.scatter(x=‘x’,y=‘z’,source=fillsource)

x_options = sorted([k for k in source.data.keys() if ‘x’ in k])

y_options = sorted([k for k in source.data.keys() if ‘y’ in k])

selex = Select(title=‘X-axis’,options=x_options,value=x_options[0])

seley1 = Select(title=‘Y-axis left’,options=y_options,value=y_options[0])

seley2 = Select(title=‘Y-axis right’,options=y_options,value=y_options[1])

selex.callback = CustomJS(args=dict(s=source,fs=fillsource,sely1=seley1,sely2=seley2),code="""

var xval = cb_obj.get("value");

var yval1 = sely1.get("value");

var yval2 = sely2.get("value");

var d = s.get('data');

var df = fs.get('data');

df['x'] = [];

df['y'] = [];

df['z'] = [];

var x = d[xval];

var y = d[yval1];

for(i=0;i<=x.length;i++){

	df['x'].push(d[xval][i]);

	df['x'].push(d[xval][i]);

}

for(i=0;i<=y.length;i++){

	df['y'].push(d[yval1][i]);

	df['z'].push(d[yval2][i]);

}

fs.trigger("change");

""")

seley2.callback = CustomJS(args=dict(s=source,fs=fillsource,sely1=seley1,selx=selex),code="""

var yval2 = cb_obj.get("value");

var xval = selx.get("value");

var yval1 = sely1.get("value");

var d = s.get('data');

var df = fs.get('data');

df['x'] = [];

df['y'] = [];

df['z'] = [];

var x = d[xval];

var y = d[yval1];

for(i=0;i<=x.length;i++){

	df['x'].push(d[xval][i]);

	df['x'].push(d[xval][i]);

}

for(i=0;i<=y.length;i++){

	df['y'].push(d[yval1][i]);

	df['z'].push(d[yval2][i]);

}

fs.trigger("change");

""")

seley1.callback = CustomJS(args=dict(s=source,fs=fillsource,sely2=seley2,selx=selex),code="""

var yval1 = cb_obj.get("value");

var xval = selx.get("value");

var yval2 = sely2.get("value");

var d = s.get('data');

var df = fs.get('data');

df['x'] = [];

df['y'] = [];

df['z'] = [];

var x = d[xval];

var y = d[yval1];

for(i=0;i<=x.length;i++){

	df['x'].push(d[xval][i]);

	df['x'].push(d[xval][i]);

}

for(i=0;i<=y.length;i++){

	df['y'].push(d[yval1][i]);

	df['z'].push(d[yval2][i]);

}

fs.trigger("change");

""")

grid = gridplot([[seley1,seley2],[fig1,fig2,selex]],toolbar_location=‘left’)

outfile=open(‘dropdwn.html’,‘w’)

outfile.write(file_html(grid,CDN,‘dropdwn’))

outfile.close()

``