Widgets and DOM elements#

Widgets are interactive control and display elements that can be added to Bokeh documents to provide a front end user interface to a visualization. Widgets can be added directly to the document root or be nested inside a layout.

Bokeh’s widgets offer a range of interactive features that you can use to drive new computations, update plots, and connect to other programmatic functionality.

Bokeh provides a simple default set of widgets. You can create your own custom widgets, or wrap different third party widget libraries by creating custom extensions as described in Custom extensions.

Widget interactivity#

While some widgets are only meant to display data, others can be used to interactively manipulate data and properties of objects in your visualization.

Bokeh uses callbacks to handle these interactions. There are two types of callbacks:

Which one to use depends on whether you are using Bokeh server or are generating standalone HTML output:

  • If you want to use widgets to interact with Bokeh objects in a standalone HTML document, the browser needs to handle all interactivity. Therefore, you can only use JavaScript callbacks. You can write your own Javascript code, or use Bokeh’s pre-defined Python conveniences such as the js_link function or a SetValue object which generate the necessary JavaScript code for you.

  • If you want to use widgets in connection with a Bokeh server, the server can handle some interactivity. This allows you to use callbacks written in Python. Additionally, since the visualization itself is displayed in a browser, you still can use JavaScript callbacks as well!

Widget tooltips#

You can attach tooltips to widgets. This can be helpful to provide additional information about the widget’s purpose or use, for example.

Hover over the question mark icon next to “Choose values” to see the tooltip.

See UI elements supporting tooltips for more information about adding tooltips to widgets.

Bokeh’s built-in widgets#

The sections below are examples for all widgets available in Bokeh. Many of the examples produce print output using the JavaScript console.log function. You can see this output in your browser’s JavaScript console log.

AutocompleteInput#

The AutocompleteInput widget is a general-purpose text input widget that uses a list of possible inputs to provide autocomplete while typing.

The default value for search_strategy property is "starts_with", which will match against the start of the possible inputs. Changing search_strategy to "includes" means that matches against any substring of the possible inputs will be shown:

from bokeh.io import show
from bokeh.models import AutocompleteInput
from bokeh.sampledata.world_cities import data

completion_list = data["name"].tolist()

auto_complete_input =  AutocompleteInput(title="Enter a city:", completions=completion_list, search_strategy="includes")

show(auto_complete_input)

More information about buttons can be found in the reference guide entry for AutocompleteInput.

Button#

Bokeh provides a simple Button:

from bokeh.io import show
from bokeh.models import Button, CustomJS

button = Button(label="Foo", button_type="success")
button.js_on_event("button_click", CustomJS(code="console.log('button: click!', this.toString())"))

show(button)

Use the button’s button_type property to change the style of the button. See button_type for possible values.

Optionally, you can add an icon to a button by passing one of Bokeh’s icon objects to the button’s icon parameter:

from bokeh.io import show
from bokeh.models import BuiltinIcon, Button, SetValue

icon = BuiltinIcon("settings", size="1.2em", color="white")
button = Button(label="Foo", icon=icon, button_type="primary")
button.js_on_event("button_click", SetValue(button, "label", "Bar"))

show(button)

Bokeh supports the following kinds of icons on buttons:

More information about buttons can be found in the reference guide entry for Button.

CheckboxButtonGroup#

Bokeh also provides a checkbox button group, that can have multiple options selected simultaneously:

from bokeh.io import show
from bokeh.models import CheckboxButtonGroup, CustomJS

LABELS = ["Option 1", "Option 2", "Option 3"]

checkbox_button_group = CheckboxButtonGroup(labels=LABELS, active=[0, 1])
checkbox_button_group.js_on_event("button_click", CustomJS(args=dict(btn=checkbox_button_group), code="""
    console.log('checkbox_button_group: active=' + btn.active, this.toString())
"""))

show(checkbox_button_group)

More information can be found in the reference guide entry for CheckboxButtonGroup.

CheckboxGroup#

A standard checkbox:

from bokeh.io import show
from bokeh.models import CheckboxGroup, CustomJS

LABELS = ["Option 1", "Option 2", "Option 3"]

checkbox_group = CheckboxGroup(labels=LABELS, active=[0, 1])
checkbox_group.js_on_change('active', CustomJS(code="""
    console.log('checkbox_group: active=' + this.active, this.toString())
"""))

show(checkbox_group)

More information can be found in the reference guide entry for CheckboxGroup.

ColorPicker#

A widget to allow the user to specify an RGB color value.

from bokeh.layouts import column
from bokeh.models import ColorPicker
from bokeh.plotting import figure, show

