I’m trying to recalculate the distance between two coordinates, one is given through 2 TextInput classes and the other is in a dataframe. I want to resolve this issue in order to select the data based on proximity conditions, maybe select options, but none of that can work unless the distance is dynamically updated based on the 2 TextInput inputs.
I followed the docs and samples, but for some reason the df[‘distance’] is not changing.
My code is below, I’m defining a function inside the callback to calculate the distance.
import numpy as np
import pandas as pd
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, CustomJS, TextInput
import math
from bokeh.layouts import column, row
from bokeh.io import show
df = pd.DataFrame(np.random.rand(100,2),columns=list('Xy'))
def distance(origin, destination):
lat1, lon1 = origin
lat2, lon2 = destination
radius = 6371 # km
dlat = math.radians(lat2 - lat1)
dlon = math.radians(lon2 - lon1)
a = (math.sin(dlat / 2) * math.sin(dlat / 2) +
math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) *
math.sin(dlon / 2) * math.sin(dlon / 2))
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
d = radius * c
return d
cord_1, cord_2 = 30.56289,70.38185
df['distance'] = [distance((cord_1,cord_2),(df['X'][i],df['y'][i])) for i in range(0,len(df['X']))]
source=ColumnDataSource(df)
cord_x = TextInput(title="X-Coordinates")
cord_y = TextInput(title="Y-Coordinates")
TOOLTIPS = [
('Distance','@distance')
]
p = figure(title='Sample Distance',width = 800, height = 600,tooltips = TOOLTIPS)
p.circle(x='X',y='y',size = 10,source=source)
callback = CustomJS(args=dict(source=source, cord_x=cord_x, cord_y=cord_y),
code="""
function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2-lat1); // deg2rad below
var dLon = deg2rad(lon2-lon1);
var a =
Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
Math.sin(dLon/2) * Math.sin(dLon/2)
;
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c; // Distance in km
return d;
}
function deg2rad(deg) {
return deg * (Math.PI/180)
}
var data = source.data;
var distance = 0;
var A = cord_x.value;
var B = cord_y.value;
//apply function
for(var i = 1; i < data['X'].length ; i++) {
distance = getDistanceFromLatLonInKm(A,B,data['X'][i],data['y']);
data['distance'][i] = distance;
}
source.change.emit()
""")
source.js_on_change('data', callback)
layout = row(
p,
column(cord_x, cord_y),
)
show(layout)
So if I'm understanding this right, you're looking to dynamically update
cord_xandcord_ywhich serves as the base coordinate to calculate the distance from the points in your dataframe? And the coordinates themselves remain the same, while the distance in the tooltip changes.Made a couple small changes: First, the
js_on_changeneeds to be applied to the widget. Second, it needs to call 'value' as the first argument. And last, you were missing the[i]part indata['y'][i]. Here is the full code: