我一直在使用bokeh可视化来显示基于代理模型(ABM)模拟的结果的项目。在recent post中,我得到了帮助,可以在非常简化的模拟版本中正确传输数据。我的下一个任务很容易理解,就是在布局中添加一个“重置”按钮,这样我就可以将图形恢复到其初始状态,并再次从“步骤0”开始运行仿真。令人惊讶的是,似乎没有简单的方法可以做到这一点。我尝试了几种不同的方法,包括重新初始化我的所有数据和重新填充ColumnDataSources,但是我无法使以前运行模拟中的数据消失。这是一个说明问题的独立代码示例:
import colorcet as cc
from bokeh.server.server import Server
from bokeh.application import Application
from bokeh.application.handlers.function import FunctionHandler
from bokeh.plotting import figure, ColumnDataSource
from bokeh.models import Button
from bokeh.layouts import column
import random
def make_document(doc):
# make a list of groups
strategies = ['DD', 'DC', 'CD', 'CCDD']
# initialize some vars
step = 0
callback_obj = None
colors = cc.glasbey_dark
#num_colors = len(colors)
# create a list to hold all CDSs for active strategies in next step
sources = []
# Create a figure container
fig = figure(title='Streaming Line Plot - Step 0', plot_width=1400, plot_height=400)
# get step 0 data for initial strategies
for i in range(len(strategies)):
step_data = dict(step=[step],
strategy = [strategies[i]],
ncount=[random.choice(range(1, 100))])
data_source = ColumnDataSource(step_data)
color = colors[i]
# this will create one fig.line renderer for each strategy & its data for this step
fig.line(x='step', y='ncount', source=data_source, color=color, line_width=2)
# add this CDS to the sources list
sources.append(data_source)
def button1_run():
nonlocal callback_obj
if button1.label == 'Run':
button1.label = 'Stop'
button1.button_type='danger'
callback_obj = doc.add_periodic_callback(button2_step, 100)
else:
button1.label = 'Run'
button1.button_type = 'success'
doc.remove_periodic_callback(callback_obj)
def button2_step():
nonlocal step
data = []
step += 1
fig.title.text = 'Streaming Line Plot - Step '+str(step)
for i in range(len(strategies)):
step_data = dict(step=[step],
strategy = [strategies[i]],
ncount=[random.choice(range(1, 100))])
data.append(step_data)
for source, data in zip(sources, data):
source.stream(data)
def button3_reset():
step = 0
fig.title.text = 'Streaming Line Plot - Step '+str(step)
for i in range(len(strategies)):
init_data = dict(step=[step],
strategy = [strategies[i]],
ncount=[random.choice(range(1, 100))])
reset_source = ColumnDataSource(init_data)
print(init_data)
color = colors[i]
# this will create one fig.line renderer for each strategy & its data for this step
fig.line(x='step', y='ncount', source=reset_source, color=color, line_width=2)
# add this CDS to the sources list
sources.append(reset_source)
# add on_click callback for button widget
button1 = Button(label="Run", button_type='success', width=390)
button1.on_click(button1_run)
button2 = Button(label="Step", button_type='primary', width=390)
button2.on_click(button2_step)
button3 = Button(label="Reset", button_type='warning', width=390)
button3.on_click(button3_reset)
doc.add_root(column(fig, button1, button2, button3))
doc.title = "Now with live updating!"
apps = {'/': Application(FunctionHandler(make_document))}
server = Server(apps, port=5004)
server.start()
if __name__ == '__main__':
server.io_loop.add_callback(server.show, "/")
server.io_loop.start()
我要在button3_reset
代码中尝试做的基本上是在make_document
函数顶部重复初始化。但是,即使该代码工作相同(从button3
步骤的中间出现的打印输出中可以看出),我也无法使图形重置为初始的空状态。我已经阅读了许多堆栈溢出文章和其他bokeh文档,但没有找到我认为简单的问题的简单答案:如何将bokeh线图重置为其原始状态,以便可以运行数据流又从起点开始了?
我正在使用bokeh 1.4.0(anaconda不允许我更新),python 3.7.6,spyder 4.0.1以及用于可视化的Chrome和Brave浏览器。
答案 0 :(得分:0)
您的button3_reset
代码不会清除任何内容-只会在现有内容之上添加新内容。
相反,您应该仅遍历sources
列表,并将每个源的data
属性设置为代码中第一个循环中使用的初始值。这意味着,您还必须将这些数据保存在某个地方。
答案 1 :(得分:0)
通常,我使事情变得非常复杂。这是完成任务的button3_reset
的代码。
def button3_reset():
nonlocal step
step = 0
data = []
fig.title.text = 'Streaming Line Plot - Step '+str(step)
for i in range(len(strategies)):
init_data = dict(step=[step],
strategy = [strategies[i]],
ncount=[random.choice(range(1, 100))])
data.append(init_data)
for source, data in zip(sources, data):
source.data = data
我之前所做的是生成新的CDS,但是旧的CDS仍然嵌入在图中。再次感谢Eugene的技巧,我意识到我只需要重新分配现有CDS的.data
属性,而无需创建新CDS。然后,为整理起见,我不得不将标题更新回“ Step 0”,然后将step
设为非局部变量,因此button2_step
会知道从1开始重新编号。它应该做什么。再次感谢您的答复。