Conditional logic inside callback not working

The following code works as expected. But in my second code block I apply some if else logic and the code does not work.

from bokeh.models import ColumnDataSource, Div, CustomJS
from bokeh.plotting import column, figure, show
from bokeh.models import PointDrawTool

# prepare some data for base line plot
a1 = [1, 2, 3, 4, 5]
b1 = [6, 7, 2, 4, 5]

p = figure(tools="tap")
p.line(a1, b1, line_width=2) #plot base data

   #next 5 lines will superimpose an interactive scatter plot over base data
   #tap anywhere on plot and new point appears, tap point and press backspace to remove point
   #tap point then left mouse down and drag point to move, then click on point to get coords
source = ColumnDataSource({'x': [1, 5], 'y': [1, 5], 'color': ['red', 'green']})
renderer = p.scatter(x='x', y='y', source=source, color='color', size=20)
draw_tool = PointDrawTool(renderers=[renderer], empty_value='black')
p.add_tools(draw_tool)
p.toolbar.active_tap = draw_tool


div = Div() #create a div below the graph
     #upon tap new point appears then tap again and below code returns x and y coordinates of position tapped
     #when moving point and tapping again new coordinates appear in div below graph
callback = CustomJS(args=dict(source=source, div=div), code="""
    var selectedIndex = source.selected.indices;
    for (var i = 0; i < selectedIndex.length; i++) {
        div.text = `x =  ${source.data['x'][selectedIndex[i]]}`+` and y =  ${source.data['y'][selectedIndex[i]]}`
        }
    """) 

source.selected.js_on_change('indices', callback) #when change event occurs (a tap), run callback

show(column(p,div))

#todo list, need to capture coords of point1 and coords of point2 separately  in order to do some math

Here is my second block, please help me do the conditional logic, thanks

from bokeh.models import ColumnDataSource, Div, CustomJS
from bokeh.plotting import column, figure, show
from bokeh.models import PointDrawTool
import math

# prepare some data for base line plot
a1 = [1, 2, 3, 4, 5]
b1 = [6, 7, 2, 4, 5]

p = figure(tools="tap")
p.line(a1, b1, line_width=2) #plot base data

   #next 5 lines will superimpose an interactive scatter plot over base data
   #tap anywhere on plot and new point appears, tap point and press backspace to remove point
   #tap point then left mouse down and drag point to move, then click on point to get coords
source = ColumnDataSource({'x': [1, 5], 'y': [1, 5], 'color': ['red', 'green']})
renderer = p.scatter(x='x', y='y', source=source, color='color', size=20)
draw_tool = PointDrawTool(renderers=[renderer], empty_value='black')
p.add_tools(draw_tool)
p.toolbar.active_tap = draw_tool


div = Div() #create a div below the graph
     #upon tap new point appears then tap again and below code returns x and y coordinates of position tapped
     #when moving point and tapping again new coordinates appear in div below graph
callback = CustomJS(args=dict(source=source, div=div), code="""
    var selectedIndex = source.selected.indices;
    for (var i = 0; i < selectedIndex.length; i++) {
        div.text = `x =  ${source.data['x'][selectedIndex[i]]}`+` and y =  ${source.data['y'][selectedIndex[i]]}`
        var counter = 1;
        var x1,y1,x2,y2;
        if counter == 1:
            x1 = `${source.data['x'][selectedIndex[i]]}`
            y1 = `${source.data['y'][selectedIndex[i]]}`
            console.log(x1)
            console.log(y1)
            counter=counter+1;
        elif counter == 2:
            console.log(counter)
            x2 = `${source.data['x'][selectedIndex[i]]}`
            y2 = `${source.data['y'][selectedIndex[i]]}`
            counter=1;
        var p1,p2,slope;
        p1 = x2-x1;
        p2 = y2-y1;
        slope = p2/p1;
        }
    """) 

source.selected.js_on_change('indices', callback) #when change event occurs (a tap), run callback

show(column(p,div))
1 Like

For one thing, you have written the if...else conditional using Python syntax. What you have above is not valid JavaScript. See e.g. this for more details about how to write conditionals in JavaScript

thanks Bryan, I was thinking of this too so here is what i did. But in second pass of for loop my x2 and y2 are undefined.

callback = CustomJS(args=dict(source=source, div=div), code="""
    var selectedIndex = source.selected.indices;
    for (var i = 0; i < 2; i++) {
        div.text = `x =  ${source.data['x'][selectedIndex[i]]}`+` and y =  ${source.data['y'][selectedIndex[i]]}`
        var counter = 1
        var x1=0
        var x2=0
        var y1=0
        var y2=0
        if (i == 0){
            console.log(i)
            x1 = `${source.data['x'][selectedIndex[i]]}`
            y1 = `${source.data['y'][selectedIndex[i]]}`
            console.log(x1)
            console.log(y1)
            }
        else if (i == 1){
            console.log(i)
            console.log("we are in i=2 now")
            x2 = `${source.data['x'][selectedIndex[i]]}`
            y2 = `${source.data['y'][selectedIndex[i]]}`
            console.log(x2)
            console.log(y2)
            }
        }
    """) 

ignore counter variable

also the if and the else condition are both appearing on the first pass

I think it has something to do with trying to use sync in an async process…something I read but don’t have a clue on how to implement