Reputation: 6055
I have code below that creates a simple line x-y plot.
I want to be able to interactively measure distances between points on the plot and display it on the graph preferably but in a nearby glyph also works.
Say I click and drag from one point to another point (or random spots on the map) using some tool, I want something that tells me the distance in x (don't really need y or euclidean distance in this example).
How do I do that?
from bokeh.io import output_file, show, save
from bokeh.layouts import column
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
data = []
x = list(range(11))
y0 = x
y1 = [10 - xx for xx in x]
y2 = [abs(xx - 5) for xx in x]
source = ColumnDataSource(data=dict(x=x, y0=y0, y1=y1, y2=y2))
for i in range(3):
p = figure(title="Title "+str(i), plot_width=300, plot_height=300)
if len(data):
p.x_range = data[0].x_range
p.y_range = data[0].y_range
p.circle('x', 'y0', size=10, color="navy", alpha=0.5, legend_label='line1', source=source)
# p.triangle('x', 'y1', size=10, color="firebrick", alpha=0.5, legend_label='line2', source=source)
# p.square('x', 'y2', size=10, color="olive", alpha=0.5, legend_label='line3', source=source)
p.legend.location = 'top_right'
p.legend.click_policy = "hide"
data.append(p)
plot_col = column(data)
# show the results
show(plot_col)
Upvotes: 0
Views: 879
Reputation: 31
Use ctrl+shift+J open js console in chorme, and can get result log. For hyles_lineata`s answer.
Upvotes: -1
Reputation: 416
You could do it with a TapTool and a CustomJS callback. I added one to your code that just logs the x-values of each point and the distance between a first and second choice to the JS console; you could update a source for a nearby glyph with this info.
from bokeh.io import output_file, show, save
from bokeh.layouts import column
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, CustomJS, TapTool
# output_file("panning.html")
data = []
x = list(range(11))
y0 = x
y1 = [10 - xx for xx in x]
y2 = [abs(xx - 5) for xx in x]
source = ColumnDataSource(data=dict(x=x, y0=y0, y1=y1, y2=y2))
x_list = []
for i in range(1):
callback = CustomJS(args=dict(source=source, x_list=x_list), code='''
var selected_x = source.data.x[source.selected.indices];
if (x_list.length == 0) // indicates that this is the first point selected
{
console.log("First point selected is "+selected_x)
x_list.push(selected_x);
}
else // this is the second point selected
{
console.log("Second point is " + selected_x + ". Distance is " + (selected_x - x_list[0]))
x_list.pop();
}
''')
p = figure(title="Basic Title", plot_width=800, plot_height=400)
p.add_tools(TapTool(callback=callback))
if len(data):
p.x_range = data[0].x_range
p.y_range = data[0].y_range
p.circle('x', 'y0', size=10, color="navy", alpha=0.5, legend_label='line1', source=source)
p.legend.location = 'top_right'
p.legend.click_policy = "hide"
data.append(p)
plot_col = column(data)
# show the results
show(plot_col)
#save(plot_col)
Upvotes: 1