From 239b5c11780dc916315ac14f7d29b39ea3cfae17 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Sun, 17 Apr 2022 12:46:09 +0200 Subject: [PATCH 1/3] Add Panel DeckGL example --- pyscriptjs/examples/panel_deckgl.html | 218 ++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 pyscriptjs/examples/panel_deckgl.html diff --git a/pyscriptjs/examples/panel_deckgl.html b/pyscriptjs/examples/panel_deckgl.html new file mode 100644 index 00000000000..52fc83e4666 --- /dev/null +++ b/pyscriptjs/examples/panel_deckgl.html @@ -0,0 +1,218 @@ + + + + + Pyscript/Panel DeckGL Demo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - bokeh + - numpy + - pandas + + +
+ + +
+ +
+
+
+
+
+ +import asyncio +import micropip + +from io import StringIO +from js import fetch + +await micropip.install(['panel==0.13.1a1']) + +import panel as pn +import param +import pandas as pd + +from panel.io.pyodide import show + +MAPBOX_KEY = "pk.eyJ1IjoicGFuZWxvcmciLCJhIjoiY2s1enA3ejhyMWhmZjNobjM1NXhtbWRrMyJ9.B_frQsAVepGIe-HiOJeqvQ" + +class App(pn.viewable.Viewer): + + data = param.DataFrame(precedence=-1) + + view = param.DataFrame(precedence=-1) + + radius = param.Integer(default=50, bounds=(20, 1000)) + + elevation = param.Integer(default=10, bounds=(0, 50)) + + hour = param.Integer(default=0, bounds=(0, 23)) + + speed = param.Integer(default=1, bounds=(0, 10), precedence=-1) + + play = param.Event(label='▷') + + def __init__(self, **params): + self.deck_gl = None + super().__init__(**params) + self.deck_gl = pn.pane.DeckGL(dict(self.spec), mapbox_api_key=MAPBOX_KEY, sizing_mode='stretch_both', margin=0) + self.deck_gl.param.watch(self.update_spec, 'hover_state') + self._playing = False + self._cb = pn.state.add_periodic_callback(self._update, 1000//self.speed, start=False) + + @param.depends('speed', watch=True) + def _update_speed(self): + self._cb.period = 1000//self.speed + + @property + def spec(self): + return { + "initialViewState": { + "bearing": 0, + "latitude": 40.7, + "longitude": -73.9, + "maxZoom": 15, + "minZoom": 5, + "pitch": 40.5, + "zoom": 11 + }, + "layers": [self.hex_layer, self.arc_layer], + "mapStyle": "mapbox://styles/mapbox/dark-v9", + "views": [ + {"@@type": "MapView", "controller": True} + ] + } + + @property + def hex_layer(self): + return { + "@@type": "HexagonLayer", + "autoHighlight": True, + "coverage": 1, + "data": self.data if self.view is None else self.view, + "elevationRange": [0, 100], + "elevationScale": self.elevation, + "radius": self.radius, + "extruded": True, + "getPosition": "@@=[pickup_x, pickup_y]", + "id": "8a553b25-ef3a-489c-bbe2-e102d18a3211" + } + + @property + def arc_layer(self): + return { + "@@type": "ArcLayer", + "id": 'arc-layer', + "data": self.arc_view, + "pickable": True, + "getWidth": 1, + "getSourcePosition": "@@=[pickup_x, pickup_y]", + "getTargetPosition": "@@=[dropoff_x, dropoff_y]", + "getSourceColor": [0, 255, 0, 180], + "getTargetColor": [240, 100, 0, 180] + } + + @property + def arc_view(self): + data = self.data if self.view is None else self.view + if not self.deck_gl or not self.deck_gl.hover_state: + return data.iloc[:0] + lon, lat = self.deck_gl.hover_state['coordinate'] + tol = 0.001 + return data[ + (df.pickup_x>=float(lon-tol)) & + (df.pickup_x<=float(lon+tol)) & + (df.pickup_y>=float(lat-tol)) & + (df.pickup_y<=float(lat+tol)) + ] + + def _update(self): + self.hour = (self.hour+1) % 24 + self.view = self.data[self.data.hour==self.hour] + + @param.depends('play', watch=True) + def _play_pause(self): + if self._playing: + self._cb.stop() + self.param.play.label = '▷' + self.param.speed.precedence = -1 + else: + self._cb.start() + self.param.play.label = '❚❚' + self.param.speed.precedence = 1 + self._playing = not self._playing + + @param.depends('view', 'radius', 'elevation', watch=True) + def update_spec(self, *events): + self.deck_gl.object = dict(self.spec) + + def __panel__(self): + return self.deck_gl + +data = await fetch('https://s3.eu-west-1.amazonaws.com/assets.holoviews.org/data/nyc_taxi_wide.csv') +df = pd.read_csv(StringIO(await data.text())) + +app = App(data=df) +controls = pn.Param(app.param, sizing_mode='stretch_width', show_name=False) + +await show(controls, 'widgets') +await show(app, 'plot') + + + From bb1c80c3ab78e67e5c4e189c440cdc8087235797 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Sun, 17 Apr 2022 12:46:35 +0200 Subject: [PATCH 2/3] Update existing panel examples --- pyscriptjs/examples/panel.html | 2 +- pyscriptjs/examples/panel_kmeans.html | 18 +++++++++--------- pyscriptjs/examples/panel_stream.html | 19 +++++++++---------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/pyscriptjs/examples/panel.html b/pyscriptjs/examples/panel.html index 119a3fc40dd..e1e2e4dd88b 100644 --- a/pyscriptjs/examples/panel.html +++ b/pyscriptjs/examples/panel.html @@ -20,7 +20,7 @@

Panel Example

import asyncio import micropip -await micropip.install(['panel==0.13.0rc10']) +await micropip.install(['panel']) import panel as pn diff --git a/pyscriptjs/examples/panel_kmeans.html b/pyscriptjs/examples/panel_kmeans.html index 7fe153c4b68..501fdcd0e91 100644 --- a/pyscriptjs/examples/panel_kmeans.html +++ b/pyscriptjs/examples/panel_kmeans.html @@ -4,14 +4,14 @@ Pyscript/Panel KMeans Demo - + - - - - + + + + @@ -20,14 +20,14 @@ - + - - + + - - - - @@ -98,6 +95,8 @@ view = param.DataFrame(precedence=-1) + arc_view = param.DataFrame(precedence=-1) + radius = param.Integer(default=50, bounds=(20, 1000)) elevation = param.Integer(default=10, bounds=(0, 50)) @@ -111,14 +110,17 @@ def __init__(self, **params): self.deck_gl = None super().__init__(**params) - self.deck_gl = pn.pane.DeckGL(dict(self.spec), mapbox_api_key=MAPBOX_KEY, sizing_mode='stretch_both', margin=0) - self.deck_gl.param.watch(self.update_spec, 'hover_state') + self.deck_gl = pn.pane.DeckGL( + dict(self.spec), mapbox_api_key=MAPBOX_KEY, throttle={'click': 10}, + sizing_mode='stretch_both', margin=0) + self.deck_gl.param.watch(self._update_arc_view, 'click_state') self._playing = False - self._cb = pn.state.add_periodic_callback(self._update, 1000//self.speed, start=False) + self._cb = pn.state.add_periodic_callback( + self._update_hour, 1000//self.speed, start=False + ) - @param.depends('speed', watch=True) - def _update_speed(self): - self._cb.period = 1000//self.speed + def __panel__(self): + return self.deck_gl @property def spec(self): @@ -168,24 +170,32 @@ "getTargetColor": [240, 100, 0, 180] } - @property - def arc_view(self): - data = self.data if self.view is None else self.view - if not self.deck_gl or not self.deck_gl.hover_state: - return data.iloc[:0] - lon, lat = self.deck_gl.hover_state['coordinate'] - tol = 0.001 - return data[ - (df.pickup_x>=float(lon-tol)) & - (df.pickup_x<=float(lon+tol)) & - (df.pickup_y>=float(lat-tol)) & - (df.pickup_y<=float(lat+tol)) - ] - - def _update(self): + def _update_hour(self): self.hour = (self.hour+1) % 24 + + @param.depends('view', watch=True) + def _update_arc_view(self, event=None): + data = self.data if self.view is None else self.view + if not self.deck_gl or not self.deck_gl.click_state: + self.arc_view = data.iloc[:0] + else: + lon, lat = self.deck_gl.click_state['coordinate'] + tol = 0.001 + self.arc_view = data[ + (df.pickup_x>=float(lon-tol)) & + (df.pickup_x<=float(lon+tol)) & + (df.pickup_y>=float(lat-tol)) & + (df.pickup_y<=float(lat+tol)) + ] + + @param.depends('hour', watch=True) + def _update_hourly_view(self): self.view = self.data[self.data.hour==self.hour] + @param.depends('speed', watch=True) + def _update_speed(self): + self._cb.period = 1000//self.speed + @param.depends('play', watch=True) def _play_pause(self): if self._playing: @@ -198,12 +208,10 @@ self.param.speed.precedence = 1 self._playing = not self._playing - @param.depends('view', 'radius', 'elevation', watch=True) - def update_spec(self, *events): + @param.depends('view', 'radius', 'elevation', 'arc_view', watch=True) + def update_spec(self): self.deck_gl.object = dict(self.spec) - def __panel__(self): - return self.deck_gl data = await fetch('https://s3.eu-west-1.amazonaws.com/assets.holoviews.org/data/nyc_taxi_wide.csv') df = pd.read_csv(StringIO(await data.text()))