【问题标题】:Bokeh not updating plot line update from CheckboxGroupBokeh 未从 CheckboxGroup 更新绘图线更新
【发布时间】:2018-07-23 15:40:19
【问题描述】:

我正在关注this great tutorial 来玩一下 Bokeh。

基本上,我有一个figure,其中添加了两个独立的line。一切都正确呈现,但是当我想更新时,即使我检查了新的ColumnDataSource 是否已用新值很好地更新,也没有任何反应。

我使用以下命令渲染它:bokeh serve --show my_app

这是我创建figure 的方法:

src_p6 = make_dataset(["select_a", "select_b"])
p6 = make_plot(src_p6)
select_selection = CheckboxGroup(labels=["select_a", "select_b"], active = [0, 1])
select_selection.on_change('active', update)
controls = WidgetBox(select_selection)
curdoc().add_root(column(controls, p6, width=1200))

def make_dataset(select_list):
  if 'select_a' in select_list and 'select_b' in select_list:
    tmp = pd.DataFrame({'time': df["time"], 
                       'a': df["a"], 
                       'b': df["b"]
                       })
  elif 'select_a' in select_list and 'select_b' not in select_list:
    tmp = pd.DataFrame({'time': df["time"], 
                       'a': df["a"]
                       })
  elif 'select_a' not in select_list and 'select_b' in select_list:
    tmp = pd.DataFrame({'time': df["time"], 
                       'b': df["b"]
                       })
  else:
    tmp = pd.DataFrame({'time': df["time"]
                       })

  src = ColumnDataSource(tmp)

  return src

def make_plot(plot_src):
  p = figure(plot_width=1000, plot_height=600, 
           title="Line x2 with hover and update",
           x_axis_label='Time', 
           y_axis_label='Values'
          )

  hover_content = [("Time", "@time")]

  if 'a' in plot_src.data:
    p.line(x='time', y='a', source=plot_src, legend="A", line_color="blue")
    hover_content.append(("A", "@a"))
  if 'b' in plot_src.data:
    p.line(x='time', y='b', source=plot_src, legend="B", line_color="red")
    hover_content.append(("B", "@b"))

  p.add_tools(HoverTool(tooltips=hover_content))

  return p

def update(attr, old, new):
  print(src_p6.data)

  select_to_plot = [select_selection.labels[i] for i in select_selection.active]

  new_src = make_dataset(select_to_plot)

  src_p6.data = new_src.data

  print("**********************")
  print(src_p6.data) # I see here that the data are well updated compared to the first print

我的传入数据是 JSON,看起来像这样:

# {"data":[{"time":0,"a":123,"b":123},{"time":1,"a":456,"b":456},{"time":2,"a":789,"b":789}]}
# data = json.load(data_file, encoding='utf-8')
# df = pd.io.json.json_normalize(data['data'])

感谢您的见解

【问题讨论】:

    标签: python plot bokeh


    【解决方案1】:

    这将无法正常工作:

    src_p6.data = new_src.data
    

    ColumnDataSource 是 Bokeh 中最复杂的对象之一,例如CDS 上的 .data 对象不是普通的 Python 字典,它有许多特殊的工具可以使高效流式传输等事情成为可能。但它也与创建它的 CDS 相关联。从一个 CDS 中提取 .data 并将其分配给另一个是行不通的。我们可能需要找到一种方法来让这种抱怨,我只是不确定如何,即兴发挥。

    在任何情况下,您都需要从普通的 Python 字典中分配 .data,就像所有示例和演示一样:

    src_p6.data = dict(...)
    

    对于您的特定代码,这可能意味着让make_dataset 直接返回它创建的字典,而不是将它们放入数据帧中然后从中制作 CDS。

    【讨论】:

    • 所以这是用 pandas 创建一个 DataFrame 搞砸一切?关于我的 JSON 输入(对象数组),CDS 的输入应该是什么?抱歉,我对 Python 很陌生
    • 不,问题不在于 pandas 部分,在这种情况下制作 DataFrame 可能是不必要但无害的。问题是制作一张 CDS,然后将其 .data 复制到另一张 CDS。
    • 好的!所以现在make_dataset 返回变量tmp。我像这样创建src_p6src_p6 = ColumnDataSource(make_dataset(.....))。对于update 我现在有:src_p6.data = new_src 但是当我尝试更新时,我收到错误消息:ValueError('expected an element of ColumnData(String, Seq(Any)), got it_looks_like_the_dict_formatted_into_string
    • 字典应该将字符串键映射到等长的列。列可以是:Python 列表、NumPy 数组、Pandas 系列……大多数具体的可迭代序列类型都可以。您传递给pd.DataFrame 的字典已经是正确的格式。正如我所说,您可以直接退回这些。
    • 我不使用 SO 聊天。我已经负担过重监控邮件列表、GH、Gitter 和 SO 问题。请随时通过 Bokeh 公共邮件列表来:groups.google.com/a/continuum.io/forum/#!forum/bokeh
    【解决方案2】:

    首先感谢@bigreddot 的时间和指导。

    我最大的问题之一是我实际上并不想更新值,而只是显示/隐藏它,所以只是从源中删除它是行不通的

    使用if 语句在我的make_plot 函数中添加line 也不起作用,因为它仅在第一次创建绘图时被调用。对于更新,它会更新图中的值,但不会从头开始重建所有内容... 因此,如果您只从一行开始,我不知道它将如何创建新行,如果可能的话。 ..


    我开始简化我的 make_dataset 函数,只返回一个简单的 Python 字典:

    tmp = dict(time=df["time"], a=df["a"], b=df["b"])
    

    但是当我想删除一行时,即使有更好的解决方案,我也使用了一个空数组(我只是在这里玩 Bokeh):Line ON/OFFInteractive legend

    empty = np.empty(len(df["time"])); empty.fill(None)
    tmp = dict(time=df["time"], a=df["a"], b=empty)
    

    当我第一次创建我的情节时,我会这样做:

    src_p6 = ColumnDataSource(data=make_dataset(["select_a", "select_b"]))
    p6 = make_plot(src_p6)
    

    更新函数使用基本 Python dict 更新 ColumnDataSource.data

    new_src = make_dataset(select_to_plot)
    src_p6.data = new_src
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多