BokehJS#

BokehJS 是一个客户端库,允许您创建交互式绘图和应用程序。它负责绘图、渲染和事件处理。Bokeh Python 库(以及 R、Scala 和 Julia 等其他语言的库)使您可以方便地与 BokehJS 进行高级交互,因此您无需担心 JavaScript 或 Web 开发。

但是,BokehJS 也有自己的 API,允许您直接使用 BokehJS 进行纯 JavaScript 开发。此外,自定义扩展(具有自定义模型)通常需要与 BokehJS 直接交互。

警告

BokehJS API 仍在开发中,可能会在将来的版本中发生更改。

获取 BokehJS#

BokehJS 可通过 CDN 和 npm 获取。有关更多详细信息,请参阅 安装独立 BokehJS 部分的 安装详细信息 页面。

低级模型#

通常,绘图和应用程序的低级模型(例如指南、图形、小部件)与 Bokeh Python 模型完全匹配。因此,参考指南 是 BokehJS 模型的主要参考,即使它侧重于 Python。

Python 库是按层次结构组织的,而 JavaScript 模型都在一个扁平的 Bokeh 模块中。通常,任何 Python ClassName 在 JavaScript 中都可用作 Bokeh.ClassName。有关 JavaScript 模型的完整列表,请参阅 bokehjs/src/lib/api/models.ts

在 JavaScript 中创建模型时,请创建一个包含您将传递给 Python 对象初始化程序的所有关键字参数的 JavaScript 对象。以下是如何在两种语言中初始化 Range1d 模型的示例

  • Python

    xdr = Range1d(start=-0.5, end=20.5)
    
  • JavaScript

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

此模式适用于所有类似情况。创建 Bokeh 模型后,您可以以完全相同的方式在两种语言中设置其属性。例如,xdr.end = 30 在 Python 和 JavaScript 中都将上述 Range1d 模型的 end 值设置为 30。

以下示例从头开始创建具有轴、网格和线图形的绘图。与 examples/models 中的示例进行比较,您会发现 Python 和 JavaScript 中的代码在这个级别上几乎完全相同

// create some data and a ColumnDataSource
const x = Bokeh.LinAlg.linspace(-0.5, 20.5, 10);
const y = x.map(function (v) { return v * 0.5 + 3.0; });
const source = new Bokeh.ColumnDataSource({ data: { x: x, y: y } });

// create some ranges for the plot
const xdr = new Bokeh.Range1d({ start: -0.5, end: 20.5 });
const ydr = new Bokeh.Range1d({ start: -0.5, end: 20.5 });

// make the plot
const plot = new Bokeh.Plot({
    title: "BokehJS Plot",
    x_range: xdr,
    y_range: ydr,
    width: 400,
    height: 400,
    background_fill_color: "#F2F2F7"
});

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

// add grids to the plot
const xgrid = new Bokeh.Grid({ ticker: xaxis.ticker, dimension: 0 });
const ygrid = new Bokeh.Grid({ ticker: yaxis.ticker, dimension: 1 });
plot.add_layout(xgrid);
plot.add_layout(ygrid);

// add a Line glyph
const 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);

上面的代码生成了以下绘图

接口#

与 Python Bokeh 库类似,BokehJS 提供了各种更高级别的接口。这些接口允许您与低级模型对象进行交互和组合。更高级别的接口包括 Bokeh.PlottingBokeh.Charts

注意

从版本 0.12.2 开始,这些 API 构成了 bokeh-api.js 文件中的 BokehJS API。您需要在导入 bokeh.js 之后导入此文件,才能启用这些 API。

Bokeh.Plotting#

JavaScript Bokeh.Plotting API 是 Python bokeh.plotting 接口的端口。因此,用户指南中 基本绘图 部分的信息可以作为除了这里提供的材料之外的有用参考。

下面的 JavaScript 示例与 examples/basic/scatters/color_scatter.py 中的 Python 代码非常相似

const plt = Bokeh.Plotting;

// set up some data
const M = 100;
const xx = [];
const yy = [];
const colors = [];
const radii = [];
for (let y = 0; y <= M; y += 4) {
    for (let x = 0; x <= M; x += 4) {
        xx.push(x);
        yy.push(y);
        colors.push(plt.color([50+2*x, 30+2*y, 150]));
        radii.push(Math.random() * 1.5);
    }
}
// create a data source
const source = new Bokeh.ColumnDataSource({
    data: { x: xx, y: yy, radius: radii, colors: colors }
});

// make the plot and add some tools
const tools = "pan,crosshair,wheel_zoom,box_zoom,reset,save";
const p = plt.figure({ title: "Colorful Scatter", tools: tools });

// call the circle glyph method to add some circle glyphs
const circles = p.circle({ field: "x" }, { field: "y" }, {field: "radius"}, {
    source: source,
    fill_color: { field: "colors" },
    fill_alpha: 0.6,
    line_color: null,
});

// show the plot
plt.show(p);

上面的代码生成了以下绘图

Bokeh.Charts#

JavaScript Bokeh.Charts API 是一个高级图表接口,是 BokehJS 独有的。该 API 支持两种高级图表:piebar

Bokeh.Charts.pie#

以下内容允许您使用 Bokeh.Charts.pie 创建基本的饼图

Bokeh.Charts.pie(data, { options })

其中 data 是一个 JavaScript 对象,它具有 labelsvalues 键,而 options 是一个可以包含以下任何可选键的对象

