1
"""
2
Defines the baseclasses that make a component render to a bokeh model
3
and become viewable including:
4

5
* Layoutable: Defines parameters concerned with layout and style
6
* ServableMixin: Mixin class that defines methods to serve object on server
7
* Renderable: Defines methods to render a component as a bokeh model
8
* Viewable: Defines methods to view the component in the
9
  notebook, on the server or in static exports
10
"""
11 7
import datetime as dt
12 7
import logging
13 7
import sys
14 7
import traceback
15 7
import uuid
16

17 7
from functools import partial
18

19 7
import param
20

21 7
from bokeh.document.document import Document as _Document
22 7
from bokeh.io import curdoc as _curdoc
23 7
from pyviz_comms import JupyterCommManager
24

25 7
from .config import config, panel_extension
26 7
from .io.embed import embed_state
27 7
from .io.loading import start_loading_spinner, stop_loading_spinner
28 7
from .io.model import add_to_doc, patch_cds_msg
29 7
from .io.notebook import (
30
    ipywidget, render_mimebundle, render_model, show_embed, show_server
31
)
32 7
from .io.save import save
33 7
from .io.state import state
34 7
from .io.server import init_doc, serve
35 7
from .util import escape, param_reprs
36

37

38 7
class Layoutable(param.Parameterized):
39
    """
40
    Layoutable defines shared style and layout related parameters
41
    for all Panel components with a visual representation.
42
    """
43

44 7
    align = param.ObjectSelector(default='start',
45
                                 objects=['start', 'end', 'center'], doc="""
46
        Whether the object should be aligned with the start, end or
47
        center of its container""")
48

49 7
    aspect_ratio = param.Parameter(default=None, doc="""
50
        Describes the proportional relationship between component's
51
        width and height.  This works if any of component's dimensions
52
        are flexible in size. If set to a number, ``width / height =
53
        aspect_ratio`` relationship will be maintained.  Otherwise, if
54
        set to ``"auto"``, component's preferred width and height will
55
        be used to determine the aspect (if not set, no aspect will be
56
        preserved).""")
57

58 7
    background = param.Parameter(default=None, doc="""
59
        Background color of the component.""")
60

61 7
    css_classes = param.List(default=None, doc="""
62
        CSS classes to apply to the layout.""")
63

64 7
    width = param.Integer(default=None, bounds=(0, None), doc="""
65
        The width of the component (in pixels). This can be either
66
        fixed or preferred width, depending on width sizing policy.""")
67

68 7
    height = param.Integer(default=None, bounds=(0, None), doc="""
69
        The height of the component (in pixels).  This can be either
70
        fixed or preferred height, depending on height sizing policy.""")
71

72 7
    min_width = param.Integer(default=None, bounds=(0, None), doc="""
73
        Minimal width of the component (in pixels) if width is adjustable.""")
74

75 7
    min_height = param.Integer(default=None, bounds=(0, None), doc="""
76
        Minimal height of the component (in pixels) if height is adjustable.""")
77

78 7
    max_width = param.Integer(default=None, bounds=(0, None), doc="""
79
        Minimal width of the component (in pixels) if width is adjustable.""")
80

81 7
    max_height = param.Integer(default=None, bounds=(0, None), doc="""
82
        Minimal height of the component (in pixels) if height is adjustable.""")
83

84 7
    margin = param.Parameter(default=5, doc="""
85
        Allows to create additional space around the component. May
86
        be specified as a two-tuple of the form (vertical, horizontal)
87
        or a four-tuple (top, right, bottom, left).""")
88

