3
votes

I have multiple figures in a column in a bokeh plot. I want to apply the same tool transformation on all the images at the same time ie, if I zoom on one figure, all the plots should zoom, if I pan one, they should all pan, if I reset one, they should all reset (don't really care about hover, I'd be ecstatic with zoom, pan and reset).

Is there a bokeh way to link figures or do I need some custom Javascript for that (if so what would that be)?

Thanks in advance.

EDIT:

Thank you to @bigreddot and @Abhinav for the solution. You need both their answers as described here: Linking Plots . The range facilitates the Pan and the same datasource facilitates the zoom,

Modified Solution from layouts example:

from bokeh.io import output_file, show
from bokeh.layouts import column
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
from  bokeh.models import PanTool,ResetTool,BoxZoomTool


output_file("layout.html")

x = list(range(11))
y0 = x
y1 = [10 - i for i in x]
y2 = [abs(i - 5) for i in x]


tools=[BoxZoomTool(), PanTool(), ResetTool()]

datasource = ColumnDataSource({'x': x, 'y0': y0, 'y1': y1, 'y2': y2})
# create a new plot
s1 = figure(plot_width=250, plot_height=250, title=None,tools=tools)
s1.circle('x', 'y0', size=10, color="navy", alpha=0.5, source=datasource)

# create another one
s2 = figure(plot_width=250, plot_height=250, title=None,tools=tools,x_range=s1.x_range,y_range=s1.y_range)
s2.triangle('x', 'y1', size=10, color="firebrick", alpha=0.5, source=datasource)

# create and another
s3 = figure(plot_width=250, plot_height=250, title=None,tools=tools,x_range=s1.x_range,y_range=s1.y_range)
s3.square('x', 'y2', size=10, color="olive", alpha=0.5, source=datasource)

# put the results in a column and show
show(column(s1, s2, s3))
2
I've rollbacked your transformation of the question into a solution: please find your solution in the revision history and post it as an answer of its own, thank you. - Cœur

2 Answers

3
votes

This is in the documentation, under Linking Plots.

TLDR: If you want plots to share ranges, then share their actual range objects:

# create a new plot
s1 = figure()
s1.circle(x, y0, size=10, color="navy", alpha=0.5)

# create a new plot and share both ranges
s2 = figure(x_range=s1.x_range, y_range=s1.y_range)
s2.triangle(x, y1, size=10, color="firebrick", alpha=0.5)
1
votes

You should create a ColumnDataSource object from your data and use it when creating the glyphs in your figures. As long as the figures are sharing the same datasource, they will have the same tool effects. When using a ColumnDataSource, you need to specify the data using the column names in the datasource rather than directly passing the arrays themselves. For example:

from bokeh.io import output_file, show
from bokeh.layouts import column
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
from  bokeh.models import PanTool,ResetTool,HoverTool,WheelZoomTool,SaveTool,BoxZoomTool


output_file("layout.html")

x = list(range(11))
y0 = x
y1 = [10 - i for i in x]
y2 = [abs(i - 5) for i in x]


#tools='hover,xpan,xwheel_zoom,box_zoom,save,reset'
tools=[HoverTool(),BoxZoomTool(dimensions='width'), PanTool(dimensions='width'),  SaveTool(), ResetTool()]

datasource = ColumnDataSource({'x': x, 'y0': y0, 'y1': y1, 'y2': y2})
# create a new plot
s1 = figure(plot_width=250, plot_height=250, title=None,tools=tools)
s1.circle('x', 'y0', size=10, color="navy", alpha=0.5, source=datasource)

# create another one
s2 = figure(plot_width=250, plot_height=250, title=None,tools=tools)
s2.triangle('x', 'y1', size=10, color="firebrick", alpha=0.5, source=datasource)

# create and another
s3 = figure(plot_width=250, plot_height=250, title=None,tools=tools)
s3.square('x', 'y2', size=10, color="olive", alpha=0.5, source=datasource)

# put the results in a column and show
show(column(s1, s2, s3))