DataCube - changing underlying data using source.change.emit() resulted in Uncaught TypeError

Hi All,

Previously, I have a functional python script that generates a static html page using DataTable widget. I use CustomJS and js_on_change in order to add ability for user to filter the data in DataTable using dropdown menu, checkboxes, etc. Essentially, based on the filter criteria, I emptied out my subset data object, and run a for loop on my main source data object to obtain data I need and append back into my subset data object. Here’s the sample code, where source is my main data and s is my subset data :

var f = d1.value;
var g = mc1.active.map(a => mc1.labels[a]);
var h = mc2.active.map(b => mc2.labels[b]);
var colNames = Object.keys(s.data);
var t_names =  [];

# remove existing data in subset
for (var i=0; i < colNames.length; i++) {
  var colName = colNames[i];
  s.data[colName] = []
}

# append filtered data back into subset
for (var j=0; j < source.get_length(); j++) {
    if (
         (source.data['column_name_1'][j] == f) & 
         (g.includes(source.data['column_name_2'][j])) &
         (h.includes(source.data['column_name_3'][j])) &
         ((!sa3.active) || (source.data['column_name_4'][j] < cutoff))
       ) {
       var t_name = source.data['column_name_5'][j];
       if (!t_names.includes(t_name)) {t_names.push(t_name)}
       for (var k=0; k < colNames.length; k++) {
          var colName = colNames[k];
          s.data[colName].push(source.data[colName][j])
    }
  }
}
s.change.emit();

Currently, I’m trying out DataCube widget instead. On its own, the widget works fine with static data. As soon as I change my previous code (that dynamically changes data based on user filter input) using DataCube, I got the following traceback:

bokeh-1.4.0.min.js:formatted:4224 Uncaught TypeError: Cannot read property 'slice' of undefined
    at e.getItemMetadata (bokeh-tables-1.4.0.min.js:formatted:10559)
    at appendRowHtml (bokeh-tables-1.4.0.min.js:formatted:6708)
    at renderRows (bokeh-tables-1.4.0.min.js:formatted:6992)
    at render (bokeh-tables-1.4.0.min.js:formatted:7030)
    at SlickGrid.invalidate (bokeh-tables-1.4.0.min.js:formatted:6758)
    at e.t.updateGrid (bokeh-tables-1.4.0.min.js:formatted:742)
    at e.<anonymous> (bokeh-tables-1.4.0.min.js:formatted:703)
    at t.n.emit (bokeh-1.4.0.min.js:formatted:4224)
    at t.emit (bokeh-1.4.0.min.js:formatted:4238)
    at eval (eval at get (bokeh-1.4.0.min.js:formatted:18365), <anonymous>:56:10)

What it’s trying to do is called this.column.slice(1), and I have no idea what this is. This error is caused by the last line of my customJS’s emit function. It doesn’t seem like it’s using the subset data object at all, since I tried adding a columns attribute to the object but still resulted in the same error.

Any idea what might have happened? There are not many documentations and stack overflow topic on DataCube so I’m kinda at a loss.

Thank you for the help!

DataCube was added by an outside contributor. It probably should have been marked something like “Experimental”, but we have not formally developed such a notion or guidelines for applying it. In any case, it’s not really possible to say much without actual code to execute. If you can provide such complete, minimal example, I am happy to take a quick look it.

Hi Bryan, thank you for offering to help!

I have reduced it to a minimal example:

from bokeh.io import output_file, save
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.models.widgets import DataTable, TableColumn, Select, DataCube, GroupingInfo
from bokeh.layouts import column, layout
import pandas as pd

output_file("datacube_example.html")

df = pd.DataFrame({'name':['A','B','C','A','B','C','A','B','C','A','B','C',],
                   'value':[1,2,3,4,5,6,7,8,9,10,11,12]})

# source are where all data are stored, subset are the data being displayed
source = ColumnDataSource(df.to_dict('list'))
subset = ColumnDataSource(df[df.name == 'B'].to_dict('list'))


target = ColumnDataSource(data=dict(row_indices=[], labels=[]))

columns = [
    TableColumn(field='name', title='Name', width=100, sortable=False),
    TableColumn(field='value', title='value', width=100, sortable=False)
]

grouping = [
    GroupingInfo(getter='name', collapsed=False)
]

# data table definition
data_table = DataTable(source=subset,
                       columns=columns,
                       fit_columns=True,
                       header_row=True,
                       index_position=None,
                       reorderable=False)


cube = DataCube(source=subset, columns=columns, grouping=grouping, target=target)


# Experiment Dropdown Menu
d1 = Select(value='B', options=sorted(list(df.name.unique())))

# main js block to fill table with data based on user's selection
c1 = CustomJS(args=dict(source=source, s=subset, d1=d1), code="""
var f = d1.value;
var colNames = Object.keys(s.data);
for (var i=0; i < colNames.length; i++) {
  var colName = colNames[i];
  s.data[colName] = []
}

for (var j=0; j < source.get_length(); j++) {
    if (
         (source.data['name'][j] == f)
       ) {
       for (var k=0; k < colNames.length; k++) {
          var colName = colNames[k];
          s.data[colName].push(source.data[colName][j])
    }
  }
}
s.change.emit();

""")

# dropdown callback
d1.js_on_change('value', c1)


report = layout([
    column(d1),
    column(data_table)  # replace with column(cube) to see the error
    ]
)

save(report)

This will generate a html file. Using column(data_table) generates no error, while using column(cube) will result in the error I mentioned previously as soon as you select a different value in the dropdown menu.

Thanks!

Hi @wiseleywu I am afraid this sort of thing just is not currently supported on DataCube. All I can recommend is to make a GitHub issue with all this information and I will see if the original contributor can be pinged to take a look.