Bokeh 绘图入门

Bokeh 绘图基础以及常用绘图功能

Posted by Paradise on November 18, 2022

Reference | Getting started with Bokeh – Medium Post

在这篇文章中,从最基本的绘图开始,逐步学习 Bokeh 中常用的绘图功能,目标是能满足大部分基础的绘图需求。

一、绘图基础

创建一个空白画布,并在浏览器中显示结果或者保存到本地:

1
2
3
4
5
6
7
8
import bokeh
import bokeh.io
import bokeh.plotting

fig = bokeh.plotting.figure()

bokeh.io.output_file('output.html')
bokeh.io.show(fig)

在画布上添加标记元素:

1
2
3
4
5
6
import numpy as np

fig = bokeh.plotting.figure()
x = np.linspace(-np.pi, np.pi, 30)
fig.line(x, np.sin(x))
bokeh.io.show(fig)

添加多个标记元素,按顺序显示:

1
2
3
4
fig = bokeh.plotting.figure()
fig.line(x, np.sin(x))
fig.circle(x, np.cos(x), fill_color='orange', size=10)
bokeh.io.show(fig)
Bokeh Plot

在移动设备中请横屏查看图像

二、更多画布设置

设置画布大小和工具栏:

1
2
3
4
5
fig = bokeh.plotting.figure(
    plot_width=800, plot_height=400,
    tools='pan, wheel_zoom, lasso_select, tap, undo, reset',
    toolbar_location='below')
bokeh.io.show(fig)

使用 models 转化 DataFrame,用 DataFrame 中的数据绘图,并设置悬停工具提示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import tushare
import bokeh.models
import pandas as pd

# 获取中国银行股价历史数据,并准备工具提示
df = tushare.get_hist_data('601988')
df['index'] = pd.to_datetime(df.index)
df['Date'] = list(df.index)
df['volume_str'] = round(df.volume/1000).map(lambda x: str(int(x))+' K')
# df['color'] = ['green' if pc<0 else 'red' for pc in df.price_change]

# 转化 DataFrame 得到绘图数据源
source = bokeh.models.ColumnDataSource(df)

# 设置工具提示
hover = bokeh.models.HoverTool(tooltips=[
            ("Date", "@Date"),
            ("Open", "@open"),
            ("High", "@high"),
            ("Low", "@low"),
            ("Close", "@close"),
            ("Volume", "@volume_str")])

# 绘图(时序数据)
fig = bokeh.plotting.figure(
    x_axis_type='datetime', 
    plot_width=800, plot_height=400,
    tools=[hover], toolbar_location=None,       # 工具提示
    title='BOC Stock Prices',                   # 标题
    x_axis_label='Date', y_axis_label='Price'   # 轴标签
    )
fig.line(x='index', y='close', source=source)
# fig.vbar(x='index', top='price_change', width=1, color='color', source=source)
bokeh.io.show(fig)
Bokeh Plot

More examples for HoverTool

三、颜色设置

Documents of palettes

使用调色板映射数据标记,线性颜色映射:

1
2
3
4
5
6
7
8
9
10
11
12
13
import bokeh.palettes
import bokeh.transform

x = np.linspace(0, 10, 100)
mapper = bokeh.transform.linear_cmap(
    field_name='y',     # 对纵坐标数值进行映射
    palette=bokeh.palettes.Spectral6,   # 所有调色板:dir(bokeh.palettes)
    low=-1, high=1      # 映射数值范围
    )

fig = bokeh.plotting.figure(plot_width=600, plot_height=300)
fig.circle(x, np.sin(x), color=mapper, size=8)
bokeh.io.show(fig)
Bokeh Plot

对数映射:

1
2
3
4
5
6
7
mapper = bokeh.transform.log_cmap(
    field_name='y',
    palette=bokeh.palettes.Plasma8,
    low=0, high=1024)
fig = bokeh.plotting.figure(plot_width=600, plot_height=300)
fig.circle(x, 2**x, color=mapper, size=8)
bokeh.io.show(fig)
Bokeh Plot

四、子图排列与关联

通过 layouts 子模块设置多个子图, 单行或单列布局:

1
2
3
4
5
6
7
8
9
10
11
12
13
import bokeh.layouts

def make_plot(func):
    fig = bokeh.plotting.figure(
        plot_width=400, plot_height=400, toolbar_location=None
    )
    x = np.linspace(-np.pi, np.pi, 100)
    fig.line(x, func(x))
    return fig
figs = [make_plot(func) for func in [np.sin, np.cos, np.tan]]

subplots = bokeh.layouts.row(*figs)     # 纵向布局使用 bokeh.layouts.column
bokeh.io.show(subplots)
Bokeh Plot

网格布局:

1
2
3
figs = [make_plot(func) for func in [np.sin, np.cos, np.tan]]
subplots = bokeh.layouts.gridplot([[figs[0],figs[1]], [None,figs[2]]])
bokeh.io.show(subplots)
Bokeh Plot

使用标签页进行布局,并联结每个子图的轴范围:

1
2
3
4
5
6
7
8
9
10
11
import bokeh.models.widgets as widgets

figs = [make_plot(func) for func in [np.sin, np.cos, np.tan]]
# 令图 1 和图 2 的轴范围在交互时同步变动
figs[0].x_range = figs[1].x_range
figs[0].y_range = figs[1].y_range

tab1 = widgets.Panel(child=bokeh.layouts.row(figs[0], figs[1]), title='Sheet1')
tab2 = widgets.Panel(child=bokeh.layouts.row(figs[2]), title='Sheet2')
tabs = widgets.Tabs(tabs=[tab1, tab2])
bokeh.io.show(tabs)
Bokeh Plot

END