89 7
    width_policy = param.ObjectSelector(
90
        default="auto", objects=['auto', 'fixed', 'fit', 'min', 'max'], doc="""
91
        Describes how the component should maintain its width.
92

93
        ``"auto"``
94
            Use component's preferred sizing policy.
95

96
        ``"fixed"``
97
            Use exactly ``width`` pixels. Component will overflow if
98
            it can't fit in the available horizontal space.
99

100
        ``"fit"``
101
            Use component's preferred width (if set) and allow it to
102
            fit into the available horizontal space within the minimum
103
            and maximum width bounds (if set). Component's width
104
            neither will be aggressively minimized nor maximized.
105

106
        ``"min"``
107
            Use as little horizontal space as possible, not less than
108
            the minimum width (if set).  The starting point is the
109
            preferred width (if set). The width of the component may
110
            shrink or grow depending on the parent layout, aspect
111
            management and other factors.
112

113
        ``"max"``
114
            Use as much horizontal space as possible, not more than
115
            the maximum width (if set).  The starting point is the
116
            preferred width (if set). The width of the component may
117
            shrink or grow depending on the parent layout, aspect
118
            management and other factors.
119
    """)
120

121 7
    height_policy = param.ObjectSelector(
122
        default="auto", objects=['auto', 'fixed', 'fit', 'min', 'max'], doc="""
123
        Describes how the component should maintain its height.
124

125
        ``"auto"``
126
            Use component's preferred sizing policy.
127

128
        ``"fixed"``
129
            Use exactly ``height`` pixels. Component will overflow if
130
            it can't fit in the available vertical space.
131

132
        ``"fit"``
133
            Use component's preferred height (if set) and allow to fit
134
            into the available vertical space within the minimum and
135
            maximum height bounds (if set). Component's height neither
136
            will be aggressively minimized nor maximized.
137

138
        ``"min"``
139
            Use as little vertical space as possible, not less than
140
            the minimum height (if set).  The starting point is the
141
            preferred height (if set). The height of the component may
142
            shrink or grow depending on the parent layout, aspect
143
            management and other factors.
144

145
        ``"max"``
146
            Use as much vertical space as possible, not more than the
147
            maximum height (if set).  The starting point is the
148
            preferred height (if set). The height of the component may
149
            shrink or grow depending on the parent layout, aspect
150
            management and other factors.
151
    """)
152

153 7
    sizing_mode = param.ObjectSelector(default=None, objects=[
154
        'fixed', 'stretch_width', 'stretch_height', 'stretch_both',
155
        'scale_width', 'scale_height', 'scale_both', None], doc="""
156

157
        How the component should size itself.
158

159
        This is a high-level setting for maintaining width and height
160
        of the component. To gain more fine grained control over
161
        sizing, use ``width_policy``, ``height_policy`` and
162
        ``aspect_ratio`` instead (those take precedence over
163
        ``sizing_mode``).
164

165
        ``"fixed"``
166
            Component is not responsive. It will retain its original
167
            width and height regardless of any subsequent browser
168
            window resize events.
169

170
        ``"stretch_width"``
171
            Component will responsively resize to stretch to the
172
            available width, without maintaining any aspect ratio. The
173
            height of the component depends on the type of the
174
            component and may be fixed or fit to component's contents.
175

176
        ``"stretch_height"``
177
            Component will responsively resize to stretch to the
178
            available height, without maintaining any aspect
179
            ratio. The width of the component depends on the type of
180
            the component and may be fixed or fit to component's
181
            contents.
182

183
        ``"stretch_both"``
184
            Component is completely responsive, independently in width
185
            and height, and will occupy all the available horizontal
186
            and vertical space, even if this changes the aspect ratio
187
            of the component.
188

189
        ``"scale_width"``
190
            Component will responsively resize to stretch to the
191
            available width, while maintaining the original or
192
            provided aspect ratio.
193

194
        ``"scale_height"``
195
            Component will responsively resize to stretch to the
196
            available height, while maintaining the original or
197
            provided aspect ratio.
198

199
        ``"scale_both"``
200
            Component will responsively resize to both the available
201
            width and height, while maintaining the original or
202
            provided aspect ratio.
203
    """)
204

205 7
    __abstract = True
206

207 7
    def __init__(self, **params):
208 7
        if (params.get('width', None) is not None and
209
            params.get('height', None) is not None and
210
            params.get('width_policy') is None and
211
            params.get('height_policy') is None and
212
            'sizing_mode' not in params):