width:

number — 图表宽度(以像素为单位)

height:

number — 图表高度(以像素为单位)

inner_radius:

number — 扇形内半径(以像素为单位)

outer_radius:

number — 扇形外半径(以像素为单位)

start_angle:

number — 扇形起始角度(以弧度为单位)

end_angle:

number — 扇形结束角度(以弧度为单位)

center:

[number, number] — 饼图中心位置的 (x, y) 坐标(以像素为单位)

palette:

Palette | Array<Color> — 用于对值进行颜色映射的命名调色板或颜色列表

slice_labels:

“labels” | “values” | “percentages” — 工具提示应显示的内容

默认情况下,使用 Bokeh.Charts.pie 创建的绘图会自动添加工具提示和悬停策略。以下是一个 pie 图表的示例,以及它生成的绘图

const plt = Bokeh.Plotting;

const pie_data = {
    labels: ['Work', 'Eat', 'Commute', 'Sport', 'Watch TV', 'Sleep'],
    values: [8, 2, 2, 4, 0, 8],
};

const p1 = Bokeh.Charts.pie(pie_data);
const p2 = Bokeh.Charts.pie(pie_data, {
    inner_radius: 0.2,
    start_angle: Math.PI / 2
});
const p3 = Bokeh.Charts.pie(pie_data, {
    inner_radius: 0.2,
    start_angle: Math.PI / 6,
    end_angle: 5 * Math.PI / 6
});
const p4 = Bokeh.Charts.pie(pie_data, {
    inner_radius: 0.2,
    palette: "Oranges9",
    slice_labels: "percentages"
});

// add the plot to a document and display it
const doc = new Bokeh.Document();
doc.add_root(plt.gridplot(
                 [[p1, p2], [p3, p4]],
                 {width: 250, height: 250}));
Bokeh.embed.add_document_standalone(doc, document.currentScript.parentElement);

上面的代码生成了以下绘图

Bokeh.Charts.bar#

以下内容允许您使用 Bokeh.Charts.bar 创建基本的条形图

Bokeh.Charts.bar(data, { options })

其中 data 是一个数组,其条目代表数据表的行。第一行应包含列标题。以下是一些来自不同地区的不同年份的销售数据的示例

const data = [
    ['Region', 'Year', 'Sales'],
    ['East',   2015,    23000 ],
    ['East',   2016,    35000 ],
    ['West',   2015,    16000 ],
    ['West',   2016,    34000 ],
    ['North',  2016,    12000 ],
];

pie 图表类似,options 参数是一个可以包含以下任何可选键的对象

width:

number — 图表宽度(以像素为单位)

height:

number — 图表高度(以像素为单位)

stacked:

boolean — 条形是否应堆叠

orientation:

“horizontal” | “vertical” — 条形应如何定向

bar_width:

number — 每个条形的宽度(以像素为单位)

palette:

Palette | Array<Color> — 用于对值进行颜色映射的命名调色板或颜色列表

axis_number_format:

string — 用于轴刻度的格式字符串

默认情况下,使用 Bokeh.Charts.bar 创建的绘图会自动添加工具提示和悬停策略。以下是一个 bar 图表的示例,以及它生成的绘图

const plt = Bokeh.Plotting;

const bar_data = [
    ['City', '2010 Population', '2000 Population'],
    ['NYC', 8175000, 8008000],
    ['LA', 3792000, 3694000],
    ['Chicago', 2695000, 2896000],
    ['Houston', 2099000, 1953000],
    ['Philadelphia', 1526000, 1517000],
];

const p1 = Bokeh.Charts.bar(bar_data, {
    axis_number_format: "0.[00]a"
});
const p2 = Bokeh.Charts.bar(bar_data, {
    axis_number_format: "0.[00]a",
    stacked: true
});
const p3 = Bokeh.Charts.bar(bar_data, {
    axis_number_format: "0.[00]a",
    orientation: "vertical"
});
const p4 = Bokeh.Charts.bar(bar_data, {
    axis_number_format: "0.[00]a",
    orientation: "vertical",
    stacked: true
});

plt.show(plt.gridplot([[p1, p2], [p3, p4]], {width: 350, height: 350}));

上面的代码生成了以下绘图

最小示例#

以下基本示例显示了如何导入库以及创建和修改绘图。

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Complete Example</title>

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

<script>
//The order of CSS and JS imports above is important.
</script>
<script>
// create a data source to hold data
const source = new Bokeh.ColumnDataSource({
    data: { x: [], y: [] }
});

// make a plot with some tools
const plot = Bokeh.Plotting.figure({
    title: 'Example of random data',
    tools: "pan,wheel_zoom,box_zoom,reset,save",
    height: 300,
    width: 300
});

// add a line with data from the source
plot.line({ field: "x" }, { field: "y" }, {
    source: source,
    line_width: 2
});

// show the plot, appending it to the end of the current section
Bokeh.Plotting.show(plot);

function addPoint() {
    // add data --- all fields must be the same length.
    source.data.x.push(Math.random())
    source.data.y.push(Math.random())

    // update the data source with local changes
    source.change.emit()
}

const addDataButton = document.createElement("Button");
addDataButton.appendChild(document.createTextNode("Some data."));
document.currentScript.parentElement.appendChild(addDataButton);
addDataButton.addEventListener("click", addPoint);

addPoint();
addPoint();
</script>
</head>

<body>
</body>

</html>

上面的代码生成了以下绘图