Python Bokeh:如何单击并拖动以显示点之间的位移
我希望能够在图形上的两点之间单击并拖动,显示点之间位置的变化,并显示连接两点的线。我怎样才能接近这一点Python Bokeh:如何单击并拖动以显示点之间的位移,python,bokeh,Python,Bokeh,我希望能够在图形上的两点之间单击并拖动,显示点之间位置的变化,并显示连接两点的线。我怎样才能接近这一点 您可以使用JS回调实现它,如下所示(Bokeh v1.3.0): 第一次单击绘图开始绘制线,下一次单击结束绘制线 或者,如果您更喜欢类似工具提示的div外观,您可以使用稍微复杂一点的代码,动态添加工具提示div: import numpy as np from bokeh.plotting import figure, show from bokeh.models import Column
您可以使用JS回调实现它,如下所示(Bokeh v1.3.0): 第一次单击绘图开始绘制线,下一次单击结束绘制线 或者,如果您更喜欢类似工具提示的div外观,您可以使用稍微复杂一点的代码,动态添加工具提示div:
import numpy as np
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.events import *
source = ColumnDataSource({'x': [], 'y': []})
p = figure(plot_width = 900)
lines = [p.line(np.arange(10), np.random.random(10)) for i in range(3)]
line = p.line('x', 'y', line_color = 'red', line_dash = 'dashed', source = source)
callback_tap = '''
if (typeof custom_tooltip == 'undefined') {
custom_tooltip = document.createElement('div');
custom_tooltip.setAttribute('id','tooltip_div');
custom_tooltip.style = 'position: absolute; left: 0px; top: 0px; z-index: 9999; border:1px solid black; padding: 10px; background: white; font-family: arial; font-size: 12px'
document.body.prepend(custom_tooltip);
}
if (true === Bokeh.drawing) {
Bokeh.drawing = false
}
else {
if (!Bokeh.drawing) {
src.data = {'x':[], 'y':[]}
src.change.emit()
}
src.data['x'].push(cb_obj.x)
src.data['y'].push(cb_obj.y)
Bokeh.drawing = true
Bokeh.sx_start = cb_obj.sx
Bokeh.x_start = cb_obj.x
Bokeh.sy_start = cb_obj.sy
Bokeh.y_start = cb_obj.y
}'''
callback_mousemove = '''
function print(...args) {
for (i in args) {
console.log(args[i])
}
}
if (Bokeh.drawing) {
if (src.data['x'].length > 1) {
src.data['x'].pop()
src.data['y'].pop()
}
src.data['x'].push(cb_obj.x)
src.data['y'].push(cb_obj.y)
src.change.emit()
tooltip = document.getElementById('tooltip_div')
tooltip.style.left = cb_obj.sx + 30 + 'px'
tooltip.style.top = cb_obj.sy + 10 + 'px'
tooltip.innerHTML = 'Distance X: ' + Math.round(cb_obj.sx - Bokeh.sx_start) + ' px' + ' (units): ' + (Math.round((cb_obj.x - Bokeh.x_start) * 100) / 100) + ' units' +
'<br />' +
'Distance Y: ' + Math.round(cb_obj.sy - Bokeh.sy_start) + ' px' + ' (units): ' + (Math.round((cb_obj.y - Bokeh.y_start) * 100) / 100) + ' units'
}'''
p.js_on_event('tap', CustomJS(args = {'src': source, }, code = callback_tap))
p.js_on_event('mousemove', CustomJS(args = {'src': source, }, code = callback_mousemove))
show(p)
将numpy导入为np
从bokeh.plotting导入图形,显示
从bokeh.models导入ColumnDataSource,CustomJS
从bokeh.events导入*
source=ColumnDataSource({'x':[],'y':[]})
p=图(绘图宽度=900)
lines=[p.line(np.arange(10),np.random.random(10))表示范围(3)内的i]
直线=p.line('x','y',直线颜色='red',直线破折号='虚线',源=源)
回调_tap=''
如果(自定义工具提示的类型=='undefined'){
自定义工具提示=document.createElement('div');
自定义工具提示.setAttribute('id','tooltip\u div');
自定义工具提示.style='位置:绝对;左:0px;顶部:0px;z索引:9999;边框:1px纯黑色;填充:10px;背景:白色;字体系列:arial;字体大小:12px'
document.body.prepend(自定义工具提示);
}
如果(真===Bokeh.drawing){
Bokeh.drawing=错误
}
否则{
如果(!Bokeh.图纸){
src.data={'x':[],'y':[]}
src.change.emit()
}
src.data['x'].push(cb_obj.x)
src.data['y'].push(cb_obj.y)
Bokeh.drawing=true
Bokeh.sx_start=cb_obj.sx
Bokeh.x_启动=cb_obj.x
Bokeh.sy\U start=cb\U obj.sy
Bokeh.y_启动=cb_对象y
}'''
回调_mousemove=''
函数打印(…参数){
for(args中的i){
console.log(args[i])
}
}
如果(Bokeh.图纸){
if(src.data['x'].length>1){
src.data['x'].pop()
src.data['y'].pop()
}
src.data['x'].push(cb_obj.x)
src.data['y'].push(cb_obj.y)
src.change.emit()
tooltip=document.getElementById('tooltip\u div')
tooltip.style.left=cb_obj.sx+30+'px'
tooltip.style.top=cb_obj.sy+10+'px'
tooltip.innerHTML='Distance X:'+数学圆(cb_obj.sx-Bokeh.sx_start)+'px'+'(单位):'+(数学圆(cb_obj.X-Bokeh.X_start)*100)/100)+'units'+
“
”+
“距离Y:”+数学圆(cb_obj.sy-Bokeh.sy_开始)+“px”+“(单位):”+(数学圆(cb_obj.Y-Bokeh.Y_开始)*100)/100)+“单位”
}'''
p、 js_on_事件('tap',CustomJS(args={'src':source,},code=callback_tap))
p、 js_on_事件('mousemove',CustomJS(args={'src':source,},code=callback_mousemove))
表演(p)
这真是太棒了!不过工具提示中有一个问题。是否可以禁用该工具?也许通过右键点击?
import numpy as np
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.events import *
source = ColumnDataSource({'x': [], 'y': []})
p = figure(plot_width = 900)
lines = [p.line(np.arange(10), np.random.random(10)) for i in range(3)]
line = p.line('x', 'y', line_color = 'red', line_dash = 'dashed', source = source)
callback_tap = '''
if (typeof custom_tooltip == 'undefined') {
custom_tooltip = document.createElement('div');
custom_tooltip.setAttribute('id','tooltip_div');
custom_tooltip.style = 'position: absolute; left: 0px; top: 0px; z-index: 9999; border:1px solid black; padding: 10px; background: white; font-family: arial; font-size: 12px'
document.body.prepend(custom_tooltip);
}
if (true === Bokeh.drawing) {
Bokeh.drawing = false
}
else {
if (!Bokeh.drawing) {
src.data = {'x':[], 'y':[]}
src.change.emit()
}
src.data['x'].push(cb_obj.x)
src.data['y'].push(cb_obj.y)
Bokeh.drawing = true
Bokeh.sx_start = cb_obj.sx
Bokeh.x_start = cb_obj.x
Bokeh.sy_start = cb_obj.sy
Bokeh.y_start = cb_obj.y
}'''
callback_mousemove = '''
function print(...args) {
for (i in args) {
console.log(args[i])
}
}
if (Bokeh.drawing) {
if (src.data['x'].length > 1) {
src.data['x'].pop()
src.data['y'].pop()
}
src.data['x'].push(cb_obj.x)
src.data['y'].push(cb_obj.y)
src.change.emit()
tooltip = document.getElementById('tooltip_div')
tooltip.style.left = cb_obj.sx + 30 + 'px'
tooltip.style.top = cb_obj.sy + 10 + 'px'
tooltip.innerHTML = 'Distance X: ' + Math.round(cb_obj.sx - Bokeh.sx_start) + ' px' + ' (units): ' + (Math.round((cb_obj.x - Bokeh.x_start) * 100) / 100) + ' units' +
'<br />' +
'Distance Y: ' + Math.round(cb_obj.sy - Bokeh.sy_start) + ' px' + ' (units): ' + (Math.round((cb_obj.y - Bokeh.y_start) * 100) / 100) + ' units'
}'''
p.js_on_event('tap', CustomJS(args = {'src': source, }, code = callback_tap))
p.js_on_event('mousemove', CustomJS(args = {'src': source, }, code = callback_mousemove))
show(p)