213 7
            params['sizing_mode'] = 'fixed'
214 7
        elif (not (self.param.sizing_mode.constant or self.param.sizing_mode.readonly) and
215
              type(self).sizing_mode is None):
216 7
            params['sizing_mode'] = params.get('sizing_mode', config.sizing_mode)
217 7
        super().__init__(**params)
218

219

220 7
class ServableMixin(object):
221
    """
222
    Mixin to define methods shared by objects which can served.
223
    """
224

225 7
    def _modify_doc(self, server_id, title, doc, location):
226
        """
227
        Callback to handle FunctionHandler document creation.
228
        """
229 7
        if server_id:
230 7
            state._servers[server_id][2].append(doc)
231 7
        return self.server_doc(doc, title, location)
232

233 7
    def _add_location(self, doc, location, root=None):
234 7
        from .io.location import Location
235 7
        if isinstance(location, Location):
236 0
            loc = location
237 7
        elif doc in state._locations:
238 0
            loc = state._locations[doc]
239
        else:
240 7
            loc = Location()
241 7
        state._locations[doc] = loc
242 7
        if root is None:
243 0
            loc_model = loc._get_root(doc)
244
        else:
245 7
            loc_model = loc._get_model(doc, root)
246 7
        loc_model.name = 'location'
247 7
        doc.add_root(loc_model)
248 7
        return loc
249

250 7
    def _on_msg(self, ref, manager, msg):
251
        """
252
        Handles Protocol messages arriving from the client comm.
253
        """
254 0
        root, doc, comm = state._views[ref][1:]
255 0
        patch_cds_msg(root, msg)
256 0
        held = doc._hold
257 0
        patch = manager.assemble(msg)
258 0
        doc.hold()
259 0
        patch.apply_to_document(doc, comm.id)
260 0
        doc.unhold()
261 0
        if held:
262 0
            doc.hold(held)
263

264 7
    def _on_error(self, ref, error):
265 7
        if ref not in state._handles or config.console_output in [None, 'disable']:
266 7
            return
267 7
        handle, accumulator = state._handles[ref]
268 7
        formatted = '\n<pre>'+escape(traceback.format_exc())+'</pre>\n'
269 7
        if config.console_output == 'accumulate':
270 7
            accumulator.append(formatted)
271 7
        elif config.console_output == 'replace':
272 7
            accumulator[:] = [formatted]
273 7
        if accumulator:
274 7
            handle.update({'text/html': '\n'.join(accumulator)}, raw=True)
275

276 7
    def _on_stdout(self, ref, stdout):
277 7
        if ref not in state._handles or config.console_output is [None, 'disable']:
278 0
            return
279 7
        handle, accumulator = state._handles[ref]
280 7
        formatted = ["%s</br>" % o for o in stdout]
281 7
        if config.console_output == 'accumulate':
282 7
            accumulator.extend(formatted)
283 7
        elif config.console_output == 'replace':
284 7
            accumulator[:] = formatted
285 7
        if accumulator:
286 7
            handle.update({'text/html': '\n'.join(accumulator)}, raw=True)
287

288
    #----------------------------------------------------------------
289
    # Public API
290
    #----------------------------------------------------------------
291

292 7
    def servable(self, title=None, location=True):
293
        """
294
        Serves the object if in a `panel serve` context and returns
295
        the Panel object to allow it to display itself in a notebook
296
        context.
297
        Arguments
298
        ---------
299
        title : str
300
          A string title to give the Document (if served as an app)
301
        location : boolean or panel.io.location.Location
302
          Whether to create a Location component to observe and
303
          set the URL location.
304

305
        Returns
306
        -------
307
        The Panel object itself
308
        """
309 0
        if _curdoc().session_context:
310 0
            logger = logging.getLogger('bokeh')
311 0
            for handler in logger.handlers:
312 0
                if isinstance(handler, logging.StreamHandler):
313 0
                    handler.setLevel(logging.WARN)
314 0
            self.server_doc(title=title, location=True)
315 0
        return self
