Skip to content

Commit

Permalink
Improve deploy and export API and docs (#269)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Mar 4, 2019
1 parent 4901ad3 commit 04d46c7
Show file tree
Hide file tree
Showing 4 changed files with 352 additions and 51 deletions.
4 changes: 4 additions & 0 deletions doc/user_guide/index.rst
Expand Up @@ -5,6 +5,9 @@ User Guide
* `Introduction <Introduction.html>`_
An overview of the capabilities of Panel.

* `Deploy & Export <Deploy_and_Export.html>`_
Introduction to displaying, exporting and deploying panel apps

* `Interact <Interact.html>`_
Quickly making a panel using `interact()`.

Expand Down Expand Up @@ -40,6 +43,7 @@ Supplementary guides
:maxdepth: 2

Introduction <Introduction>
Deploy & Export <Deploy_and_Export>
Interact <Interact>
Panes <Panes>
Widgets <Widgets>
Expand Down
243 changes: 243 additions & 0 deletions examples/user_guide/Deploy_and_Export.ipynb
@@ -0,0 +1,243 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import panel as pn\n",
"pn.extension()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"One of the main goals when designing ``Panel`` was that it should make it possible to seamlessly transition from interactively prototyping a dashboard in the notebook or on the commandline to deploying it as a standalone server app. This section will discover how to display panels interactively, embed static output, saving a snapshot and deploying it as a standalone app.\n",
"\n",
"## In the Notebook\n",
"\n",
"As you may have noticed almost all the ``Panel`` documentation is written using notebooks, ``Panel`` objects display themselves in the notebook and take advantage of Jupyter Comms to support communication between the rendered app and the Jupyter kernel backing it on the Python end. To display a panel object in the notebook is as simple as putting it on the end of a cell. Note however that the ``panel.extension`` has to be loaded to initialize the required Javascript and if you are working in JupyterLab the pyviz labextension has to be installed with:\n",
"\n",
" jupyter labextension install @pyviz/jupyterlab_pyviz\n",
" \n",
"#### The repr\n",
" \n",
"Once these conditions are met a panel will display itself:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pane = pn.panel('<marquee>Here is some custom HTML</marquee>')\n",
"\n",
"pane"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To instead see a textual representation of the app you can use the ``pprint`` method on all panel objects:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pane.pprint()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### The ``display`` function\n",
"\n",
"To avoid having to put a panel on the last line of a cell, e.g. to display it from inside a function call you can use the IPython built-in ``display`` function:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def display_marquee(text):\n",
" display(pn.panel('<marquee>{text}</marquee>'.format(text=text)))\n",
" \n",
"display_marquee('This Panel was displayed from within a function')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Inline apps\n",
"\n",
"Lastly it is also possible to display a panel object as a bokeh server app inside the notebook, to do so call the ``.app`` method on the panel object and provide the URL of your notebook server:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pane.app('localhost:8888')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The app will now run on a bokeh server instance separate from the Jupyter notebook kernel. This allows quickly testing that all the functionality works both in a notebook and app context."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## On the Commandline\n",
"\n",
"When working on the commandline you have to give up on none of the interactivity you would get in a notebook, however instead of display the output inline it will start a bokeh server instance and open a separate browser window. To launch the server and open the browser window use the ``show`` method. The method exposes the following arguments:\n",
"\n",
" port: int (optional)\n",
" Allows specifying a specific port (default=0 chooses random open port)\n",
" websocket_origin: str or list(str) (optional)\n",
" A list of hosts that can connect to the websocket.\n",
"\n",
" This is typically required when embedding a server app in\n",
" an external web site.\n",
"\n",
" If None, \"localhost\" is used.\n",
" threaded: boolean (optional, default=False)\n",
" Whether to launch the Server on a separate thread, allowing\n",
" interactive use.\n",
" \n",
"To work with an app completely interactively you can set ``threaded=True`` which will launch the server on a separate thread letting you interactively play with the app.\n",
"\n",
"<img src='https://assets.holoviews.org/panel/gifs/commandline_show.gif'></img>\n",
"\n",
"The ``show`` call will return either a bokeh server instance (if ``threaded=False``) or a ``StoppableThread`` instance (if ``threaded=True``) which both provide a ``stop`` method to stop the server instance.\n",
"\n",
"## Deploying\n",
"\n",
"Once the app is ready for deployment it can be served using the bokeh server, for a detailed breakdown of the design and functionality of bokeh server see the [bokeh documentation](https://bokeh.pydata.org/en/latest/docs/user_guide/server.html). The most important thing to know is that ``panel`` (and ``bokeh``) provide a CLI command to serve a Python script, app directory or Jupyter notebook containing a bokeh or panel app. To launch a server using the CLI simply run:\n",
"\n",
" panel serve app.ipynb\n",
" \n",
"The ``panel serve`` command has the following options:\n",
"\n",
" positional arguments:\n",
" DIRECTORY-OR-SCRIPT The app directories or scripts to serve (serve empty\n",
" document if not specified)\n",
"\n",
" optional arguments:\n",
" -h, --help show this help message and exit\n",
" --port PORT Port to listen on\n",
" --address ADDRESS Address to listen on\n",
" --log-level LOG-LEVEL\n",
" One of: trace, debug, info, warning, error or critical\n",
" --log-format LOG-FORMAT\n",
" A standard Python logging format string (default:\n",
" '%(asctime)s %(message)s')\n",
" --log-file LOG-FILE A filename to write logs to, or None to write to the\n",
" standard stream (default: None)\n",
" --args ... Any command line arguments remaining are passed on to\n",
" the application handler\n",
" --show Open server app(s) in a browser\n",
" --allow-websocket-origin HOST[:PORT]\n",
" Public hostnames which may connect to the Bokeh\n",
" websocket\n",
" --prefix PREFIX URL prefix for Bokeh server URLs\n",
" --keep-alive MILLISECONDS\n",
" How often to send a keep-alive ping to clients, 0 to\n",
" disable.\n",
" --check-unused-sessions MILLISECONDS\n",
" How often to check for unused sessions\n",
" --unused-session-lifetime MILLISECONDS\n",
" How long unused sessions last\n",
" --stats-log-frequency MILLISECONDS\n",
" How often to log stats\n",
" --mem-log-frequency MILLISECONDS\n",
" How often to log memory usage information\n",
" --use-xheaders Prefer X-headers for IP/protocol information\n",
" --session-ids MODE One of: unsigned, signed or external-signed\n",
" --index INDEX Path to a template to use for the site index\n",
" --disable-index Do not use the default index on the root path\n",
" --disable-index-redirect\n",
" Do not redirect to running app from root path\n",
" --num-procs N Number of worker processes for an app. Using 0 will\n",
" autodetect number of cores (defaults to 1)\n",
" --websocket-max-message-size BYTES\n",
" Set the Tornado websocket_max_message_size value\n",
" (defaults to 20MB) NOTE: This setting has effect ONLY\n",
" for Tornado>=4.5\n",
" --dev [FILES-TO-WATCH [FILES-TO-WATCH ...]]\n",
" Enable live reloading during app development.By\n",
" default it watches all *.py *.html *.css *.yaml\n",
" filesin the app directory tree. Additional files can\n",
" be passedas arguments.NOTE: This setting only works\n",
" with a single app.It also restricts the number of\n",
" processes to 1.\n",
"\n",
"To turn a notebook into a deployable app simply append ``.servable()`` to one or more panel objects, this will add the app to bokeh's ``curdoc`` ensuring it can be discovered by bokeh server on deployment. In this way it is trivial to build dashboards which can be used interactively in a notebook and then seamlessly deployed on bokeh server.\n",
"\n",
"## Exporting\n",
"\n",
"In case you don't need an actual server or simply want to export a static snapshot of a panel app you can use the ``save`` method which allows exporting the app to a standalone HTML or PNG file."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"By default, the HTML file generated will depend on loading JavaScript code for BokehJS from the online ``CDN`` repository, to reduce the file size. If you need to work in an airgapped or no-network environment, you can declare that ``INLINE`` resources should be used instead of ``CDN``:\n",
"\n",
"```python\n",
"from bokeh.resources import INLINE\n",
"panel.save('test.html', resources=INLINE)\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, if a 'png' file extension is specified, the exported plot will be rendered as a PNG, which currently requires Selenium and PhantomJS to be installed:\n",
"\n",
"```python\n",
"pane.save('test.png')\n",
"```"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.8"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

0 comments on commit 04d46c7

Please sign in to comment.