plot = figure(x_range=(0, 1), y_range=(0, 1), width=350, height=350)
line = plot.line(x=(0,1), y=(0,1), color="black", line_width=4)

picker = ColorPicker(title="Line Color")
picker.js_link('color', line.glyph, 'line_color')

show(column(plot, picker))

More information can be found in the reference guide entry for ColorPicker.

DataCube#

Bokeh provides a data cube widget based capable of aggregating hierarchical data. Note that since the data cube is configured with a data source object, any plots that share this data source will automatically have selections linked between the plot and the table (even in static HTML documents).

from bokeh.io import show
from bokeh.models import (ColumnDataSource, DataCube, GroupingInfo,
                          StringFormatter, SumAggregator, TableColumn)

source = ColumnDataSource(data=dict(
    d0=['A', 'E', 'E', 'E', 'J', 'L', 'M'],
    d1=['B', 'D', 'D', 'H', 'K', 'L', 'N'],
    d2=['C', 'F', 'G', 'H', 'K', 'L', 'O'],
    px=[10, 20, 30, 40, 50, 60, 70],
))

target = ColumnDataSource(data=dict(row_indices=[], labels=[]))

formatter = StringFormatter(font_style='bold')

columns = [
    TableColumn(field='d2', title='Name', width=80, sortable=False, formatter=formatter),
    TableColumn(field='px', title='Price', width=40, sortable=False),
]

grouping = [
    GroupingInfo(getter='d0', aggregators=[SumAggregator(field_='px')]),
    GroupingInfo(getter='d1', aggregators=[SumAggregator(field_='px')]),
]

cube = DataCube(source=source, columns=columns, grouping=grouping, target=target)

show(cube)

More information can be found in the reference guide entry for DataTable.

DataTable#

Bokeh provides a sophisticated data table widget. Note that since the table is configured with a data source object, any plots that share this data source will automatically have selections linked between the plot and the table (even in static HTML documents).

from datetime import date
from random import randint

from bokeh.io import show
from bokeh.models import ColumnDataSource, DataTable, DateFormatter, TableColumn

data = dict(
        dates=[date(2014, 3, i+1) for i in range(10)],
        downloads=[randint(0, 100) for i in range(10)],
    )
source = ColumnDataSource(data)

columns = [
        TableColumn(field="dates", title="Date", formatter=DateFormatter()),
        TableColumn(field="downloads", title="Downloads"),
    ]
data_table = DataTable(source=source, columns=columns, width=400, height=280)

show(data_table)

More information can be found in the reference guide entry for DataTable.

DatePicker#

A widget to allow the user to specify a date value.

from bokeh.io import show
from bokeh.models import CustomJS, DatePicker

date_picker = DatePicker(
    title="Select date",
    value="2019-09-20",
    min_date="2019-08-01",
    max_date="2019-10-30",
)
date_picker.js_on_change("value", CustomJS(code="""
    console.log("date_picker: value=" + this.value, this.toString())
"""))

show(date_picker)

More information can be found in the reference guide entry for DatePicker.

DateRangePicker#

A widget to allow the user to specify a range between two date values.

from bokeh.io import show
from bokeh.models import CustomJS, DateRangePicker

date_range_picker = DateRangePicker(
    title="Select date range",
    value=("2019-09-20", "2019-10-15"),
    min_date="2019-08-01",
    max_date="2019-10-30",
    width=400,
)
date_range_picker.js_on_change("value", CustomJS(code="""
    console.log("date_range_picker: value=" + this.value, this.toString())
"""))

show(date_range_picker)

More information can be found in the reference guide entry for DateRangePicker.

MultipleDatePicker#

A widget to allow the user to specify multiple date values.

from bokeh.io import show
from bokeh.models import CustomJS, MultipleDatePicker

multiple_date_picker = MultipleDatePicker(
    title="Select dates",
    value=["2019-09-20", "2019-09-21", "2019-10-15"],
    min_date="2019-08-01",
    max_date="2019-10-30",
    width=400,
)
multiple_date_picker.js_on_change("value", CustomJS(code="""
    console.log("multiple_date_picker: value=" + this.value, this.toString())
"""))

show(multiple_date_picker)

More information can be found in the reference guide entry for MultipleDatePicker.

DatetimePicker#

A widget to allow the user to specify a date and time value.

from bokeh.io import show
from bokeh.models import CustomJS, DatetimePicker

datetime_picker = DatetimePicker(
    title="Select date and time",
    value="2019-09-20T12:37:51",
    min_date="2019-08-01T09:00:00",
    max_date="2019-10-30T18:00:00",
)
datetime_picker.js_on_change("value", CustomJS(code="""
    console.log("datetime_picker: value=" + this.value, this.toString())
"""))

