我试图在散景中制作一个有点复杂的仪表板,其中有几个不同的图形对象和按行和列排列的小部件。
当用户与小部件交互时,某些图表会更新,而某些图表保持不变。我正在创建新的绘图对象并用layout.children [i] = x替换它们,然后发送push_notebook来更新仪表板,但这会导致一些绘图调整为最小的画布大小。
我创建了一个简单的例子来说明我的意思:
from numpy import random
from bokeh.plotting import figure, curdoc
from bokeh.layouts import row, widgetbox, column
from bokeh.models.widgets import Button, Slider
from bokeh.io import push_notebook, show, output_notebook
from bokeh.models.callbacks import CustomJS
output_notebook()
num_samples = 500
def bUpdate(var, val):
global num_samples
if var == "Number of Samples":
num_samples = int(val)
replotBottom()
def bReCalc():
x = [random.random() for i in range(num_samples)]
y = [random.random() for i in range(num_samples)]
p = figure(plot_width=COL1_W, plot_height=250)
p.circle(x, y, color='red')
p.toolbar.logo = None
layout.children[0].children[0].children[0].children[1] = p
x = [random.random() for i in range(num_samples)]
y = [random.random() for i in range(num_samples)]
p2 = figure(plot_width=COL2_W, plot_height=int(COL1_W*1.8))
p2.circle(x,y)
layout.children[0].children[0].children[1].children[0] = p2
push_notebook(handle=bokeh_handle)
def replotBottom():
x = [random.random() for i in range(num_samples)]
y = [random.random() for i in range(num_samples)]
p2 = figure()
p2.circle(x,y)
p2.plot_width=COL1_W
p2.plot_height=COL1_W
x = [random.random() for i in range(num_samples)]
y = [random.random() for i in range(num_samples)]
p3 = figure(plot_width = COL2_W, plot_height = int(COL1_W*1.5))
p3.circle(x,y,color='green')
x = [random.random() for i in range(num_samples)]
y = [random.random() for i in range(num_samples)]
z = [random.random() for i in range(num_samples)]
p4 = figure(plot_width = int(TOTAL_WIDTH/2-5), plot_height=COL1_W)
p5 = figure(plot_width = int(TOTAL_WIDTH/2-5), plot_height=COL1_W)
p4.circle(x,y)
p5.circle(x,z)
layout.children[0].children[0].children[0].children[3]=p2
layout.children[0].children[0].children[1].children[1]=p3
layout.children[0].children[1].children[0] = p4
layout.children[0].children[1].children[1] = p5
push_notebook(handle=bokeh_handle)
cb = CustomJS(code="""
if (IPython.notebook.kernel !== undefined) {
var kernel = IPython.notebook.kernel;
cmd = "bUpdate('" + cb_obj.title + "','" + cb_obj.value + "')";
kernel.execute(cmd, {}, {});
}
""")
cbRC = CustomJS(code="""
if (IPython.notebook.kernel !== undefined) {
var kernel = IPython.notebook.kernel;
cmd = "bReCalc()";
kernel.execute(cmd, {}, {});
}
""")
TOTAL_WIDTH = 800
COL1_W = int(0.25*TOTAL_WIDTH)-5
COL2_W = int(0.75*TOTAL_WIDTH)-5
WID_W = int(0.5*COL1_W) - 15
btnCalc = Button(label="Recalculate", callback=cbRC, width=WID_W)
sldSamples = Slider(start=20, end=1000, step=10, title="Number of Samples", callback_policy="mouseup", callback=cb, width=WID_W)
layout = row(column( row( column( btnCalc, figure(plot_width=COL1_W, plot_height=250), \
sldSamples, figure(plot_width=COL1_W, plot_height=COL1_W)), \
column( figure(plot_width=COL2_W, plot_height=int(COL1_W*1.8)), \
figure(plot_width=COL2_W, plot_height = int(COL1_W*1.5), sizing_mode="scale_height")) \
), \
row(figure(plot_width = int(TOTAL_WIDTH/2-5), plot_height=COL1_W), figure(plot_width = int(TOTAL_WIDTH/2-5), plot_height=COL1_W))))
bokeh_handle = show(layout, notebook_handle=True)
当用户单击按钮或更改滑块的值时,某些图表会更新并重新绘制,而其他图表会随机调整大小。但是,如果您只是在另一个单元格中调用“show(layout)”,则布局会正确显示。任何人对这类事情有最佳实践的想法吗?
== EDIT ==
即使嵌入类似于此示例的散景服务器,也会发生相同类型的错误:https://github.com/bokeh/bokeh/blob/master/examples/howto/server_embed/notebook_embed.ipynb
output_notebook()
def modify_doc(doc):
num_samples = 500
def sampChange(attr, old, new):
global num_samples
num_samples = int(new)
x = [random.random() for i in range(num_samples)]
y = [random.random() for i in range(num_samples)]
p2 = figure()
p2.circle(x,y)
p2.plot_width=COL1_W
p2.plot_height=COL1_W
x = [random.random() for i in range(num_samples)]
y = [random.random() for i in range(num_samples)]
p3 = figure(plot_width = COL2_W, plot_height = int(COL1_W*1.5))
p3.circle(x,y,color='green')
x = [random.random() for i in range(num_samples)]
y = [random.random() for i in range(num_samples)]
z = [random.random() for i in range(num_samples)]
p4 = figure(plot_width = int(TOTAL_WIDTH/2-5), plot_height=COL1_W)
p5 = figure(plot_width = int(TOTAL_WIDTH/2-5), plot_height=COL1_W)
p4.circle(x,y)
p5.circle(x,z)
layout.children[0].children[1] = row(p4,p5)
layout.children[0].children[0].children[0].children[3]=p2
layout.children[0].children[0].children[1].children[1]=p3
#layout.children[0].children[1].children[1] = p5
#doc.add_root(layout)
def bReCalc():
x = [random.random() for i in range(num_samples)]
y = [random.random() for i in range(num_samples)]
p = figure(plot_width=COL1_W, plot_height=250)
p.circle(x, y, color='red')
p.toolbar.logo = None
layout.children[0].children[0].children[0].children[1] = p
x = [random.random() for i in range(num_samples)]
y = [random.random() for i in range(num_samples)]
p2 = figure(plot_width=COL2_W, plot_height=int(COL1_W*1.8))
p2.circle(x,y)
layout.children[0].children[0].children[1].children[0] = p2
#doc.add_root(layout)
#push_notebook(handle=bokeh_handle)
TOTAL_WIDTH = 800
COL1_W = int(0.25*TOTAL_WIDTH)-5
COL2_W = int(0.75*TOTAL_WIDTH)-5
WID_W = int(0.5*COL1_W) - 15
btnCalc = Button(label="Recalculate", width=WID_W)
sldSamples = Slider(start=20, end=500, step=10, title="Number of Samples", callback_policy="mouseup", width=WID_W)
btnCalc.on_click(bReCalc)
sldSamples.on_change('value', sampChange)
layout = row(column( row( column( btnCalc, figure(plot_width=COL1_W, plot_height=250), \
sldSamples, figure(plot_width=COL1_W, plot_height=COL1_W)), \
column( figure(plot_width=COL2_W, plot_height=int(COL1_W*1.8)), \
figure(plot_width=COL2_W, plot_height = int(COL1_W*1.5))) \
), \
row(figure(plot_width = int(TOTAL_WIDTH/2-5), plot_height=COL1_W), figure(plot_width = int(TOTAL_WIDTH/2-5), plot_height=COL1_W))))
doc.add_root(layout)
bReCalc()
return doc
from bokeh.application.handlers import FunctionHandler
from bokeh.application import Application
handler = FunctionHandler(modify_doc)
app = Application(handler)
show(app)