Adding panels dynamically

I’m trying to add a panel to my document dynamically from a separate thread. Here is the (simplified) code I have so far:

from bokeh.plotting import curdoc
from bokeh.models import Panel, Tabs, TextInput
from bokeh.layouts import layout
from threading import Thread
import time

input_text1 = TextInput(title='Input1', value="", height=60)
l1 = layout(input_text1,
            sizing_mode='fixed')

paneltab1 = Panel(child=l1, title='Panel1')

tabs_list = [paneltab1]
tabs = Tabs(tabs=tabs_list)

print "Initializing curdoc()"
doc = curdoc() # necessary for multi-threaded access
doc.add_root(tabs)

def addPanel():
    global tabs_list
    global tabs

    input_text2 = TextInput(title='Input2', value="", height=60)
    l2 = layout(input_text2,
                sizing_mode='fixed')

    paneltab2 = Panel(child=l2, title='Panel2')

    tabs_list.append(paneltab2)
    tabs.update(tabs=tabs_list)

def panelLoop():

    time.sleep(5)

    doc.add_next_tick_callback(addPanel())

thread = Thread(target=panelLoop)
thread.start()


It creates the first panel, but then after 5 seconds when it runs the line "tabs.update(tabs=tabs_list)" from addPanel(), it gives the following error message:

RuntimeError: _pending_writes should be non-None when we have a document lock, and we should have the lock when the document changes


What is the correct way to achieve this?

Hi,

You are passing the wrong thing to add_next_tick_callback. You should pass the *function* to call:

  doc.add_next_tick_callback(addPanel) # GOOD

instead, you are passing the result of calling the function yourself:

  doc.add_next_tick_callback(addPanel( )) # BAD

Also I feel compelled to note:

* Bokeh will be dropping support for Python 2.x later this year (along with Numpy, Pandas, MPL, and many others)

* Since this involves updating a layout, Bokeh >= 1.1 is definitely advised.

Thanks,

Bryan

···

On Apr 30, 2019, at 9:39 AM, Simon Ouellette <[email protected]> wrote:

from bokeh.plotting import curdoc
from bokeh.models import Panel, Tabs, TextInput
from bokeh.layouts import layout
from threading import Thread
import time

input_text1 = TextInput(title='Input1', value="", height=60)
l1 = layout(input_text1,
            sizing_mode='fixed')

paneltab1 = Panel(child=l1, title='Panel1')

tabs_list = [paneltab1]
tabs = Tabs(tabs=tabs_list)

print "Initializing curdoc()"
doc = curdoc() # necessary for multi-threaded access
doc.add_root(tabs)

def addPanel():
    global tabs_list
    global tabs

    input_text2 = TextInput(title='Input2', value="", height=60)
    l2 = layout(input_text2,
                sizing_mode='fixed')

    paneltab2 = Panel(child=l2, title='Panel2')

    tabs_list.append(paneltab2)
    tabs.update(tabs=tabs_list)

def panelLoop():

    time.sleep(5)

    doc.add_next_tick_callback(addPanel())

thread = Thread(target=panelLoop)
thread.start()