316

317 7
    def show(self, title=None, port=0, address=None, websocket_origin=None,
318
             threaded=False, verbose=True, open=True, location=True, **kwargs):
319
        """
320
        Starts a Bokeh server and displays the Viewable in a new tab.
321

322
        Arguments
323
        ---------
324
        title : str
325
          A string title to give the Document (if served as an app)
326
        port: int (optional, default=0)
327
          Allows specifying a specific port
328
        address : str
329
          The address the server should listen on for HTTP requests.
330
        websocket_origin: str or list(str) (optional)
331
          A list of hosts that can connect to the websocket.
332
          This is typically required when embedding a server app in
333
          an external web site.
334
          If None, "localhost" is used.
335
        threaded: boolean (optional, default=False)
336
          Whether to launch the Server on a separate thread, allowing
337
          interactive use.
338
        verbose: boolean (optional, default=True)
339
          Whether to print the address and port
340
        open : boolean (optional, default=True)
341
          Whether to open the server in a new browser tab
342
        location : boolean or panel.io.location.Location
343
          Whether to create a Location component to observe and
344
          set the URL location.
345

346
        Returns
347
        -------
348
        server: bokeh.server.Server or threading.Thread
349
          Returns the Bokeh server instance or the thread the server
350
          was launched on (if threaded=True)
351
        """
352 0
        return serve(
353
            self, port=port, address=address, websocket_origin=websocket_origin,
354
            show=open, start=True, title=title, verbose=verbose,
355
            location=location, threaded=threaded, **kwargs
356
        )
357

358

359 7
class Renderable(param.Parameterized):
360
    """
361
    Baseclass for objects which can be rendered to a Bokeh model.
362

363
    It therefore declare APIs for initializing the models from
364
    parameter values.
365
    """
366

367 7
    __abstract = True
368

369 7
    def __init__(self, **params):
370 7
        super().__init__(**params)
371 7
        self._callbacks = []
372 7
        self._documents = {}
373 7
        self._models = {}
374 7
        self._comms = {}
375 7
        self._kernels = {}
376 7
        self._found_links = set()
377

378 7
    def _get_model(self, doc, root=None, parent=None, comm=None):
379
        """
380
        Converts the objects being wrapped by the viewable into a
381
        bokeh model that can be composed in a bokeh layout.
382

383
        Arguments
384
        ----------
385
        doc: bokeh.Document
386
          Bokeh document the bokeh model will be attached to.
387
        root: bokeh.Model
388
          The root layout the viewable will become part of.
389
        parent: bokeh.Model
390
          The parent layout the viewable will become part of.
391
        comm: pyviz_comms.Comm
392
          Optional pyviz_comms when working in notebook
393

394
        Returns
395
        -------
396
        model: bokeh.Model
397
        """
398 0
        raise NotImplementedError
399

400 7
    def _cleanup(self, root):
401
        """
402
        Clean up method which is called when a Viewable is destroyed.
403

404
        Arguments
405
        ---------
406
        root: bokeh.model.Model
407
          Bokeh model for the view being cleaned up
408
        """
409 7
        ref = root.ref['id']
410 7
        if ref in state._handles:
411 7
            del state._handles[ref]
412

413 7
    def _preprocess(self, root):
414
        """
415
        Applies preprocessing hooks to the model.
416
        """
417 7
        hooks = self._preprocessing_hooks+self._hooks
418 7
        for hook in hooks:
419 7
            hook(self, root)
420

421 7
    def _render_model(self, doc=None, comm=None):
422 0
        if doc is None:
423 0
            doc = _Document()
424 0
        if comm is None:
425 0
            comm = state._comm_manager.get_server_comm()
426 0
        model = self.get_root(doc, comm)
427

428 0
        if config.embed:
429 0
            embed_state(self, model, doc,
430
                        json=config.embed_json,
431
                        json_prefix=config.embed_json_prefix,
432
                        save_path=config.embed_save_path,
433
                        load_path=config.embed_load_path,
434
                        progress=False)
