<jupyter_start><jupyter_text>10. Parameters and Widgets In previous sections we have mostly been learning about using HoloViews to build visualizations. There is only so much information that can be packed on to the screen at once, and in practice it's often necessary to supply interactive widgets so the user can further select what is shown. HoloViews can provide widgets automatically for dimensions that have been declared on the data, but often you will want to express other types of user-settable parameters to control your plots. Here we will discover how to leverage the ``param``, ``paramnb`` and ``parambokeh`` libraries to declare your own custom parameters and how to link widgets to your visualization.<jupyter_code>import param
import paramnb
import parambokeh

import numpy as np
import holoviews as hv
from bokeh.document import Document

hv.extension('bokeh')<jupyter_output><empty_output><jupyter_text>Declaring parameters As a first step we need to declare a so called ``Parameterized`` class with a number of parameters, which will control our visualization. In this example we will stick with something simple and we will simply expose some styling options for a Curve plot, declaring ``alpha``, ``color``, and ``line_width`` parameters. We'll use a special type of ``Parameterized`` called a ``Stream`` that defines an ``event`` method that we will use later.<jupyter_code>class StyleOptions(hv.streams.Stream):

    alpha = param.Magnitude(default=0.8)
    
    color = param.ObjectSelector(default='red', objects=['red', 'green', 'blue'])
    
    line_width = param.Number(default=1, bounds=(0, 10))<jupyter_output><empty_output><jupyter_text>Displaying parameters We can automatically get a UI to control these parameters using the ``parambokeh`` and ``paramnb`` libraries. Simply call the ``Widgets`` function with a ``Parameterized`` instance as the first argument and it will display a set of widgets based on ``bokeh`` or ``ipywidgets``: ParamBokeh<jupyter_code>opts = StyleOptions()
parambokeh.Widgets(opts)<jupyter_output><empty_output><jupyter_text>ParamNB<jupyter_code>opts = StyleOptions()
paramnb.Widgets(opts)<jupyter_output><empty_output><jupyter_text>Linking parameters as streams As a final step we will link the Parameterized class and the widgets to an actual plot. To do this, we will declare a ``DynamicMap``, which sets the style options on an existing ``Curve``. The only thing we need to declare is that the ``Widgets`` should call the ``event`` method on our stream whenever the widget is updated. This will immediately link the widgets to the actual plot.<jupyter_code>opts = StyleOptions()
curve = hv.Curve(np.sin(np.linspace(0, np.pi*3, 100)))
dmap = hv.DynamicMap(lambda **kwargs: curve.opts(style=kwargs), streams=[opts])
paramnb.Widgets(opts, callback=opts.event, continuous_update=True)
dmap<jupyter_output><empty_output><jupyter_text>Laying out plots and widgets In a Jupyter notebook, the widgets and the plot they control can be in any cell, because the notebook ensures that all of them are laid out on to the screen.  When deploying the dashboard as a standalone bokeh app, we have to combine the plot and widgets into a single layout, because there is no default linear ordering of "cells" at the Bokeh server level. The easiest way to build such a layout is to use the BokehRenderer to convert our plot to a Bokeh model, then pass that to the ``parambokeh.Widgets`` call. We can also supply a ``view_position`` telling it how to lay out the widgets and plots.<jupyter_code>viewer = StyleOptions()
curve = hv.Curve(np.sin(np.linspace(0, np.pi*3, 100)))
dmap = hv.DynamicMap(lambda **kwargs: curve.opts(style=kwargs), streams=[viewer])

# Get bokeh model for the plot
plot = hv.renderer('bokeh').get_plot(dmap, doc=Document()).state

parambokeh.Widgets(viewer, callback=viewer.event, view_position='right',
                   continuous_update=True, plots=[plot])
## Exercise: Subclass the StyleOptions class and add a parameter to control the line_dash style option

# Hint: The valid options for line_dash are: 'solid', 'dashed', 'dotted', 'dotdash', 'dashdot'<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08594126143476168, 'fraction_numerical': 0.004333172845450169, 'mean_word_length': 5.701612903225806, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '381432', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 1187, 'n_tokens_neox': 1152, 'n_words': 509, 'path': 'notebooks/10-parameters-and-widgets.ipynb', 'repo_name': 'lancelot1969/jupytercon2017-holoviews-tutorial', 'size': '4154'}