Bokeh: How to click and drag to display displacement between points

自作多情 提交于 2020-01-16 05:22:05

问题


I want to be able to click and drag between two points on my graph and display the change in position between points and display a line connecting the two points. How can I go about approaching this?


回答1:


You can realize it with JS callback like this (Bokeh v1.3.0):

import numpy as np
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource, CustomJS, Div, Row
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)]
lilne = p.line('x', 'y', line_color = 'red', line_dash = 'dashed', source = source)
div = Div(text='')

callback_tap = '''
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
}'''

callback_mousemove = '''
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()

    div.text = 'Distance: ' + Math.round(cb_obj.sx - Bokeh.sx_start) + ' px' + ' (' + (Math.round((cb_obj.x - Bokeh.x_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, 'div': div}, code = callback_mousemove))

show(Row(p, div))

The first click on the plot starts the line, the next click ends it.

Or if you prefer a tooltip-like div appearance you could use this a little bit more complicated code which dynamically adds a tooltip 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)



来源:https://stackoverflow.com/questions/58860910/bokeh-how-to-click-and-drag-to-display-displacement-between-points

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!