0

我正在尝试在 jupyter-notebook 中的 bokeh-lineplot、box_select 工具和 TextInput 小部件的帮助下标记 pandas-df(包含时间序列数据)。如何通过 box_select 选定的数据点访问?

我尝试通过将 CustomJS 更改为以下内容来编辑类似的问题代码(获取包含在 Bokeh 中的框选择工具中的选定数据):

source.callback = CustomJS(args=dict(p=p), code="""
        var inds = cb_obj.get('selected')['1d'].indices;
        [source.data['xvals'][i] for i in inds] = 'b'
        """
)

但无法对所选点的来源应用更改。

因此,短期目标是操纵选定点的特定源列。

长期我想使用 TextInput 小部件通过提供的 Textinput 标记所选点。那看起来像:

在此处输入图像描述

编辑:

这是我在笔记本中尝试的当前代码,以重建问题:

from random import random

import bokeh as bk
from bokeh.layouts import row
from bokeh.models import CustomJS, ColumnDataSource, HoverTool
from bokeh.plotting import figure, output_file, show, output_notebook

output_notebook()

x = [random() for x in range(20)]
y = [random() for y in range(20)]

hovertool=HoverTool(tooltips=[("Index", "$index"), ("Label", "@label")])

source = ColumnDataSource(data=dict(x=x, y=y, label=[i for i in "a"*20]))
p1 = figure(plot_width=400, plot_height=400, tools="box_select", title="Select Here")
p1.circle('x', 'y', source=source, alpha=0.6)
p1.add_tools(hovertool)
source.selected.js_on_change('indices', CustomJS(args=dict(source=source), code="""
        var inds = cb_obj.indices;
        for (var i = 0; i < inds.length; i++) {
            source.data['label'][inds[i]] = 'b'
        }
        source.change.emit();
    """)
)

layout = row(p1)

show(layout)
4

2 回答 2

1

需要注意的主要事情是 BokehJS 只能在进行实际分配时自动通知更新,例如

source.data = some_new_data

这将触发更新。如果您“就地”更新数据,则 BokehJS 无法注意到这一点。您必须明确并致电source.change.emit()让 BokehJS 知道某些内容已更新。

但是,您还应该知道您正在使用三种不同的东西,它们早已被弃用,将在下一个版本中删除。

  • cb_obj.get('selected')

    无需使用.get您可以直接访问属性:

    cb_obj.selected
    
  • ['1d']语法。这种 dict 方法非常笨拙,很快就会被删除。对于大多数选择,您需要选择的indices属性:

    source.selected.indices
    
  • source.callback

    这是一个古老的临时回调。有一种更新的通用机制用于回调属性,应该始终使用它

    source.selected.js_on_change('indices', CustomJS(...))
    

    请注意,在这种情况下,cb_obj是选择,而不是数据源。

于 2019-09-26T04:12:27.963 回答
0

在本指南关于如何在笔记本中嵌入散景服务器的帮助下,我为我的目的想出了以下最小示例:

from random import random
import pandas as pd
import numpy as np
from bokeh.io import output_notebook, show
from bokeh.layouts import column
from bokeh.models import Button
from bokeh.plotting import figure
from bokeh.models import HoverTool, ColumnDataSource, BoxSelectTool
from bokeh.models.widgets import TextInput
output_notebook()

def modify_doc(doc):
    # create a plot and style its properties
    TOOLS="pan,wheel_zoom,reset"
    p = figure(title = "My chart", tools=TOOLS)
    p.xaxis.axis_label = 'X'
    p.yaxis.axis_label = 'Y'
    hovertool=HoverTool(tooltips=[("Index", "$index"), ("Label", "@label")])

    source = ColumnDataSource(
    data=dict(
            xvals=list(range(0, 10)),
            yvals=list(np.random.normal(0, 1, 10)),
            label = [i for i in "a"*10]
    ))
    p.scatter("xvals", "yvals",source=source, color="white")
    p.line("xvals", "yvals",source=source)
    p.add_tools(BoxSelectTool(dimensions="width"))
    p.add_tools(hovertool)

    # create a callback that will add a number in a random location
    def callback():
            inds = source.selected.indices
            for i in inds:
                    source.data['label'][i] = label_input.value.strip()
            print(source.data)
            new_data =  pd.DataFrame(source.data)
            new_data.to_csv("new_data.csv", index=False)

    # TextInput to specify the label
    label_input = TextInput(title="Label")
    # add a button widget and configure with the call back
    button = Button(label="Label Data")
    button.on_click(callback)

    # put the button and plot in a layout and add to the document
    doc.add_root(column(button,label_input, p))

show(modify_doc, notebook_url="http://localhost:8888")

这会生成以下 UI: 在此处输入图像描述

顺便说一句:由于不存在用于线条字形的 box_select 工具,我使用了一种解决方法,将其与不可见的散点相结合。

到目前为止一切都很好,有没有比在回调中导出它更优雅的方式来访问 modify_doc() 之外的笔记本中的 data.source/new_data df?

于 2019-09-30T11:37:09.947 回答