show(datetime_picker)

More information can be found in the reference guide entry for DatetimePicker.

DatetimeRangePicker#

A widget to allow the user to specify a range between two date and time values.

from bokeh.io import show
from bokeh.models import CustomJS, DatetimeRangePicker

datetime_range_picker = DatetimeRangePicker(
    title="Select date and time range",
    value=("2019-09-20T12:37:51", "2019-10-15T17:59:18"),
    min_date="2019-08-01T09:00:00",
    max_date="2019-10-30T18:00:00",
    width=400,
)
datetime_range_picker.js_on_change("value", CustomJS(code="""
    console.log("datetime_range_picker: value=" + this.value, this.toString())
"""))

show(datetime_range_picker)

More information can be found in the reference guide entry for DatetimeRangePicker.

MultipleDatetimePicker#

A widget to allow the user to specify multiple date and time values.

from bokeh.io import show
from bokeh.models import CustomJS, MultipleDatetimePicker

multiple_datetime_picker = MultipleDatetimePicker(
    title="Select dates and times",
    value=[
        "2019-09-20T12:59:31",
        "2019-09-21T13:31:00",
        "2019-10-15T14:00:18",
    ],
    min_date="2019-08-01T09:00:00",
    max_date="2019-10-30T18:00:00",
    width=400,
)
multiple_datetime_picker.js_on_change("value", CustomJS(code="""
    console.log("multiple_datetime_picker: value=" + this.value, this.toString())
"""))

show(multiple_datetime_picker)

More information can be found in the reference guide entry for MultipleDatetimePicker.

TimePicker#

A widget to allow the user to specify a time value.

from bokeh.io import show
from bokeh.models import CustomJS, TimePicker

time_picker = TimePicker(title="Select time", value="12:59:31", min_time="09:00:00", max_time="18:00:00")
time_picker.js_on_change("value", CustomJS(code="""
    console.log("time_picker: value=" + this.value, this.toString())
"""))

show(time_picker)

More information can be found in the reference guide entry for TimePicker.

DateRangeSlider#

The Bokeh date range-slider can be configured with start and end date values, a step size in units of days, an initial value, and a title:

from datetime import date

from bokeh.io import show
from bokeh.models import CustomJS, DateRangeSlider

date_range_slider = DateRangeSlider(value=(date(2016, 1, 1), date(2016, 12, 31)),
                                    start=date(2015, 1, 1), end=date(2017, 12, 31))
date_range_slider.js_on_change("value", CustomJS(code="""
    console.log('date_range_slider: value=' + this.value, this.toString())
"""))

show(date_range_slider)

More information can be found in the reference guide entry for DateRangeSlider.

DateSlider#

The Bokeh date slider can be configured with start and end date values, a step size in units of days, an initial value, and a title:

from datetime import date

from bokeh.io import show
from bokeh.models import CustomJS, DateSlider

date_slider = DateSlider(value=date(2016, 1, 1),
                         start=date(2015, 1, 1),
                         end=date(2017, 12, 31))
date_slider.js_on_change("value", CustomJS(code="""
    console.log('date_slider: value=' + this.value, this.toString())
"""))

show(date_slider)

More information can be found in the reference guide entry for DateSlider.

DatetimeRangeSlider#

The Bokeh datetime range slider is the same as the date range slider except that it uses datetimes that include hours, minutes and seconds:

from datetime import datetime

from bokeh.io import show
from bokeh.models import CustomJS, DatetimeRangeSlider

datetime_range_slider = DatetimeRangeSlider(value=(datetime(2022, 3, 8, 12), datetime(2022, 3, 25, 18)),
                                            start=datetime(2022, 3, 1), end=datetime(2022, 3, 31))
datetime_range_slider.js_on_change("value", CustomJS(code="""
    console.log('datetime_range_slider: value=' + this.value, this.toString())
"""))

show(datetime_range_slider)

More information can be found in the reference guide entry for DatetimeRangeSlider.

Div#

A widget for displaying text that can support HTML in a <div> tag:

from bokeh.io import show
from bokeh.models import Div

div = Div(text="""Your <a href="https://en.wikipedia.org/wiki/HTML">HTML</a>-supported text is initialized with the <b>text</b> argument.  The
remaining div arguments are <b>width</b> and <b>height</b>. For this example, those values
are <i>200</i> and <i>100</i>, respectively.""",
width=200, height=100)

show(div)

More information can be found in the reference guide entry for Div.

FileInput#

A widget allowing users to choose a file and store its contents.

