【问题标题】:JS code to reference row/column in Bokeh DataTable erroring在 Bokeh DataTable 错误中引用行/列的 JS 代码
【发布时间】:2019-05-23 09:10:53
【问题描述】:

我使用以前的帖子herehere 尝试运行代码,借此我可以在 Bokeh 的 DataTable 中选择一行,并获取行号。但是我发现使用该代码,一旦我超过第 6 行或第 7 行,生成的行号是错误的 - 例如,我可以单击第 17 行,它会说它是第 6 行。我该如何解决这个问题?

请注意this 帖子中的代码,仅当我将“源”ColumnDataSource 中的范围从 10 增加到 20 时才会发生错误。

from random import randint
from datetime import date
from bokeh.models import ColumnDataSource, TableColumn, DateFormatter, DataTable, CustomJS
from bokeh.layouts import column
from bokeh.models.widgets import TextInput
from bokeh.plotting import curdoc

source = ColumnDataSource(dict(dates = [date(2014, 3, i + 1) for i in range(20)], downloads = [randint(0, 100) for i in range(20)]))
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)

text_row = TextInput(value = None, title = "Row index:", width = 420)
text_column = TextInput(value = None, title = "Column Index:", width = 420)
text_date = TextInput(value = None, title = "Date:", width = 420)
text_downloads = TextInput(value = None, title = "Downloads:", width = 420)
test_cell = TextInput(value = None, title = "Cell Contents:", width = 420)

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 }
    }
}
text_row.value = String(row);
text_column.value = String(column);
text_date.value = String(new Date(source.data['dates'][row]));
text_downloads.value = String(source.data['downloads'][row]); 
test_cell.value = column == 1 ? text_date.value : text_downloads.value; """

def py_callback(attr, old, new):
    print(test_cell.value)
    print(text_date.value)
    source.selected.update(indices = [])

source.selected.on_change('indices', py_callback)
callback = CustomJS(args = dict(source = source, text_row = text_row, text_column = text_column, text_date = text_date, text_downloads = text_downloads, test_cell = test_cell), code = source_code)
source.selected.js_on_change('indices', callback)
curdoc().add_root(column(data_table, text_row, text_column, text_date, text_downloads, test_cell))

我附上了运行代码时遇到的错误的图片。你可以 我点击了第 16 行,它说的是第 10 行。

或者我的其他代码(引用我已经从本地工作服务器上的数据创建的许多不同的数据框等):

import pandas as pd
pd.options.mode.chained_assignment = None
import datetime as dt
import math
import random
import pandas as pd
import itertools
import pickle
from bokeh.layouts import layout
from collections import OrderedDict
from bokeh.models import ColumnDataSource, Column, TableColumn, DateFormatter, DataTable, CustomJS, DataRange1d
from bokeh.plotting import figure, curdoc

source = ColumnDataSource(dict(products=dfNew['Products'], prices=dfNew['Current Prices']))
columns = [TableColumn(field="products", title="Products"), TableColumn(field="prices", title="Current Prices")]
data_table = DataTable(source=source, columns=columns, width=400, height=350, editable=True, reorderable=False)
location_source = ColumnDataSource(dict(row=[], column=[]))

prodPx = OrderedDict()
pVal = 0
for i in products:
    key = str(i)
    prodPx[key] = [(dfNew['Current Prices'])[pVal]]
    pVal += 1

noProd = OrderedDict()
kVal = 0
for i in products:
    key = str(kVal)
    noProd[key] = [i]
    kVal += 1

prodpx_source = ColumnDataSource(prodPx)
noprod_source = ColumnDataSource(noProd)


#initial chart
x = new_dates
y = df[products[0]]
sourceChart = ColumnDataSource(data=dict(x=x, y=y))

chart = figure(title=ccy + ' Charting', x_axis_type='datetime', plot_width = 1200, plot_height=500)
chart.line('x', 'y', source=sourceChart, line_width=3, line_alpha=0.6)

#callbacks
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]};
            }
    }
}
source.change.emit();
source2.change.emit();
source3.change.emit();
source4.change.emit();
"""

#js callback
callback = CustomJS(args=dict(source=source, source2=location_source, source3=prodpx_source,
                              source4=noprod_source), code=source_code)

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

#python callback
def py_callback(attr, old, new):
    row = str((location_source.data['row'][0]))
    chartVals = (noprod_source.data[row][0])
    try:
        yVar = df[chartVals]
    except:
        yVar = df[totalProducts[0]]
    sourceChart.data = dict(x=x, y=yVar)
    source.selected.update(indices=[])
    print(location_source.data)

source.selected.on_change('indices', py_callback)
layout = layout([data_table], [chart])
curdoc().add_root(layout)


【问题讨论】:

  • 您需要发布您的代码,否则无法猜测。
  • 嗨,Tony - 已从其中一个链接帖子中发布了代码 - 在“源”ColumnDataSource 中已将“for i in range(10)”更改为“for i in range(20)”,并且得到错误。例如。当我点击第 14 行时,生成的“行索引”为 8。
  • 抱歉,我要求您发布 您的代码 不起作用,而不是其他帖子中的代码起作用。
  • 嗨,托尼 - 很抱歉澄清一下,但我重新发布的另一篇文章中的上述代码(范围(10)到范围(20)的微小变化)对我不起作用。我可以运行它,当点击到第 10 行时它会按预期执行,但之后它吐出的“行”是不正确的。我还在上面发布了我自己的代码,它有同样的问题,但它引用了许多非常长的以前代码中的许多数据帧和变量等,因此无法按原样运行。感谢您的帮助 - 谢谢!
  • Tony - 我添加了运行上述另一篇文章中的代码时发生的情况的屏幕截图,以帮助解释错误。

标签: javascript charts bokeh


【解决方案1】:

我的回调代码不适用于具有滚动条的表格。从那以后,我将它更新为更强大的东西(但它仅适用于文档中的第一个表格小部件)

from bokeh.io import show
from bokeh.layouts import widgetbox
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.models.widgets import DataTable,TableColumn

column_list = ['col1','col2','col3']

source = ColumnDataSource(data = {key:range(20) for key in column_list})

columns = [TableColumn(field=col, title=col) for col in column_list]

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

source_code = """
var grid = document.getElementsByClassName('grid-canvas')[0];

var active_row = grid.querySelectorAll('.active')[0];

if (active_row!=undefined){

    var active_row_ID = Number(active_row.children[0].innerText);

    for (var i=1, imax=active_row.children.length; i<imax; i++){
        if (active_row.children[i].className.includes('active')){
            var active_col_ID = i-1;
        }
    }

    console.log('row',active_row_ID);
    console.log('col',active_col_ID);

    var active_cells = grid.querySelectorAll('.active');
    for (i=0, imax=active_cells.length;i<imax;i++){
        active_cells[i].classList.remove('active');
    }

    cb_obj.indices = [];
}
"""

source.selected.js_on_change('indices', CustomJS(args={'source':source},code= source_code) )

show(widgetbox(data_table))

您可以使用 active_row_ID 和 active_col_ID

cb_obj.indices = [] 允许在连续两次单击同一单元格时触发回调。但这会触发第二次回调。

这就是为什么在active_cells 上的最后一个循环用于从活动单元格的类名中去除.active,这将使active_row 在第二次执行中未定义。

if (active_row!=undefined) 会丢弃回调的第二次执行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-22
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    • 2020-02-02
    • 2012-01-25
    • 1970-01-01
    • 2017-07-15
    相关资源
    最近更新 更多