435
        else:
436 0
            add_to_doc(model, doc)
437 0
        return model
438

439 7
    def _init_params(self):
440 0
        return {k: v for k, v in self.param.get_param_values() if v is not None}
441

442 7
    def _server_destroy(self, session_context):
443
        """
444
        Server lifecycle hook triggered when session is destroyed.
445
        """
446 7
        session_id = session_context.id
447 7
        sessions = state.session_info['sessions']
448 7
        if session_id in sessions and sessions[session_id]['ended'] is None:
449 7
            session = sessions[session_id]
450 7
            if session['rendered'] is not None:
451 7
                state.session_info['live'] -= 1
452 7
            session['ended'] = dt.datetime.now().timestamp()
453 7
        doc = session_context._document
454 7
        root = self._documents[doc]
455 7
        ref = root.ref['id']
456 7
        self._cleanup(root)
457 7
        del self._documents[doc]
458 7
        if ref in state._views:
459 7
            del state._views[ref]
460 7
        if doc in state._locations:
461 7
            loc = state._locations[doc]
462 7
            loc._cleanup(root)
463 7
            del state._locations[doc]
464

465 7
    def get_root(self, doc=None, comm=None, preprocess=True):
466
        """
467
        Returns the root model and applies pre-processing hooks
468

469
        Arguments
470
        ---------
471
        doc: bokeh.Document
472
          Bokeh document the bokeh model will be attached to.
473
        comm: pyviz_comms.Comm
474
          Optional pyviz_comms when working in notebook
475
        preprocess: boolean (default=True)
476
          Whether to run preprocessing hooks
477

478
        Returns
479
        -------
480
        Returns the bokeh model corresponding to this panel object
481
        """
482 7
        doc = init_doc(doc)
483 7
        root = self._get_model(doc, comm=comm)
484 7
        if preprocess:
485 7
            self._preprocess(root)
486 7
        ref = root.ref['id']
487 7
        state._views[ref] = (self, root, doc, comm)
488 7
        return root
489

490

491 7
class Viewable(Renderable, Layoutable, ServableMixin):
492
    """
493
    Viewable is the baseclass all visual components in the panel
494
    library are built on. It defines the interface for declaring any
495
    object that displays itself by transforming the object(s) being
496
    wrapped into models that can be served using bokeh's layout
497
    engine. The class also defines various methods that allow Viewable
498
    objects to be displayed in the notebook and on bokeh server.
499
    """
500

501 7
    loading = param.Boolean(doc="""
502
        Whether or not the Viewable is loading. If True a loading spinner
503
        is shown on top of the Viewable.""")
504

505 7
    _preprocessing_hooks = []
506

507 7
    def __init__(self, **params):
508 7
        hooks = params.pop('hooks', [])
509 7
        super().__init__(**params)
510 7
        self._hooks = hooks
511 7
        self._update_loading()
512 7
        watcher = self.param.watch(self._update_loading, 'loading')
513 7
        self._callbacks.append(watcher)
514

515 7
    def _update_loading(self, *_):
516 7
        if self.loading:
517 0
            start_loading_spinner(self)
518
        else:
519 7
            stop_loading_spinner(self)
520

521 7
    def __repr__(self, depth=0):
522 7
        return '{cls}({params})'.format(cls=type(self).__name__,
523
                                        params=', '.join(param_reprs(self)))
524

525 7
    def __str__(self):
526 7
        return self.__repr__()
527

528 7
    def _repr_mimebundle_(self, include=None, exclude=None):
529 7
        loaded = panel_extension._loaded
530 7
        if not loaded and 'holoviews' in sys.modules:
531 7
            import holoviews as hv
532 7
            loaded = hv.extension._loaded
533

534

535 7
        if config.comms in ('vscode', 'ipywidgets'):
536 7
            widget = ipywidget(self)
537 7
            if hasattr(widget, '_repr_mimebundle_'):
538 0
                return widget._repr_mimebundle_(include, exclude)
539 7
            plaintext = repr(widget)