from bokeh.io import show
from bokeh.models import FileInput

file_input = FileInput()

show(file_input)

More information can be found in the reference guide entry for FileInput.

HelpButton#

A widget that provides a help symbol that displays additional text in a Tooltip when hovered over or clicked.

The default behavior of the help button’s tooltip is as follows:

  • If the mouse is hovered over the help button, the tooltip is closed automatically once the mouse is moved away.

  • If the help button is clicked, the tooltip will be persistent. The user needs to click the “x” symbol in the top right corner of the tooltip to close it.

from bokeh.io import show
from bokeh.models import HelpButton, Tooltip
from bokeh.models.dom import HTML

help_button = HelpButton(tooltip=Tooltip(content=HTML("""
This is a tooltip with additional information.<br />
It can use <b>HTML tags</b> like <a href="https://bokeh.org">links</a>!
"""), position="right"))

show(help_button)

More information can be found in the reference guide entry for HelpButton.

MultiChoice#

A multi-select widget to present multiple available options in a compact horizontal layout:

from bokeh.io import show
from bokeh.models import CustomJS, MultiChoice

OPTIONS = ["foo", "bar", "baz", "quux"]

multi_choice = MultiChoice(value=["foo", "baz"], options=OPTIONS)
multi_choice.js_on_change("value", CustomJS(code="""
    console.log('multi_choice: value=' + this.value, this.toString())
"""))

show(multi_choice)

More information can be found in the reference guide entry for MultiChoice.

MultiSelect#

A multi-select widget to present multiple available options in vertical list:

from bokeh.io import show
from bokeh.models import CustomJS, MultiSelect

OPTIONS = [("1", "foo"), ("2", "bar"), ("3", "baz"), ("4", "quux")]

multi_select = MultiSelect(value=["1", "2"], options=OPTIONS)
multi_select.js_on_change("value", CustomJS(code="""
    console.log('multi_select: value=' + this.value, this.toString())
"""))

show(multi_select)

More information can be found in the reference guide entry for MultiSelect.

NumericInput#

A widget to allow the user to enter a numeric value.

from bokeh.io import show
from bokeh.models import NumericInput

numeric_input = NumericInput(value=1, low=1, high=10, title="Enter a number between 1 and 10:")

show(numeric_input)

More information can be found in the reference guide entry for NumericInput.

Paragraph#

A widget for displaying a block of text in an HTML <p> tag:

from bokeh.io import show
from bokeh.models import Paragraph

p = Paragraph(text="""Your text is initialized with the 'text' argument.  The
remaining Paragraph arguments are 'width' and 'height'. For this example, those values
are 200 and 100, respectively.""",
width=200, height=100)

show(p)

More information can be found in the reference guide entry for Paragraph.

PasswordInput#

A text input that obscures the entered text:

from bokeh.io import show
from bokeh.models import CustomJS, PasswordInput

password_input = PasswordInput(placeholder="enter password...")
password_input.js_on_change("value", CustomJS(code="""
    console.log('password_input: value=' + this.value, this.toString())
"""))

show(password_input)

More information can be found in the reference guide entry for PasswordInput.

PreText#

A widget for displaying a block of pre-formatted text in an HTML <pre> tag:

from bokeh.io import show
from bokeh.models import PreText

pre = PreText(text="""Your text is initialized with the 'text' argument.

The remaining Paragraph arguments are 'width' and 'height'. For this example,
those values are 500 and 100, respectively.""",
width=500, height=100)

show(pre)

More information can be found in the reference guide entry for PreText.

RadioButtonGroup#

A radio button group can have at most one selected button at a time:

from bokeh.io import show
from bokeh.models import CustomJS, RadioButtonGroup

LABELS = ["Option 1", "Option 2", "Option 3"]

radio_button_group = RadioButtonGroup(labels=LABELS, active=0)
radio_button_group.js_on_event("button_click", CustomJS(args=dict(btn=radio_button_group), code="""
    console.log('radio_button_group: active=' + btn.active, this.toString())
"""))

show(radio_button_group)

More information can be found in the reference guide entry for RadioButtonGroup.

RadioGroup#

A radio group uses standard radio button appearance:

from bokeh.io import show
from bokeh.models import CustomJS, RadioGroup

LABELS = ["Option 1", "Option 2", "Option 3"]

radio_group = RadioGroup(labels=LABELS, active=0)
radio_group.js_on_event('button_click', CustomJS(code="""
    console.log('radio_group: active=' + this.origin.active, this.toString())
"""))

show(radio_group)

More information can be found in the reference guide entry for RadioGroup.

RangeSlider#

