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中创建模型时,创建一个包含所有关键字参数的JavaScript对象,这些参数将传递给Python对象初始化器。以下是如何在两种语言中初始化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 是一个包含 labelsvalues 键的 JavaScript 对象,而 options 是一个可以包含 以下任意可选键的对象:

width:

number — 图表宽度,单位为像素

height:

number — 图表高度,单位为像素

inner_radius:

number — 楔形的内半径,单位为像素

outer_radius:

number — 楔形外半径,单位为像素

start_angle:

number — 楔形的起始角度,以弧度表示

end_angle:

number — 楔形的结束角度,以弧度表示

center:

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

palette:

调色板 | 数组<颜色> — 一个命名的调色板或颜色列表,用于将值映射为颜色

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:

调色板 | 数组<颜色> — 一个命名的调色板或颜色列表,用于将值映射为颜色

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.2.min.js"></script>
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.6.2.min.js"></script>
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.6.2.min.js"></script>
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.6.2.min.js"></script>
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.6.2.min.js"></script>
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-api-3.6.2.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>

上面的代码生成以下图表: