MarcSkovMadsen commited on
Commit
a19fe56
1 Parent(s): 326ffdb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -132
app.py CHANGED
@@ -1,134 +1,98 @@
1
- import time
2
- from concurrent.futures import ThreadPoolExecutor
3
- from contextlib import contextmanager
 
 
 
 
 
 
 
4
 
5
- import numpy as np
6
  import panel as pn
7
- import param
8
- from asyncio import wrap_future
9
-
10
- class ProgressExtMod(pn.viewable.Viewer):
11
- """A custom component for easy progress reporting"""
12
-
13
- completed = param.Integer(default=0)
14
- bar_color = param.String(default="info")
15
- num_tasks = param.Integer(default=100, bounds=(1, None))
16
-
17
- # @param.depends('completed', 'num_tasks')
18
- @property
19
- def value(self) -> int:
20
- """Returns the progress value
21
-
22
- Returns:
23
- int: The progress value
24
- """
25
- return int(100 * (self.completed / self.num_tasks))
26
-
27
- def reset(self):
28
- """Resets the value and message"""
29
- # Please note the order matters as the Widgets updates two times. One for each change
30
- self.completed = 0
31
-
32
- def __panel__(self):
33
- return self.view
34
-
35
- @param.depends("completed", "bar_color")
36
- def view(self):
37
- """View the widget
38
- Returns:
39
- pn.viewable.Viewable: Add this to your app to see the progress reported
40
- """
41
- if self.value:
42
- return pn.widgets.Progress(
43
- active=True, value=self.value, align="center", sizing_mode="stretch_width"
44
- )
45
- return None
46
-
47
- @contextmanager
48
- def increment(self):
49
- """Increments the value
50
-
51
- Can be used as context manager or decorator
52
-
53
- Yields:
54
- None: Nothing is yielded
55
- """
56
- self.completed += 1
57
- yield
58
- if self.completed == self.num_tasks:
59
- self.reset()
60
-
61
- executor = ThreadPoolExecutor(max_workers=2) # pylint: disable=consider-using-with
62
- progress = ProgressExtMod()
63
-
64
-
65
- class AsyncComponent(pn.viewable.Viewer):
66
- """A component that demonstrates how to run a Blocking Background task asynchronously
67
- in Panel"""
68
-
69
- select = param.Selector(objects=range(10))
70
- slider = param.Number(2, bounds=(0, 10))
71
-
72
- run_blocking_task = param.Event(label="RUN")
73
- result = param.Number(0)
74
- view = param.Parameter()
75
-
76
- def __init__(self, **params):
77
- super().__init__(**params)
78
-
79
- self._layout = pn.Column(
80
- pn.pane.Markdown("## Blocking Task Running in Background"),
81
- pn.Param(
82
- self,
83
- parameters=["run_blocking_task", "result"],
84
- widgets={"result": {"disabled": True}, "run_blocking_task": {"button_type": "primary"}},
85
- show_name=False,
86
- ),
87
- progress,
88
- pn.pane.Markdown("## Other, Non-Blocked Tasks"),
89
- pn.Param(
90
- self,
91
- parameters=["select", "slider"],
92
- widgets={"text": {"disabled": True}},
93
- show_name=False,
94
- ),
95
- self.text
96
- )
97
-
98
- def __panel__(self):
99
- return self._layout
100
-
101
- @param.depends("slider", "select")
102
- def text(self):
103
- if self.select:
104
- select = self.select
105
- else:
106
- select = 0
107
- return f"{select} + {self.slider} = {select + self.slider}"
108
-
109
- @pn.depends("run_blocking_task", watch=True)
110
- async def _run_blocking_tasks(self, num_tasks=10):
111
- """Runs background tasks num_tasks times"""
112
- num_tasks = 20
113
- progress.num_tasks = num_tasks
114
- for _ in range(num_tasks):
115
- future = executor.submit(self._run_blocking_task)
116
- result = await wrap_future(future)
117
- self._update(result)
118
-
119
- @progress.increment()
120
- def _update(self, number):
121
- self.result += number
122
-
123
- @staticmethod
124
- def _run_blocking_task():
125
- time.sleep(np.random.randint(1, 2))
126
- return 5
127
-
128
- if pn.state.served:
129
- pn.extension()
130
-
131
- component = AsyncComponent()
132
- pn.template.FastListTemplate(
133
- site="Awesome Panel", site_url="https://awesome-panel.org", title="Async Tasks", main=[component], main_layout=None, main_max_width="400px"
134
- ).servable()
 
