Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DeckGL pane [doc-build] #1019

Merged
merged 17 commits into from
Jan 28, 2020
Merged
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,8 @@ builtdocs/
panel/models/*.json
node_modules
package-lock.json

# vscode settings
.vscode/
.vscode/panel.code-workspace
discover/.generated_defaults/
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ jobs:
env: DESC="docs" PANEL_DOC_BUILD='true'
script:
- doit develop_install $CHANS_DEV -o doc -o examples
- pip install pydeck
# note: will vastly simplified in a future version of nbsite
- nbsite generate-rst --org pyviz --project-name panel
- nbsite build --what=html --output=builtdocs
Expand Down
165 changes: 165 additions & 0 deletions examples/reference/panes/DeckGL.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import panel as pn\n",
"import pydeck as pdk\n",
"pn.extension('deckgl')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[Deck.gl](https://deck.gl/#/) is a very powerful WebGL-powered framework for visual exploratory data analysis of large datasets.\n",
"\n",
"The [`PyDeck`](https://deckgl.readthedocs.io/en/latest/) *package* provides Python bindings. Please follow the [installation instructions](https://github.com/uber/deck.gl/blob/master/bindings/pydeck/README.md) closely to get it working in this Jupyter Notebook.\n",
"\n",
"The `DeckGL` *pane* renders JSON Deck.gl JSON specification as well as `PyDeck` plots inside a panel.\n",
"\n",
"#### Parameters:\n",
"\n",
"For layout and styling related parameters see the [customization user guide](../../user_guide/Customization.ipynb).\n",
"\n",
"* **``object``** (object or dict): The deck.GL JSON or PyDeck object being displayed\n",
"\n",
"___"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In order to use Deck.gl you need a MAP BOX Key which you can acquire for free for limited use at [mapbox.com](https://account.mapbox.com/access-tokens/).\n",
"\n",
"Now we can define a JSON spec and pass it to the DeckGL pane along with the Mapbox key:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"MAPBOX_KEY = (\n",
" \"pk.eyJ1IjoibWFyY3Nrb3ZtYWRzZW4iLCJhIjoiY2s1anMzcG5rMDYzazNvcm10NTFybTE4cSJ9.\"\n",
" \"TV1XBgaMfR-iTLvAXM_Iew\"\n",
")\n",
"\n",
"json_spec = {\n",
" \"initialViewState\": {\n",
" \"bearing\": -27.36,\n",
" \"latitude\": 52.2323,\n",
" \"longitude\": -1.415,\n",
" \"maxZoom\": 15,\n",
" \"minZoom\": 5,\n",
" \"pitch\": 40.5,\n",
" \"zoom\": 6\n",
" },\n",
" \"layers\": [{\n",
" \"@@type\": \"HexagonLayer\",\n",
" \"autoHighlight\": True,\n",
" \"coverage\": 1,\n",
" \"data\": \"https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/3d-heatmap/heatmap-data.csv\",\n",
" \"elevationRange\": [0, 3000],\n",
" \"elevationScale\": 50,\n",
" \"extruded\": True,\n",
" \"getPosition\": \"@@=[lng, lat]\",\n",
" \"id\": \"8a553b25-ef3a-489c-bbe2-e102d18a3211\", \"pickable\": True\n",
" }],\n",
" \"mapStyle\": \"mapbox://styles/mapbox/dark-v9\",\n",
" \"views\": [{\"@@type\": \"MapView\", \"controller\": True}]\n",
"}\n",
"\n",
"deck_gl = pn.pane.DeckGL(json_spec, mapbox_api_key=MAPBOX_KEY, sizing_mode='stretch_width')\n",
"\n",
"deck_gl"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Alternatively the `DeckGL` pane can also be given a PyDeck object to render:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pydeck\n",
"\n",
"DATA_URL = \"https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/geojson/vancouver-blocks.json\"\n",
"\n",
"LAND_COVER = [[[-123.0, 49.196], [-123.0, 49.324], [-123.306, 49.324], [-123.306, 49.196]]]\n",
"\n",
"INITIAL_VIEW_STATE = pydeck.ViewState(\n",
" latitude=49.254,\n",
" longitude=-123.13,\n",
" zoom=11,\n",
" max_zoom=16,\n",
" pitch=45,\n",
" bearing=0\n",
")\n",
"\n",
"polygon = pydeck.Layer(\n",
" 'PolygonLayer',\n",
" LAND_COVER,\n",
" stroked=False,\n",
" # processes the data as a flat longitude-latitude pair\n",
" get_polygon='-',\n",
" get_fill_color=[0, 0, 0, 20]\n",
")\n",
"\n",
"geojson = pydeck.Layer(\n",
" 'GeoJsonLayer',\n",
" DATA_URL,\n",
" opacity=0.8,\n",
" stroked=False,\n",
" filled=True,\n",
" extruded=True,\n",
" wireframe=True,\n",
" get_elevation='properties.valuePerSqm / 20',\n",
" get_fill_color='[255, 255, properties.growth * 255]',\n",
" get_line_color=[255, 255, 255],\n",
" pickable=True\n",
")\n",
"\n",
"r = pydeck.Deck(\n",
" mapbox_key=MAPBOX_KEY,\n",
" layers=[polygon, geojson],\n",
" initial_view_state=INITIAL_VIEW_STATE\n",
")\n",
"\n",
"pn.pane.DeckGL(r, sizing_mode='stretch_width')"
]
}
],
"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.7.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
2 changes: 1 addition & 1 deletion panel/_templates/autoload_panel_js.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ calls it with the rendered model.

if (window.requirejs) {
{%- for conf in configs %}
window.requirejs.config({{ conf }});
window.requirejs.config({{ conf|conffilter }});
{%- endfor %}
require({{ requirements|json }}, function({%- for e in exports -%}{{ e }},{%- endfor -%}) {
{%- for exp in exports %}
Expand Down
3 changes: 2 additions & 1 deletion panel/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def comms(self):
def comms(self, value):
validate_config(self, '_comms', value)
self._comms_ = value

@property
def embed_json(self):
if self._embed_json_ is not None:
Expand Down Expand Up @@ -238,6 +238,7 @@ class panel_extension(_pyviz_extension):
_imports = {'katex': 'panel.models.katex',
'mathjax': 'panel.models.mathjax',
'plotly': 'panel.models.plotly',
'deckgl': 'panel.models.deckgl',
'vega': 'panel.models.vega',
'vtk': 'panel.models.vtk',
'ace': 'panel.models.ace'}
Expand Down
5 changes: 5 additions & 0 deletions panel/io/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import json
import os
from collections import OrderedDict

from bokeh.resources import Resources
from jinja2 import Environment, Markup, FileSystemLoader
Expand Down Expand Up @@ -41,9 +42,13 @@ def css_files(self):
files.append(cssf)
return files

def conffilter(value):
return json.dumps(OrderedDict(value)).replace('"', '\'')

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

_env = get_env()
_env.filters['json'] = lambda obj: Markup(json.dumps(obj))
_env.filters['conffilter'] = conffilter
44 changes: 44 additions & 0 deletions panel/models/deckgl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""Defines a custom DeckGLPlot to render DeckGL Plots

[Deck.gl](https://deck.gl/#/) is an awesome WebGL-powered framework for visual exploratory data
analysis of large datasets.

And now DeckGL provides Python bindings. See

- [DeckGL Docs](https://deckgl.readthedocs.io/en/latest/)
- [PyDeck Repo](https://github.com/uber/deck.gl/tree/master/bindings/pydeck)
"""

from collections import OrderedDict

from bokeh.core.properties import String, Bool, JSON, Override
from bokeh.models import HTMLBox


class DeckGLPlot(HTMLBox):
"""A Bokeh model that wraps around a DeckGL plot and renders it inside a HTMLBox"""

__css__ = ["https://cdn.jsdelivr.net/npm/[email protected]/dist/mapbox-gl.css"]

__javascript__ = ["https://cdn.jsdelivr.net/npm/[email protected]/dist.min.js",
"https://cdn.jsdelivr.net/npm/@deck.gl/[email protected]/dist/dist.dev.js",
"https://cdn.jsdelivr.net/npm/[email protected]",
"https://cdn.jsdelivr.net/npm/@loaders.gl/[email protected]/dist/dist.min.js",
"https://cdn.jsdelivr.net/npm/@loaders.gl/[email protected]/dist/dist.min.js",
"https://cdn.jsdelivr.net/npm/@loaders.gl/[email protected]/dist/dist.min.js"]

__js_require__ = {
'paths': OrderedDict([
("deck.gl", "https://cdn.jsdelivr.net/npm/@deck.gl/jupyter-widget@^8.0.0/dist/index"),
("mapbox-gl", 'https://cdn.jsdelivr.net/npm/[email protected]/dist/mapbox-gl.min'),
]),
'exports': {"deck.gl": "deck", "mapbox-gl": "mapboxgl"}
}

json_input = JSON()
mapbox_api_key = String()
tooltip = Bool()

height = Override(default=400)
width = Override(default=600)

Loading