☰Read-only archive⌕
Looking for help with Bokeh?

This is a read-only archive. Ask questions and join the conversation on GitHub.

Visit Community Support on GitHub →
Archived discussions · Captured October 28, 2026

Drag and Delete event for Plot

Community Support
rbeucher
rbeucher

HI All,

I am trying to implement an interactive plot where the user can add points to a
multi-segments line.

So far I managed to do this:

from bokeh.plotting import figure, output_notebook, show
from bokeh.models import ColumnDataSource, PointDrawTool
from bokeh.events import Tap
import numpy as np

output_notebook()

def bkapp(doc):

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

    source = ColumnDataSource({'x': [1, 5, 9], 'y': [1, 5, 9]})

    def add_point(event):
        x = np.array(source.data["x"])
        y = np.array(source.data["y"])
        indices = np.argsort(x)
        x = np.sort(x)
        y = y[indices]
        data = {"x": list(x), "y": list(y)}
        source.data = data

    renderer = p.scatter(x="x", y="y", source=source, size=10)
    draw_tool = PointDrawTool(renderers=[renderer], empty_value='black')
    p.line(x="x", y="y", source=source)
    p.on_event(Tap, add_point)

    p.add_tools(draw_tool)
    p.toolbar.active_tap = draw_tool

    doc.add_root(p)

show(bkapp)

That seems to work just fine… My issue is that I would like the the python callback to be called when a point is deleted or moved.

Any ideas?

R

⌁   Link to post
rbeucher
rbeucher

Hi @Bryan

Thanks. I tried that. The issue is that this results in some recursion that I don’t want…

from bokeh.plotting import figure, output_notebook, show
from bokeh.models import ColumnDataSource, PointDrawTool
from bokeh.events import Tap
import numpy as np

output_notebook()

def bkapp(doc):

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

    source = ColumnDataSource({
        'x': [1, 5, 9], 'y': [1, 5, 9]})

    def add_point(attr, old, new):
        x = np.array(source.data["x"])
        y = np.array(source.data["y"])
        indices = np.argsort(x)
        x = np.sort(x)
        y = y[indices]
        data = {"x": list(x), "y": list(y)}
        source.data = data
        print("OK")

    renderer = p.scatter(x="x", y="y", source=source, size=10)
    draw_tool = PointDrawTool(renderers=[renderer], empty_value='black')
    p.line(x="x", y="y", source=source)
    source.on_change("data", add_point)

    p.add_tools(draw_tool)
    p.toolbar.active_tap = draw_tool
    
    doc.add_root(p)

show(bkapp) 
⌁   Link to post
Bryan
Bryan

@rbeucher Right, you are updating the data, in a callback on data updates. Is that actually something you need to do? If you just need be able to add/delete points, then the tool does that for you, including updating the data source as necessary.

⌁   Link to post

End of archived discussion · Replies are disabled