7

I want to build an app with many plots. It will have some tabs, and one gridplot within the tabs with some plots. In addition, I need to update the plots layout dynamically when the server is running.

  • Remove or add some plots
  • Remove or add some tabs

I have read this thread, where Bryan (@bigreddot) says:

The most well-used and understood (as well as more efficient) method is to create your plots once, up front, then update only their data when they need to change.

Bokeh's layout capability is ambitious and complicated. It works well in a number of situations but I can easily believe there are update bugs that might be exposed when replacing complicated composite models like entire plots deep in a nested layout.

I have written the following example where I update the layout in four different ways:

  1. Replacing the old plot by the children attribute on the layout object.
  2. Replacing the layout with curdoc()
  3. Replacing the plot using remove() and append()
  4. Inserting a new plot using insert()
from bokeh.models import Button, ColumnDataSource
from bokeh.layouts import column
from bokeh.plotting import curdoc, figure

# ------------------- PLOT 1 --------------------------- #

plot_1 = figure(
    width=400,
    height=400,
)

x = [1, 2, 3, 4]
y = [4, 3, 2, 1]

source = ColumnDataSource(data=dict(x=x, y=y))

plot_1.circle(
    x='x',
    y='y',
    source=source,
    radius=0.5,
    fill_alpha=0.6,
    fill_color='green',
)

# ------------------- PLOT 2 --------------------------- #

plot_2 = figure(
    width=400,
    height=400,
)

plot_2.circle(
    x='x',
    y='y',
    source=source,
    radius=0.5,
    fill_alpha=0.6,
    fill_color='red',
)

# ------------------- PLOT 3 --------------------------- #

plot_3 = figure(
    width=400,
    height=400,
)

plot_3.circle(
    x='x',
    y='y',
    source=source,
    radius=0.5,
    fill_alpha=0.6,
    fill_color='yellow',
)

# ------------------- BUTTONS --------------------------- #

def replace_by_children_attr():
    column_1.children = buttons + [plot_2]

def replace_by_curdoc():
    column_2 = column(buttons + [plot_2])

    curdoc().clear()
    curdoc().add_root(column_2)

def replace_by_remove_append():
    column_1.children.remove(plot_1)
    column_1.children.append(plot_2)

def insert_plot():
    column_1.children.insert(2, plot_3)

button_1 = Button(label="Replace plot by children attribute", button_type="success")
button_1.on_click(replace_by_children_attr)

button_2 = Button(label="Replace plot by curdoc", button_type="success")
button_2.on_click(replace_by_curdoc)

button_3 = Button(label="Replace plot remove-append", button_type="success")
button_3.on_click(replace_by_remove_append)

button_4 = Button(label="Insert plot", button_type="success")
button_4.on_click(insert_plot)

# ------------------- LAYOUT --------------------------- #

buttons = [button_1, button_2, button_3, button_4]
column_1 = column(buttons + [plot_1])

curdoc().add_root(column_1)

I realized that if I press the button "Replace plot by children attribute" the layout changes a little. But when I press "Replace plot by curdoc" the layout is not changed:
  • So, which of these options is the best solution?
  • Any of these solutions are going to give me problems? I know at least the first option is going to give me problems for sure

Note: Actually, what I want to avoid is to restart the bokeh server to rebuild the layout because it takes a while. And I need to do it very often.

Note 2: Bokeh version 0.12.14

Rizwan
  • 103
  • 4
  • 24
ChesuCR
  • 9,352
  • 5
  • 51
  • 114
  • If I had to do something like dynamic layout, I will look toward [bokeh.models api](https://bokeh.github.io/blog/2017/7/5/idiomatic_bokeh/). You can easily add and remove glyphs from plot renderers (which is a list), I imagine you can do same with document/layout.. – Louc Feb 03 '18 at 20:41
  • @louc Sure, I can use `append` as well instead of reassigning the layout to the complete list. But the problem is what I have written in my question: "It works well in a number of situations" (as Bryan says). I want to build a complex layout, so I was wondering if I do `curdoc().clear()` and `curdoc().add_root(new_layout)` would solve the problem. Moreover I can read on your link "Additive development, not subtractive or mutative", what I need to do is substractive or mutative. – ChesuCR Feb 04 '18 at 11:06
  • If you can .append() , you can .remove() . I do so to add and remove glyph in a plot, legend ... The thing with the bokeh.models api is that you can keep in variable/list/dict the instance of object, so it is easy to remove them after. From what I have tested, update is rather smart and is done automatically – Louc Feb 05 '18 at 13:21
  • @louc OK, I have updated my question with your suggestion. So, can you guarantee that `append()` and `remove()` works well even if the layout is too complex? Could I also use `insert()` to avoid the limitation of appending elements always to the end of the list? – ChesuCR Feb 05 '18 at 14:05
  • insert() will also work, I tested it [here](https://stackoverflow.com/questions/47820780/adding-widgets-dynamically-in-bokeh/47876820#47876820). But I honestly don't know if it will work with very complex layout, I don't see why it couldn't work... – Louc Feb 05 '18 at 19:21
  • OK, thank you for your time. I will let you know if something goes wrong – ChesuCR Feb 05 '18 at 21:04
  • Hi, i create plot through components(). So i include div and script into my html file. How is it possible to use on client side with JS, change one plot on another plot? – VolArt Feb 20 '18 at 17:35
  • @VolArt I don´t really know, I am trying to program as much as possible within python – ChesuCR Feb 20 '18 at 18:11

0 Answers0