Bokeh 简明教程

Bokeh - Quick Guide

Bokeh - Introduction

Bokeh是Python的数据可视化库。与Matplotlib和Seaborn不同,它们也是用于数据可视化的Python包,Bokeh使用HTML和JavaScript渲染其图。因此,事实证明对于开发基于Web的仪表板非常有用。

Bokeh项目由NumFocus https://numfocus.org/. 赞助。 NumFocus还支持PyData,这是一个教育计划,涉及NumPy、Pandas等其他重要工具的开发。 Bokeh可以轻松地与这些工具连接并生成交互式图、仪表板和数据应用程序。

Features

Bokeh主要将数据源转换为JSON文件,该文件用作JavaScript库BokehJS的输入,而JavaScript库又用TypeScript编写并渲染现代浏览器中的可视化效果。

以下是一些 important features of Bokeh

Flexibility

Bokeh可用于常见绘图要求以及自定义和复杂的使用案例。

Productivity

Bokeh可以轻松地与其他流行的Pydata工具(如Pandas和Jupyter笔记本)进行交互。

Interactivity

与Matplotlib和Seaborn相比,这是Bokeh的一项重要优势,它们都生成静态图。 Bokeh创建交互式图,当用户与它们交互时会发生变化。您可以为您的受众提供广泛的选择和工具,以便从各个角度推理和查看数据,以便用户可以执行“假设”分析。

Powerful

通过添加自定义JavaScript,可以生成针对特定用例的可视化效果。

Sharable

图形可以嵌入在启用了 FlaskDjango 的 Web 应用程序的输出中。它们也可以在以下应用程序中呈现:

Jupyter

Open source

Bokeh 是一个开源项目。它根据伯克利源代码分发 (BSD) 许可证进行分发。其源代码可从 https://github.com/bokeh/bokeh. 获取

Bokeh - Environment Setup

只能使用标准发行版和 Anaconda 发行版在 CPython 版本 2.73.5+ 上安装 Bokeh。在撰写本教程时,Bokeh 的当前版本是版本 1.3.4。Bokeh 包具有以下依赖关系 -

  1. jinja2 >= 2.7

  2. numpy >= 1.7.1

  3. packaging >= 16.8

  4. pillow >= 4.0

  5. python-dateutil >= 2.1

  6. pyyaml >= 3.10

  7. six >= 1.5.2

  8. tornado >= 4.3

通常,使用 Python 的内置包管理器 PIP 安装 Bokeh 时,会自动安装上述包,如下所示:

pip3 install bokeh

如果你使用 Anaconda 发行版,请按以下方式使用 conda 包管理器:

conda install bokeh

除了上述依赖项之外,你可能需要其他包,例如 pandas、psutil 等,以满足特定目的。

要验证 Bokeh 是否已成功安装,请在 Python 终端中导入 bokeh 包并检查其版本:

>>> import bokeh
>>> bokeh.__version__
'1.3.4'

Bokeh - Getting Started

在两个 numpy 数组之间创建简单的折线图非常简单。首先,从 bokeh.plotting 模块导入以下函数 -

from bokeh.plotting import figure, output_file, show

figure() 函数创建了用于绘制的新图形。

output_file() 函数用于指定来存储输出的 HTML 文件。

show() 函数在笔记本的浏览器中显示 Bokeh 图形。

接下来,设置两个 numpy 数组,其中第二个数组是第一个数组的正弦值。

import numpy as np
import math
x = np.arange(0, math.pi*2, 0.05)
y = np.sin(x)

要获取 Bokeh 图形对象,请指定标题和 x 和 y 轴标签,如下所示 −

p = figure(title = "sine wave example", x_axis_label = 'x', y_axis_label = 'y')

图形对象包含一个 line() 方法,该方法将线形图形添加到图形中。它需要 x 和 y 轴的数据序列。

p.line(x, y, legend = "sine", line_width = 2)

最后,设置输出文件并调用 show() 函数。

output_file("sine.html")
show(p)

这将在 ‘sine.html’ 中渲染线形图表,并将其显示在浏览器中。

Complete code and its output is as follows

from bokeh.plotting import figure, output_file, show
import numpy as np
import math
x = np.arange(0, math.pi*2, 0.05)
y = np.sin(x)
output_file("sine.html")
p = figure(title = "sine wave example", x_axis_label = 'x', y_axis_label = 'y')
p.line(x, y, legend = "sine", line_width = 2)
show(p)

Output on browser

figure

Bokeh - Jupyter Notebook

在 Jupyter 笔记本中显示 Bokeh 图与上述图非常相似。您需要进行的唯一更改是从 bokeh.plotting 模块导入 output_notebook 而不是 output_file。

from bokeh.plotting import figure, output_notebook, show

调用 output_notebook() 函数将 Jupyter 笔记本的输出单元格设置为 show() 函数的目标,如下所示 -

output_notebook()
show(p)

在一本笔记本单元格中输入代码并运行它。正弦波将显示在笔记本内。

Bokeh - Basic Concepts

Bokeh 包提供了两个接口,使用这些接口可以执行各种绘图操作。

bokeh.models

此模块是一个低级接口。它为应用程序开发人员在开发可视化效果时提供了极大的灵活性。Bokeh 图形会导致一个对象,其中包含场景的可视和数据方面,而 BokehJS 库使用该对象。构成 Bokeh 场景图的低级对象称为模型。

bokeh.plotting

这是一个更高级别的界面,具有用于组合视觉图形的功能。此模块包含 Figure 类的定义。它实际上是 bokeh.models 模块中定义的图表类的子类。

Figure 类简化了图表创建。它包含各种方法来绘制不同的矢量化图形图形。图形是 Bokeh 图形的基础块,例如线、圆、矩形和其他形状。

bokeh.application

Bokeh 包应用程序类,它是一个用于创建 Bokeh 文档的轻量级工厂。文档是 Bokeh 模型的容器,用于反映到客户端 BokehJS 库中。

bokeh.server

它提供了可定制的 Bokeh Server Tornadocore 应用程序。服务器用于向您选择的受众分享和发布交互式绘图和应用程序。

Bokeh - Plots with Glyphs

任何图表通常由一个或多个几何形状组成,例如 line, circle, rectangle, 等。这些形状具有关于相应数据集的视觉信息。在 Bokeh 术语中,这些几何形状称为图形。使用 bokeh.plotting interface 构造的 Bokeh 图表使用一组默认工具和样式。但是,可以使用可用的绘图工具自定义样式。

Types of Plots

使用图形创建的不同类型的图表如下所示 −

Line plot

此类型的图表对于以线条形式沿 x 轴和 y 轴可视化点的移动非常有用。它用于执行时间序列分析。

Bar plot

这通常对于指示数据集中的特定列或字段的每个类别的计数非常有用。

Patch plot

此图表指示特定阴影中某个区域中的点。此类图表用于区分同一数据集内的不同组。

Scatter plot

此类型的图表用于可视化两个变量之间的关系并指示它们之间的相关性强度。

通过调用 Figure 类 的适当方法,可以形成不同的图形图表。通过遵循构造函数获得 Figure 对象 −

from bokeh.plotting import figure
figure(**kwargs)

Figure 对象可以通过各种关键字参数进行自定义。

Sr.No

Title

设置图表的标题

1

x_axis_label

设置 x 轴的标题

2

y_axis_label

设置 y 轴的标题

3

plot_width

Set width of figure

4

plot_height

Set height of figure

Line plot

Figure 对象的 line() method 将线形图形添加到 Bokeh 图形中。它需要 x 和 y 参数作为数据数组,以显示其线性关系。

from bokeh.plotting import figure, show
fig = figure()
fig.line(x,y)
show(fig)

以下代码在两个值集中渲染了一条简单的折线图,形式为 Python 列表对象 −

from bokeh.plotting import figure, output_file, show
x = [1,2,3,4,5]
y = [2,4,6,8,10]
output_file('line.html')
fig = figure(title = 'Line Plot example', x_axis_label = 'x', y_axis_label = 'y')
fig.line(x,y)
show(fig)

Output

line plot

Bar plot

figure 对象具有两种不同的方法用于构建条形图

hbar()

