【问题标题】:Chart on click selection from data table in Bokeh从 Bokeh 中的数据表中单击选择的图表
【发布时间】:2019-05-03 07:16:32
【问题描述】:

我从其他来源获取了以下代码 - 这不是我自己的代码。

该代码允许您在数据表中选择一个单元格,该单元格的“下载”数据将根据所选单元格的行绘制图表。

如何扩展此代码,以便如果我有多个变量(例如“下载”和“上传”)以及数据表中的更多列,我可以基于该单元格绘制数据图表(因此行和列是重要的)?或者,如何将选定单元格的列号定义为变量(与下面的 selected_row 可用于定义行号相同)?

from datetime import date
from random import randint
from bokeh.models import ColumnDataSource, Column
from bokeh.plotting import figure, curdoc
from bokeh.models.widgets import DataTable, DateFormatter, TableColumn, Div
import numpy as np

data = dict(dates = [date(2014, 3, i + 1) for i in range(10)],
            downloads = [randint(0, 100) for i in range(10)])
d_source = ColumnDataSource(data)

columns = [TableColumn(field = "dates", title = "Date", formatter = DateFormatter()),
           TableColumn(field = "downloads", title = "Downloads")]

data_table = DataTable(source = d_source, columns = columns, width = 400, height = 280)

def table_select_callback(attr, old, new):
    selected_row = new[0]
    download_count = data['downloads'][selected_row]
    chart_data = np.random.uniform(0, 100, size = download_count)
    p = figure(title = 'bla')
    r = p.line(x = range(len(chart_data)), y = chart_data)
    root_layout.children[1] = p

d_source.selected.on_change('indices', table_select_callback)

root_layout = Column(data_table, Div(text = 'Select Date'))
curdoc().add_root(root_layout)

【问题讨论】:

    标签: python bokeh


    【解决方案1】:

    这是最终的工作代码(从命令行使用bokeh serve --show app.py 运行):

    from datetime import date
    from random import randint
    from bokeh.models import ColumnDataSource, Column, TableColumn, DateFormatter, DataTable, CustomJS
    from bokeh.plotting import figure, curdoc
    
    source = ColumnDataSource(dict(dates = [date(2014, 3, i + 1) for i in range(10)], downloads = [randint(0, 100) for i in range(10)]))
    columns = [TableColumn(field = "dates", title = "Date", formatter = DateFormatter()), TableColumn(field = "downloads", title = "Downloads")]
    data_table = DataTable(source = source, columns = columns, width = 400, height = 280, editable = True, reorderable = False)
    info_source = ColumnDataSource(dict(row = [], column = []))
    
    source_code = """
    var grid = document.getElementsByClassName('grid-canvas')[0].children;
    var row, column = '';
    
    for (var i = 0,max = grid.length; i < max; i++){
        if (grid[i].outerHTML.includes('active')){
            row = i;
            for (var j = 0, jmax = grid[i].children.length; j < jmax; j++)
                if(grid[i].children[j].outerHTML.includes('active')) {
                    column = j; 
                    source2.data = {row: [row], column: [column]};
                }
        }
    }"""
    
    callback = CustomJS(args = dict(source = source, source2 = info_source), code = source_code)
    source.selected.js_on_change('indices', callback)
    
    def py_callback(attr, old, new):
        source.selected.update(indices = [])
        print(info_source.data)
    
    source.selected.on_change('indices', py_callback)
    curdoc().add_root(Column(data_table))
    

    【讨论】:

      【解决方案2】:

      我的建议是使用my another post,它使用 JS 回调来访问所选单元格的行和列。这必须是一个 JS 回调,因为它使用 HTML 元素来遍历。所以步骤如下:

      1. 定义一个新的ColumnDataSource,它将包含被点击单元格的行号和列号

        info_source = ColumnDataSource(dict(row = [], column = []))

      2. 使用来自this post 的JS 回调在这个新的table_info_source 中填写rowcolumn 值,如下所示:

      callback=CustomJS(args=dict(source=d_source,source2=info_source),code=source_code)
      source.selected.js_on_change('indices', callback)

      1. 在 JS 回调中存储 rowcolumn 索引,如下所示:

        source2.data = {row:[row],column:[column]};

      2. 在 Python 回调中访问 info_source.data 信息以绘制绘图

        print (info_source.data)

      两个回调都附加到同一个源,但通常首先执行 JS 回调,因此数据应该在 Python 回调中准时可用。有了单击单元格的行和列的索引,您应该能够检索所需的数据并绘制图表。

      【讨论】:

      • 感谢您的回复-从您在上面第一位所说的话看来,没有,但只是为了澄清有没有什么方法可以在不需要 JS 的情况下做到这一点,或者是唯一的选择?我所在的团队已经表达了不使用 JS 的偏好
      • 据我所知,JS 回调是获取单击单元格的列索引的唯一选项。请注意,浏览器中的 Bokeh 应用程序是由 BokehJS 模型制成的,因此它是 100% JS 并且禁止 JS 是一种奇怪的要求。 BokehJS 通过 Bokeh 服务器定期与 Python 模型同步。最终,包含列索引的info_source.data 将可以在 Python 代码中访问,您可以在其中执行任何您需要的操作。
      • 我已经尝试按照这些说明进行操作,但我目前拥有的代码(发布在下面)正在打印 {'column': [], 'row': []} - 它没有填充信息。我做错了什么?
      • 我相应地更新了我的答案和您的代码。显然,只有在将新对象分配给 ColumnDataSource.data 时,BokehJS 才能检测到更改。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 2021-09-13
      • 1970-01-01
      相关资源
      最近更新 更多