We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Bokeh server warning message
the code server = renderer.app(dmap, show=True, new_window=True)
results in a warning message
WARNING:root:BokehServerWidgets24371: Setting non-parameter attribute display_options={'fps': 20} using a mechanism intended only for parameters

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `holoviews/plotting/bokeh/widgets.py`
Content:
```
1 from __future__ import unicode_literals
2 
3 import math
4 import json
5 from functools import partial
6 
7 import param
8 import numpy as np
9 from bokeh.models.widgets import Select, Slider, AutocompleteInput, TextInput, Div
10 from bokeh.layouts import widgetbox, row, column
11 
12 from ...core import Store, NdMapping, OrderedDict
13 from ...core.util import (drop_streams, unique_array, isnumeric,
14                           wrap_tuple_streams, unicode)
15 from ..widgets import NdWidget, SelectionWidget, ScrubberWidget
16 from .util import serialize_json
17 
18 
19 
20 class BokehServerWidgets(param.Parameterized):
21     """
22     BokehServerWidgets create bokeh widgets corresponding to all the
23     key dimensions found on a BokehPlot instance. It currently supports
24     to types of widgets sliders (which may be discrete or continuous)
25     and dropdown widgets letting you select non-numeric values.
26     """
27 
28     editable = param.Boolean(default=False, doc="""
29         Whether the slider text fields should be editable. Disabled
30         by default for a more compact widget layout.""")
31 
32     position = param.ObjectSelector(default='right',
33         objects=['right', 'left', 'above', 'below'])
34 
35     sizing_mode = param.ObjectSelector(default='fixed',
36         objects=['fixed', 'stretch_both', 'scale_width',
37                  'scale_height', 'scale_both'])
38 
39     width = param.Integer(default=250, doc="""
40         Width of the widget box in pixels""")
41 
42     basejs = param.String(default=None, precedence=-1, doc="""
43         Defines the local CSS file to be loaded for this widget.""")
44 
45     extensionjs = param.String(default=None, precedence=-1, doc="""
46         Optional javascript extension file for a particular backend.""")
47 
48     css = param.String(default=None, precedence=-1, doc="""
49         Defines the local CSS file to be loaded for this widget.""")
50 
51     def __init__(self, plot, renderer=None, **params):
52         super(BokehServerWidgets, self).__init__(**params)
53         self.plot = plot
54         streams = []
55         for stream in plot.streams:
56             if any(k in plot.dimensions for k in stream.contents):
57                 streams.append(stream)
58         self.dimensions, self.keys = drop_streams(streams,
59                                                   plot.dimensions,
60                                                   plot.keys)
61         if renderer is None:
62             backend = Store.current_backend
63             self.renderer = Store.renderers[backend]
64         else:
65             self.renderer = renderer
66         # Create mock NdMapping to hold the common dimensions and keys
67         self.mock_obj = NdMapping([(k, None) for k in self.keys],
68                                   kdims=self.dimensions)
69         self.widgets, self.lookups = self.get_widgets()
70         self.reverse_lookups = {d: {v: k for k, v in item.items()}
71                                 for d, item in self.lookups.items()}
72         self.subplots = {}
73         if self.plot.renderer.mode == 'default':
74             self.attach_callbacks()
75         self.state = self.init_layout()
76         self._queue = []
77 
78 
79     @classmethod
80     def create_widget(self, dim, holomap=None, editable=False):
81         """"
82         Given a Dimension creates bokeh widgets to select along that
83         dimension. For numeric data a slider widget is created which
84         may be either discrete, if a holomap is supplied or the
85         Dimension.values are set, or a continuous widget for
86         DynamicMaps. If the slider is discrete the returned mapping
87         defines a mapping between values and labels making it possible
88         sync the two slider and label widgets. For non-numeric data
89         a simple dropdown selection widget is generated.
90         """
91         label, mapping = None, None
92         if holomap is None:
93             if dim.values:
94                 if all(isnumeric(v) for v in dim.values):
95                     values = dim.values
96                     labels = [unicode(dim.pprint_value(v)) for v in dim.values]
97                     if editable:
98                         label = AutocompleteInput(value=labels[0], completions=labels,
99                                                   title=dim.pprint_label)
100                     else:
101                         label = Div(text='<b>%s</b>' % dim.pprint_value_string(labels[0]))
102                     widget = Slider(value=0, start=0, end=len(dim.values)-1, title=None, step=1)
103                     mapping = list(zip(values, labels))
104                 else:
105                     values = [(v, dim.pprint_value(v)) for v in dim.values]
106                     widget = Select(title=dim.pprint_label, value=values[0][0],
107                                     options=values)
108             else:
109                 start = dim.soft_range[0] if dim.soft_range[0] else dim.range[0]
110                 end = dim.soft_range[1] if dim.soft_range[1] else dim.range[1]
111                 dim_range = end - start
112                 int_type = isinstance(dim.type, type) and issubclass(dim.type, int)
113                 if isinstance(dim_range, int) or int_type:
114                     step = 1
115                 elif dim.step is not None:
116                     step = dim.step
117                 else:
118                     step = 10**((round(math.log10(dim_range))-3))
119                 if editable:
120                     label = TextInput(value=str(start), title=dim.pprint_label)
121                 else:
122                     label = Div(text='<b>%s</b>' % dim.pprint_value_string(start))
123                 widget = Slider(value=start, start=start,
124                                 end=end, step=step, title=None)
125         else:
126             values = (dim.values if dim.values else
127                       list(unique_array(holomap.dimension_values(dim.name))))
128             labels = [dim.pprint_value(v) for v in values]
129             if isinstance(values[0], np.datetime64) or isnumeric(values[0]):
130                 if editable:
131                     label = AutocompleteInput(value=labels[0], completions=labels,
132                                               title=dim.pprint_label)
133                 else:
134                     label = Div(text='<b>%s</b>' % (dim.pprint_value_string(labels[0])))
135                 widget = Slider(value=0, start=0, end=len(values)-1, title=None, step=1)
136             else:
137                 widget = Select(title=dim.pprint_label, value=values[0],
138                                 options=list(zip(values, labels)))
139             mapping = list(zip(values, labels))
140         return widget, label, mapping
141 
142 
143     def get_widgets(self):
144         """
145         Creates a set of widgets representing the dimensions on the
146         plot object used to instantiate the widgets class.
147         """
148         widgets = OrderedDict()
149         mappings = {}
150         for dim in self.mock_obj.kdims:
151             holomap = None if self.plot.dynamic else self.mock_obj
152             widget, label, mapping = self.create_widget(dim, holomap, self.editable)
153             if label is not None and not isinstance(label, Div):
154                 label.on_change('value', partial(self.on_change, dim, 'label'))
155             widget.on_change('value', partial(self.on_change, dim, 'widget'))
156             widgets[dim.pprint_label] = (label, widget)
157             if mapping:
158                 mappings[dim.pprint_label] = OrderedDict(mapping)
159         return widgets, mappings
160 
161 
162     def init_layout(self):
163         widgets = [widget for d in self.widgets.values()
164                    for widget in d if widget]
165         wbox = widgetbox(widgets, width=self.width)
166         if self.position in ['right', 'below']:
167             plots = [self.plot.state, wbox]
168         else:
169             plots = [wbox, self.plot.state]
170         layout_fn = row if self.position in ['left', 'right'] else column
171         layout = layout_fn(plots, sizing_mode=self.sizing_mode)
172         return layout
173 
174 
175     def attach_callbacks(self):
176         """
177         Attach callbacks to interact with Comms.
178         """
179         pass
180 
181 
182     def on_change(self, dim, widget_type, attr, old, new):
183         self._queue.append((dim, widget_type, attr, old, new))
184         if self.update not in self.plot.document._session_callbacks:
185             self.plot.document.add_timeout_callback(self.update, 50)
186 
187 
188     def update(self):
189         """
190         Handle update events on bokeh server.
191         """
192         if not self._queue:
193             return
194         dim, widget_type, attr, old, new = self._queue[-1]
195         dim_label = dim.pprint_label
196 
197         label, widget = self.widgets[dim_label]
198         if widget_type == 'label':
199             if isinstance(label, AutocompleteInput):
200                 value = [new]
201                 widget.value = value
202             else:
203                 widget.value = float(new)
204         elif label:
205             lookups = self.lookups.get(dim_label)
206             if not self.editable:
207                 if lookups:
208                     new = list(lookups.keys())[widget.value]
209                 label.text = '<b>%s</b>' % dim.pprint_value_string(new)
210             elif isinstance(label, AutocompleteInput):
211                 text = lookups[new]
212                 label.value = text
213             else:
214                 label.value = dim.pprint_value(new)
215 
216         key = []
217         for dim, (label, widget) in self.widgets.items():
218             lookups = self.lookups.get(dim)
219             if label and lookups:
220                 val = list(lookups.keys())[widget.value]
221             else:
222                 val = widget.value
223             key.append(val)
224         key = wrap_tuple_streams(tuple(key), self.plot.dimensions,
225                                  self.plot.streams)
226         self.plot.update(key)
227 
228 
229 
230 class BokehWidget(NdWidget):
231 
232     css = param.String(default='bokehwidgets.css', doc="""
233         Defines the local CSS file to be loaded for this widget.""")
234 
235     extensionjs = param.String(default='bokehwidgets.js', doc="""
236         Optional javascript extension file for a particular backend.""")
237 
238     def _get_data(self):
239         # Get initial frame to draw immediately
240         init_frame = self._plot_figure(0, fig_format='html')
241         data = super(BokehWidget, self)._get_data()
242         return dict(data, init_frame=init_frame)
243 
244     def encode_frames(self, frames):
245         if self.export_json:
246             self.save_json(frames)
247             frames = {}
248         else:
249             frames = json.dumps(frames).replace('</', r'<\/')
250         return frames
251 
252     def _plot_figure(self, idx, fig_format='json'):
253         """
254         Returns the figure in html format on the
255         first call and
256         """
257         self.plot.update(idx)
258         if self.embed or fig_format == 'html':
259             if fig_format == 'html':
260                 msg = self.renderer.html(self.plot, fig_format)
261             else:
262                 json_patch = self.renderer.diff(self.plot, serialize=False)
263                 msg = dict(patch=json_patch, root=self.plot.state._id)
264                 msg = serialize_json(msg)
265             return msg
266 
267 
268 class BokehSelectionWidget(BokehWidget, SelectionWidget):
269     pass
270 
271 
272 class BokehScrubberWidget(BokehWidget, ScrubberWidget):
273     pass
274
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/holoviews/plotting/bokeh/widgets.py b/holoviews/plotting/bokeh/widgets.py
--- a/holoviews/plotting/bokeh/widgets.py
+++ b/holoviews/plotting/bokeh/widgets.py
@@ -25,6 +25,9 @@
     and dropdown widgets letting you select non-numeric values.
     """
 
+    display_options = param.Dict(default={}, doc="""
+        Additional options controlling display options of the widgets.""")
+
     editable = param.Boolean(default=False, doc="""
         Whether the slider text fields should be editable. Disabled
         by default for a more compact widget layout.""")

{"golden_diff": "diff --git a/holoviews/plotting/bokeh/widgets.py b/holoviews/plotting/bokeh/widgets.py\n--- a/holoviews/plotting/bokeh/widgets.py\n+++ b/holoviews/plotting/bokeh/widgets.py\n@@ -25,6 +25,9 @@\n     and dropdown widgets letting you select non-numeric values.\n     \"\"\"\n \n+    display_options = param.Dict(default={}, doc=\"\"\"\n+        Additional options controlling display options of the widgets.\"\"\")\n+\n     editable = param.Boolean(default=False, doc=\"\"\"\n         Whether the slider text fields should be editable. Disabled\n         by default for a more compact widget layout.\"\"\")\n", "issue": "Bokeh server warning message\nthe code server = renderer.app(dmap, show=True, new_window=True)\r\nresults in a warning message\r\nWARNING:root:BokehServerWidgets24371: Setting non-parameter attribute display_options={'fps': 20} using a mechanism intended only for parameters\n", "before_files": [{"content": "from __future__ import unicode_literals\n\nimport math\nimport json\nfrom functools import partial\n\nimport param\nimport numpy as np\nfrom bokeh.models.widgets import Select, Slider, AutocompleteInput, TextInput, Div\nfrom bokeh.layouts import widgetbox, row, column\n\nfrom ...core import Store, NdMapping, OrderedDict\nfrom ...core.util import (drop_streams, unique_array, isnumeric,\n                          wrap_tuple_streams, unicode)\nfrom ..widgets import NdWidget, SelectionWidget, ScrubberWidget\nfrom .util import serialize_json\n\n\n\nclass BokehServerWidgets(param.Parameterized):\n    \"\"\"\n    BokehServerWidgets create bokeh widgets corresponding to all the\n    key dimensions found on a BokehPlot instance. It currently supports\n    to types of widgets sliders (which may be discrete or continuous)\n    and dropdown widgets letting you select non-numeric values.\n    \"\"\"\n\n    editable = param.Boolean(default=False, doc=\"\"\"\n        Whether the slider text fields should be editable. Disabled\n        by default for a more compact widget layout.\"\"\")\n\n    position = param.ObjectSelector(default='right',\n        objects=['right', 'left', 'above', 'below'])\n\n    sizing_mode = param.ObjectSelector(default='fixed',\n        objects=['fixed', 'stretch_both', 'scale_width',\n                 'scale_height', 'scale_both'])\n\n    width = param.Integer(default=250, doc=\"\"\"\n        Width of the widget box in pixels\"\"\")\n\n    basejs = param.String(default=None, precedence=-1, doc=\"\"\"\n        Defines the local CSS file to be loaded for this widget.\"\"\")\n\n    extensionjs = param.String(default=None, precedence=-1, doc=\"\"\"\n        Optional javascript extension file for a particular backend.\"\"\")\n\n    css = param.String(default=None, precedence=-1, doc=\"\"\"\n        Defines the local CSS file to be loaded for this widget.\"\"\")\n\n    def __init__(self, plot, renderer=None, **params):\n        super(BokehServerWidgets, self).__init__(**params)\n        self.plot = plot\n        streams = []\n        for stream in plot.streams:\n            if any(k in plot.dimensions for k in stream.contents):\n                streams.append(stream)\n        self.dimensions, self.keys = drop_streams(streams,\n                                                  plot.dimensions,\n                                                  plot.keys)\n        if renderer is None:\n            backend = Store.current_backend\n            self.renderer = Store.renderers[backend]\n        else:\n            self.renderer = renderer\n        # Create mock NdMapping to hold the common dimensions and keys\n        self.mock_obj = NdMapping([(k, None) for k in self.keys],\n                                  kdims=self.dimensions)\n        self.widgets, self.lookups = self.get_widgets()\n        self.reverse_lookups = {d: {v: k for k, v in item.items()}\n                                for d, item in self.lookups.items()}\n        self.subplots = {}\n        if self.plot.renderer.mode == 'default':\n            self.attach_callbacks()\n        self.state = self.init_layout()\n        self._queue = []\n\n\n    @classmethod\n    def create_widget(self, dim, holomap=None, editable=False):\n        \"\"\"\"\n        Given a Dimension creates bokeh widgets to select along that\n        dimension. For numeric data a slider widget is created which\n        may be either discrete, if a holomap is supplied or the\n        Dimension.values are set, or a continuous widget for\n        DynamicMaps. If the slider is discrete the returned mapping\n        defines a mapping between values and labels making it possible\n        sync the two slider and label widgets. For non-numeric data\n        a simple dropdown selection widget is generated.\n        \"\"\"\n        label, mapping = None, None\n        if holomap is None:\n            if dim.values:\n                if all(isnumeric(v) for v in dim.values):\n                    values = dim.values\n                    labels = [unicode(dim.pprint_value(v)) for v in dim.values]\n                    if editable:\n                        label = AutocompleteInput(value=labels[0], completions=labels,\n                                                  title=dim.pprint_label)\n                    else:\n                        label = Div(text='<b>%s</b>' % dim.pprint_value_string(labels[0]))\n                    widget = Slider(value=0, start=0, end=len(dim.values)-1, title=None, step=1)\n                    mapping = list(zip(values, labels))\n                else:\n                    values = [(v, dim.pprint_value(v)) for v in dim.values]\n                    widget = Select(title=dim.pprint_label, value=values[0][0],\n                                    options=values)\n            else:\n                start = dim.soft_range[0] if dim.soft_range[0] else dim.range[0]\n                end = dim.soft_range[1] if dim.soft_range[1] else dim.range[1]\n                dim_range = end - start\n                int_type = isinstance(dim.type, type) and issubclass(dim.type, int)\n                if isinstance(dim_range, int) or int_type:\n                    step = 1\n                elif dim.step is not None:\n                    step = dim.step\n                else:\n                    step = 10**((round(math.log10(dim_range))-3))\n                if editable:\n                    label = TextInput(value=str(start), title=dim.pprint_label)\n                else:\n                    label = Div(text='<b>%s</b>' % dim.pprint_value_string(start))\n                widget = Slider(value=start, start=start,\n                                end=end, step=step, title=None)\n        else:\n            values = (dim.values if dim.values else\n                      list(unique_array(holomap.dimension_values(dim.name))))\n            labels = [dim.pprint_value(v) for v in values]\n            if isinstance(values[0], np.datetime64) or isnumeric(values[0]):\n                if editable:\n                    label = AutocompleteInput(value=labels[0], completions=labels,\n                                              title=dim.pprint_label)\n                else:\n                    label = Div(text='<b>%s</b>' % (dim.pprint_value_string(labels[0])))\n                widget = Slider(value=0, start=0, end=len(values)-1, title=None, step=1)\n            else:\n                widget = Select(title=dim.pprint_label, value=values[0],\n                                options=list(zip(values, labels)))\n            mapping = list(zip(values, labels))\n        return widget, label, mapping\n\n\n    def get_widgets(self):\n        \"\"\"\n        Creates a set of widgets representing the dimensions on the\n        plot object used to instantiate the widgets class.\n        \"\"\"\n        widgets = OrderedDict()\n        mappings = {}\n        for dim in self.mock_obj.kdims:\n            holomap = None if self.plot.dynamic else self.mock_obj\n            widget, label, mapping = self.create_widget(dim, holomap, self.editable)\n            if label is not None and not isinstance(label, Div):\n                label.on_change('value', partial(self.on_change, dim, 'label'))\n            widget.on_change('value', partial(self.on_change, dim, 'widget'))\n            widgets[dim.pprint_label] = (label, widget)\n            if mapping:\n                mappings[dim.pprint_label] = OrderedDict(mapping)\n        return widgets, mappings\n\n\n    def init_layout(self):\n        widgets = [widget for d in self.widgets.values()\n                   for widget in d if widget]\n        wbox = widgetbox(widgets, width=self.width)\n        if self.position in ['right', 'below']:\n            plots = [self.plot.state, wbox]\n        else:\n            plots = [wbox, self.plot.state]\n        layout_fn = row if self.position in ['left', 'right'] else column\n        layout = layout_fn(plots, sizing_mode=self.sizing_mode)\n        return layout\n\n\n    def attach_callbacks(self):\n        \"\"\"\n        Attach callbacks to interact with Comms.\n        \"\"\"\n        pass\n\n\n    def on_change(self, dim, widget_type, attr, old, new):\n        self._queue.append((dim, widget_type, attr, old, new))\n        if self.update not in self.plot.document._session_callbacks:\n            self.plot.document.add_timeout_callback(self.update, 50)\n\n\n    def update(self):\n        \"\"\"\n        Handle update events on bokeh server.\n        \"\"\"\n        if not self._queue:\n            return\n        dim, widget_type, attr, old, new = self._queue[-1]\n        dim_label = dim.pprint_label\n\n        label, widget = self.widgets[dim_label]\n        if widget_type == 'label':\n            if isinstance(label, AutocompleteInput):\n                value = [new]\n                widget.value = value\n            else:\n                widget.value = float(new)\n        elif label:\n            lookups = self.lookups.get(dim_label)\n            if not self.editable:\n                if lookups:\n                    new = list(lookups.keys())[widget.value]\n                label.text = '<b>%s</b>' % dim.pprint_value_string(new)\n            elif isinstance(label, AutocompleteInput):\n                text = lookups[new]\n                label.value = text\n            else:\n                label.value = dim.pprint_value(new)\n\n        key = []\n        for dim, (label, widget) in self.widgets.items():\n            lookups = self.lookups.get(dim)\n            if label and lookups:\n                val = list(lookups.keys())[widget.value]\n            else:\n                val = widget.value\n            key.append(val)\n        key = wrap_tuple_streams(tuple(key), self.plot.dimensions,\n                                 self.plot.streams)\n        self.plot.update(key)\n\n\n\nclass BokehWidget(NdWidget):\n\n    css = param.String(default='bokehwidgets.css', doc=\"\"\"\n        Defines the local CSS file to be loaded for this widget.\"\"\")\n\n    extensionjs = param.String(default='bokehwidgets.js', doc=\"\"\"\n        Optional javascript extension file for a particular backend.\"\"\")\n\n    def _get_data(self):\n        # Get initial frame to draw immediately\n        init_frame = self._plot_figure(0, fig_format='html')\n        data = super(BokehWidget, self)._get_data()\n        return dict(data, init_frame=init_frame)\n\n    def encode_frames(self, frames):\n        if self.export_json:\n            self.save_json(frames)\n            frames = {}\n        else:\n            frames = json.dumps(frames).replace('</', r'<\\/')\n        return frames\n\n    def _plot_figure(self, idx, fig_format='json'):\n        \"\"\"\n        Returns the figure in html format on the\n        first call and\n        \"\"\"\n        self.plot.update(idx)\n        if self.embed or fig_format == 'html':\n            if fig_format == 'html':\n                msg = self.renderer.html(self.plot, fig_format)\n            else:\n                json_patch = self.renderer.diff(self.plot, serialize=False)\n                msg = dict(patch=json_patch, root=self.plot.state._id)\n                msg = serialize_json(msg)\n            return msg\n\n\nclass BokehSelectionWidget(BokehWidget, SelectionWidget):\n    pass\n\n\nclass BokehScrubberWidget(BokehWidget, ScrubberWidget):\n    pass\n", "path": "holoviews/plotting/bokeh/widgets.py"}], "after_files": [{"content": "from __future__ import unicode_literals\n\nimport math\nimport json\nfrom functools import partial\n\nimport param\nimport numpy as np\nfrom bokeh.models.widgets import Select, Slider, AutocompleteInput, TextInput, Div\nfrom bokeh.layouts import widgetbox, row, column\n\nfrom ...core import Store, NdMapping, OrderedDict\nfrom ...core.util import (drop_streams, unique_array, isnumeric,\n                          wrap_tuple_streams, unicode)\nfrom ..widgets import NdWidget, SelectionWidget, ScrubberWidget\nfrom .util import serialize_json\n\n\n\nclass BokehServerWidgets(param.Parameterized):\n    \"\"\"\n    BokehServerWidgets create bokeh widgets corresponding to all the\n    key dimensions found on a BokehPlot instance. It currently supports\n    to types of widgets sliders (which may be discrete or continuous)\n    and dropdown widgets letting you select non-numeric values.\n    \"\"\"\n\n    display_options = param.Dict(default={}, doc=\"\"\"\n        Additional options controlling display options of the widgets.\"\"\")\n\n    editable = param.Boolean(default=False, doc=\"\"\"\n        Whether the slider text fields should be editable. Disabled\n        by default for a more compact widget layout.\"\"\")\n\n    position = param.ObjectSelector(default='right',\n        objects=['right', 'left', 'above', 'below'])\n\n    sizing_mode = param.ObjectSelector(default='fixed',\n        objects=['fixed', 'stretch_both', 'scale_width',\n                 'scale_height', 'scale_both'])\n\n    width = param.Integer(default=250, doc=\"\"\"\n        Width of the widget box in pixels\"\"\")\n\n    basejs = param.String(default=None, precedence=-1, doc=\"\"\"\n        Defines the local CSS file to be loaded for this widget.\"\"\")\n\n    extensionjs = param.String(default=None, precedence=-1, doc=\"\"\"\n        Optional javascript extension file for a particular backend.\"\"\")\n\n    css = param.String(default=None, precedence=-1, doc=\"\"\"\n        Defines the local CSS file to be loaded for this widget.\"\"\")\n\n    def __init__(self, plot, renderer=None, **params):\n        super(BokehServerWidgets, self).__init__(**params)\n        self.plot = plot\n        streams = []\n        for stream in plot.streams:\n            if any(k in plot.dimensions for k in stream.contents):\n                streams.append(stream)\n        self.dimensions, self.keys = drop_streams(streams,\n                                                  plot.dimensions,\n                                                  plot.keys)\n        if renderer is None:\n            backend = Store.current_backend\n            self.renderer = Store.renderers[backend]\n        else:\n            self.renderer = renderer\n        # Create mock NdMapping to hold the common dimensions and keys\n        self.mock_obj = NdMapping([(k, None) for k in self.keys],\n                                  kdims=self.dimensions)\n        self.widgets, self.lookups = self.get_widgets()\n        self.reverse_lookups = {d: {v: k for k, v in item.items()}\n                                for d, item in self.lookups.items()}\n        self.subplots = {}\n        if self.plot.renderer.mode == 'default':\n            self.attach_callbacks()\n        self.state = self.init_layout()\n        self._queue = []\n\n\n    @classmethod\n    def create_widget(self, dim, holomap=None, editable=False):\n        \"\"\"\"\n        Given a Dimension creates bokeh widgets to select along that\n        dimension. For numeric data a slider widget is created which\n        may be either discrete, if a holomap is supplied or the\n        Dimension.values are set, or a continuous widget for\n        DynamicMaps. If the slider is discrete the returned mapping\n        defines a mapping between values and labels making it possible\n        sync the two slider and label widgets. For non-numeric data\n        a simple dropdown selection widget is generated.\n        \"\"\"\n        label, mapping = None, None\n        if holomap is None:\n            if dim.values:\n                if all(isnumeric(v) for v in dim.values):\n                    values = dim.values\n                    labels = [unicode(dim.pprint_value(v)) for v in dim.values]\n                    if editable:\n                        label = AutocompleteInput(value=labels[0], completions=labels,\n                                                  title=dim.pprint_label)\n                    else:\n                        label = Div(text='<b>%s</b>' % dim.pprint_value_string(labels[0]))\n                    widget = Slider(value=0, start=0, end=len(dim.values)-1, title=None, step=1)\n                    mapping = list(zip(values, labels))\n                else:\n                    values = [(v, dim.pprint_value(v)) for v in dim.values]\n                    widget = Select(title=dim.pprint_label, value=values[0][0],\n                                    options=values)\n            else:\n                start = dim.soft_range[0] if dim.soft_range[0] else dim.range[0]\n                end = dim.soft_range[1] if dim.soft_range[1] else dim.range[1]\n                dim_range = end - start\n                int_type = isinstance(dim.type, type) and issubclass(dim.type, int)\n                if isinstance(dim_range, int) or int_type:\n                    step = 1\n                elif dim.step is not None:\n                    step = dim.step\n                else:\n                    step = 10**((round(math.log10(dim_range))-3))\n                if editable:\n                    label = TextInput(value=str(start), title=dim.pprint_label)\n                else:\n                    label = Div(text='<b>%s</b>' % dim.pprint_value_string(start))\n                widget = Slider(value=start, start=start,\n                                end=end, step=step, title=None)\n        else:\n            values = (dim.values if dim.values else\n                      list(unique_array(holomap.dimension_values(dim.name))))\n            labels = [dim.pprint_value(v) for v in values]\n            if isinstance(values[0], np.datetime64) or isnumeric(values[0]):\n                if editable:\n                    label = AutocompleteInput(value=labels[0], completions=labels,\n                                              title=dim.pprint_label)\n                else:\n                    label = Div(text='<b>%s</b>' % (dim.pprint_value_string(labels[0])))\n                widget = Slider(value=0, start=0, end=len(values)-1, title=None, step=1)\n            else:\n                widget = Select(title=dim.pprint_label, value=values[0],\n                                options=list(zip(values, labels)))\n            mapping = list(zip(values, labels))\n        return widget, label, mapping\n\n\n    def get_widgets(self):\n        \"\"\"\n        Creates a set of widgets representing the dimensions on the\n        plot object used to instantiate the widgets class.\n        \"\"\"\n        widgets = OrderedDict()\n        mappings = {}\n        for dim in self.mock_obj.kdims:\n            holomap = None if self.plot.dynamic else self.mock_obj\n            widget, label, mapping = self.create_widget(dim, holomap, self.editable)\n            if label is not None and not isinstance(label, Div):\n                label.on_change('value', partial(self.on_change, dim, 'label'))\n            widget.on_change('value', partial(self.on_change, dim, 'widget'))\n            widgets[dim.pprint_label] = (label, widget)\n            if mapping:\n                mappings[dim.pprint_label] = OrderedDict(mapping)\n        return widgets, mappings\n\n\n    def init_layout(self):\n        widgets = [widget for d in self.widgets.values()\n                   for widget in d if widget]\n        wbox = widgetbox(widgets, width=self.width)\n        if self.position in ['right', 'below']:\n            plots = [self.plot.state, wbox]\n        else:\n            plots = [wbox, self.plot.state]\n        layout_fn = row if self.position in ['left', 'right'] else column\n        layout = layout_fn(plots, sizing_mode=self.sizing_mode)\n        return layout\n\n\n    def attach_callbacks(self):\n        \"\"\"\n        Attach callbacks to interact with Comms.\n        \"\"\"\n        pass\n\n\n    def on_change(self, dim, widget_type, attr, old, new):\n        self._queue.append((dim, widget_type, attr, old, new))\n        if self.update not in self.plot.document._session_callbacks:\n            self.plot.document.add_timeout_callback(self.update, 50)\n\n\n    def update(self):\n        \"\"\"\n        Handle update events on bokeh server.\n        \"\"\"\n        if not self._queue:\n            return\n        dim, widget_type, attr, old, new = self._queue[-1]\n        dim_label = dim.pprint_label\n\n        label, widget = self.widgets[dim_label]\n        if widget_type == 'label':\n            if isinstance(label, AutocompleteInput):\n                value = [new]\n                widget.value = value\n            else:\n                widget.value = float(new)\n        elif label:\n            lookups = self.lookups.get(dim_label)\n            if not self.editable:\n                if lookups:\n                    new = list(lookups.keys())[widget.value]\n                label.text = '<b>%s</b>' % dim.pprint_value_string(new)\n            elif isinstance(label, AutocompleteInput):\n                text = lookups[new]\n                label.value = text\n            else:\n                label.value = dim.pprint_value(new)\n\n        key = []\n        for dim, (label, widget) in self.widgets.items():\n            lookups = self.lookups.get(dim)\n            if label and lookups:\n                val = list(lookups.keys())[widget.value]\n            else:\n                val = widget.value\n            key.append(val)\n        key = wrap_tuple_streams(tuple(key), self.plot.dimensions,\n                                 self.plot.streams)\n        self.plot.update(key)\n\n\n\nclass BokehWidget(NdWidget):\n\n    css = param.String(default='bokehwidgets.css', doc=\"\"\"\n        Defines the local CSS file to be loaded for this widget.\"\"\")\n\n    extensionjs = param.String(default='bokehwidgets.js', doc=\"\"\"\n        Optional javascript extension file for a particular backend.\"\"\")\n\n    def _get_data(self):\n        # Get initial frame to draw immediately\n        init_frame = self._plot_figure(0, fig_format='html')\n        data = super(BokehWidget, self)._get_data()\n        return dict(data, init_frame=init_frame)\n\n    def encode_frames(self, frames):\n        if self.export_json:\n            self.save_json(frames)\n            frames = {}\n        else:\n            frames = json.dumps(frames).replace('</', r'<\\/')\n        return frames\n\n    def _plot_figure(self, idx, fig_format='json'):\n        \"\"\"\n        Returns the figure in html format on the\n        first call and\n        \"\"\"\n        self.plot.update(idx)\n        if self.embed or fig_format == 'html':\n            if fig_format == 'html':\n                msg = self.renderer.html(self.plot, fig_format)\n            else:\n                json_patch = self.renderer.diff(self.plot, serialize=False)\n                msg = dict(patch=json_patch, root=self.plot.state._id)\n                msg = serialize_json(msg)\n            return msg\n\n\nclass BokehSelectionWidget(BokehWidget, SelectionWidget):\n    pass\n\n\nclass BokehScrubberWidget(BokehWidget, ScrubberWidget):\n    pass\n", "path": "holoviews/plotting/bokeh/widgets.py"}]}