还在只会用 Matplotlib 画静态图?想要制作可缩放、可平移、可框选、带悬浮提示的网页交互式图表,那就一定要掌握 Bokeh!Bokeh 是 Python 中非常适合做交互式可视化的工具。它最大的特点是:代码相对简洁,图表可以直接生成 HTML 网页,并且支持缩放、拖动、框选、悬浮提示、多图联动等交互功能。对于数据分析、课程展示、论文辅助图表、可视化报告、数据大屏和公众号知识分享来说,都非常实用。本文整理了一份适合小白入门的 Bokeh 速查指南,从基本绘图逻辑、画布设置、数据源管理、常见图形绘制,到多图布局、坐标轴联动和 SVG 导出,一篇帮你快速入门。Bokeh 是 Python 中常用的交互式可视化库。如果说 Matplotlib 更擅长绘制静态图表,那么 Bokeh 更擅长绘制可以在网页中操作的动态图表。- ✅ 支持悬浮提示,鼠标放到数据点上可以显示详细信息
- ✅ 支持折线图、散点图、柱状图、多图布局等常见图表
- ✅ 支持 PNG、SVG 等格式导出,但需要额外环境配置
简单来说,Bokeh 适合用来做“能动起来、能交互、能网页展示”的 Python 图表。导入工具 → 准备数据 → 创建画布 → 绘制图形 → 输出展示下面是一个最基础、可以直接运行的 Bokeh 折线图示例:from bokeh.plotting import figure, showfrom bokeh.io import output_filex= [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.line(x, y,legend_label="数据曲线",line_width=2)output_file("lines.html")show(p)
这段代码运行后,会生成一个名为 `lines.html` 的网页文件,并在浏览器中打开图表。`from bokeh.plotting import figure, show` 表示导入 Bokeh 中最常用的两个工具。`figure()` 用来创建图表画布,`show()` 用来显示图表。`from bokeh.io import output_file` 表示导入输出 HTML 文件的工具。`x= [1, 2, 3, 4, 5]` 是横坐标数据。`y= [6, 7, 2, 4, 5]` 是纵坐标数据。`p= figure(...)` 表示创建一张图表。这里的 `p` 可以理解为一张“画布”。`xaxislabel="横轴 X"` 设置横坐标名称。`yaxislabel="纵轴 Y"` 设置纵坐标名称。`width=600` 和 `height=400` 设置图表的宽度和高度。注意,Bokeh 3.x 推荐使用 `width` 和 `height`,不要再使用旧版的 `plotwidth` 和 `plotheight`。`p.line(x, y,legendlabel="数据曲线",linewidth=2)` 表示在图表中绘制一条折线。`legend_label="数据曲线"` 表示图例名称。`line_width=2` 表示线条宽度为 2。`output_file("lines.html")` 表示把图表保存成网页文件。from bokeh.plotting import figurep1= figure(width=500,height=350,tools="pan,box_zoom,box_select,reset,save")p2= figure(width=500,height=400,x_range=(0, 8),y_range=(0, 8),title="固定范围图表")p3= figure()
原因很简单:这三行只是创建了三个空白画布 `p1`、`p2`、`p3`,还没有真正画任何东西,也没有使用 `show()` 显示出来。可以把它理解成:你新建了三张白纸,但还没有在纸上画线、画点、画柱子,也没有把纸拿出来展示。如果想让图表显示出来,需要增加绘图语句和显示语句:from bokeh.plotting import figure, showfrom bokeh.layouts import rowfrom bokeh.io import output_filep1= figure(width=500,height=350,tools="pan,box_zoom,box_select,reset,save",title="图1:折线图")p1.line([1, 2, 3, 4], [2, 5, 3, 7],line_width=2,legend_label="折线")p2= figure(width=500,height=400,x_range=(0, 8),y_range=(0, 8),title="图2:固定范围散点图")p2.scatter([1, 2, 3, 4, 5], [2, 4, 3, 6, 5],size=12,color="red",legend_label="散点")p3= figure(width=500,height=350,title="图3:柱状图")p3.vbar(x=[1, 2, 3, 4],top=[3, 6, 4, 8],width=0.5,legend_label="柱状图")layout= row(p1, p2, p3)output_file("三图布局.html")show(layout)
这里 `p1.line()` 是画折线,`p2.scatter()` 是画散点,`p3.vbar()` 是画柱状图。`row(p1, p2, p3)` 表示把三张图横向排列。`show(layout)` 表示显示整个多图布局。Bokeh 中最核心的对象就是 `figure()`。它负责创建图表画布。常见设置包括:图表标题、宽度、高度、坐标轴范围、工具栏等。from bokeh.plotting import figure, showfrom bokeh.io import output_filep= figure(title="画布设置示例",width=600,height=400,x_axis_label="X轴",y_axis_label="Y轴",x_range=(0, 10),y_range=(0, 10),tools="pan,wheel_zoom,box_zoom,box_select,reset,save")p.line([1, 2, 3, 4, 5], [2, 5, 4, 7, 6],line_width=2)output_file("figure_setting.html")show(p)
这里需要特别注意 `tools` 参数。Bokeh 的工具栏名称必须写英文,不能写中文。tools="pan,wheel_zoom,box_zoom,box_select,reset,save"
五、ColumnDataSource:Bokeh 的标准数据源在 Bokeh 中,`ColumnDataSource` 是非常重要的数据格式。它可以把 Pandas 表格转换成 Bokeh 能识别的数据源,后面绘图时可以直接使用列名。这对小白来说非常方便,因为我们做数据分析时,经常会用 Pandas 处理表格数据。import pandas as pdfrom bokeh.plotting import figure, showfrom bokeh.io import output_filefrom bokeh.models import ColumnDataSourcedf= pd.DataFrame({"油耗": [33.9, 32.4, 21.4, 25.8, 28.1],"气缸": [4, 4, 4, 6, 8],"马力": [65, 66, 109, 120, 150],"产地": ["US","Asia","Europe","US","Asia"]})source= ColumnDataSource(df)p= figure(title="ColumnDataSource 示例",width=600,height=400,x_axis_label="油耗",y_axis_label="马力")p.scatter("油耗","马力",source=source,size=14,color="blue",alpha=0.6)output_file("column_data_source.html")show(p)
`df= pd.DataFrame({...})` 创建一个 Pandas 表格。`source= ColumnDataSource(df)` 把 Pandas 表格转换成 Bokeh 专用数据源。`p.scatter("油耗","马力",source=source, ...)` 表示横坐标使用“油耗”这一列,纵坐标使用“马力”这一列。折线图适合展示趋势变化,比如时间序列、指标变化、政策前后变化等。from bokeh.plotting import figure, showfrom bokeh.io import output_filex= [2019, 2020, 2021, 2022, 2023]y= [0.45, 0.48, 0.53, 0.60, 0.67]p= figure(title="折线图示例",width=600,height=400,x_axis_label="年份",y_axis_label="指标值")p.line(x,y,line_width=2,color="blue",legend_label="指标趋势")p.scatter(x,y,size=10,color="blue")p.legend.location="top_left"output_file("line_chart.html")show(p)
这里同时使用了 `p.line()` 和 `p.scatter()`。`p.scatter()` 负责在线上添加数据点。这样图表会更清楚,读者既能看到趋势,也能看到每个年份的具体点位。散点图适合展示两个变量之间的关系,比如油耗和马力、收入和消费、城市规模和能源效率等。from bokeh.plotting import figure, showfrom bokeh.io import output_filex= [33.9, 32.4, 21.4, 25.8, 28.1]y= [65, 66, 109, 120, 150]p= figure(title="散点图示例",width=600,height=400,x_axis_label="油耗",y_axis_label="马力",tools="pan,wheel_zoom,box_select,reset,save")p.scatter(x,y,size=14,color="green",alpha=0.7,legend_label="样本点")p.legend.location="top_left"output_file("scatter_chart.html")show(p)
`color="green"` 表示散点颜色为绿色。`alpha=0.7` 表示透明度为 0.7,数值越小越透明。`legend_label="样本点"` 表示图例名称。柱状图适合做类别比较,比如不同地区、不同年份、不同组别的指标对比。from bokeh.plotting import figure, showfrom bokeh.io import output_filecategories= ["A地区","B地区","C地区","D地区"]values= [23, 45, 31, 56]p= figure(x_range=categories,title="柱状图示例",width=600,height=400,x_axis_label="地区",y_axis_label="数值")p.vbar(x=categories,top=values,width=0.5,color="orange",legend_label="指标值")p.legend.location="top_left"output_file("bar_chart.html")show(p)
`x=categories` 表示柱子对应的类别。九、常用图形四:多条折线 multi_line()需要注意,`multi_line()` 不能随便写成:p.multi_line(数据表, 数据表,color="blue")
from bokeh.plotting import figure, showfrom bokeh.io import output_filexs= [[2019, 2020, 2021, 2022, 2023],[2019, 2020, 2021, 2022, 2023],[2019, 2020, 2021, 2022, 2023]]ys= [[0.45, 0.48, 0.53, 0.60, 0.67],[0.40, 0.43, 0.47, 0.51, 0.58],[0.35, 0.38, 0.41, 0.46, 0.52]]p= figure(title="多条折线图示例",width=600,height=400,x_axis_label="年份",y_axis_label="指标值")p.multi_line(xs,ys,color=["blue","green","red"],line_width=2)output_file("multi_line_chart.html")show(p)
第一组 `xs[0]` 会对应第一组 `ys[0]`,第二组 `xs[1]` 会对应第二组 `ys[1]`,以此类推。Bokeh 的一大优势是可以交互式选择数据。比如用鼠标框选某些点,被选中的点可以变色,未选中的点可以变淡。import pandas as pdfrom bokeh.plotting import figure, showfrom bokeh.io import output_filefrom bokeh.models import ColumnDataSourcedf= pd.DataFrame({"油耗": [33.9, 32.4, 21.4, 25.8, 28.1],"气缸": [4, 4, 4, 6, 8],"马力": [65, 66, 109, 120, 150],"产地": ["US","Asia","Europe","US","Asia"]})source= ColumnDataSource(df)p= figure(title="选中高亮示例",width=600,height=400,x_axis_label="油耗",y_axis_label="气缸",tools="box_select,pan,wheel_zoom,reset,save")p.scatter("油耗","气缸",source=source,size=14,color="blue",selection_color="red",nonselection_alpha=0.1)output_file("selection_chart.html")show(p)
`tools="boxselect,pan,wheelzoom,reset,save"` 开启框选工具。`selection_color="red"` 表示被选中的点显示为红色。`nonselection_alpha=0.1` 表示没有被选中的点透明度变为 0.1。如果数据里有不同类别,比如产地包括 `US`、`Asia`、`Europe`,可以让不同类别自动显示不同颜色。注意:Bokeh 的颜色不能写“蓝色”“红色”“绿色”这种中文名称,要写英文颜色名或十六进制颜色值。["#1f77b4", "#d62728", "#2ca02c"]
import pandas as pdfrom bokeh.plotting import figure, showfrom bokeh.io import output_filefrom bokeh.models import ColumnDataSourcefrom bokeh.transform import factor_cmapfrom bokeh.palettes import Category10df= pd.DataFrame({"油耗": [33.9, 32.4, 21.4, 25.8, 28.1, 30.5],"气缸": [4, 4, 4, 6, 8, 6],"马力": [65, 66, 109, 120, 150, 130],"产地": ["US","Asia","Europe","US","Asia","Europe"]})source= ColumnDataSource(df)factors= ["US","Asia","Europe"]p= figure(title="分类颜色映射示例",width=600,height=400,x_axis_label="油耗",y_axis_label="气缸")p.scatter("油耗","气缸",source=source,size=14,color=factor_cmap("产地",palette=Category10[3],factors=factors),legend_field="产地")p.legend.location="top_right"output_file("category_color_chart.html")show(p)
这里的 `factor_cmap()` 会根据“产地”这一列自动分配颜色。`legend_field="产地"` 表示根据“产地”字段自动生成图例。悬浮提示是 Bokeh 非常实用的功能。鼠标移动到数据点上时,可以显示该数据点的详细信息。import pandas as pdfrom bokeh.plotting import figure, showfrom bokeh.io import output_filefrom bokeh.models import ColumnDataSource, HoverTooldf= pd.DataFrame({"油耗": [33.9, 32.4, 21.4, 25.8, 28.1],"气缸": [4, 4, 4, 6, 8],"马力": [65, 66, 109, 120, 150],"产地": ["US","Asia","Europe","US","Asia"]})source= ColumnDataSource(df)p= figure(title="悬浮提示示例",width=600,height=400,x_axis_label="油耗",y_axis_label="马力",tools="pan,wheel_zoom,box_select,reset,save")p.scatter("油耗","马力",source=source,size=14,color="navy",alpha=0.6)hover= HoverTool(tooltips=[("油耗","@油耗"),("马力","@马力"),("气缸","@气缸"),("产地","@产地")])p.add_tools(hover)output_file("hover_tool_chart.html")show(p)
这里的 `HoverTool` 用于设置鼠标悬浮时显示的信息。`("@油耗")` 表示读取数据源中“油耗”这一列的值。`("@马力")` 表示读取数据源中“马力”这一列的值。只要数据来自 `ColumnDataSource`,就可以用 `@列名` 的方式读取对应字段。图例可以帮助读者快速理解不同线条、颜色、点代表什么含义。from bokeh.plotting import figure, showfrom bokeh.io import output_filex= [1, 2, 3, 4, 5]y1= [2, 5, 8, 6, 7]y2= [1, 3, 4, 5, 6]p= figure(title="图例美化示例",width=600,height=400)p.line(x, y1,line_width=2,color="blue",legend_label="数据 A")p.line(x, y2,line_width=2,color="red",legend_label="数据 B")p.legend.location="bottom_left"p.legend.orientation="vertical"p.legend.border_line_color="navy"p.legend.background_fill_color="white"output_file("legend_chart.html")show(p)
`p.legend.location="bottom_left"` 表示图例放在左下角。`p.legend.orientation="vertical"` 表示图例垂直排列。`p.legend.borderlinecolor="navy"` 设置图例边框颜色。`p.legend.backgroundfillcolor="white"` 设置图例背景颜色。Bokeh 可以把多张图组合到一个页面中,非常适合做可视化报告。from bokeh.plotting import figure, showfrom bokeh.layouts import rowfrom bokeh.io import output_filep1= figure(width=300,height=300,title="图1:折线图")p1.line([1, 2, 3], [1, 4, 9],line_width=2)p2= figure(width=300,height=300,title="图2:散点图")p2.scatter([1, 2, 3], [3, 2, 1],size=12)p3= figure(width=300,height=300,title="图3:柱状图")p3.vbar(x=[1, 2, 3],top=[2, 5, 3],width=0.5)layout= row(p1, p2, p3)output_file("row_layout.html")show(layout)
`row(p1, p2, p3)` 表示三张图横向排列。from bokeh.plotting import figure, showfrom bokeh.layouts import columnfrom bokeh.io import output_filep1= figure(width=500,height=300,title="上方图表")p1.line([1, 2, 3], [1, 4, 9],line_width=2)p2= figure(width=500,height=300,title="下方图表")p2.scatter([1, 2, 3], [3, 2, 1],size=12)layout= column(p1, p2)output_file("column_layout.html")show(layout)
`column(p1, p2)` 表示两张图纵向排列。from bokeh.plotting import figure, showfrom bokeh.layouts import gridplotfrom bokeh.io import output_filep1= figure(width=300,height=300,title="折线图")p1.line([1, 2, 3], [1, 4, 9],line_width=2)p2= figure(width=300,height=300,title="散点图")p2.scatter([1, 2, 3], [3, 2, 1],size=12)p3= figure(width=300,height=300,title="柱状图")p3.vbar(x=[1, 2, 3],top=[2, 5, 3],width=0.5)layout= gridplot([[p1, p2], [p3, None]])output_file("grid_layout.html")show(layout)
`gridplot([[p1, p2], [p3, None]])` 表示第一行放 `p1` 和 `p2`,第二行放 `p3`,右下角空着。Bokeh 3.x 中推荐使用 `TabPanel` 和 `Tabs`。from bokeh.plotting import figure, showfrom bokeh.models import TabPanel, Tabsfrom bokeh.io import output_filep1= figure(width=500,height=300,title="折线图")p1.line([1, 2, 3], [1, 4, 9],line_width=2)p2= figure(width=500,height=300,title="散点图")p2.scatter([1, 2, 3], [3, 2, 1],size=12)tab1= TabPanel(child=p1,title="折线图")tab2= TabPanel(child=p2,title="散点图")tabs= Tabs(tabs=[tab1, tab2])output_file("tabs_layout.html")show(tabs)
这样生成的网页中会有两个标签页,一个显示折线图,一个显示散点图。坐标轴联动适合多图对比分析。比如两张图使用同一个横轴和纵轴范围,缩放其中一张图时,另一张图也会同步变化。from bokeh.plotting import figure, showfrom bokeh.layouts import columnfrom bokeh.io import output_filep1= figure(width=600,height=300,title="图1:原始趋势",tools="pan,wheel_zoom,reset,save")p1.line([1, 2, 3, 4, 5], [2, 5, 8, 6, 7],line_width=2)p2= figure(width=600,height=300,title="图2:共享坐标轴",x_range=p1.x_range,y_range=p1.y_range,tools="pan,wheel_zoom,reset,save")p2.scatter([1, 2, 3, 4, 5], [2, 5, 8, 6, 7],size=12,color="red")layout= column(p1, p2)output_file("linked_axes.html")show(layout)
x_range=p1.x_rangey_range=p1.y_range
因此,当你缩放或平移第一张图时,第二张图也会跟着变化。Bokeh 最推荐、最稳定的导出方式是 HTML,因为它可以保留图表交互功能。from bokeh.plotting import figure, showfrom bokeh.io import output_filep= figure(title="HTML 导出示例",width=600,height=400)p.line([1, 2, 3], [4, 5, 6],line_width=2)output_file("图表.html")show(p)
生成的 `图表.html` 可以直接用浏览器打开,也可以作为网页交互图表分享。2. 在 Jupyter Notebook 中显示from bokeh.plotting import figure, showfrom bokeh.io import output_notebookoutput_notebook()p= figure(title="Notebook 显示示例",width=600,height=400)p.line([1, 2, 3], [4, 5, 6],line_width=2)show(p)
`output_notebook()` 表示在 Jupyter Notebook 内部直接显示图表。from bokeh.plotting import figurefrom bokeh.io import export_pngp= figure(title="PNG 导出示例",width=600,height=400)p.line([1, 2, 3], [4, 5, 6],line_width=2)export_png(p,filename="图表.png")
注意:导出 PNG 通常需要安装 `selenium`,并且电脑上需要有可用的浏览器环境。from bokeh.plotting import figurefrom bokeh.io import export_svgsp= figure(title="SVG 导出示例",width=600,height=400)p.output_backend="svg"p.line([1, 2, 3], [4, 5, 6],line_width=2)export_svgs(p,filename="图表.svg")
这句非常重要。没有它,Bokeh 可能无法找到可以导出的 SVG 图形。export_svgs(p,filename="图表.svg")
ModuleNotFoundError: No module named'selenium'
这说明你的 Python 环境里没有安装 `selenium`。Bokeh 导出 PNG 或 SVG 时,需要借助浏览器把图表渲染出来,再导出为图片或矢量图。因此,除了 Bokeh 本身,还需要额外依赖。解决方法是在 Anaconda Prompt 或终端中安装:安装完成后,需要重启 Jupyter Notebook 内核,再重新运行导出代码。如果安装 `selenium` 后仍然报错,可能是浏览器或浏览器驱动环境没有配置好。一般来说,先确认自己电脑上安装了 Chrome、Edge 或 Firefox 浏览器。对于新手来说,最稳妥的方式是:优先导出 HTML。如果确实需要 SVG,再配置 `selenium` 环境。下面这段代码整合了 Bokeh 中最常用的功能:表格数据、分类颜色、悬浮提示、框选高亮、图例和 HTML 输出。适合初学者直接运行学习。import pandas as pdfrom bokeh.plotting import figure, showfrom bokeh.io import output_filefrom bokeh.models import ColumnDataSource, HoverToolfrom bokeh.transform import factor_cmapfrom bokeh.palettes import Category10df= pd.DataFrame({"油耗": [33.9, 32.4, 21.4, 25.8, 28.1, 30.5],"气缸": [4, 4, 4, 6, 8, 6],"马力": [65, 66, 109, 120, 150, 130],"产地": ["US","Asia","Europe","US","Asia","Europe"]})source= ColumnDataSource(df)factors= ["US","Asia","Europe"]p= figure(title="Bokeh 交互式散点图综合示例",width=700,height=450,x_axis_label="油耗",y_axis_label="马力",tools="pan,wheel_zoom,box_select,reset,save")p.scatter("油耗","马力",source=source,size=16,alpha=0.7,color=factor_cmap("产地",palette=Category10[3],factors=factors),legend_field="产地",selection_color="red",nonselection_alpha=0.15)hover= HoverTool(tooltips=[("油耗","@油耗"),("马力","@马力"),("气缸","@气缸"),("产地","@产地")])p.add_tools(hover)p.legend.location="top_left"p.legend.title="产地分类"p.legend.border_line_color="gray"p.legend.background_fill_color="white"output_file("Bokeh交互式散点图.html")show(p)
- ✅ 使用 ColumnDataSource 管理数据
p.line([1, 2, 3], [4, 5, 6])show(p)
tools="pan,box_zoom,box_select,reset,save"
4. Bokeh 3.x 不建议使用 plotwidth 和 plotheightfigure(plot_width=600,plot_height=400)
figure(width=600,height=400)
5. multi_line() 不能随便写“数据表”p.multi_line(数据表, 数据表,color="blue")
p.multi_line(xs, ys,color=["blue","green","red"],line_width=2)
6. SVG 导出需要设置 output_backendexport_svgs(p,filename="图表.svg")
p.output_backend="svg"export_svgs(p,filename="图表.svg")
7. PNG 和 SVG 导出需要 seleniumModuleNotFoundError: No module named'selenium'
准备数据 → 创建 figure → 绘制图形 → 添加交互 → 输出 HTML先学会画一张基础折线图,再学会散点图和柱状图,然后掌握 `ColumnDataSource`,最后学习悬浮提示、多图布局和导出功能。Bokeh 最适合的输出方式是 HTML,因为它可以完整保留交互效果。如果只是想做公众号展示,也可以截图使用;如果想做可编辑矢量图,可以尝试 SVG 导出,但需要提前安装 `selenium` 并配置浏览器环境。Matplotlib 更像是“静态科研绘图工具”,而 Bokeh 更像是“网页交互式可视化工具”。如果你的图表只需要放在论文或报告里,Matplotlib 已经足够;但如果你想让图表可以缩放、平移、框选、悬浮显示信息,甚至嵌入网页或做数据大屏,那么 Bokeh 就非常值得学习。持续分享 Python 编程|数据分析|可视化干货