Trying to implement Drag event on a Line Segment

Hi team, I have a large use case for calculating slopes and angles of line segments. Is there functionality to use points instead of circles (in below code) and be able to drag the points and line together to form different angles? I notice with your PointDrawTool that source.selected.indices are auto updated as the point is dragged. But I can not figure a way to have this functionality using circles. Once I can accomplish dragging the line segment then I feel confident about implementing my source data in a ColumnDataSource along with a callback to show my results. Thanks very much

from bokeh.plotting import figure, show
import math

x1 = [2]
y1 = [4]
x2 = [3]
y2 = [9]

p = figure(x_range=(0, 10), y_range=(0, 10), width=400, height=400, title='line segment')

p.segment(x1, y1, x2, y2, color="lightgrey", line_width=3), y1, color="blue", size=20), y2, color="red", size=20)
  #then calc the slope and angle
rise = y2[0]-y1[0]
run = x2[0]-x1[0]
slope = rise/run
at=(math.atan(slope)) #using math module getting arc tangent of slope
degree = at*57.295 #57.295 is 180/pi or 3.1415

result = round(degree,2)
print("angle of line = "+str(result)+" degrees")


@RickD If I understand your question correctly then the below code is one idea of how to solve it.

I use a CDS that defines the 2 set of coordinates of points that define the points (circle) and line. I use line and circle glyphs and both use the same CDS. Use the tool PointDrawTool which is associated with the circle glyph. Hence when you move a point (circle) then the CDS data is automatically updated and both circle and line is updated.

Have added a Div to display slope and angle. I use a CustomJS to update the text property of the Div with new angle and slope when data of the CDS is changed.

I did not find any argument for PointDrawTool that can prevent deletion of a point. So I have a dummy CDS to keep a copy of the points.

from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, Div, CustomJS, PointDrawTool
from bokeh.layouts import column
from import output_file, save
from math import atan2, degrees


source = ColumnDataSource(
    data = {
        'x': [1,8],
        'y': [2,7]
# using an extra CDS - did not find any argument to prevent deletion of a point
src_copy = ColumnDataSource(data = {
        'x': [1,8],
        'y': [2,7]

p = figure(
    x_range=(0, 10),
    y_range=(0, 10),
    width = 400,
    height = 400,
    tools = []

r_c =
    x = 'x',
    y = 'y',
    size = 20,
    fill_color = 'red',
    line_color = 'black',
    alpha = 0.7,
    source = source
r_l = p.line(
    x = 'x',
    y = 'y',
    line_color = 'blue',
    line_width = 3,
    line_alpha = 0.7,
    source = source

tool = PointDrawTool(renderers=[r_c], add = False)
p.toolbar.active_tap = tool

dx =['x'][1]['x'][0]
dy =['y'][1]['y'][0]
slope = dy/dx
angle = degrees(atan2(dy, dx))

div = Div(text = f'slope: {slope:.2f}, angle (deg): {angle:.2f}')

cb = CustomJS(
    args = {
        'src': source,
        'src_copy': src_copy,
        'div': div
    code = '''
        // did not find any argument to prevent delete of a point
        if ( === 1) {
 = {
            'x': [[0],[1]],
            'y': [[0],[1]],

        const dx =[1] -[0];
        const dy =[1] -[0];

        const slope = dx/dy;
        const angle = (180/Math.PI)*(Math.atan2(dy, dx));

        div.text = `slope: ${slope.toFixed(2)}, angle (deg): ${angle.toFixed(2)}`; = {
          'x': [[0],[1]],
          'y': [[0],[1]],
source.js_on_change('data', cb)

save(column(p, div))
1 Like

hey THANKS so much Jonas, works as expected !!!
ps: also thx for helping a newbie and putting up with our issues