条形图水平显示在绘图宽度上。 hbar() method 具有以下参数 −

Sr.No

y

水平条形图的中心的 y 坐标。

1

height

垂直条形图的高度。

2

right

右边缘的 x 坐标。

3

left

左边缘的 x 坐标。

以下代码是使用 Bokeh 的 horizontal bar 的示例。

from bokeh.plotting import figure, output_file, show
fig = figure(plot_width = 400, plot_height = 200)
fig.hbar(y = [2,4,6], height = 1, left = 0, right = [1,2,3], color = "Cyan")
output_file('bar.html')
show(fig)

Output

hbar plot

vbar()

条形图垂直显示在绘图高度上。 vbar() method 具有以下参数 −

Sr.No

x

垂直条形图中心的 x 坐标。

1

width

垂直条形图的宽度。

2

top

顶部边缘的 y 坐标。

3

bottom

底部边缘的 y 坐标。

以下代码显示 vertical bar plot

from bokeh.plotting import figure, output_file, show
fig = figure(plot_width = 200, plot_height = 400)
fig.vbar(x = [1,2,3], width = 0.5, bottom = 0, top = [2,4,6], color = "Cyan")
output_file('bar.html')
show(fig)

Output

vbar plot

Patch plot

在 Bokeh 中,将特定颜色的某个区域着色的图称为补丁图,用来显示区域或具有相似属性的组。Figure 对象具有 patch() 和 patches() 方法,可用于此目的。

patch()

此方法将补丁字形添加到给定的 figure。此方法具有以下参数 −

1

x

补丁点的 x 坐标。

2

y

补丁点的 y 坐标。

以下 Python 代码生成了一个简单的 patch plot

from bokeh.plotting import figure, output_file, show
p = figure(plot_width = 300, plot_height = 300)
p.patch(x = [1, 3,2,4], y = [2,3,5,7], color = "green")
output_file('patch.html')
show(p)

Output

path

patches()

此方法用于绘制多个多边形块,它需要以下参数−

1

xs

以“列表列表”形式给出的所有块的 x 坐标。

2

ys

以“列表列表”形式给出的所有块的 y 坐标。

作为 patches() 方法的一个示例,运行以下代码 −

from bokeh.plotting import figure, output_file, show
xs = [[5,3,4], [2,4,3], [2,3,5,4]]
ys = [[6,4,2], [3,6,7], [2,4,7,8]]
fig = figure()
fig.patches(xs, ys, fill_color = ['red', 'blue', 'black'], line_color = 'white')
output_file('patch_plot.html')
show(fig)

Output

patches

Scatter Markers

散点图通常用于确定两个变量之间的双变量关系。可以利用 Bokeh 向其中添加更强的交互性。可通过调用 Figure 对象的 scatter() 方法获得散点图。此方法使用以下参数−

1

x

中心 x 坐标的值或字段名称

2

y

中心 y 坐标的值或字段名称

3

size

屏幕单位中大小的值或字段名称

4

marker

标记类型的值或字段名称

5

color

设置填充和线条颜色

在 Bokeh 中定义了以下标记类型常量:−

  1. Asterisk

  2. Circle

  3. CircleCross

  4. CircleX

  5. Cross

  6. Dash

  7. Diamond

  8. DiamondCross

  9. Hex

  10. InvertedTriangle

  11. Square

  12. SquareCross

  13. SquareX

  14. Triangle

  15. X

以下 Python 代码会生成具有圆圈标记的散点图。

from bokeh.plotting import figure, output_file, show
fig = figure()
fig.scatter([1, 4, 3, 2, 5], [6, 5, 2, 4, 7], marker = "circle", size = 20, fill_color = "grey")
output_file('scatter.html')
show(fig)

Output

scatter markers

Bokeh - Area Plots

面积图是两个共享公共索引的序列之间的填充区域。Bokeh 的图形类有以下两种方法:

varea()

varea() 方法的输出是一个垂直有向区域,它有一个 x 坐标数组和两个 y 坐标数组 (y1 和 y2),它们将在之间填写。

1

x

区域中各点的 x 坐标。

2

y1

区域一侧中各点的 y 坐标。

3

y2

区域另一侧中各点的 y 坐标。

Example

from bokeh.plotting import figure, output_file, show
fig = figure()
x = [1, 2, 3, 4, 5]
y1 = [2, 6, 4, 3, 5]
y2 = [1, 4, 2, 2, 3]
fig.varea(x = x,y1 = y1,y2 = y2)
output_file('area.html')
show(fig)

Output

varea

harea()

另一方面,harea() 方法需要 x1、x2 和 y 参数。

1

x1

一个区域其中一侧的点的 x 坐标。

2

x2

另一个区域中点的 x 坐标。

3

y

该区域中的点的 y 坐标。

Example

from bokeh.plotting import figure, output_file, show
fig = figure()
y = [1, 2, 3, 4, 5]
x1 = [2, 6, 4, 3, 5]
x2 = [1, 4, 2, 2, 3]
fig.harea(x1 = x1,x2 = x2,y = y)
output_file('area.html')
show(fig)

Output

harea

Bokeh - Circle Glyphs

figure 对象具有许多使用矢量图形的不同形状(如 circle, rectangle, polygon, 等)的方法,可以进行绘制。

提供以下方法绘制 circle glyphs -

circle()

circle() 方法向 figure 添加圆形字形,并需要其中心的 x 和 y 坐标。此外,可以使用诸如 fill_color, line-color, line_width 等参数对其进行配置。

circle_cross()

circle_cross() 方法通过圆心添加带有 “+” 交叉的圆形字形。

circle_x()

circle_x() 方法通过圆心添加带有 “X” 交叉的圆形。

Example

以下示例展示了添加到 Bokeh 图形中的各种圆形字形的用法 -

from bokeh.plotting import figure, output_file, show
plot = figure(plot_width = 300, plot_height = 300)
plot.circle(x = [1, 2, 3], y = [3,7,5], size = 20, fill_color = 'red')
plot.circle_cross(x = [2,4,6], y = [5,8,9], size = 20, fill_color = 'blue',fill_alpha = 0.2, line_width = 2)
plot.circle_x(x = [5,7,2], y = [2,4,9], size = 20, fill_color = 'green',fill_alpha = 0.6, line_width = 2)
show(plot)

Output

circle cross

Bokeh - Rectangle, Oval and Polygon

可以在 Bokeh 图形中渲染 rectangle, ellipse and polygons 。Figure 类的 rect() method 基于中心的 x 和 y 坐标、宽度和高度添加矩形图形。另一方面,square() 方法具有大小参数来确定尺寸。

ellipse() 和 oval() 方法添加椭圆和椭圆图形。它们使用与 rect() 相似的签名,具有 x、y、w 和 h 参数。此外,angle 参数确定从水平旋转。

Example

以下代码显示了不同 shape glyph methods 的用法 −

from bokeh.plotting import figure, output_file, show
fig = figure(plot_width = 300, plot_height = 300)
fig.rect(x = 10,y = 10,width = 100, height = 50, width_units = 'screen', height_units = 'screen')
fig.square(x = 2,y = 3,size = 80, color = 'red')
fig.ellipse(x = 7,y = 6, width = 30, height = 10, fill_color = None, line_width = 2)
fig.oval(x = 6,y = 6,width = 2, height = 1, angle = -0.4)
show(fig)

Output

polygons

Bokeh - Wedges and Arcs

arc() method 基于 x 和 y 坐标、起始和结束角度以及半径绘制一个简单的线弧。角度以弧度给出,而半径可能以屏幕单位或数据单位给出。扇形是一个填充的圆弧。

wedge() method 的属性与 arc() 方法相同。两种方法都提供了可选的方向属性,可以是顺时针或逆时针,它确定了圆弧/扇形渲染的方向。annular_wedge() 函数渲染一个填充在内部和外部半径圆弧之间的区域。

Example

以下是添加到 Bokeh 图形中的 arcwedge glyphs 的示例 −

