☰Read-only archive⌕
Looking for help with Bokeh?

This is a read-only archive. Ask questions and join the conversation on GitHub.

Visit Community Support on GitHub →
Archived discussions · Captured October 28, 2026

Linked ranges with bokehJS

Community Supportbokehjs
PBrockmann
PBrockmann

I have a python script adapted from the documentation to test linked ranges with the option x_range used when the plot is created. It works nicelly.

How to do the same with bokehJS ?
I got an error: Uncaught Error: models must be owned by only a single document

With python

xdr = DataRange1d(bounds=None)
p1 = figure(
        plot_width = 400,
        plot_height = 400,
        tools = "pan,wheel_zoom,box_zoom,reset,save",
        active_scroll = "wheel_zoom",
        x_range = xdr
)

With bokehJS

var xdr = new Bokeh.DataRange1d({bounds: "none"});
var plot = new Bokeh.Plotting.figure({
          plot_width: 400,
          plot_height: 400,
          tools: "pan,wheel_zoom,box_zoom,reset,save",
          //active_scroll:  "wheel_zoom",
          x_range: xdr
        });
⌁   Link to post
PBrockmann
PBrockmann

Here is the basic example I would like to run.
I expect to have a linked x axis for both plots.

https://jsfiddle.net/PBrockmann/hvmcptke/

This exemple works in python, but I have a lot of interactivity on the browser side so I prefer to work with bokehJS for this specific project.

import numpy as np
from bokeh.models import Legend, DataRange1d
from bokeh.plotting import figure, show, output_file, gridplot

x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)

output_file("legend_labels.html")

#===================================================
xdr = DataRange1d(bounds=None)

#===================================================
p1 = figure(
        plot_width = 400,
        plot_height = 400,
        tools = "pan,wheel_zoom,box_zoom,reset,save",
        toolbar_location = "above",
        active_scroll = "wheel_zoom",
        x_range = xdr
)

r0 = p1.circle(x, y)
r1 = p1.line(x, y)
r2 = p1.line(x, 2*y, line_dash=[4, 4], line_color="orange", line_width=2)
r3 = p1.square(x, 3*y, fill_color=None, line_color="green")
r4 = p1.line(x, 3*y, line_color="green")

legend = Legend(items=[
    ("sin(x)",   [r0, r1]),
    ("2*sin(x)", [r2]),
    ("3*sin(x)", [r3, r4])
], location=(0,0))

p1.toolbar.logo = None
p1.add_layout(legend, 'right')

#===================================================
p2 = figure(
        plot_width = 400,
        plot_height = 400,
        tools = "pan,wheel_zoom,box_zoom,reset,save",
        toolbar_location = "above",
        active_scroll = "wheel_zoom",
        x_range = xdr
)


r3 = p2.square(x, 3*y, fill_color=None, line_color="green")
r4 = p2.line(x, 3*y, line_color="green")

legend = Legend(items=[
    ("3*sin(x)", [r3, r4])
], location=(0,0))

p2.add_layout(legend, 'right')

#===================================================
p = gridplot([[p1, p2]])

show(p)
⌁   Link to post
Bryan
Bryan

Right, the issue is the separate calls to show, which each individually create a new (separate) Document behind the scenes. In Python you are putting everying in a gridplot with one call to show which keeps everything in the same Document. I’m not sure what the options are in the BokehJS API are if you can’t accomplish what you need with one show call. Perhaps @mateusz can comment.

⌁   Link to post
PBrockmann
PBrockmann

Thanks Xavier for your answer.

Yes indeed but you need to create an array of plot objects at the start.
How do have this feature (linked x_range) when the user will add or remove plots dynamically ?

⌁   Link to post
Bryan
Bryan

@PBrockmann The BokehJS API is not very advanced/developed in this regard (standard OSS refrain: lack of resources). You should understand that you are breaking new ground. Looking at the code for show

It always creates a new Document every call. So it is not going to be an option for the kind of usage you describe. Your best bet will probably be to do something like implement your own version of show that can accept an explicit Document instance that you completely control and manage the lifecycle of yourself.

⌁   Link to post
PBrockmann
PBrockmann

Thank you Bryan for your answer.
I think I understand what should be done.
Synchonization can be painful when plot are dynamically created.

I have a prototype if you want to have a look: http://webportals.ipsl.jussieu.fr/VERIFY/app/v1.4/
The target is to exposed netcdf time series as synchronous plots with possible add/delete specific regions of interest. Add/delete a plot per variable as well.
I think I could recode this prototype with a bokeh/flask approach and be closer to the real bokeh API. But not sure it will solve this specific problem of synchronisation on axis.

⌁   Link to post
mateusz
mateusz

For a start one could use a single call to show([p1, p2]) to resolve this issue. However, we could allow multiple calls like proposed here. One option, as mentioned, is to allow explicit Document handling, but that can be tedious. A better solution is to allow show() to check if a model has a document already attached, and then utilize internal logic (build_views()) to make sure we don’t render models multiple times. That should be a pretty straightforward change.

⌁   Link to post
PBrockmann
PBrockmann

Still interested to be able to instantiate a new document with a model (here an x_range) inherit from a previous document.

I have illustrated what I would like to achieve (2 plots with linked xaxis but created one after the other) from: bokehJS linked on x_range - JSFiddle - Code Playground
I get:
Error: models must be owned by only a single document

I will try to modify bokeh/plotting.ts at branch-3.0 · bokeh/bokeh · GitHub
according to your suggestion.
Just would be nice to know if it is still on the cards.

⌁   Link to post
Bryan
Bryan

Is there a way to offer a “bounty” on this feature ?

Dubious. Eg. my own employer would get angry at my taking actual outside money. I suspect others are in similar positions. I still think the best option is to move to explicitly managing a single Document that you could pass in to show (i.e. by modifying show to accept document as an optional parameter instead of unconditionally creating a new Document on every call). Have you tried this?

Speaking my own opinion (@mateusz can comment if he disagrees) I think the idea of allowing models to “live” in multiple documents is a non-starter, since it wholly breaks fundamental assumptions about serializing Bokeh from Python (or other languages). The document is precisely the “envelope” that defines serialization boundaries.

⌁   Link to post

End of archived discussion · Replies are disabled