.. _first_steps_9:

First steps 9: Using widgets
============================

In the :ref:`previous first steps guides <first_steps_8>`, you used different
sources and structures to import and filter data.

In this section, you will add interactive widgets to your plots.

Adding widgets
--------------

Widgets are additional visual elements that you can include in your
visualization. Use widgets to display additional information or to
interactively control elements of your Bokeh document, for example:

.. bokeh-plot:: docs/first_steps/examples/first_steps_9_widgets.py
    :source-position: none

This Bokeh document combines a plot with three widgets:

* A :class:`~bokeh.models.widgets.markups.Div` widget to display HTML text
* A :class:`~bokeh.models.widgets.inputs.Spinner` widget to select a numeric
  value
* A :class:`~bokeh.models.widgets.sliders.RangeSlider` widget to adjust a
  range

See :ref:`userguide_interaction_widgets_examples` in the user guide for a
complete list of Bokeh's widgets.

Follow these steps to recreate the example from above:

1. Import the ``Div``, ``RangeSlider``, and ``Spinner`` widgets
   from ``bokeh.models``:

    .. code-block:: python

        from bokeh.models import Div, RangeSlider, Spinner

2. Set up your data, your figure, and your renderer:

    .. code-block:: python

        x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        y = [4, 5, 5, 7, 2, 6, 4, 9, 1, 3]

        output_file("first_steps.html")

        p = figure(x_range=(1,9), plot_width=500, plot_height=250)
        points = p.circle(x=x, y=y, size=30, fill_color="#21a7df")

3. Create a ``Div`` object and pass it some HTML code as a string:

    .. code-block:: python

        div = Div(
            text="""
                <p>Select the circle's size using this control element:</p>
                """,
            width=200,
            height=30,
        )

4. Create a ``Spinner`` object:

    .. code-block:: python

        spinner = Spinner(
            title="Circle size",  # a string to display above the widget
            low=0,  # the lowest possible number to pick
            high=60,  # the highest possible number to pick
            step=5,  # the increments by which the number can be adjusted
            value=points.glyph.size,  # the initial value to display in the widget
            width=200,  #  the width of the widget in pixels
            )

5. To link the value generated by the spinner to the ``size`` property of your
   glyph, use the :func:`~bokeh.model.Model.js_link` function. This function
   uses JavaScript to interactively link two Bokeh models. The first argument
   you pass to this function is the attribute of your spinner (``"value"``)
   that you want to link to your circle glyphs. The second attribute is the
   glyph you want to link to your spinner (``points.glyph``). The third
   argument is the property of your glyph that you want to link to your
   spinner's ``value``:

    .. code-block:: python

        spinner.js_link("value", points.glyph, "size")

6. Create a RangeSlider object:

    .. code-block:: python

        range_slider = RangeSlider(
            title="Adjust x-axis range", # a title to display above the slider
            start=0,  # set the minimum value for the slider
            end=10,  # set the maximum value for the slider
            step=1,  # increments for the slider
            value=(p.x_range.start, p.x_range.end),  # initial values for slider
            )

7. To link the values generated by the RangeSlider to the existing plot, use the
   :func:`~bokeh.model.Model.js_link` function again. This time, however, you
   need to assign two values at once: the beginning of the plot's x-axis and
   the end of its x-axis. The RangeSlider returns a tuple of those two values.
   Therefore, you need to use the ``attr_selector`` of the ``js_link()``
   function to tell Bokeh which part of the Tuple to assign to either the start
   or the end of the plot's x-axis:

    .. code-block:: python

        range_slider.js_link("value", p.x_range, "start", attr_selector=0)
        range_slider.js_link("value", p.x_range, "end", attr_selector=1)

8. Create a layout with all the elements of your dashboard and display it in a
   browser:

    .. code-block:: python

        layout = layout([
            [div, spinner],
            [range_slider],
            [p],
        ])

        show(layout)

This is what the completed example looks like:

.. literalinclude:: examples/first_steps_9_widgets.py
   :language: python
   :emphasize-lines: 2,14-20,23-31,34-42

.. seealso::
    To learn more about Bokeh's widgets and building interactive dashboards, see
    :ref:`userguide_interaction_widgets` in the user guide.

    To learn about creating interactive legends, see
    :ref:`userguide_interaction_legends` in the user guide.

    See :ref:`userguide_interaction_jscallbacks` in the user guide to learn more
    about adding custom JavaScript code that you can use in combination
    with widgets, among other things.

    To learn more about combining widgets and plots into layouts, see
    :ref:`userguide_layout` in the user guide.

Using widgets with a Bokeh server
---------------------------------

Another way to use widgets is with a Bokeh server application. Bokeh includes a
standalone server component. Use the Bokeh server if you want to connect your
JavaScript-based visualization running in a browser to Python code running on a
server.

Use this command on a command line to start Bokeh in server mode:

.. code-block:: sh

    bokeh serve

You can use Bokeh Server to build complex dashboards and interactive
applications. Some of the capabilities of the Bokeh server include:

* UI widgets and plot selections that drive computations and plot updates
* Streaming live data to automatically updating plots
* Intelligent server-side downsampling of large datasets
* Sophisticated glyph re-writing and transformations for “Big Data”
* Plot and dashboard publishing for wider audiences

This is an example of a simple Bokeh server app. Adjust the sliders in the
widgets on the left to change the sine wave on the right:

.. raw:: html

    <div>
    <iframe
        src="https://demo.bokeh.org/sliders"
        frameborder="0"
        style="overflow:hidden;height:460px;width: 120%;
        -moz-transform: scale(0.85, 0.85);
        -webkit-transform: scale(0.85, 0.85);
        -o-transform: scale(0.85, 0.85);
        -ms-transform: scale(0.85, 0.85);
        transform: scale(0.85, 0.85);
        -moz-transform-origin: top left;
        -webkit-transform-origin: top left;
        -o-transform-origin: top left;
        -ms-transform-origin: top left;
        transform-origin: top left;"
        height="460"
    ></iframe>
    </div>

Find the source code for this Bokeh server app in the
`Bokeh repository on GitHub <https://github.com/bokeh/bokeh/blob/master/examples/app/sliders.py>`_.
For more examples of Bokeh server applications, see the
:ref:`gallery_server_examples` section of the :ref:`gallery`.

.. seealso::
    For information on using the server and writing Bokeh server plots
    and apps, see :ref:`userguide_server` in the user guide.

    For more examples of Bokeh server applications, see the
    :ref:`gallery_server_examples` section of the :ref:`gallery`.

    An easy way to create more complex dashboards is to use
    `Panel (https://panel.holoviz.org) <https://panel.holoviz.org/index.html>`_.
    Panel is a separate Python library that uses Bokeh and Bokeh server in the
    background.

Next steps
----------

Congratulations, you have completed all of Bokeh's first steps guides!

More information about Bokeh is available in the :ref:`user guide <userguide>`.
For more in-depth information about all aspects of Bokeh, see the
:ref:`reference guide <refguide>`.

For more examples of what you can do with Bokeh, check the :ref:`gallery` and
the :bokeh-tree:`examples` directory in Bokeh's GitHub repository.

Finally, on the `Bokeh community page <https://bokeh.org/community/>`_, you can
find links and information about asking for help and contributing to Bokeh and
the Bokeh community.

.. panels::
    :column: col-lg-12 col-md-12 col-sm-12 col-xs-12 p-2

    ---
    :card: + text-left
    .. link-button:: first_steps_8.html
        :text: Previous
        :classes: stretched-link