from bokeh.plotting import figure, output_file, show
import math
fig = figure(plot_width = 300, plot_height = 300)
fig.arc(x = 3, y = 3, radius = 50, radius_units = 'screen', start_angle = 0.0, end_angle = math.pi/2)
fig.wedge(x = 3, y = 3, radius = 30, radius_units = 'screen',
start_angle = 0, end_angle = math.pi, direction = 'clock')
fig.annular_wedge(x = 3,y = 3, inner_radius = 100, outer_radius = 75,outer_radius_units = 'screen',
inner_radius_units = 'screen',start_angle = 0.4, end_angle = 4.5,color = "green", alpha = 0.6)
show(fig)

Output

wedge glyphs

Bokeh - Specialized Curves

bokeh.plotting API 支持以下专门曲线渲染方法 −

beizer()

此方法将贝塞尔曲线添加到图形对象中。贝塞尔曲线是用于计算机图形学的参数曲线。其他用途包括设计计算机字体和动画、用户界面设计以及用于平滑光标轨迹。

在矢量图形中,贝塞尔曲线用于对可无限缩放的平滑曲线进行建模。一条“路径”是链接的贝塞尔曲线的组合。

beizer() 方法具有以下定义的参数 −

1

x0

起始点的 x 坐标。

2

y0

起始点的 y 坐标。

3

x1

结束点的 x 坐标。

4

y1

结束点的 y 坐标。

5

cx0

第一控制点的 x 坐标。

6

cy0

第一控制点的 y 坐标。

7

cx1

第二控制点的 x 坐标。

8

cy1

第二控制点的 y 坐标。

所有参数的默认值设为 None。

Example

以下代码生成 HTML 页面,以在 Bokeh 图中显示贝塞尔曲线和抛物线 -

x = 2
y = 4
xp02 = x+0.4
xp01 = x+0.1
xm01 = x-0.1
yp01 = y+0.2
ym01 = y-0.2
fig = figure(plot_width = 300, plot_height = 300)
fig.bezier(x0 = x, y0 = y, x1 = xp02, y1 = y, cx0 = xp01, cy0 = yp01,
cx1 = xm01, cy1 = ym01, line_color = "red", line_width = 2)

Output

beizer

quadratic()

此方法将 parabola glyph 添加到 Bokeh 图。函数具有与 beizer() 相同的参数,除了 cx0cx1

Example

下面给出的代码生成二次曲线。

x = 2
y = 4
xp02 = x + 0.3
xp01 = x + 0.2
xm01 = x - 0.4
yp01 = y + 0.1
ym01 = y - 0.2
x = x,
y = y,
xp02 = x + 0.4,
xp01 = x + 0.1,
yp01 = y + 0.2,
fig.quadratic(x0 = x, y0 = y, x1 = x + 0.4, y1 = y + 0.01, cx = x + 0.1,
cy = y + 0.2, line_color = "blue", line_width = 3)

Output

quadratic

Bokeh - Setting Ranges

绘图中数据轴的数字范围由 Bokeh 根据处理中的数据集自动设置。但是,有时您可能希望明确定义 x 和 y 轴上的值范围。这是通过将 x_range 和 y_range 属性分配给 figure() 函数来完成的。

使用 range1d() 函数定义这些范围。

Example

xrange = range1d(0,10)

若要将此范围对象用作 x_range 属性,请使用以下代码 -

fig = figure(x,y,x_range = xrange)

Bokeh - Axes

在本章中,我们讨论几种不同类型的轴。

Sr.No

Axes

Description

1

Categorical Axes

Bokeh 图表沿着 x 和 y 轴显示数值数据。为了沿任一轴使用分类数据,我们需要指定 FactorRange 来为其中一个分类维度。

2

Log Scale Axes

如果 x 和 y 数据序列之间存在幂律关系,则最好在两个轴上使用对数刻度。

3

Twin Axes

在单个图表上显示多个表示不同范围的轴可能必不可少。figure 对象可通过定义 extra_x_rangeextra_y_range 属性进行配置。

Categorical Axes

在迄今为止的示例中,Bokeh 图表沿着 x 和 y 轴显示数值数据。为了沿任一轴使用分类数据,我们需要指定 FactorRange 来为其中一个分类维度。例如,要在 x 轴上使用给定列表中的字符串 −

langs = ['C', 'C++', 'Java', 'Python', 'PHP']
fig = figure(x_range = langs, plot_width = 300, plot_height = 300)

Example

通过以下示例,显示一个简单的条形图,显示注册了各种课程的学生数量。

from bokeh.plotting import figure, output_file, show
langs = ['C', 'C++', 'Java', 'Python', 'PHP']
students = [23,17,35,29,12]
fig = figure(x_range = langs, plot_width = 300, plot_height = 300)
fig.vbar(x = langs, top = students, width = 0.5)
show(fig)

Output

categorical axes

要以不同颜色显示每个条形,可将 vbar() 函数的 color 属性设置为一个颜色值列表。

cols = ['red','green','orange','navy', 'cyan']
fig.vbar(x = langs, top = students, color = cols,width=0.5)

Output

plot

要使用 vbar_stack() 或 hbar_stack() 函数呈现垂直(或水平)堆叠条形,将 stackers 属性设置要依次堆叠的字段列表,source 属性设置为一个包含与每个字段相应的 dict 对象。

在以下示例中,sales 是一个字典,显示了三个产品在三个月内的销售额。

from bokeh.plotting import figure, output_file, show
products = ['computer','mobile','printer']
months = ['Jan','Feb','Mar']
sales = {'products':products,
   'Jan':[10,40,5],
   'Feb':[8,45,10],
   'Mar':[25,60,22]}
cols = ['red','green','blue']#,'navy', 'cyan']
fig = figure(x_range = products, plot_width = 300, plot_height = 300)
fig.vbar_stack(months, x = 'products', source = sales, color = cols,width = 0.5)
show(fig)

Output

sales dictionary

通过使用 bokeh.transform 模块中的 dodge() 函数,对条形指定可视位移,便可获得分组条形图。

dodge() function 为每个条形图增加一个相对偏移量,从而在视觉上营造出分组效果。在以下示例中, vbar() glyph 针对某个月的特定条形组以 0.25 的偏移量分开。

from bokeh.plotting import figure, output_file, show
from bokeh.transform import dodge
products = ['computer','mobile','printer']
months = ['Jan','Feb','Mar']
sales = {'products':products,
   'Jan':[10,40,5],
   'Feb':[8,45,10],
   'Mar':[25,60,22]}
fig = figure(x_range = products, plot_width = 300, plot_height = 300)
fig.vbar(x = dodge('products', -0.25, range = fig.x_range), top = 'Jan',
   width = 0.2,source = sales, color = "red")
fig.vbar(x = dodge('products', 0.0, range = fig.x_range), top = 'Feb',
   width = 0.2, source = sales,color = "green")
fig.vbar(x = dodge('products', 0.25, range = fig.x_range), top = 'Mar',
   width = 0.2,source = sales,color = "blue")
show(fig)

Output

visual displacement

Log Scale Axes

当图表中某一轴上的值随另一轴上值线性增加而呈指数增长时,通常需要在对数刻度上显示前轴上的数据。例如,如果 x 和 y 数据序列之间存在幂律关系,则最好在两个轴上使用对数刻度。

Bokeh.plotting API 的 figure() 函数接受 x_axis_type 和 y_axis_type 作为参数,可通过为这些参数中的任何一个传递“log”值来将其指定为对数轴。

第一幅图以线性刻度绘制 x 和 10x 之间的图。在第二幅图中,y_axis_type 设置为“log”。

from bokeh.plotting import figure, output_file, show
x = [0.1, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0]
y = [10**i for i in x]
fig = figure(title = 'Linear scale example',plot_width = 400, plot_height = 400)
fig.line(x, y, line_width = 2)
show(fig)

Output

log scale axes

现在,将 figure() 函数更改为配置 y_axis_type=’log’。

fig = figure(title = 'Linear scale example',plot_width = 400, plot_height = 400, y_axis_type = "log")

Output

linear scale

Twin Axes

在某些情况下,在单个图表上显示多个表示不同范围的轴可能必不可少。figure 对象可通过定义 extra_x_rangeextra_y_range 属性进行配置。在向 figure 添加新的 glyph 时,将使用这些命名的范围。

