Bokeh:Python交互式可视化开发
一、Bokeh 简介
Bokeh 是一个针对现代 Web 浏览器的交互式可视化库,专注于为大型数据集提供优雅、简洁的呈现。与 Matplotlib 和 Seaborn 等传统静态可视化库不同,Bokeh 生成的是在浏览器中渲染的交互式图表,具有缩放、平移、悬停等丰富的互动功能。
Bokeh 的核心理念是创建面向 Web 的可视化工具,它使用现代 Web 技术(如 HTML5 Canvas 和 WebGL)实现高性能图形渲染,无需依赖 JavaScript 编程即可在 Python 中构建复杂的可视化项目。
1.1 Bokeh 的主要特点
- 原生交互性:无需额外代码即可支持缩放、平移、选择、悬停等交互操作
- 高性能渲染:基于 HTML5 Canvas/WebGL 渲染,支持大数据集可视化
- 服务器组件:支持 Bokeh 服务器实现更复杂的交互和数据流
- 灵活的输出:支持输出为独立 HTML 文件、Jupyter Notebook 或嵌入到 Django/Flask 应用中
- 无 JavaScript 依赖:纯 Python 接口,无需编写 JavaScript 代码
- 链式 API:支持链式调用的 API 设计,代码简洁易读
- 可扩展性:从基本图表到复杂仪表板都能支持
1.2 与其他可视化库的比较
特性 | Bokeh | Matplotlib | Plotly | D3.js |
---|---|---|---|---|
交互性 | 原生支持 | 有限 | 原生支持 | 完全支持 |
开发语言 | Python | Python | Python/R/JS | JavaScript |
输出格式 | HTML/服务器 | 图片/PDF | HTML/服务器 | HTML |
大数据支持 | 良好 | 有限 | 良好 | 有限 |
学习曲线 | 中等 | 平缓 | 中等 | 陡峭 |
编程模型 | 声明式/命令式 | 命令式 | 声明式/命令式 | 声明式 |
独立性 | 可独立使用 | 可独立使用 | 依赖云服务(免费版) | 需要网页环境 |
1.3 Bokeh 的应用场景
Bokeh 特别适合以下应用场景:
- 数据探索与分析:交互式探索大型数据集
- 科学计算可视化:复杂数据关系的动态展示
- Web 应用集成:与 Django、Flask 等框架集成创建数据可视化应用
- 流数据可视化:结合 Bokeh Server 展示实时变化的数据
- 地理空间可视化:地图数据的交互式展示
- 金融数据分析:股票、交易数据的动态图表
二、安装与环境配置
2.1 安装 Bokeh
# 使用 pip 安装
pip install bokeh
# 或使用 conda 安装
conda install bokeh -c conda-forge
2.2 基础依赖
Bokeh 的核心依赖包括:
- NumPy:用于数值计算
- Pillow:用于图像处理
- Jinja2:用于模板渲染
- PyYAML:用于配置文件处理
- Tornado:用于 Bokeh 服务器(可选,如果使用服务器功能)
2.3 验证安装
from bokeh.plotting import figure, show
from bokeh.io import output_notebook
# 创建一个简单图表验证安装
plot = figure(width=400, height=400, title="Bokeh 安装验证")
plot.circle([1, 2, 3, 4, 5], [6, 7, 8, 9, 10], size=10)
# 在笔记本中展示图表
output_notebook()
show(plot)
# 或将图表保存为HTML文件
from bokeh.io import output_file
output_file("bokeh_test.html")
show(plot)
2.4 开发环境设置
对于 Bokeh 开发,推荐以下环境设置:
# Jupyter Notebook 中配置
from bokeh.io import output_notebook, set_curdoc
from bokeh.themes import Theme
# 启用笔记本输出
output_notebook()
# 设置主题(可选)
theme = Theme(json={
'attrs': {
'Figure': {
'background_fill_color': '#f5f5f5',
'border_fill_color': '#ffffff',
'outline_line_color': '#444444',
},
'Axis': {
'axis_line_color': '#444444',
'major_tick_line_color': '#444444',
'minor_tick_line_color': '#444444',
},
'Grid': {
'grid_line_color': '#dddddd',
}
}
})
set_curdoc(theme=theme)
三、Bokeh 基础绘图
3.1 绘图核心概念
Bokeh 的绘图架构包含以下核心概念:
- Figure:绘图的容器,相当于画布
- Glyphs:图形元素,如圆形、线条、矩形等
- Tools:交互工具,如缩放、平移、选择等
- Layouts:布局系统,如行、列、网格等
- Models:低级组件,构成 Bokeh 可视化的基本元素
3.2 创建基本图表
散点图
from bokeh.plotting import figure, show
from bokeh.io import output_file
# 准备数据
x = [1, 2, 3, 4, 5]
y = [6, 7, 2, 4, 5]
# 创建图表
p = figure(title="基本散点图",
x_axis_label="X轴",
y_axis_label="Y轴",
width=600, height=400)
# 添加圆形图元
p.circle(x, y, size=10, color="navy", alpha=0.5)
# 输出为HTML文件并显示
output_file("scatter.html")
show(p)
线图
from bokeh.plotting import figure, show
from bokeh.io import output_file
import numpy as np
# 准备数据
x = np.linspace(0, 10, 100)
y = np.sin(x)
# 创建图表
p = figure(title="基本线图",
x_axis_label="X轴",
y_axis_label="Y轴",
width=600, height=400)
# 添加线条图元
p.line(x, y, line_width=2, color="coral")
# 添加圆形标记
p.circle(x, y, size=6, color="coral", alpha=0.3)
# 输出为HTML文件并显示
output_file("line.html")
show(p)
柱状图
from bokeh.plotting import figure, show
from bokeh.io import output_file
# 准备数据
fruits = ['苹果', '橙子', '香蕉', '梨', '葡萄']
counts = [5, 3, 4, 2, 4]
# 创建图表
p = figure(x_range=fruits,
title="水果数量统计",
x_axis_label="水果",
y_axis_label="数量",
width=600, height=400,
toolbar_location="right")
# 添加柱状图
p.vbar(x=fruits, top=counts, width=0.5, color="green", alpha=0.6)
# 设置其他属性
p.xgrid.grid_line_color = None
p.y_range.start = 0
# 输出为HTML文件并显示
output_file("bar.html")
show(p)
3.3 图形属性设置
Bokeh 提供丰富的图形属性设置选项:
from bokeh.plotting import figure, show
from bokeh.io import output_file
# 准备数据
x = [1, 2, 3, 4, 5]
y = [6, 7, 2, 4, 5]
# 创建图表
p = figure(title="图形属性设置示例")
# 添加圆形图元,设置属性
p.circle(x, y,
size=20, # 大小
color="navy", # 填充颜色
alpha=0.5, # 透明度
line_color="orange", # 边框颜色
line_width=2, # 边框宽度
line_dash="dashed", # 边框样式:dashed, dotted, solid 等
legend_label="数据系列" # 图例标签
)
# 设置图表属性
p.title.text_font_size = "20px" # 标题字体大小
p.title.text_font_style = "italic" # 标题字体样式
p.title.align = "center" # 标题对齐方式
# 设置坐标轴属性
p.xaxis.axis_label = "X轴"
p.yaxis.axis_label = "Y轴"
p.axis.axis_label_text_font_style = "bold"
p.axis.major_label_text_font_size = "14px"
# 设置网格线属性
p.grid.grid_line_color = "gray"
p.grid.grid_line_alpha = 0.3
p.grid.grid_line_dash = [6, 4]
# 设置图例属性
p.legend.location = "top_left"
p.legend.title = "图例标题"
p.legend.title_text_font_style = "bold"
p.legend.border_line_color = "black"
p.legend.background_fill_alpha = 0.7
# 输出为HTML文件并显示
output_file("styled_plot.html")
show(p)
3.4 组合多种图形
Bokeh 允许在同一图表中组合多种图形:
from bokeh.plotting import figure, show
from bokeh.io import output_file
import numpy as np
# 准备数据
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.tan(x/3)
# 创建图表
p = figure(title="多图形组合示例", width=700, height=400)
# 添加多个图形
p.line(x, y1, color="red", legend_label="sin(x)", line_width=2)
p.circle(x, y1, color="red", size=6, alpha=0.3)
p.line(x, y2, color="blue", legend_label="cos(x)", line_width=2)
p.square(x, y2, color="blue", size=6, alpha=0.3)
# 多图形可以通过 visible 属性控制显示和隐藏
tangent = p.line(x, y3, color="green", legend_label="tan(x/3)",
line_width=2, visible=False)
p.triangle(x, y3, color="green", size=6, alpha=0.3, visible=False)
# 设置图例为点击切换显示/隐藏
p.legend.click_policy = "hide"
# 输出为HTML文件并显示
output_file("combined_plot.html")
show(p)
四、交互特性
4.1 基本交互工具
Bokeh 提供多种内置交互工具:
from bokeh.plotting import figure, show
from bokeh.io import output_file
from bokeh.models import HoverTool, BoxZoomTool, ResetTool, SaveTool, PanTool
# 准备数据
x = [1, 2, 3, 4, 5]
y = [6, 7, 2, 4, 5]
# 创建图表,指定工具
p = figure(title="交互工具示例",
tools="pan,box_zoom,wheel_zoom,lasso_select,reset,save,hover",
tooltips=[("索引", "$index"), ("(x,y)", "($x, $y)")],
width=600, height=400)
# 添加圆形图元
p.circle(x, y, size=20, color="navy", alpha=0.5)
# 或者可以单独添加工具
hover = HoverTool(tooltips=[
("索引", "$index"),
("(x,y)", "($x, $y)"),
("描述", "@desc") # 如果数据中有desc列,则显示该列值
])
p.add_tools(hover)
# 输出为HTML文件并显示
output_file("interactive_tools.html")
show(p)
4.2 自定义悬停工具提示
Bokeh 的 HoverTool 可以高度自定义:
from bokeh.plotting import figure, show
from bokeh.io import output_file
from bokeh.models import ColumnDataSource, HoverTool
import pandas as pd
# 准备带有额外数据的数据源
source = ColumnDataSource(data=dict(
x=[1, 2, 3, 4, 5],
y=[6, 7, 2, 4, 5],
desc=['A', 'B', 'C', 'D', 'E'],
imgs=['image1.jpg', 'image2.jpg', 'image3.jpg', 'image4.jpg', 'image5.jpg'],
colors=['red', 'green', 'blue', 'orange', 'purple']
))
# 创建图表
p = figure(title="自定义悬停提示示例", width=600, height=400)
# 添加圆形图元,使用数据源
circles = p.circle('x', 'y', size=20, fill_color='colors', line_color='black',
source=source, alpha=0.6)
# 添加自定义悬停工具
hover = HoverTool(renderers=[circles], tooltips="""
<div style="padding: 10px; background-color: #f0f0f0; border-radius: 5px;">
<div>
<span style="font-size: 16px; color: #333;">@desc</span>
</div>
<div>
<span style="font-weight: bold;">坐标:</span>
<span>($x, $y)</span>
</div>
<div>
<img src="@imgs" height="60" alt="@desc" style="margin-top: 5px; border: 1px solid #ddd;">
</div>
</div>
""")
p.add_tools(hover)
# 输出为HTML文件并显示
output_file("custom_hover.html")
show(p)
4.3 选择与链接
Bokeh 支持选择交互和图表间的选择链接:
from bokeh.plotting import figure, show
from bokeh.io import output_file
from bokeh.layouts import row
from bokeh.models import ColumnDataSource, TapTool, CustomJS
import numpy as np
# 准备数据源
source1 = ColumnDataSource(data=dict(
x=np.random.rand(20),
y=np.random.rand(20),
))
source2 = ColumnDataSource(data=dict(
x=np.random.rand(20),
y=np.random.rand(20),
))
# 创建第一个图表
p1 = figure(title="图表1 - 点击选择", width=400, height=400,
tools="tap,pan,wheel_zoom,reset")
p1.circle('x', 'y', source=source1, size=15, color="navy", alpha=0.5,
selection_color="firebrick", nonselection_alpha=0.1)
# 创建第二个图表
p2 = figure(title="图表2 - 联动高亮", width=400, height=400,
tools="tap,pan,wheel_zoom,reset")
p2.circle('x', 'y', source=source2, size=15, color="green", alpha=0.5,
selection_color="firebrick", nonselection_alpha=0.1)
# 创建选择联动的JavaScript回调
callback = CustomJS(args=dict(source1=source1, source2=source2), code="""
// 获取选中的索引
const selected_indices = source1.selected.indices;
// 更新第二个图表的选择
source2.selected.indices = selected_indices;
""")
# 为第一个图表的选择添加回调
source1.selected.js_on_change('indices', callback)
# 布局并展示图表
layout = row(p1, p2)
output_file("linked_selection.html")
show(layout)
4.4 滑块和按钮交互
Bokeh 提供了丰富的交互控件:
from bokeh.plotting import figure, show
from bokeh.io import output_file
from bokeh.layouts import column, row
from bokeh.models import Slider, Button, ColumnDataSource, CustomJS
import numpy as np
# 准备初始数据
x = np.linspace(0, 10, 500)
y = np.sin(x)
source = ColumnDataSource(data=dict(x=x, y=y))
# 创建图表
p = figure(title="交互控件示例", width=800, height=400)
p.line('x', 'y', source=source, line_width=3, line_alpha=0.6, color="navy")
# 创建滑块控件
amplitude_slider = Slider(start=0.1, end=2, value=1, step=0.1, title="振幅")
frequency_slider = Slider(start=0.1, end=5, value=1, step=0.1, title="频率")
phase_slider = Slider(start=0, end=6.28, value=0, step=0.1, title="相位")
offset_slider = Slider(start=-2, end=2, value=0, step=0.1, title="偏移")
# 创建按钮
reset_button = Button(label="重置参数", button_type="success")
# 添加JavaScript回调来更新图表
callback = CustomJS(args=dict(source=source,
amp=amplitude_slider,
freq=frequency_slider,
phase=phase_slider,
offset=offset_slider), code="""
// 获取滑块当前值
const amp = amp.value;
const freq = freq.value;
const phase = phase.value;
const offset = offset.value;