540 7
            if len(plaintext) > 110:
541 7
                plaintext = plaintext[:110] + '…'
542 7
            data = {
543
                'text/plain': plaintext,
544
            }
545 7
            if widget._view_name is not None:
546 7
                data['application/vnd.jupyter.widget-view+json'] = {
547
                    'version_major': 2,
548
                    'version_minor': 0,
549
                    'model_id': widget._model_id
550
                }
551 7
            if config.comms == 'vscode':
552 0
                from IPython.display import display
553 0
                display(data, raw=True)
554 0
                return {'text/html': '<div style="display: none"></div>'}, {}
555 7
            return data, {}
556

557 0
        if not loaded:
558 0
            self.param.warning('Displaying Panel objects in the notebook '
559
                               'requires the panel extension to be loaded. '
560
                               'Ensure you run pn.extension() before '
561
                               'displaying objects in the notebook.')
562 0
            return None
563

564 0
        if config.comms == 'colab':
565 0
            from .io.notebook import load_notebook
566 0
            load_notebook(config.inline)
567

568 0
        try:
569 0
            from IPython import get_ipython
570 0
            assert get_ipython().kernel is not None
571 0
            state._comm_manager = JupyterCommManager
572 0
        except Exception:
573 0
            pass
574

575 0
        if not state._views:
576
            # Initialize the global Location
577 0
            from .io.location import Location
578 0
            state._location = location = Location()
579
        else:
580 0
            location = None
581

582 0
        from IPython.display import display
583 0
        from .models.comm_manager import CommManager
584

585 0
        doc = _Document()
586 0
        comm = state._comm_manager.get_server_comm()
587 0
        model = self._render_model(doc, comm)
588 0
        ref = model.ref['id']
589 0
        manager = CommManager(comm_id=comm.id, plot_id=ref)
590 0
        client_comm = state._comm_manager.get_client_comm(
591
            on_msg=partial(self._on_msg, ref, manager),
592
            on_error=partial(self._on_error, ref),
593
            on_stdout=partial(self._on_stdout, ref)
594
        )
595 0
        self._comms[ref] = (comm, client_comm)
596 0
        manager.client_comm_id = client_comm.id
597

598 0
        if config.console_output != 'disable':
599 0
            handle = display(display_id=uuid.uuid4().hex)
600 0
            state._handles[ref] = (handle, [])
601

602 0
        if config.embed:
603 0
            return render_model(model)
604 0
        return render_mimebundle(model, doc, comm, manager, location)
605

606
    #----------------------------------------------------------------
607
    # Public API
608
    #----------------------------------------------------------------
609

610 7
    def clone(self, **params):
611
        """
612
        Makes a copy of the object sharing the same parameters.
613

614
        Arguments
615
        ---------
616
        params: Keyword arguments override the parameters on the clone.
617

618
        Returns
619
        -------
620
        Cloned Viewable object
621
        """
622 7
        inherited = {p: v for p, v in self.param.get_param_values()
623
                     if not self.param[p].readonly}
624 7
        return type(self)(**dict(inherited, **params))
625

626 7
    def pprint(self):
627
        """
628
        Prints a compositional repr of the class.
629
        """
630 0
        print(self)
631

632 7
    def select(self, selector=None):
633
        """
634
        Iterates over the Viewable and any potential children in the
635
        applying the Selector.
636

637
        Arguments
638
        ---------
639
        selector: type or callable or None
640
          The selector allows selecting a subset of Viewables by
641
          declaring a type or callable function to filter by.
642

643
        Returns
644
        -------
645
        viewables: list(Viewable)
646
        """
647 7
        if (selector is None or
648
            (isinstance(selector, type) and isinstance(self, selector)) or
649
            (callable(selector) and not isinstance(selector, type) and selector(self))):
650 7
            return [self]
651
        else:
652 7
            return []
653

654 7
    def app(self, notebook_url="localhost:8888", port=0):
