Skip to content

Instantly share code, notes, and snippets.

@almarklein
Last active November 24, 2015 16:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save almarklein/d5421e187e4429cca6fb to your computer and use it in GitHub Desktop.
Save almarklein/d5421e187e4429cca6fb to your computer and use it in GitHub Desktop.
How to pick a line among multiple lines in Bokeh
import numpy as np
from bokeh.plotting import output_notebook, show, figure
from bokeh.models import Plot, CustomJS, TapTool, ColumnDataSource, Line, DataRange1d
output_notebook()
p = figure()
t = np.linspace(0, 5, 100)
l1 = p.line(t, np.sin(t), color='#ff0000', nonselection_color='#888', line_width=5)
l2 = p.line(t, np.sin(t+1), color='#00ff00', nonselection_color='#888', line_width=5)
#l3 = p.line(t, np.sin(t+2), color='#0000ff', nonselection_color='#888', line_width=5)
lines = [l1, l2]
code = """
// Monkey patch to use until Bokeh has this functionality
LineView = line.default_view.prototype; // need example line object
if (!LineView._ori_hit_point) {
var dist2 = function(x1, y1, x2, y2) {return (x1-x2) * (x1-x2) + (y1-y2)* (y1-y2);};
var dist_to_segment = function (p, v, w) {
var l2, t;
l2 = dist2(v.x, v.y, w.x, w.y);
if (l2 == 0) return dist2(p.x, p.y, v.x, v.y);
t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
if (t < 0) return dist2(p.x, p.y, v.x, v.y);
if (t > 1) return dist2(p.x, p.y, w.x, w.y);
return dist2(p.x, p.y, v.x + t * (w.x - v.x), v.y + t * (w.y - v.y))
}
LineView._ori_hit_point = LineView._hit_point;
LineView._hit_point = function (geometry) {
var result, vx, vy, x, y, shortest, threshold, p0, p1, dist;
//result = this._ori_hit_point(geometry);
result = result = {'0d': {flag: false, indices: []},
'1d': {indices: []},
'2d': {indices: []}}
point = {x: this.renderer.plot_view.canvas.vx_to_sx(geometry.vx),
y: this.renderer.plot_view.canvas.vy_to_sy(geometry.vy)};
shortest = 99999;
threshold = 2;
for (var i=0; i<this.sx.length-1; i++) {
p0 = {x: this.sx[i], y: this.sy[i]};
p1 = {x: this.sx[i+1], y: this.sy[i+1]};
dist = Math.sqrt(dist_to_segment(point, p0, p1));
if (dist < threshold && dist < shortest) {
shortest = dist;
result['0d'].flag = true
result['0d'].indices = [i]
}
}
if (result['0d'].flag) result['0d'].glyph = this;
return result;
}
}
// Call Python func with id of the line being clicked
d0 = cb_obj.get("selected")["0d"];
if (d0.flag && d0.glyph) {
IPython.notebook.kernel.execute('click_line("' + d0.glyph.renderer.model.id + '")');
console.log(d0.glyph.id, 'picked')
}
window.p = plot;
"""
p.tools.append(TapTool(plot=p, callback=CustomJS(code=code, args=dict(line=l1.glyph, plot=p))))
clicked_lines = []
def click_line(id):
for line in lines:
if line._id == id:
clicked_lines.append(line)
show(p)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment