Skip to content

Commit

Permalink
Allow defining external JS and CSS resources via config (#330)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Mar 24, 2019
1 parent 2403468 commit e67415c
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 18 deletions.
35 changes: 20 additions & 15 deletions examples/user_guide/Deploy_and_Export.ipynb
Expand Up @@ -22,9 +22,24 @@
"\n",
" jupyter labextension install @pyviz/jupyterlab_pyviz\n",
" \n",
"Note that to use certain components such as Vega, LaTeX and Plotly plots in a notebook the models must be loaded using the extension, e.g.:\n",
"\n",
" pn.extension('vega', 'katex')\n",
" \n",
"will ensure that the Vega and LaTeX JS dependencies are loaded. Additionally any external ``css_files``, ``js_files`` and ``raw_css`` should be declared in the extension. The ``js_files`` should be declared as a dictionary mapping from the exported JS module name to the URL containing the JS components, while the ``css_files`` can be defined as a list:\n",
"\n",
" pn.extension(js_files={'deck': https://unpkg.com/deck.gl@~5.2.0/deckgl.min.js},\n",
" css_files=['https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.css'])\n",
"\n",
"Meanwhile ``raw_css`` can be defined as a list of CSS strings. Providing keyword arguments via the ``extension`` is the same as setting them on ``pn.config``, which is the preferred approach outside the notebook, e.g. ``js_files`` and ``css_files`` may be set as follows:\n",
"\n",
" pn.config.js_files = {'deck': https://unpkg.com/deck.gl@~5.2.0/deckgl.min.js}\n",
" pn.config.css_files = ['https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.css']\n",
"\n",
"\n",
"#### The repr\n",
" \n",
"Once these conditions are met a panel will display itself:"
"Once the extension is loaded panel objects will display themselves if placed at the end of cell:"
]
},
{
Expand Down Expand Up @@ -192,25 +207,15 @@
"\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": [
"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.\n",
"\n",
"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": [
"```\n",
"\n",
"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",
Expand Down
18 changes: 15 additions & 3 deletions panel/compiler.py
Expand Up @@ -74,11 +74,23 @@ def require_components():
Returns JS snippet to load the required dependencies in the classic
notebook using REQUIRE JS.
"""
from .config import config

configs, requirements, exports = [], [], []
for model in CUSTOM_MODELS.values():
if not hasattr(model, '__js_require__'):
js_requires = list(CUSTOM_MODELS.values())

for export, js in config.js_files.items():
name = js.split('/')[-1].replace('.min', '').split('.')[-2]
conf = {'paths': {name: js[:-3]}, 'exports': {name: export}}
js_requires.append(conf)

for model in js_requires:
if not (hasattr(model, '__js_require__') or isinstance(model, dict)):
continue
model_require = model.__js_require__
if isinstance(model, dict):
model_require = model
else:
model_require = model.__js_require__
model_exports = model_require.pop('exports', {})
configs.append(model_require)
for req in model_require.get('paths', []):
Expand Down
10 changes: 10 additions & 0 deletions panel/config.py
Expand Up @@ -37,6 +37,16 @@ class _config(param.Parameterized):
os.environ['PANEL_EMBED'] = 'True'
"""

css_files = param.List(default=[], doc="""
External CSS files to load as part of the template.""")

js_files = param.Dict(default={}, doc="""
External JS files to load as part of the template. Dictionary
should map from exported name to the URL of the JS file.""")

raw_css = param.List(default=[], doc="""
List of raw CSS strings to add to the template.""")

_embed = param.Boolean(default=False, allow_None=True, doc="""
Whether plot data will be embedded.""")

Expand Down
1 change: 1 addition & 0 deletions panel/io/__init__.py
Expand Up @@ -6,5 +6,6 @@
from .embed import embed_state # noqa
from .state import state # noqa
from .model import add_to_doc, remove_root, diff # noqa
from .resources import Resources # noqa
from .server import get_server # noqa
from .notebook import block_comm, load_notebook, push # noqa
26 changes: 26 additions & 0 deletions panel/io/resources.py
@@ -0,0 +1,26 @@
"""
Patches bokeh resources to make it easy to add external JS and CSS
resources via the panel.config object.
"""
from __future__ import absolute_import, division, unicode_literals

from bokeh.resources import Resources

def css_raw(self):
from ..config import config
raw = super(Resources, self).css_raw
return raw + config.raw_css

def js_files(self):
from ..config import config
files = super(Resources, self).js_files
return files + list(config.js_files.values())

def css_files(self):
from ..config import config
files = super(Resources, self).css_files
return files + config.css_files

Resources.css_raw = property(css_raw)
Resources.js_files = property(js_files)
Resources.css_files = property(css_files)

0 comments on commit e67415c

Please sign in to comment.