embedding without widgetbox and assigning a callback to source leads to nonfunctioning div

Hey all,

I’m using bokeh 0.13.0 and tried to change a bokeh side from save to embedding to have greater control over the layout. After doing this my CustomJS could no longer update my div, although a console.log(...) was still working. After some time I minimized my problem to the code below. The problem only occures when I assign something to source.callback (reproduced in cb_embed.html), if I do not the div doesn’t work correctly (shown in without_cb_embed.html). This can be fixed by wrapping the div in a widgetbox (as done automatically by the layout call, I first thought save was somehow responsible, but wrapping the div in a widgetbox and embedding also works).

While I think having a “raw” div without a widgetbox is not really supported it feels very buggy that this only happens if a callback is assigned to source.callback. I’m not sure if this is a bug or if this is “working as expected” - if it is the later maybe an error should be thrown when trying to embed an raw widget without a widgetbox.

from bokeh.io import save, output_file, show
from bokeh.plotting import figure
from bokeh.events import ButtonClick
from bokeh.models import CustomJS, Div, Button, ColumnDataSource
from bokeh.layouts import layout, widgetbox
from bokeh.embed import components

import jinja2

def make_plots(include_cb, embed):

source_dict = {"x": [1,2], "y": [3,4]}
source = ColumnDataSource(source_dict)

p = figure()
p.circle(x="x", y="y", source=source)

div = Div(text="Div Initialized")

cb = CustomJS(args=dict(div=div), code='console.log("Callback 1"); div.text="cb";')
cb1 = CustomJS(args=dict(div=div), code='console.log("Callback 1"); div.text="cb";')

button = Button(label="Foo", button_type="success")
button.js_on_event(ButtonClick, cb)

template = jinja2.Template("""
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title></title>
        <link href="https://cdn.pydata.org/bokeh/release/bokeh-0.13.0.min.css" rel="stylesheet" type="text/css">
        <link href="https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.13.0.min.css" rel="stylesheet" type="text/css">
        <link href="https://cdn.pydata.org/bokeh/release/bokeh-tables-0.13.0.min.css" rel="stylesheet" type="text/css">

        <script src="https://cdn.pydata.org/bokeh/release/bokeh-0.13.0.min.js"></script>
        <script src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.13.0.min.js"></script>
        <script src="https://cdn.pydata.org/bokeh/release/bokeh-tables-0.13.0.min.js"></script>

    </head>
    <body>
        <div>
            {{ map }}
        </div>
        <div>
            {{button}}
            {{ div }}
        </div>
        {{ script }}
    </body>
</html>
""")

name = "cb_" if include_cb else "without_cb_"
name = name + ("embed.html" if embed else "save.html")

if include_cb:
    source.callback = cb

if embed:
    script, (map, div_, button_) = components([p, div, button])

    with open(name, mode="w") as f:
        f.write(template.render(script=script,
            map=map,
            div=div_, button=button_))
else:
    output_file(name)
    save(layout([p, widgetbox(div), widgetbox(button)]))

make_plots(False, False)
make_plots(True, True)
make_plots(True, False)
make_plots(False, True)

``

Best wishes,

Simon