from bokeh.io import output_notebook, show
from bokeh.plotting import figure
output_notebook()
前面展示了一个画布上展示多张图。
其实这些图片也可以有联动关系。
展示相同位置
from bokeh.layouts import gridplot
x = list(range(11))
y0, y1, y2 = x, [10-i for i in x], [abs(i-5) for i in x]
plot_options = dict(width=250, plot_height=250, tools='pan,wheel_zoom')
# create a new plot
s1 = figure(**plot_options)
s1.circle(x, y0, size=10, color="navy")
# create a new plot and share both ranges
s2 = figure(x_range=s1.x_range, y_range=s1.y_range, **plot_options)
s2.triangle(x, y1, size=10, color="firebrick")
# create a new plot and share only one range
s3 = figure(x_range=s1.x_range, **plot_options)
s3.square(x, y2, size=10, color="olive")
p = gridplot([[s1, s2, s3]])
# show the results
show(p)
link.PNG
如上代码, 它们的关联关系为wheel_zoom
, 这意味着其中几张图片拥有相同的坐标定位, 拉动其中一张图, 观察它的上下左右不同方向时, 其他几张图也会跟着改变左边的展示位置。
选择相同区域
from bokeh.models import ColumnDataSource
x = list(range(-20, 21))
y0, y1 = [abs(xx) for xx in x], [xx**2 for xx in x]
# create a column data source for the plots to share
source = ColumnDataSource(data=dict(x=x, y0=y0, y1=y1))
TOOLS = "box_select,lasso_select,help"
# create a new plot and add a renderer
left = figure(tools=TOOLS, width=300, height=300)
left.circle('x', 'y0', source=source)
# create another new plot and add a renderer
right = figure(tools=TOOLS, width=300, height=300)
right.circle('x', 'y1', source=source)
p = gridplot([[left, right]])
show(p)
linked_1.PNG
上面样例就是在多个图中选择相同区域的标记。
鼠标悬停展示更多信息
from bokeh.models import HoverTool
source = ColumnDataSource(
data=dict(
x=[1, 2, 3, 4, 5],
y=[2, 5, 8, 2, 7],
desc=['A', 'b', 'C', 'd', 'E'],
)
)
hover = HoverTool(
tooltips=[
("index", "$index"),
("(x,y)", "($x, $y)"),
("desc", "@desc"),
]
)
p = figure(plot_width=300, plot_height=300, tools=[hover], title="Mouse over the dots")
p.circle('x', 'y', size=20, source=source)
show(p)
hover_tools.PNG
了解更多信息,点击这里
小工具
from bokeh.models.widgets import Slider
slider = Slider(start=0, end=10, value=1, step=.1, title="foo")
show(slider)
Bokeh支持直接加入小工具, 了解更多, 点击这里
CustomJS 回调
为了让小工具更有用, 我们需要让它能执行某些真是的动作。
下面举例看看CustomJS
如何通过JavaSript编码实现行为的相应。
from bokeh.models import TapTool, CustomJS, ColumnDataSource
callback = CustomJS(code="alert('you tapped a circle!')")
tap = TapTool(callback=callback)
p = figure(plot_width=600, plot_height=300, tools=[tap])
p.circle(x=[1, 2, 3, 4, 5], y=[2, 5, 8, 2, 7], size=20)
show(p)
widgets_js.PNG
如上代码可以实现点击某个标记符号时, 将会出现弹窗信息, 并选中该标记点。
控制条的样例
from bokeh.layouts import column
from bokeh.models import CustomJS, ColumnDataSource, Slider
x = [x*0.005 for x in range(0, 201)]
source = ColumnDataSource(data=dict(x=x, y=x))
plot = figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)
slider = Slider(start=0.1, end=6, value=1, step=.1, title="power")
update_curve = CustomJS(args=dict(source=source, slider=slider), code="""
var data = source.data;
var f = slider.value;
var x = data['x']
var y = data['y']
for (var i = 0; i < x.length; i++) {
y[i] = Math.pow(x[i], f)
}
// necessary becasue we mutated source.data in-place
source.change.emit();
""")
slider.js_on_change('value', update_curve)
show(column(slider, plot))
SliderWidget.PNG
通过拉动上面的控制条, 可以改变图片中线条的曲线。
数据选择样例
from random import random
x = [random() for x in range(500)]
y = [random() for y in range(500)]
color = ["navy"] * len(x)
s1 = ColumnDataSource(data=dict(x=x, y=y, color=color))
p = figure(plot_width=400, plot_height=400, tools="lasso_select", title="Select Here")
p.circle('x', 'y', color='color', size=8, alpha=0.4, source=s1,
selection_color="firebrick", selection_alpha=0.4)
s2 = ColumnDataSource(data=dict(xm=[0,1],ym=[0.5, 0.5]))
p.line(x='xm', y='ym', color="orange", line_width=5, alpha=0.6, source=s2)
callback = CustomJS(args=dict(s1=s1, s2=s2), code="""
var inds = s1.selected.indices;
if (inds.length == 0)
return;
var ym = 0
for (var i = 0; i < inds.length; i++) {
ym += s1.data.y[inds[i]]
}
ym /= inds.length
s2.data.ym = [ym, ym]
// necessary becasue we mutated source.data in-place
s2.change.emit();
""")
s1.selected.js_on_change('indices', callback)
show(p)
DataSelection.PNG
CustomJS for UI Events
更多详细的UI Events 点击bokeh.events
from bokeh.plotting import figure
from bokeh import events
from bokeh.models import CustomJS, Div, Button
from bokeh.layouts import column, row
import numpy as np
x = np.random.random(size=2000) * 100
y = np.random.random(size=2000) * 100
p = figure(tools="box_select")
p.scatter(x, y, radius=1, fill_alpha=0.6, line_color=None)
div = Div(width=400)
button = Button(label="Button", width=300)
layout = column(button, row(p, div))
# Events with no attributes
button.js_on_event(events.ButtonClick, CustomJS(args=dict(div=div), code="""
div.text = "Button!";
"""))
p.js_on_event(events.SelectionGeometry, CustomJS(args=dict(div=div), code="""
div.text = "Selection! <p> <p>" + JSON.stringify(cb_obj.geometry, undefined, 2);
"""))
show(layout)
更多信息
其实有很多interactions和events可以与CustomJS
的回调相连接。
- Widgets - Button, Toggle, Dropdown, TextInput, AutocompleteInput, Select, Multiselect, Slider, (DateRangeSlider), DatePicker,
- Tools - TapTool, BoxSelectTool, HoverTool,
- Selection - ColumnDataSource, AjaxDataSource, BlazeDataSource, ServerDataSource
- Ranges - Range1d, DataRange1d, FactorRange
更多详细信息请见 JavaScript Interactions