我一直在做一个项目,使用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浏览器来进行可视化。
发布于 2020-04-24 17:45:16
您的button3_reset代码不会清理任何东西-它只是在现有内容的基础上添加新内容。
相反,您应该遍历sources列表,并将每个源的data属性设置为代码中第一个循环中使用的初始值。这意味着,您还必须将这些数据保存在某个地方。
发布于 2020-04-25 03:18:52
像往常一样,我把事情搞得过于复杂了。下面是完成这项工作的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。然后,为了整理东西,我不得不将标题更新回“步骤0”,然后让step成为一个非局部变量,这样button2_step就可以知道从1开始重新开始步骤编号,这样就可以重新设置它应该做的事情。再次感谢您的回复。
https://stackoverflow.com/questions/61400585
复制相似问题