我们尝试在同一图上显示正弦曲线和直线。两种 glyph 的 y 轴的范围不同。正弦曲线和直线的 x 和 y 数据序列通过以下内容获取 −

from numpy import pi, arange, sin, linspace
x = arange(-2*pi, 2*pi, 0.1)
y = sin(x)
y2 = linspace(0, 100, len(y))

在此,x和y之间的图解表示正弦关系,x和y2之间的图解表示直线。使用显式y范围定义Figure对象,并添加表示正弦曲线的线形字形,如下所示:

fig = figure(title = 'Twin Axis Example', y_range = (-1.1, 1.1))
fig.line(x, y, color = "red")

我们需要一个额外的y范围。定义为:

fig.extra_y_ranges = {"y2": Range1d(start = 0, end = 100)}

要在右侧添加额外的y轴,请使用add_layout()方法。在图像中添加表示x和y2的新线形字形。

fig.add_layout(LinearAxis(y_range_name = "y2"), 'right')
fig.line(x, y2, color = "blue", y_range_name = "y2")

这将生成一个具有两个y轴的图。完整代码和输出如下:

from numpy import pi, arange, sin, linspace
x = arange(-2*pi, 2*pi, 0.1)
y = sin(x)
y2 = linspace(0, 100, len(y))
from bokeh.plotting import output_file, figure, show
from bokeh.models import LinearAxis, Range1d
fig = figure(title='Twin Axis Example', y_range = (-1.1, 1.1))
fig.line(x, y, color = "red")
fig.extra_y_ranges = {"y2": Range1d(start = 0, end = 100)}
fig.add_layout(LinearAxis(y_range_name = "y2"), 'right')
fig.line(x, y2, color = "blue", y_range_name = "y2")
show(fig)

Output

twin axes

Bokeh - Annotations and Legends

注释是对图表添加的解释性文本片段。可以通过指定绘图标题、x 和 y 轴标签以及在绘图区域的任何位置插入文本标签来注释 Bokeh 绘图。

可以在 Figure 构造函数中提供绘图标题以及 x 和 y 轴标签。

fig = figure(title, x_axis_label, y_axis_label)

在以下绘图中,这些属性如下所示 -

from bokeh.plotting import figure, output_file, show
import numpy as np
import math
x = np.arange(0, math.pi*2, 0.05)
y = np.sin(x)
fig = figure(title = "sine wave example", x_axis_label = 'angle', y_axis_label = 'sin')
fig.line(x, y,line_width = 2)
show(p)

Output

annotations

标题的文本和轴标签也可以通过将适当的字符串值分配给 figure 对象的对应属性来指定。

fig.title.text = "sine wave example"
fig.xaxis.axis_label = 'angle'
fig.yaxis.axis_label = 'sin'

还可以指定标题的位置、对齐方式、字体和颜色。

fig.title.align = "right"
fig.title.text_color = "orange"
fig.title.text_font_size = "25px"
fig.title.background_fill_color = "blue"

向绘图图形中添加图例非常容易。我们必须使用任何字形方法的图例属性。

下面我们有三个带有三个不同图例的绘图曲线 -

from bokeh.plotting import figure, output_file, show
import numpy as np
import math
x = np.arange(0, math.pi*2, 0.05)
fig = figure()
fig.line(x, np.sin(x),line_width = 2, line_color = 'navy', legend = 'sine')
fig.circle(x,np.cos(x), line_width = 2, line_color = 'orange', legend = 'cosine')
fig.square(x,-np.sin(x),line_width = 2, line_color = 'grey', legend = '-sine')
show(fig)

Output

legends

Bokeh - Pandas

在以上所有示例中,要绘制的数据以 Python 列表或 numpy 数组的形式提供。也可以以 pandas DataFrame 对象的形式提供数据源。

DataFrame 是一种二维数据结构。数据帧中的列可以是不同的数据类型。Pandas 库具有从各种来源(例如 CSV 文件、Excel 工作表、SQL 表等)创建数据帧的功能。

为了后面的示例,我们使用一个由表示数字 x 及 10x 的两列组成的 CSV 文件。test.csv 文件如下 -

x,pow
0.0,1.0
0.5263157894736842,3.3598182862837818
1.0526315789473684,11.28837891684689
1.5789473684210527,37.926901907322495
2.1052631578947367,127.42749857031335
2.631578947368421,428.1332398719391
3.1578947368421053,1438.449888287663
3.6842105263157894,4832.930238571752
4.2105263157894735,16237.76739188721
4.7368421052631575,54555.947811685146

我们将使用 pandas 中的 read_csv() 函数将此文件读入一个数据帧对象中。

import pandas as pd
df = pd.read_csv('test.csv')
print (df)

数据帧如下所示 -

x        pow
0 0.000000 1.000000
1 0.526316 3.359818
2 1.052632 11.288379
3 1.578947 37.926902
4 2.105263 127.427499
5 2.631579 428.133240
6 3.157895 1438.449888
7 3.684211 4832.930239
8 4.210526 16237.767392
9 4.736842 54555.947812

“x”列和“pow”列用作 bokeh 绘图 figure 中折线字形的的数据序列。

from bokeh.plotting import figure, output_file, show
p = figure()
x = df['x']
y = df['pow']
p.line(x,y,line_width = 2)
p.circle(x, y,size = 20)
show(p)

Output

pandas

Bokeh - ColumnDataSource

Bokeh API 中的大多数绘制图形方法都能够通过 ColumnDatasource 对象接收数据源参数。它可以在绘制图形和“数据表”之间共享数据。

可以将 ColumnDatasource 视为列名称和数据列表之间的映射。通过字符串键及列表或 numpy 数组作为值,将 Python dict 对象传递给 ColumnDataSource 构造函数。

Example

以下为示例

from bokeh.models import ColumnDataSource
data = {'x':[1, 4, 3, 2, 5],
   'y':[6, 5, 2, 4, 7]}
cds = ColumnDataSource(data = data)

然后将此对象用作符号方法中 source 属性的值。以下代码使用 ColumnDataSource 生成散点图。

from bokeh.plotting import figure, output_file, show
from bokeh.models import ColumnDataSource
data = {'x':[1, 4, 3, 2, 5],
   'y':[6, 5, 2, 4, 7]}
cds = ColumnDataSource(data = data)
fig = figure()
fig.scatter(x = 'x', y = 'y',source = cds, marker = "circle", size = 20, fill_color = "grey")
show(fig)

Output

columndatasource

除了向 ColumnDataSource 分配 Python 字典之外,我们还可以为它使用 Pandas DataFrame。

让我们使用“test.csv”(在本节的前面使用)来获取 DataFrame,并使用它来获取 ColumnDataSource 并呈现线形绘制图形。

from bokeh.plotting import figure, output_file, show
import pandas as pd
from bokeh.models import ColumnDataSource
df = pd.read_csv('test.csv')
cds = ColumnDataSource(df)
fig = figure(y_axis_type = 'log')
fig.line(x = 'x', y = 'pow',source = cds, line_color = "grey")
show(fig)

Output

rendering

Bokeh - Filtering Data

通常,您可能希望获取与满足特定条件的数据部分相关的绘图,而不是整个数据集。bokeh.models 模块中定义的 CDSView 类的对象通过在其上应用一个或多个筛选器来返回正在考虑的 ColumnDatasource 的子集。

IndexFilter 是最简单的筛选器类型。您必须仅指定要使用的绘图图形时的那些行从数据集中的索引。

以下示例演示了使用 IndexFilter 设置 CDSView 的用法。结果图形显示 ColumnDataSource 的 x 和 y 数据序列之间的直线符号。通过在其上应用索引筛选器获得视图对象。该视图用于将圆形符号绘图作为 IndexFilter 的结果。

Example

from bokeh.models import ColumnDataSource, CDSView, IndexFilter
from bokeh.plotting import figure, output_file, show
source = ColumnDataSource(data = dict(x = list(range(1,11)), y = list(range(2,22,2))))
view = CDSView(source=source, filters = [IndexFilter([0, 2, 4,6])])
fig = figure(title = 'Line Plot example', x_axis_label = 'x', y_axis_label = 'y')
fig.circle(x = "x", y = "y", size = 10, source = source, view = view, legend = 'filtered')
fig.line(source.data['x'],source.data['y'], legend = 'unfiltered')
show(fig)

