Developing with JavaScript#

BokehJS is a client-side library that lets you create interactive plots and applications. It takes care of drawing, rendering, and event handling. The Bokeh Python library (and libraries for other languages such as R, Scala, and Julia) enables convenient high-level interaction with BokehJS, so you don’t have to worry about JavaScript or web development.

However, BokehJS also has its own API that lets you do pure JavaScript development using BokehJS directly. Additionally, Extending Bokeh with custom models typically require direct interaction with BokehJS.

Warning

The BokehJS APIs is still in development and may undergo changes in future releases.

Obtaining BokehJS#

BokehJS is available via CDN and npm. See the Installing standalone BokehJS section of the Installation details page for more details.

Low-level models#

Generally, the low-level models for plots and applications (such as guides, glyphs, widgets) match the Bokeh Python models exactly. The reference guide is therefore the primary reference for BokehJS models, even though it focuses on Python.

Whereas the Python library is organized hierarchically, JavaScript models are all in one flat Bokeh module. Typically any Python ClassName is available as Bokeh.ClassName in JavaScript. For a complete list of JavaScript models, see bokehjs/src/lib/api/models.ts.

When creating models in JavaScript, make a JavaScript object of all the keyword arguments you’d pass to the Python object initializer. Here is an example of how to initialize a Range1d model in both languages:

  • Python

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

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

This pattern works in all similar situations. Once you create a Bokeh model, you can set its properties in exactly the same way in both languages. For example, xdr.end = 30 sets the end value to 30 on the Range1d model above in both Python and JavaScript.

Below is an example that creates a plot with axes, grids, and a line glyph from scratch. Compare with samples in examples/models and you’ll see that the code in Python and JavaScript is nearly identical at this level:

// 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);

The code above generates the following plot:

Interfaces#

Similar to the Python Bokeh library, BokehJS provides various higher-level interfaces. These interfaces let you interact with and compose low-level model objects. The higher-level interfaces comprise Bokeh.Plotting and Bokeh.Charts.

Note

Starting from version 0.12.2 these APIs make up the BokehJS API in the bokeh-api.js file. You’ll have to import this file in addition to bokeh.js to enable these APIs.

Bokeh.Plotting#

The JavaScript Bokeh.Plotting API is a port of the Python bokeh.plotting interface. Accordingly, the information in the Plotting with basic glyphs section of the User guide can be a useful reference in addition to the material provided here.

The JavaScript sample below is very similar to the Python code in examples/plotting/file/color_scatter.py:

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() * 0.4 + 1.7)
    }
}

// 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" }, {
    source: source,
    radius: radii,
    fill_color: { field: "colors" },
    fill_alpha: 0.6,
    line_color: null
});

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

The code above generates the following plot:

Bokeh.Charts#

The JavaScript Bokeh.Charts API is a high-level charting interface that is unique to BokehJS. The API supports two high-level charts: pie and bar.

Bokeh.Charts.pie#

The following lets you create basic pie charts with Bokeh.Charts.pie:

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

Where data is a JavaScript object that has labels and values keys and options is an object that can include any of the following optional keys:

width

number — chart width in pixels

height

number — chart height in pixels

inner_radius

number — inner radius for wedges in pixels

outer_radius

number — outer radius for wedges in pixels

start_angle

number — start angle for wedges in radians

end_angle

number — end angle for wedges in radians

center

[number, number](x, y) location of the pie center in pixels

palette

Palette | Array<Color> — a named palette or list of colors to color-map the values

slice_labels

“labels” | “values” | “percentages” — what the tooltip should show

By default, plots created with Bokeh.Charts.pie automatically add a tooltip and hover policy. Here is an example of a pie chart and the plot it generates:

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);

The code above generates the following plot:

Bokeh.Charts.bar#

The following lets you create basic bar charts with Bokeh.Charts.bar:

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

Where data is an array with entries representing rows of a data table. The first row should contain the column headers. Here is an example of some sales data from different regions for different years:

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

Similar to the pie chart, the options parameter is an object that can include any of the following optional keys:

width

number — chart width in pixels

height

number — chart height in pixels

stacked

boolean — whether the bars should be stacked or not

orientation

“horizontal” | “vertical” — how the bars should be oriented

bar_width

number — width of each bar in pixels

palette

Palette | Array<Color> — a named palette or list of colors to color-map the values

axis_number_format

string — a format string to use for axis ticks

By default, plots created with Bokeh.Charts.bar automatically add a tooltip and hover policy. Here is an example of a bar chart and the plot it generates:

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}));

The code above generates the following plot:

Known Issues#

  • #11016 Figure name passed to renderer.glyph.name but not renderer.name

  • #11034 Palettes not accessible by name for ColorMapper objects in BokehJS

  • #11035 Bokeh.Widgets.Div() missing tools, required by Bokeh.Plotting.gridplot()

  • #11036 Making axis range padding persistent requires changing ._initial_range_padding as well

  • #11037 Using sizing_mode in gridplot layouts requires explicit assignment

  • #11038 Calling figure({title:”some title”}) replaces Title object with string, prevents subsequent updates to title text

Minimal example#

The following basic example shows how to import libraries and create and modify plots.

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

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

The code above generates the following plot: