背景
数据可视化,尤其是高阶交互,echarts完成还是很吃力的;这也是我选择bokeh这个开源库的原因。
下面代码,你很难想象是用讯飞模型进行的注释,它直接识别了字符变量,并翻译为中文,不影响代码的执行。
这一点,必须给讯飞模型一个大大的赞。
代码
from bokeh.io import output_notebook, show, output_file
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, Select, Slider, TextInput, CustomJS, HoverTool, Slope
from bokeh.layouts import column, row
from bokeh.models import Legend, LegendItem, Label, LabelSet,Text
# 创建HTML文件并显示交互式Bokeh绘图
# output_file("InteractivePlotBokeh.html")
# 生成正弦函数y=sin(x)的数据
x = x = np.linspace(0, 8*np.pi, 800)
y = np.sin(x)
# 创建数据源以用于Bokeh绘图
source = ColumnDataSource(data={'x': x, 'y': y})
# 创建初始绘图以显示正弦函数,使用标准绘图工具栏
plot = figure(width=400, height=400, title="正弦函数")
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)
# 创建文本框以显示标题
text = TextInput(title="标题", value="正弦函数") # 标题
offset = Slider(title="沿y轴的偏移量", value=-5.0, start=-5.0, end=5.1, step=0.1) # 垂直偏移量
amplitude = Slider(title="振幅", value=1.0, start=-5.0, end=5.1, step=0.1) # 振幅
phase = Slider(title="相位(度数)", value=0.0, start=0.0, end=360.0, step=1) # 相位偏移量
freq = Slider(title="频率", value=1.0, start=0.1, end=5.1, step=0.1) # 频率
trig = Select(title="三角函数方程", value="sin",
options=['sin', 'cos'] ) # 三角函数方程
# 创建定义绘图变化的函数
update_title = CustomJS(args=dict(text=text, plot=plot), code="""
// 设置变量;
var t= text.value;
// 定义与小部件之间的交互;
plot.title.text = t""")
# 使标题小部件与绘图交互
text.js_on_change('value', update_title)
# 创建定义绘图变化的函数
update_curve = CustomJS(args=dict(source=source, offset=offset, amplitude=amplitude, phase=phase, freq=freq, trig=trig),
code="""
// 将角度转换为弧度;
Math.radians = function(degrees) {
return degrees * Math.PI / 180};
// 建立变量;
var data = source.data;
var x = data['x'];
var y = data['y'];
var f = offset.value;
var a = amplitude.value;
var w = Math.radians(phase.value);
var k = freq.value;
var t = trig.value;
// 对每个元素进行绘图;
for (var i = 0; i < x.length; i++) {
if (t == 'sin'){y[i] = a*Math.sin(k*x[i]+w) + f} else{y[i] = a*Math.cos(k*x[i]+w) + f}
}
// 确保更改得到实现;
source.change.emit();""")
# 使小部件与绘图交互,相当于前端对事件进行一个监控,一旦发生变化,通过回调函数进行调整
for w in [offset, amplitude, phase, freq, trig]:
w.js_on_change('value', update_curve)
inputs = column(text, trig, offset, amplitude, phase, freq)
show(row(inputs, plot))
结果
其他
点击按钮改变标量值:
from bokeh.models import ColumnDataSource, Button
from bokeh.layouts import column
from bokeh.plotting import figure, curdoc
from bokeh.models.widgets import TextInput, Paragraph, RadioButtonGroup, Select
# 创建数据源
source = ColumnDataSource(data=dict(x=[0], y=[0]))
# 创建绘画对象
plot = figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source)
# 创建HTML段落和按钮组件
text = Paragraph(text="initial value")
button = Button(label="Change Value")
# 通过CustomJS跟新数据
callback = CustomJS(args=dict(source=source, text=text), code="""
// 获取当前数据
var data = source.data;
// 随机生成数据并更新
data['x'] = [Math.random(), Math.random()];
data['y'] = [Math.random(), Math.random()];
// 将更新的数据写入数据源
source.change.emit();
// 更新HTML段落的文字
text.text = "New value: " + data['x'][0].toFixed(2);
""")
# 将callback关联到button上
button.js_on_click(callback)
# 将图形和组件装进布局中
layout = column(button, text, plot)
# 将布局添加到文档中
curdoc().add_root(layout)
修改选项卡名称:
from bokeh.models.widgets import Tabs, Panel
from bokeh.models import CustomJS
# 创建两个panel,每个panel包含一个图形对象
tab1 = Panel(child=figure(), title="Tab 1")
tab2 = Panel(child=figure(), title="Tab 2")
# 创建一个tab组件,包含上述两个panel
tabs = Tabs(tabs=[tab1, tab2])
# 在callback函数中修改选项卡的名称
callback = CustomJS(args=dict(tab1=tab1, tab2=tab2), code="""
// 修改选项卡标题
tab1.title = "New Title for Tab 1";
tab2.title = "New Title for Tab 2";
""")
# 将callback关联到button上
button.js_on_click(callback)
# 将tab组件和button组件装进布局。button位于tab组件的下方。
layout = column(tabs, button)
# 将布局添加到文档中
curdoc().add_root(layout)
以上是两个简单的示例,CustomJS能够完成的功能很丰富,可以用于各种交互行为的实现。