Output

indexfilter

若要仅选择满足特定布尔条件的数据源中的那些行,请应用 BooleanFilter。

典型的 Bokeh 安装包含 sampledata 目录中的许多样本数据集。对于以下示例,我们使用 unemployment1948.csv 形式提供的 unemployment1948 数据集。它存储 1948 年以来美国按年计算的失业百分比。我们想仅为 1980 年及以后的年份生成绘图。为此,通过应用 BooleanFilter 获得 CDSView 对象在给定的数据源上。

from bokeh.models import ColumnDataSource, CDSView, BooleanFilter
from bokeh.plotting import figure, show
from bokeh.sampledata.unemployment1948 import data
source = ColumnDataSource(data)
booleans = [True if int(year) >= 1980 else False for year in
source.data['Year']]
print (booleans)
view1 = CDSView(source = source, filters=[BooleanFilter(booleans)])
p = figure(title = "Unemployment data", x_range = (1980,2020), x_axis_label = 'Year', y_axis_label='Percentage')
p.line(x = 'Year', y = 'Annual', source = source, view = view1, color = 'red', line_width = 2)
show(p)

Output

booleanfilter

为了灵活地应用筛选器,Bokeh 提供了一个 CustomJSFilter 类,借助该类,可以使用用户定义的 JavaScript 函数筛选数据源。

以下给出的示例使用相同的美国失业数据。定义 CustomJSFilter 以绘出 1980 及以后的失业数据。

from bokeh.models import ColumnDataSource, CDSView, CustomJSFilter
from bokeh.plotting import figure, show
from bokeh.sampledata.unemployment1948 import data
source = ColumnDataSource(data)
custom_filter = CustomJSFilter(code = '''
   var indices = [];

   for (var i = 0; i < source.get_length(); i++){
      if (parseInt(source.data['Year'][i]) > = 1980){
         indices.push(true);
      } else {
         indices.push(false);
      }
   }
   return indices;
''')
view1 = CDSView(source = source, filters = [custom_filter])
p = figure(title = "Unemployment data", x_range = (1980,2020), x_axis_label = 'Year', y_axis_label = 'Percentage')
p.line(x = 'Year', y = 'Annual', source = source, view = view1, color = 'red', line_width = 2)
show(p)

Bokeh - Layouts

Bokeh 可视化可以适当地布置在不同的布局选项中。这些布局以及大小调整模式会导致根据浏览器窗口的大小自动调整大小。为了保持一致的外观,布局中的所有元素必须具有相同的大小调整模式。小部件(按钮、菜单等)保存在一个单独的小部件框中,而不在绘制图形中。

第一种布局是 Column 布局,它垂直显示绘制图形。 column() functionbokeh.layouts 模块中定义,并采用以下特征签名 −

from bokeh.layouts import column
col = column(children, sizing_mode)

children – 绘制图形和/或小部件的列表。

sizing_mode – 确定布局中元素的大小调整方式。可能的值为“fixed”(固定)、“stretch_both”(双向拉伸)、“scale_width”(按宽度缩放)、“scale_height”(按高度缩放)、“scale_both”(双向缩放)。默认值为“fixed”(固定)。

以下代码生成两个 Bokeh 图形,并将它们放置在 column 布局中,以便它们垂直显示。每个图形中显示表示 x 和 y 数据序列中正弦和余弦关系的线形符号。

from bokeh.plotting import figure, output_file, show
from bokeh.layouts import column
import numpy as np
import math
x = np.arange(0, math.pi*2, 0.05)
y1 = np.sin(x)
y2 = np.cos(x)
fig1 = figure(plot_width = 200, plot_height = 200)
fig1.line(x, y1,line_width = 2, line_color = 'blue')
fig2 = figure(plot_width = 200, plot_height = 200)
fig2.line(x, y2,line_width = 2, line_color = 'red')
c = column(children = [fig1, fig2], sizing_mode = 'stretch_both')
show(c)

Output

sizing mode

类似地,Row 布局横向排列绘制图形,它使用 bokeh.layouts 模块中定义的 row() function 。正如您所想,它也采用两个参数(类似于 column() function )——children 和 sizing_mode。

上图中垂直显示的正弦和余弦曲线现在通过以下代码以 row 布局水平显示

from bokeh.plotting import figure, output_file, show
from bokeh.layouts import row
import numpy as np
import math
x = np.arange(0, math.pi*2, 0.05)
y1 = np.sin(x)
y2 = np.cos(x)
fig1 = figure(plot_width = 200, plot_height = 200)
fig1.line(x, y1,line_width = 2, line_color = 'blue')
fig2 = figure(plot_width = 200, plot_height = 200)
fig2.line(x, y2,line_width = 2, line_color = 'red')
r = row(children = [fig1, fig2], sizing_mode = 'stretch_both')
show(r)

Output

layout arranges

Bokeh 包还具有网格布局。它在一个由行和列组成的二维网格中容纳多个绘制图形(以及小部件)。bokeh.layouts 模块中的 gridplot() function 返回一个网格和一个可以通过 toolbar_location 属性进行定位的单一统一工具栏。

这与 row 或 column 布局不同,其中每个绘制图形都显示自己的工具栏。grid() 函数也使用 children 和 sizing_mode 参数,其中 children 是列表的列表。请确保每个子列表的维度相同。

在以下代码中,在两行两列的网格中绘制了 x 和 y 数据序列之间四个不同的关系。

from bokeh.plotting import figure, output_file, show
from bokeh.layouts import gridplot
import math
x = list(range(1,11))

y1 = x
y2 =[11-i for i in x]
y3 = [i*i for i in x]
y4 = [math.log10(i) for i in x]

fig1 = figure(plot_width = 200, plot_height = 200)
fig1.line(x, y1,line_width = 2, line_color = 'blue')
fig2 = figure(plot_width = 200, plot_height = 200)
fig2.circle(x, y2,size = 10, color = 'green')
fig3 = figure(plot_width = 200, plot_height = 200)
fig3.circle(x,y3, size = 10, color = 'grey')
fig4 = figure(plot_width = 200, plot_height = 200, y_axis_type = 'log')
fig4.line(x,y4, line_width = 2, line_color = 'red')
grid = gridplot(children = [[fig1, fig2], [fig3,fig4]], sizing_mode = 'stretch_both')
show(grid)

Output

plotted

Bokeh - Plot Tools

当渲染 Bokeh 图形时,通常在图形的右侧会出现一个工具栏。它包含一组默认工具。首先,工具栏的位置可通过 figure() 函数中的 toolbar_location 属性进行配置。此属性可以采用以下一个值 −

  1. "above"

  2. "below"

  3. "left"

  4. "right"

  5. "None"

例如,以下语句将导致在绘图下面显示工具栏 −

Fig = figure(toolbar_location = "below")

可通过从 bokeh.models 模块中定义的各种工具添加所需内容来根据要求配置此工具栏。例如 −

Fig.add_tools(WheelZoomTool())

可将工具分类为以下类别 −

  1. Pan/Drag Tools

  2. Click/Tap Tools

  3. Scroll/Pinch Tools

Tool

Description

Icon

BoxSelectTool Name : 'box_select'

允许用户通过鼠标左键拖拽来定义矩形选择区域

LassoSelectTool name: 'lasso_select

允许用户通过鼠标左键拖拽来定义任意的选择区域

PanTool name: 'pan', 'xpan', 'ypan',

允许用户通过左键拖拽鼠标来平移绘图

TapTool name: 'tap

允许用户通过单击鼠标左键选择单个点

WheelZoomTool name: 'wheel_zoom', 'xwheel_zoom', 'ywheel_zoom'

以当前鼠标位置为中心缩小和放大绘图。

WheelPanTool name: 'xwheel_pan', 'ywheel_pan'

沿着指定维度平移绘图窗口,而不改变窗口的长宽比。

ResetTool name: 'reset'

将绘图范围恢复到它们的原始值。

SaveTool name: 'save'