1
+ """
2
+ Checkout https://awesome-panel.org/resources/lonboard_dashboard/
3
+ """
4
+ # pip install panel colorcet ipywidgets_bokeh geopandas palettable lonboard
5
+ import colorcet as cc
6
+ import geopandas as gpd
7
+
8
+ from lonboard import Map, PathLayer
9
+ from lonboard.colormap import apply_continuous_cmap
10
+ from palettable.palette import Palette
11
 
 
12
  import panel as pn
13
+
14
+ url = "https://naciscdn.org/naturalearth/10m/cultural/ne_10m_roads_north_america.zip"
15
+ path = "ne_10m_roads_north_america.zip"
16
+
17
+ try:
18
+ gdf = pn.state.as_cached(
19
+ "ne_10m_roads_north_america", gpd.read_file, filename=path, engine="pyogrio"
20
+ )
21
+ except:
22
+ gdf = pn.state.as_cached(
23
+ "ne_10m_roads_north_america", gpd.read_file, filename=url, engine="pyogrio"
24
+ )
25
+
26
+ state_options = sorted(state for state in gdf["state"].unique() if state)
27
+
28
+
29
+ def to_rgb(hex: str) -> list:
30
+ h = hex.strip("#")
31
+ return list(int(h[i : i + 2], 16) for i in (0, 2, 4))
32
+
33
+
34
+ def to_palette(cmap) -> Palette:
35
+ """Returns the ColorCet colormap as a palettable Palette"""
36
+ colors = [to_rgb(item) for item in cmap]
37
+ return Palette(name="colorcet", map_type="colorcet", colors=colors)
38
+
39
+
40
+ def create_map(state="California", cmap=cc.fire, alpha=0.8):
41
+ palette = to_palette(cmap)
42
+ data = gdf[gdf["state"] == state]
43
+ layer = PathLayer.from_geopandas(data, width_min_pixels=0.8)
44
+ normalized_scale_rank = (data["scalerank"] - 3) / 9
45
+ layer.get_color = apply_continuous_cmap(normalized_scale_rank, palette, alpha=alpha)
46
+ map_ = Map(layers=[layer], _height=650)
47
+ return map_
48
+
49
+
50
+ description = """# lonboard
51
+
52
+ A Python library for **fast, interactive geospatial vector data visualization** in Jupyter (and Panel).
53
+
54
+ By utilizing new technologies like `GeoArrow` and `GeoParquet` in conjunction with GPU-based map rendering, lonboard aims to enable visualizing large geospatial datasets interactively through a simple interface."""
55
+
56
+
57
+ # THE PANEL APP
58
+ pn.extension("ipywidgets")
59
+ state = pn.widgets.Select(
60
+ value="California",
61
+ options=state_options,
62
+ width=150,
63
+ name="State",
64
+ sizing_mode="stretch_width",
65
+ )
66
+ cmap = pn.widgets.ColorMap(
67
+ value=cc.fire,
68
+ options=cc.palette,
69
+ ncols=3,
70
+ swatch_width=100,
71
+ name="cmap by Colorcet",
72
+ sizing_mode="stretch_width",
73
+ )
74
+ alpha = pn.widgets.FloatSlider(
75
+ value=0.8, start=0, end=1, name="Alpha", min_width=100, sizing_mode="stretch_width"
76
+ )
77
+ logo = pn.pane.Image(
78
+ "https://github.com/developmentseed/lonboard/raw/main/assets/dalle-lonboard.jpg"
79
+ )
80
+ def title(state):
81
+ return f"# North America Roads: {state}"
82
+
83
+ settings = pn.Column(state, cmap, alpha)
84
+ description = pn.Column(pn.pane.Markdown(description, margin=5), logo)
85
+ component = pn.Column(
86
+ pn.bind(title, state=state),
87
+ pn.panel(
88
+ pn.bind(create_map, state=state, cmap=cmap, alpha=alpha.param.value_throttled),
89
+ sizing_mode="stretch_both",
90
+ ),
91
+ sizing_mode="stretch_both",
92
+ )
93
+ pn.template.FastListTemplate(
94
+ logo="https://panel.holoviz.org/_static/logo_horizontal_dark_theme.png",
95
+ title="Works with LonBoard",
96
+ main=[component],
97
+ sidebar=[description, settings],
98
+ ).servable()