1

Here is a complete code example that re-produces the error. I was able to do this in previous versions of Bokeh but after upgrading this code no longer lets me add a div to the GridBox.

from bokeh.models import Panel, Tabs
from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.io import curdoc
from bokeh.models.widgets import Div
from bokeh.layouts import gridplot


p1 = figure(plot_width=300, plot_height=300)
p1.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)

p2 = figure(plot_width=300, plot_height=300)
p2.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)

p3 = figure(plot_width=300, plot_height=300)
p3.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)

p4 = figure(plot_width=300, plot_height=300)
p4.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)

g1 = gridplot([p1, p2, p3, p4], ncols=2, plot_width=800, plot_height=600)

tab1 = Panel(child=g1, title="circle")

tabs = Tabs(tabs=[ tab1 ])

doc = curdoc()
doc.add_root(tabs)

my_div = Div(text="Please wait...")

doc._roots[0].tabs[0].child.children[1].children.append(my_div)

This is the error message I got,

ValueError: expected an element of List(Either(Tuple(Instance(LayoutDOM), Int, Int), Tuple(Instance(LayoutDOM), Int, Int, Int, Int))), got seq with invalid items [Div(id='2515', ...)]

1 Answer 1

1

A few notes first:

  • Please, please, please always provide all the relevant information. In this case your comment about grid led me astray to only consider the gridplot API. If you had included the line number/more context from the exception, your question would have been answered yesterday.

  • You should definitely not go mucking around doc._roots. It is marked "private" for a reason, and may change names or be removed at any time, without warning. (That's what being private means, there are no guarantees). You have a reference to the Tabs object you made, you should update that directly.

There was a very large overhaul of the entire layout system for 1.1 awhile back. Many, many bugs and problems were fixed. We have many thousands of tests to maintain version compatibility, but this is (evidently) an accidental API breakage that happened. It's unusual for users to muck directly with GridPlot so that is why it was missed. The children for GridPlot must now provide explicit grid coordinates, if you look at the contents of GridPlot.children you see:

[(Figure(id='1852', ...), 0, 0),
 (Figure(id='1889', ...), 0, 1),
 (Figure(id='1926', ...), 1, 0),
 (Figure(id='1963', ...), 1, 1)]

Which is a list of tuples that include explicit grid positions.

So in your case specifically, you probably want:

tabs.tabs[0].child.children[1].children.append((my_div, 2, 0))

However, I would also note that you could also append the div to the column that contains the GridPlot, which also seems like it would be easier to do.

3
  • My version is 1.1.0. I'm running the code in a Jupyter notebook.
    – tink3r
    Commented Jul 10, 2019 at 16:27
  • I still get this error. ValueError: expected an element of List(Either(Tuple(Instance(LayoutDOM), Int, Int), Tuple(Instance(LayoutDOM), Int, Int, Int, Int))), got seq with invalid items [Div(id='2140', ...)]
    – tink3r
    Commented Jul 10, 2019 at 16:28
  • I will try this tomorrow.
    – tink3r
    Commented Jul 12, 2019 at 4:31

Not the answer you're looking for? Browse other questions tagged or ask your own question.