允许用户保存绘图的 PNG 图片。

ZoomInTool name: 'zoom_in', 'xzoom_in', 'yzoom_in'

缩小工具将在 x、y 或两个坐标中放大绘图

ZoomOutTool name: 'zoom_out', 'xzoom_out', 'yzoom_out'

放大工具将在 x、y 或两个坐标中缩小绘图

CrosshairTool name: 'crosshair'

在绘图上绘制十字光标注,以当前鼠标位置为中心。

Bokeh - Styling Visual Attributes

Bokeh 图表默认的外观可以通过设置各种属性为所需的值来进行定制。这些属性主要有三种类型 −

Line properties

下表列出与线形形状有关的各种属性。

1

line_color

颜色用于描绘线条

2

line_width

这以像素为单位,作为线描绘制宽度

3

line_alpha

在 0(透明)和 1(不透明)之间,这作为一个浮点数

4

line_join

如何将路径段连接在一起。定义的值为:'miter' (miter_join),'round' (round_join),'bevel' (bevel_join)

5

line_cap

如何终止路径段。定义的值为:'butt' (butt_cap),'round' (round_cap),'square' (square_cap)

6

line_dash

B这用于线型。定义的值为:'solid'、'dashed'、'dotted'、'dotdash'、'dashdot'

7

line_dash_offset

line_dash 中模式从哪个像素距离开始

Fill properties

下面列出了各种填充属性 −

1

fill_color

这用于填充路径

2

fill_alpha

在 0(透明)和 1(不透明)之间,这作为一个浮点数

Text properties

下表中列出了许多与文本相关的属性 −

1

text_font

字体名称,例如“times”、“helvetica”

2

text_font_size

以像素、em 或 pt 为单位的字体大小,例如“12pt”、“1.5em”

3

text_font_style

用于‘normal’‘italic’‘bold’的字体样式

4

text_color

这用于以呈现文本

5

text_alpha

介于 0(透明)和 1(不透明)之间,这是一个浮点数

6

text_align

文本的水平锚点 -“left”、“right”、“center”

7

text_baseline

文本的垂直锚点“top”、“middle”、“bottom”、“alphabetic”、“hanging”

Bokeh - Customising legends

图中的各种字形可以通过在默认情况下显示为图区右上角标签的图例属性来识别。可以通过以下属性自定义此图例:

1

legend.label_text_font

将默认标签字体更改为指定的字体名称

2

legend.label_text_font_size

font size in points

3

legend.location

将标签设置在指定的位置。

4

legend.title

为图例标签设置标题

5

legend.orientation

设置为水平(默认)或垂直

6

legend.clicking_policy

Example

图例自定义的示例代码如下:

from bokeh.plotting import figure, output_file, show
import math
x2 = list(range(1,11))
y4 = [math.pow(i,2) for i in x2]
y2 = [math.log10(pow(10,i)) for i in x2]
fig = figure(y_axis_type = 'log')
fig.circle(x2, y2,size = 5, color = 'blue', legend = 'blue circle')
fig.line(x2,y4, line_width = 2, line_color = 'red', legend = 'red line')
fig.legend.location = 'top_left'
fig.legend.title = 'Legend Title'
fig.legend.title_text_font = 'Arial'
fig.legend.title_text_font_size = '20pt'
show(fig)

Output

customising legends

Bokeh - Adding Widgets

bokeh.models.widgets 模块包含与 HTML 表单元素相似的 GUI 对象的定义,例如按钮、滑块、复选框、单选按钮等。这些控件为绘制图形提供交互式界面。可以通过根据相应事件执行自定义 JavaScript 函数来调用处理,如修改绘制图形数据、更改绘制图形参数等。

Bokeh 允许使用两种方法定义回调功能 −

  1. 使用 CustomJS callback ,以便交互性可以在独立 HTML 文档中工作。

  2. 使用 Bokeh server 和设置事件处理程序。

在本节中,我们将了解如何添加 Bokeh 控件并分配 JavaScript 回调。

Button

此控件是一个可点击按钮,通常用于调用用户定义的回叫处理程序。构造函数采用以下参数 −

Button(label, icon, callback)

标签参数是用作按钮标题的字符串,callback 是在单击时要调用的自定义 JavaScript 函数。

在以下示例中,图和按钮控件显示在 Column 布局中。该图本身在 x 和 y 数据系列之间呈现一条线形符号。

已使用 CutomJS() function 定义了一个名为“callback”的自定义 JavaScript 函数。它以变量 cb_obj 的形式接收对触发回调的对象(在本例中为按钮)的引用。

此函数更改源 ColumnDataSource 数据,并最终在此源数据中发出此更新。

from bokeh.layouts import column
from bokeh.models import CustomJS, ColumnDataSource
from bokeh.plotting import Figure, output_file, show
from bokeh.models.widgets import Button

x = [x*0.05 for x in range(0, 200)]
y = x

source = ColumnDataSource(data=dict(x=x, y=y))
plot = Figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)

callback = CustomJS(args=dict(source=source), code="""
   var data = source.data;
   x = data['x']
   y = data['y']
   for (i = 0; i < x.length; i++) {
      y[i] = Math.pow(x[i], 4)
   }
   source.change.emit();
""")

btn = Button(label="click here", callback=callback, name="1")

layout = column(btn , plot)
show(layout)

Output (initial)

button

单击图顶部上的按钮,并查看更新后的图例,如下所示 −

Output (after click)

button after

Slider

借助滑块控件,可以在分配给它的 start 和 end 属性之间选择一个数字。

Slider(start, end, step, value)

在以下示例中,我们在滑块的 on_change 事件上注册了一个回调函数。滑块的瞬时数值以 cb_obj.value 的形式提供给处理程序,该值用于修改 ColumnDatasource 数据。随着您滑动位置,该图例会不断更新。

from bokeh.layouts import column
from bokeh.models import CustomJS, ColumnDataSource
from bokeh.plotting import Figure, output_file, show
from bokeh.models.widgets import Slider

x = [x*0.05 for x in range(0, 200)]
y = x

source = ColumnDataSource(data=dict(x=x, y=y))
plot = Figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)

handler = CustomJS(args=dict(source=source), code="""
   var data = source.data;
   var f = cb_obj.value
   var x = data['x']
   var y = data['y']
   for (var i = 0; i < x.length; i++) {
      y[i] = Math.pow(x[i], f)
   }
   source.change.emit();
""")

slider = Slider(start=0.0, end=5, value=1, step=.25, title="Slider Value")

slider.js_on_change('value', handler)
layout = column(slider, plot)
show(layout)

Output

slider

RadioGroup

此控件呈现一组互斥切换按钮,在标题的左侧显示圆形按钮。

RadioGroup(labels, active)

其中,标签是标题列表,active 是所选选项的索引。

Select

此控件是一个简单的字符串项下拉列表,可以从中选择一个。所选字符串显示在顶部窗口中,它是值参数。

Select(options, value)

下拉列表中的字符串元素列表以 options 列表对象的形式给出。

以下是单选按钮和选择控件的组合示例,两个控件都提供了 x 和 y 数据系列之间的三种不同关系。 RadioGroupSelect widgets 通过 on_change() 方法向相应的处理程序注册。

from bokeh.layouts import column
from bokeh.models import CustomJS, ColumnDataSource
from bokeh.plotting import Figure, output_file, show
from bokeh.models.widgets import RadioGroup, Select

x = [x*0.05 for x in range(0, 200)]
y = x

source = ColumnDataSource(data=dict(x=x, y=y))

plot = Figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)

radiohandler = CustomJS(args=dict(source=source), code="""
   var data = source.data;
   console.log('Tap event occurred at x-position: ' + cb_obj.active);
   //plot.title.text=cb_obj.value;
   x = data['x']
   y = data['y']
   if (cb_obj.active==0){
      for (i = 0; i < x.length; i++) {
         y[i] = x[i];
      }
   }
   if (cb_obj.active==1){
      for (i = 0; i < x.length; i++) {
         y[i] = Math.pow(x[i], 2)
      }
   }
   if (cb_obj.active==2){
      for (i = 0; i < x.length; i++) {
         y[i] = Math.pow(x[i], 4)
      }
   }
   source.change.emit();
""")

