I am new to using Bokeh. For my project, I am trying to use bokeh to make arrows from one point to the next. So I am making the points by double-clicking and then drawing the arrows by a single click. But it doesn't seem to do anything.
from bokeh.models import Arrow, OpenHead
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
from bokeh.io import curdoc
from bokeh.events import DoubleTap, Tap
coordList=[]
source = ColumnDataSource(data=dict(x=[], y=[]))
#add a dot where the click happened
def callback(event):
Coords=(event.x,event.y)
coordList.append(Coords)
source.data = dict(x=[i[0] for i in coordList], y=[i[1] for i in coordList])
for x, y in coordList:
if x == None and y == None:
coordList.pop(0)
p = figure(plot_width=700, plot_height=700)
def draw(event):
# Function to add arrows from the coordList
p.add_layout(Arrow(end=OpenHead(line_color="firebrick", line_width=4),
x_start=1, y_start=1, x_end=4, y_end=4))
p.circle(source=source,x='x',y='y')
p.on_event(DoubleTap, callback)
p.on_event(Tap, draw)
curdoc().add_root(p)
Any help would be appreciated. Thanks
Yeah, it's a bug: https://github.com/bokeh/bokeh/issues/8862
See my comments inline.
from bokeh.events import DoubleTap, Tap
from bokeh.io import curdoc
from bokeh.models import Arrow, OpenHead, CustomJS
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
p = figure(plot_width=700, plot_height=700)
# We need to have at least one renderer present for the plot
# to be able to compute the initial ranges. Otherwise, the very
# first double tap event will have no coordinates.
bogus_renderer = p.circle(x=[0], y=[0], fill_alpha=0, line_alpha=0)
# This is needed to make sure that PlotView recalculates
# all renderers' views when we call `add_layout`.
p.js_on_change('center', CustomJS(code='cb_obj.properties.renderers.change.emit();'))
source = ColumnDataSource(data=dict(x=[], y=[]))
def callback(event):
# Removing the renderer to avoid messing with DataRange1d.
bogus_renderer.data_source.data = dict(x=[], y=[])
source.stream(dict(x=[event.x], y=[event.y]))
def draw(event):
if source.data['x']:
last_dot_x = source.data['x'][-1]
lalt_dot_y = source.data['y'][-1]
p.add_layout(Arrow(end=OpenHead(line_color="firebrick", line_width=4),
x_start=last_dot_x, y_start=lalt_dot_y, x_end=event.x, y_end=event.y))
p.circle(source=source, x='x', y='y')
p.on_event(DoubleTap, callback)
p.on_event(Tap, draw)
curdoc().add_root(p)