Skip to content

Commit 239b5c1

Browse files
committed
Add Panel DeckGL example
1 parent 51c2efd commit 239b5c1

File tree

1 file changed

+218
-0
lines changed

1 file changed

+218
-0
lines changed

pyscriptjs/examples/panel_deckgl.html

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Pyscript/Panel DeckGL Demo</title>
6+
7+
<link rel="icon" href="https://unpkg.com/@holoviz/panel@0.13.0/dist/icons/favicon.ico" type="">
8+
<meta name="name" content="PyScript/Panel KMeans Demo">
9+
10+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" type="text/css" />
11+
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.0/dist/css/widgets.css" type="text/css" />
12+
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.0/dist/css/markdown.css" type="text/css" />
13+
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.0/dist/css/loading.css" type="text/css" />
14+
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.0/dist/css/dataframe.css" type="text/css" />
15+
16+
<script type="text/javascript" src="https://unpkg.com/h3-js@3.7.2/dist/h3-js.umd.js"></script>
17+
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/deck.gl@8.6.7/dist.min.js"></script>
18+
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@deck.gl/json@8.6.7/dist.min.js"></script>
19+
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@loaders.gl/csv@3.1.7/dist/dist.min.js"></script>
20+
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@loaders.gl/json@3.1.7/dist/dist.min.js"></script>
21+
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@loaders.gl/3d-tiles@3.1.7/dist/dist.min.js"></script>
22+
<script type="text/javascript" src="https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.js"></script>
23+
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.js"></script>
24+
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js"></script>
25+
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js"></script>
26+
<script type="text/javascript" src="https://unpkg.com/@holoviz/panel@0.13.0/dist/panel.js"></script>
27+
<script type="text/javascript">
28+
Bokeh.set_log_level("info");
29+
</script>
30+
31+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
32+
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.0/dist/bundled/bootstraptemplate/bootstrap.css">
33+
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.0/dist/bundled/defaulttheme/default.css">
34+
35+
<style>
36+
#sidebar {
37+
width: 350px;
38+
}
39+
</style>
40+
41+
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
42+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
43+
44+
<link rel="stylesheet" href="../build/pyscript.css" />
45+
<script defer src="../build/pyscript.js"></script>
46+
</head>
47+
<body>
48+
<py-env>
49+
- bokeh
50+
- numpy
51+
- pandas
52+
</py-env>
53+
54+
<div class="container-fluid d-flex flex-column vh-100 overflow-hidden" id="container">
55+
<nav class="navbar navbar-expand-md navbar-dark sticky-top shadow" id="header" style="background-color: #0072b5;">
56+
<button type="button" class="navbar-toggle collapsed" id="sidebarCollapse">
57+
<span class="navbar-toggler-icon"></span>
58+
</button>
59+
<div class="app-header">
60+
<a class="title" href="/" >&nbsp;Panel</a>
61+
<span class="title">&nbsp;-</span>
62+
<a class="title" href="" >&nbsp;Pyscript DeckGL NYC Taxi</a>
63+
</div>
64+
</nav>
65+
66+
<div class="row overflow-hidden" id="content">
67+
<div class="sidenav" id="sidebar">
68+
<ul class="nav flex-column">
69+
<div class="bk-root" id="widgets" data-root-id="1021"></div>
70+
<py-repl id="my-repl" auto-generate="true"> </py-repl>
71+
</ul>
72+
</div>
73+
<div class="col mh-100 float-left" style="padding: 0;">
74+
<div class="bk-root" id="plot" data-root-id="1008"></div>
75+
</div>
76+
</div>
77+
</div>
78+
<py-script>
79+
import asyncio
80+
import micropip
81+
82+
from io import StringIO
83+
from js import fetch
84+
85+
await micropip.install(['panel==0.13.1a1'])
86+
87+
import panel as pn
88+
import param
89+
import pandas as pd
90+
91+
from panel.io.pyodide import show
92+
93+
MAPBOX_KEY = "pk.eyJ1IjoicGFuZWxvcmciLCJhIjoiY2s1enA3ejhyMWhmZjNobjM1NXhtbWRrMyJ9.B_frQsAVepGIe-HiOJeqvQ"
94+
95+
class App(pn.viewable.Viewer):
96+
97+
data = param.DataFrame(precedence=-1)
98+
99+
view = param.DataFrame(precedence=-1)
100+
101+
radius = param.Integer(default=50, bounds=(20, 1000))
102+
103+
elevation = param.Integer(default=10, bounds=(0, 50))
104+
105+
hour = param.Integer(default=0, bounds=(0, 23))
106+
107+
speed = param.Integer(default=1, bounds=(0, 10), precedence=-1)
108+
109+
play = param.Event(label='▷')
110+
111+
def __init__(self, **params):
112+
self.deck_gl = None
113+
super().__init__(**params)
114+
self.deck_gl = pn.pane.DeckGL(dict(self.spec), mapbox_api_key=MAPBOX_KEY, sizing_mode='stretch_both', margin=0)
115+
self.deck_gl.param.watch(self.update_spec, 'hover_state')
116+
self._playing = False
117+
self._cb = pn.state.add_periodic_callback(self._update, 1000//self.speed, start=False)
118+
119+
@param.depends('speed', watch=True)
120+
def _update_speed(self):
121+
self._cb.period = 1000//self.speed
122+
123+
@property
124+
def spec(self):
125+
return {
126+
"initialViewState": {
127+
"bearing": 0,
128+
"latitude": 40.7,
129+
"longitude": -73.9,
130+
"maxZoom": 15,
131+
"minZoom": 5,
132+
"pitch": 40.5,
133+
"zoom": 11
134+
},
135+
"layers": [self.hex_layer, self.arc_layer],
136+
"mapStyle": "mapbox://styles/mapbox/dark-v9",
137+
"views": [
138+
{"@@type": "MapView", "controller": True}
139+
]
140+
}
141+
142+
@property
143+
def hex_layer(self):
144+
return {
145+
"@@type": "HexagonLayer",
146+
"autoHighlight": True,
147+
"coverage": 1,
148+
"data": self.data if self.view is None else self.view,
149+
"elevationRange": [0, 100],
150+
"elevationScale": self.elevation,
151+
"radius": self.radius,
152+
"extruded": True,
153+
"getPosition": "@@=[pickup_x, pickup_y]",
154+
"id": "8a553b25-ef3a-489c-bbe2-e102d18a3211"
155+
}
156+
157+
@property
158+
def arc_layer(self):
159+
return {
160+
"@@type": "ArcLayer",
161+
"id": 'arc-layer',
162+
"data": self.arc_view,
163+
"pickable": True,
164+
"getWidth": 1,
165+
"getSourcePosition": "@@=[pickup_x, pickup_y]",
166+
"getTargetPosition": "@@=[dropoff_x, dropoff_y]",
167+
"getSourceColor": [0, 255, 0, 180],
168+
"getTargetColor": [240, 100, 0, 180]
169+
}
170+
171+
@property
172+
def arc_view(self):
173+
data = self.data if self.view is None else self.view
174+
if not self.deck_gl or not self.deck_gl.hover_state:
175+
return data.iloc[:0]
176+
lon, lat = self.deck_gl.hover_state['coordinate']
177+
tol = 0.001
178+
return data[
179+
(df.pickup_x>=float(lon-tol)) &
180+
(df.pickup_x<=float(lon+tol)) &
181+
(df.pickup_y>=float(lat-tol)) &
182+
(df.pickup_y<=float(lat+tol))
183+
]
184+
185+
def _update(self):
186+
self.hour = (self.hour+1) % 24
187+
self.view = self.data[self.data.hour==self.hour]
188+
189+
@param.depends('play', watch=True)
190+
def _play_pause(self):
191+
if self._playing:
192+
self._cb.stop()
193+
self.param.play.label = '▷'
194+
self.param.speed.precedence = -1
195+
else:
196+
self._cb.start()
197+
self.param.play.label = '❚❚'
198+
self.param.speed.precedence = 1
199+
self._playing = not self._playing
200+
201+
@param.depends('view', 'radius', 'elevation', watch=True)
202+
def update_spec(self, *events):
203+
self.deck_gl.object = dict(self.spec)
204+
205+
def __panel__(self):
206+
return self.deck_gl
207+
208+
data = await fetch('https://s3.eu-west-1.amazonaws.com/assets.holoviews.org/data/nyc_taxi_wide.csv')
209+
df = pd.read_csv(StringIO(await data.text()))
210+
211+
app = App(data=df)
212+
controls = pn.Param(app.param, sizing_mode='stretch_width', show_name=False)
213+
214+
await show(controls, 'widgets')
215+
await show(app, 'plot')
216+
</py-script>
217+
</body>
218+
</html>

0 commit comments

Comments
 (0)