selecthandler = CustomJS(args=dict(source=source), code="""
   var data = source.data;
   console.log('Tap event occurred at x-position: ' + cb_obj.value);
   //plot.title.text=cb_obj.value;
   x = data['x']
   y = data['y']
   if (cb_obj.value=="line"){
      for (i = 0; i < x.length; i++) {
         y[i] = x[i];
      }
   }
   if (cb_obj.value=="SquareCurve"){
      for (i = 0; i < x.length; i++) {
         y[i] = Math.pow(x[i], 2)
      }
   }
   if (cb_obj.value=="CubeCurve"){
      for (i = 0; i < x.length; i++) {
         y[i] = Math.pow(x[i], 4)
      }
   }
   source.change.emit();
""")

radio = RadioGroup(
   labels=["line", "SqureCurve", "CubeCurve"], active=0)
radio.js_on_change('active', radiohandler)
select = Select(title="Select:", value='line', options=["line", "SquareCurve", "CubeCurve"])
select.js_on_change('value', selecthandler)

layout = column(radio, select, plot)
show(layout)

Output

select
select op

Tab widget

就像在浏览器中一样,每个选项卡都可以显示不同的网页,Tab 控件是 Bokeh 模块,它为每个数字提供不同的视图。在以下示例中,在两个不同的选项卡中渲染了正弦曲线和余弦曲线的两个图例 −

from bokeh.plotting import figure, output_file, show
from bokeh.models import Panel, Tabs
import numpy as np
import math
x=np.arange(0, math.pi*2, 0.05)
fig1=figure(plot_width=300, plot_height=300)

fig1.line(x, np.sin(x),line_width=2, line_color='navy')

tab1 = Panel(child=fig1, title="sine")
fig2=figure(plot_width=300, plot_height=300)
fig2.line(x,np.cos(x), line_width=2, line_color='orange')
tab2 = Panel(child=fig2, title="cos")

tabs = Tabs(tabs=[ tab1, tab2 ])

show(tabs)

Output

tab widget

Bokeh - Server

Bokeh 架构采用分离设计,其中使用 Python 创建诸如绘图和符号之类的对象,并将其转换为 JSON 供 BokehJS client library 使用。

但是,可以在 Python 和浏览器中保持对象彼此同步,借助 Bokeh Server 。它允许响应浏览器中生成的带有 Python 全部功能的用户界面 (UI) 事件。它还有助于自动将服务器端更新推送到浏览器中的小部件或绘图。

Bokeh 服务器使用用 Python 编写的应用程序代码来创建 Bokeh 文档。来自客户端浏览器的每次新连接都会导致 Bokeh 服务器创建新文档,仅适用于该会话。

server

首先,我们必须开发要在客户端浏览器中提供的应用程序代码。下面的代码呈现正弦波线形符号。除了绘图之外,还呈现了一个滑块控件来控制正弦波的频率。回调函数 update_data() 更新 ColumnDataSource 数据,将滑块的瞬时值作为当前频率。

import numpy as np
from bokeh.io import curdoc
from bokeh.layouts import row, column
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Slider, TextInput
from bokeh.plotting import figure
N = 200
x = np.linspace(0, 4*np.pi, N)
y = np.sin(x)
source = ColumnDataSource(data = dict(x = x, y = y))
plot = figure(plot_height = 400, plot_width = 400, title = "sine wave")
plot.line('x', 'y', source = source, line_width = 3, line_alpha = 0.6)
freq = Slider(title = "frequency", value = 1.0, start = 0.1, end = 5.1, step = 0.1)
def update_data(attrname, old, new):
   a = 1
   b = 0
   w = 0
   k = freq.value
   x = np.linspace(0, 4*np.pi, N)
   y = a*np.sin(k*x + w) + b
   source.data = dict(x = x, y = y)
freq.on_change('value', update_data)
curdoc().add_root(row(freq, plot, width = 500))
curdoc().title = "Sliders"

接下来,按以下命令行启动 Bokeh 服务器:

Bokeh serve –show sliders.py

Bokeh 服务器开始在 localhost:5006/sliders 处运行并为应用程序提供服务。控制台日志显示以下显示:

C:\Users\User>bokeh serve --show scripts\sliders.py
2019-09-29 00:21:35,855 Starting Bokeh server version 1.3.4 (running on Tornado 6.0.3)
2019-09-29 00:21:35,875 Bokeh app running at: http://localhost:5006/sliders
2019-09-29 00:21:35,875 Starting Bokeh server with process id: 3776
2019-09-29 00:21:37,330 200 GET /sliders (::1) 699.99ms
2019-09-29 00:21:38,033 101 GET /sliders/ws?bokeh-protocol-version=1.0&bokeh-session-id=VDxLKOzI5Ppl9kDvEMRzZgDVyqnXzvDWsAO21bRCKRZZ (::1) 4.00ms
2019-09-29 00:21:38,045 WebSocket connection opened
2019-09-29 00:21:38,049 ServerConnection created

打开你喜欢的浏览器并输入上述地址。正弦波绘图如下所示:

serverconnection

你可以滚动滑块将频率尝试更改为 2。

frequency

Bokeh - Using Bokeh Subcommands

Bokeh 应用程序提供了一些可从命令行执行的子命令。下表显示了子命令:

1

Html

为一个或多个应用程序创建 HTML 文件

2

info

打印 Bokeh 服务器配置信息

3

json

为一个或多个应用程序创建 JSON 文件

4

png

为一个或多个应用程序创建 PNG 文件

5

sampledata

下载 bokeh 样本数据集

6

secret

为 Bokeh 服务器使用创建 Bokeh 密钥

7

serve

运行托管一个或多个应用程序的 Bokeh 服务器

8

static

服务 BokeJS 库使用的静态资源(JavaScipt、CSS、图像、字体等)

9

svg

为主一个或多个应用程序创建 SVG 文件

下面的命令为具有 Bokeh 图形的 Python 脚本生成 HTML 文件。

C:\python37>bokeh html -o app.html app.py

添加 show 选项会自动在浏览器中打开 HTML 文件。同样,Python 脚本使用相应的子命令转换为 PNG、SVG、JSON 文件。

若要显示 Bokeh 服务器信息,请按如下方式使用 info 子命令:

C:\python37>bokeh info
Python version : 3.7.4 (tags/v3.7.4:e09359112e, Jul 8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)]
IPython version : (not installed)
Tornado version : 6.0.3
Bokeh version : 1.3.4
BokehJS static path : c:\python37\lib\site-packages\bokeh\server\static
node.js version : (not installed)
npm version : (not installed)

为了研究不同类型的绘图,Bokeh 网站 https://bokeh.pydata.org 提供了样本数据集。可通过 sampledata 子命令将它们下载到本地机器。

C:\python37>bokeh info

以下数据集下载至 C:\Users\User\.bokeh\data 文件夹:

AAPL.csv                                     airports.csv
airports.json                                CGM.csv
FB.csv                                       gapminder_fertility.csv
gapminder_life_expectancy.csv                gapminder_population.csv
gapminder_regions.csv                        GOOG.csv
haarcascade_frontalface_default.xml          IBM.csv
movies.db                                    MSFT.csv
routes.csv                                   unemployment09.csv
us_cities.json                               US_Counties.csv
world_cities.csv
WPP2012_SA_DB03_POPULATION_QUINQUENNIAL.csv

secret 子命令生成要与 SECRET_KEY 环境变量一起用于 serve 子命令的密钥。

Bokeh - Exporting Plots

除上面所述的子命令外,可以使用 export() 函数以 PNG 和 SVG 文件格式导出 Bokeh 图表。为此,本地 Python 安装应具备以下依赖库。

PhantomJS

PhantomJS 是一个 JavaScript API,它支持自动导航、屏幕截图、用户行为和断言。它用于运行基于浏览器的单元测试。PhantomJS 基于 WebKit,为不同浏览器提供类似的浏览环境,并为各种 Web 标准提供快速且本地的支持:DOM 处理、CSS 选择器、JSON、画布和 SVG。换句话说,PhantomJS 是一款没有图形用户界面的 Web 浏览器。

