I recently started on a new project that requires me to plot lat and long data on a map. I've managed to plot everything out so far, but I've gotten stuck at creating the callback function for the Range Slider I'm using to control which data to plot.
My current code uses this response here by Amstrad2Python as its base. Running the code that Amstrad2Python provided gave me no errors. However, when I try to run the code, it gives me the error "Cannot read property 'emit' of undefined" when I check the console output in the html plot.
Here is sample code that is similar to the actual code I am using, which creates the exact same error:
import bokeh.events as bev
import bokeh.layouts as bla
import bokeh.models as bmo
import numpy as np
import pandas as pd
from bokeh.plotting import figure, output_file, show
sample_data = pd.DataFrame(
data=np.array(
[
[1, 12, 21, 15000],
[2, 25, 90, 15500],
[3, 37, 47, 15500],
[4, 41, 56, 15000],
[5, 50, 21, 14500]
]
),
columns=['Seconds', 'lat', 'long', 'alt']
)
#create 2 sources, 1 for editting, 1 for referencing
source = bmo.ColumnDataSource(sample_data) #const data
filtered_source = bmo.ColumnDataSource(sample_data) #alterable data
#create callback function
callback = bmo.CustomJS(args=dict(source=source, filtered_source = filtered_source),
code="""
var data = source.data;
var start = cb_obj.value[0];
var end = cb_obj.value[1];
function generateNewDataObject(oldDataObject){
var newDataObject = {}
for (var key of Object.keys(oldDataObject)){
newDataObject[key] = [];
}
return newDataObject
}
function addRowToAccumulator(accumulator, dataObject, index) {
for (var key of Object.keys(dataObject)){
accumulator[key][index] = dataObject[key][index];
}
return accumulator;
}
var new_data = generateNewDataObject(data);
for (var i = 0; i < source.data['Seconds'].length; i++){
if (source.data['Seconds'][i] > start) {
if (source.data['Seconds'][i] <= end) {
new_data = addRowToAccumulator(new_data, source.data, i);
}
}
}
console.log(new_data)
filtered_source = new_data;
filtered_source.change.emit();
""")
#create slider and add on_change event
testSlider = bmo.RangeSlider(width = 525, bar_color = 'red',
start = 0, end = sample_data['Seconds'].max(),
value=(0,1), step = 1 )
testSlider.js_on_change('value', callback)
#create figure and plot points
p = figure(toolbar_location = 'below',
x_axis_label = 'Longitude', y_axis_label = 'Latitude')
p.circle(x = 'long', y = 'lat', source=filtered_source)
#create layout and show
layout = bla.column(p, testSlider)
show(layout)
For reference, this is the resulting error I get when I try to change the slider:
https://i.sstatic.net/OTBEm.png
Does anyone know what the issue is with my current code? Any feedback regarding to my code is also appreciated. Thank you in advance.
You need to assign the new_data
to the .data
field of filtered_source
.
When changing the line filtered_source = new_data;
to filtered_source.data = new_data;
, your example works for me.