655
        """
656
        Displays a bokeh server app inline in the notebook.
657

658
        Arguments
659
        ---------
660
        notebook_url: str
661
          URL to the notebook server
662
        port: int (optional, default=0)
663
          Allows specifying a specific port
664
        """
665 0
        return show_server(self, notebook_url, port)
666

667 7
    def embed(self, max_states=1000, max_opts=3, json=False, json_prefix='',
668
              save_path='./', load_path=None, progress=False, states={}):
669
        """
670
        Renders a static version of a panel in a notebook by evaluating
671
        the set of states defined by the widgets in the model. Note
672
        this will only work well for simple apps with a relatively
673
        small state space.
674

675
        Arguments
676
        ---------
677
        max_states: int
678
          The maximum number of states to embed
679
        max_opts: int
680
          The maximum number of states for a single widget
681
        json: boolean (default=True)
682
          Whether to export the data to json files
683
        json_prefix: str (default='')
684
          Prefix for JSON filename
685
        save_path: str (default='./')
686
          The path to save json files to
687
        load_path: str (default=None)
688
          The path or URL the json files will be loaded from.
689
        progress: boolean (default=False)
690
          Whether to report progress
691
        states: dict (default={})
692
          A dictionary specifying the widget values to embed for each widget
693
        """
694 0
        show_embed(
695
            self, max_states, max_opts, json, json_prefix, save_path,
696
            load_path, progress, states
697
        )
698

699 7
    def save(self, filename, title=None, resources=None, template=None,
700
             template_variables=None, embed=False, max_states=1000,
701
             max_opts=3, embed_json=False, json_prefix='', save_path='./',
702
             load_path=None, progress=True, embed_states={}):
703
        """
704
        Saves Panel objects to file.
705

706
        Arguments
707
        ---------
708
        filename: string or file-like object
709
           Filename to save the plot to
710
        title: string
711
           Optional title for the plot
712
        resources: bokeh resources
713
           One of the valid bokeh.resources (e.g. CDN or INLINE)
714
        template:
715
           passed to underlying io.save
716
        template_variables:
717
           passed to underlying io.save
718
        embed: bool
719
           Whether the state space should be embedded in the saved file.
720
        max_states: int
721
           The maximum number of states to embed
722
        max_opts: int
723
           The maximum number of states for a single widget
724
        embed_json: boolean (default=True)
725
           Whether to export the data to json files
726
        json_prefix: str (default='')
727
           Prefix for the auto-generated json directory
728
        save_path: str (default='./')
729
           The path to save json files to
730
        load_path: str (default=None)
731
           The path or URL the json files will be loaded from.
732
        progress: boolean (default=True)
733
          Whether to report progress
734
        embed_states: dict (default={})
735
          A dictionary specifying the widget values to embed for each widget
736
        """
737 7
        return save(self, filename, title, resources, template,
738
                    template_variables, embed, max_states, max_opts,
739
                    embed_json, json_prefix, save_path, load_path,
740
                    progress, embed_states)
741

742 7
    def server_doc(self, doc=None, title=None, location=True):
743
        """
744
        Returns a serveable bokeh Document with the panel attached
745

746
        Arguments
747
        ---------
748
        doc : bokeh.Document (optional)
749
          The bokeh Document to attach the panel to as a root,
750
          defaults to bokeh.io.curdoc()
751
        title : str
752
          A string title to give the Document
753
        location : boolean or panel.io.location.Location
754
          Whether to create a Location component to observe and
755
          set the URL location.
756

757
        Returns
758
        -------
759
        doc : bokeh.Document
760
          The bokeh document the panel was attached to
761
        """
762 7
        doc = init_doc(doc)
763 7
        title = title or 'Panel Application'
764 7
        doc.title = title
765 7
        model = self.get_root(doc)
766 7
        if hasattr(doc, 'on_session_destroyed'):
767 7
            doc.on_session_destroyed(self._server_destroy)
768 7
            self._documents[doc] = model
769 7
        add_to_doc(model, doc)
770 7
        if location: self._add_location(doc, location, model)
771 7
        return doc

Read our documentation on viewing source code .

Loading