Pillow

Pillow,一个 Python 成像库(早前称为 PIL)是一个免费的 Python 编程语言库,它支持打开、操作和保存许多不同的图像文件格式。(包括 PPM、PNG、JPEG、GIF、TIFF 和 BMP。)它的部分功能包括逐像素操作、遮罩和透明度处理、图像滤镜、图像增强等。

export_png() 函数从布局生成 RGBA 格式的 PNG 图像。此函数使用无头 Webkit 浏览器在内存中呈现布局,然后捕获屏幕截图。生成的图像将与源布局具有相同的尺寸。确保 Plot.background_fill_color 和 Plot.border_fill_color 属性为 None。

from bokeh.io import export_png
export_png(plot, filename = "file.png")

可以使用诸如 Adobe Illustrator 等程序编辑带有 SVG 元素的 HTML5 画布图表输出。SVG 对象也可以转换为 PDF。在此,canvas2svg 是一个 JavaScript 库,它用于使用 SVG 元素模拟普通的画布元素及其方法。与 PNG 相同,为了使用透明背景创建 SVG,Plot.background_fill_color 和 Plot.border_fill_color 属性应为 None。

首先,通过将 Plot.output_backend 属性设为“svg”来激活 SVG 后端。

plot.output_backend = "svg"

对于无头导出,Bokeh 有一个实用函数 export_svgs()。此函数会将布局中所有支持 SVG 的图表下载为不同的 SVG 文件。

from bokeh.io import export_svgs
plot.output_backend = "svg"
export_svgs(plot, filename = "plot.svg")

Bokeh - Embedding Plots and Apps

以独立文档或 Bokeh 应用程序的形式显示图和数据也可以嵌入 HTML 文档中。

独立文档是 Bokeh 图或未由 Bokeh 服务器支持的文档。此类图中的交互纯粹以自定义 JS 形式进行,而不是 Pure Python 回调。

由 Bokeh 服务器支持的 Bokeh 图和文档也可以嵌入。此类文档包含在服务器上运行的 Python 回调。

在独立文档的情况下,可以通过 file_html() 函数获取表示 Bokeh 图的原始 HTML 代码。

from bokeh.plotting import figure
from bokeh.resources import CDN
from bokeh.embed import file_html
fig = figure()
fig.line([1,2,3,4,5], [3,4,5,2,3])
string = file_html(plot, CDN, "my plot")

file_html() 函数的返回值可以保存为 HTML 文件,也可以通过 Flask 应用程序中的 URL 路由来渲染。

在独立文档的情况下,可以通过 json_item() 函数获取其 JSON 表示。

from bokeh.plotting import figure
from bokeh.embed import file_html
import json
fig = figure()
fig.line([1,2,3,4,5], [3,4,5,2,3])
item_text = json.dumps(json_item(fig, "myplot"))

此输出可以用一个网页上的 Bokeh.embed.embed_item 函数 -

item = JSON.parse(item_text);
Bokeh.embed.embed_item(item);

Bokeh 服务器上的 Bokeh 应用程序也可以嵌入,以便每次加载页面时创建一个新会话和文档,以便加载特定的现有会话。这可以使用 server_document() 函数来完成。它接受一个 Bokeh 服务器应用程序的 URL,并返回一个脚本,该脚本将在每次执行该脚本时从该服务器嵌入新会话。

server_document() function 接受 URL 参数。如果设置为“默认”,将使用默认 URL [role="bare"] [role="bare"]http://localhost:5006/

from bokeh.embed import server_document
script = server_document("http://localhost:5006/sliders")

server_document() 函数返回以下脚本代码 −

<script
   src="http://localhost:5006/sliders/autoload.js?bokeh-autoload-element=1000&bokeh-app-path=/sliders&bokeh-absolute-url=https://localhost:5006/sliders"
   id="1000">
</script>

Bokeh - Extending Bokeh

Bokeh 可与多种其他库很好地集成,允许您针对每项任务使用最合适的工具。Bokeh 生成 JavaScript 这件事使其能将 Bokeh 输出与各种 JavaScript 库(如 PhosphorJS)结合使用。

Datashader (https://github.com/bokeh/datashader) 是另一种可通过它扩展 Bokeh 输出的库。这是一个将大型数据集预渲染成大尺寸栅格图像的 Python 库。该功能克服了浏览器在处理非常大的数据时的局限性。Datashader 包括构建交互式 Bokeh 绘图的工具,这些绘图可在 Bokeh 中缩放和平移时动态重新渲染这些图像,使其在 Web 浏览器中处理任意大的数据集变得切实可行。

另一个库是 Holoviews ( (http://holoviews.org/) ,它提供了用于构建 Bokeh 绘图的简洁声明式界面,尤其是在 Jupyter Notebook 中。它便于快速制作数据分析图形的原型。

Bokeh - WebGL

当必须使用大型数据集来借助 Bokeh 创建可视化时,交互可能会非常慢。为此,可以启用 Web Graphics Library (WebGL) 支持。

WebGL 是一个 JavaScript API,使用 GPU(图形处理单元)在浏览器中渲染内容。此标准化插件在所有现代浏览器中都可用。

要启用 WebGL,你只需将 Bokeh Figure 对象的 output_backend 属性设置为“webgl”。

fig = figure(output_backend="webgl")

在下面的示例中,我们绘制一个带 10,000 个点的 scatter glyph ,借助 WebGL 支持。

import numpy as np
from bokeh.plotting import figure, show, output_file
N = 10000
x = np.random.normal(0, np.pi, N)
y = np.sin(x) + np.random.normal(0, 0.2, N)
output_file("scatterWebGL.html")
p = figure(output_backend="webgl")
p.scatter(x, y, alpha=0.1)
show(p)

Output

webgl

Bokeh - Developing with JavaScript

Bokeh Python 库和 R、Scala 和 Julia 等其他语言的库主要在高级别与 BokehJS 交互。Python 程序员不必担心 JavaScript 或 web 开发。但是,有人可以使用 BokehJS API 直接使用 BokehJS 进行纯 JavaScript 开发。

内置于 Bokeh Python API 中的字形和窗口小部件等 BokehJS 对象的构建方式或多或少类似。通常,任何 Python ClassName 都可以在 JavaScript 中作为 Bokeh.ClassName 使用。例如,在 Python 中获得的 Range1d 对象。

xrange = Range1d(start=-0.5, end=20.5)

它通过 BokehJS 以如下方式等效获得 -

var xrange = new Bokeh.Range1d({ start: -0.5, end: 20.5 });

当以下 JavaScript 代码嵌入 HTML 文件中时,会在浏览器中呈现一个简单的折线图。

首先在网页的 <head>..</head> 部分中包含所有 BokehJS 库,如下所示

<head>
<script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-1.3.4.min.js"></script>
<script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.3.4.min.js"></script>
<script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-tables-1.3.4.min.js"></script>
<script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-gl-1.3.4.min.js"></script>
<script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-api-1.3.4.min.js"></script>
<script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-api-1.3.4.min.js"></script>
</head>

在 body 部分中,以下 JavaScript 片段构建 Bokeh Plot 的各个部分。

<script>
// create some data and a ColumnDataSource
var x = Bokeh.LinAlg.linspace(-0.5, 20.5, 10);
var y = x.map(function (v) { return v * 0.5 + 3.0; });
var source = new Bokeh.ColumnDataSource({ data: { x: x, y: y } });
// make the plot
var plot = new Bokeh.Plot({
   title: "BokehJS Plot",
   plot_width: 400,
   plot_height: 400
});

// add axes to the plot
var xaxis = new Bokeh.LinearAxis({ axis_line_color: null });
var yaxis = new Bokeh.LinearAxis({ axis_line_color: null });
plot.add_layout(xaxis, "below");
plot.add_layout(yaxis, "left");

// add a Line glyph
var line = new Bokeh.Line({
   x: { field: "x" },
   y: { field: "y" },
   line_color: "#666699",
   line_width: 2
});
plot.add_glyph(line, source);

Bokeh.Plotting.show(plot);
</script>

将以上代码保存为网页,然后在选定的浏览器中打开它。

bokehjs libraries