The Bokeh range-slider can be configured with start and end values, a step size, an initial value, and a title:

from bokeh.io import show
from bokeh.models import CustomJS, RangeSlider

range_slider = RangeSlider(start=0, end=10, value=(1,9), step=.1, title="Stuff")
range_slider.js_on_change("value", CustomJS(code="""
    console.log('range_slider: value=' + this.value, this.toString())
"""))

show(range_slider)

More information can be found in the reference guide entry for RangeSlider.

Select#

A single selection widget:

from bokeh.io import show
from bokeh.models import CustomJS, Select

select = Select(title="Option:", value="foo", options=["foo", "bar", "baz", "quux"])
select.js_on_change("value", CustomJS(code="""
    console.log('select: value=' + this.value, this.toString())
"""))

show(select)

More information can be found in the reference guide entry for Select.

Slider#

The Bokeh slider can be configured with start and end values, a step size, an initial value, and a title:

from bokeh.io import show
from bokeh.models import CustomJS, Slider

slider = Slider(start=0, end=10, value=1, step=.1, title="Stuff")
slider.js_on_change("value", CustomJS(code="""
    console.log('slider: value=' + this.value, this.toString())
"""))

show(slider)

More information can be found in the reference guide entry for Slider.

Spinner#

A numeric spinner widget:

import numpy as np

from bokeh.layouts import column, row
from bokeh.models import Spinner
from bokeh.plotting import figure, show

x = np.random.rand(10)
y = np.random.rand(10)

p = figure(x_range=(0, 1), y_range=(0, 1))
points = p.scatter(x=x, y=y, size=4)

spinner = Spinner(title="Glyph size", low=1, high=40, step=0.5, value=4, width=80)
spinner.js_link('value', points.glyph, 'size')

show(row(column(spinner, width=100), p))

More information can be found in the reference guide entry for Spinner.

Switch#

An on/off toggle switch:

from bokeh.io import show
from bokeh.models import CustomJS, Switch

switch = Switch(active=True)
switch.js_on_change("active", CustomJS(code="""
    console.log('switch: active=' + this.active, this.toString())
"""))
show(switch)

More information can be found in the reference guide entry for Switch.

Tabs#

Tab panes allow multiple plots or layouts to be shown in selectable tabs:

from bokeh.models import TabPanel, Tabs, Tooltip
from bokeh.models.layouts import Row
from bokeh.plotting import figure, show

p1 = figure(width=300, height=300)
p1.scatter([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)

p2 = figure(width=300, height=300)
p2.line([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], line_width=3, color="navy", alpha=0.5)

p3 = figure(width=300, height=300)
p3.scatter([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)

p4 = figure(width=300, height=300)
p4.line([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], line_width=3, color="navy", alpha=0.5)

tabs0 = Tabs(tabs=[
    TabPanel(child=p1, title="circle"),
    TabPanel(child=p2, title="line"),
])

tabs1 = Tabs(tabs=[
    TabPanel(child=p1, title="circle", tooltip=Tooltip(content="This is the first tab.", position="bottom_center")),
    TabPanel(child=p2, title="line", tooltip=Tooltip(content="This is the second tab.", position="bottom_center")),
])

show(Row(tabs0, tabs1))

More information can be found in the reference guide entry for Tabs.

TextAreaInput#

A widget for collecting multiple lines of text from a user:

from bokeh.io import show
from bokeh.models import CustomJS, TextAreaInput

text_area_input = TextAreaInput(value="default", rows=6, title="Label:")
text_area_input.js_on_change("value", CustomJS(code="""
    console.log('text_area_input: value=' + this.value, this.toString())
"""))

show(text_area_input)

More information can be found in the reference guide entry for TextAreaInput.

TextInput#

A widget for collecting a line of text from a user:

from bokeh.io import show
from bokeh.models import CustomJS, TextInput

text_input = TextInput(value="default", title="Label:")
text_input.js_on_change("value", CustomJS(code="""
    console.log('text_input: value=' + this.value, this.toString())
"""))

show(text_input)

More information can be found in the reference guide entry for TextInput.

Toggle#

The toggle button holds an on/off state:

from bokeh.io import show
from bokeh.models import CustomJS, Toggle

toggle = Toggle(label="Foo", button_type="success")
toggle.js_on_event('button_click', CustomJS(args=dict(btn=toggle), code="""
    console.log('toggle: active=' + btn.active, this.toString())
"""))

show(toggle)

Like with a standard Button widget, the toggle button can also use an Icon (such as BuiltinIcon, SVGIcon, or TablerIcon).

More information can be found in the reference guide entry for Toggle.