MarcSkovMadsen's picture
Improve efficiency with in-place updates
c32e2b7 verified
raw
history blame
4.34 kB
import colorcet as cc
import geopandas as gpd
import param
from lonboard import Map, PathLayer
from lonboard.colormap import apply_continuous_cmap
from lonboard._viewport import compute_view
from palettable.palette import Palette
import panel as pn
pn.extension("ipywidgets")
url = "https://naciscdn.org/naturalearth/10m/cultural/ne_10m_roads_north_america.zip"
@pn.cache
def get_data():
return gpd.read_file(filename=url, engine="pyogrio")
gdf = get_data()
state_options = sorted(state for state in gdf["state"].unique() if state)
description = """# Lonboard
A Python library for **fast, interactive geospatial vector data visualization** in Jupyter (and Panel).
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."""
logo = pn.pane.Image(
"https://github.com/developmentseed/lonboard/raw/main/assets/dalle-lonboard.jpg"
)
def to_rgb(hex: str) -> list:
h = hex.strip("#")
return list(int(h[i : i + 2], 16) for i in (0, 2, 4))
def to_palette(cmap) -> Palette:
"""Returns the ColorCet colormap as a palettable Palette"""
colors = [to_rgb(item) for item in cmap]
return Palette(name="colorcet", map_type="colorcet", colors=colors)
class StateViewer(pn.viewable.Viewer):
value: Map = param.ClassSelector(class_=Map, doc="The map object", constant=True)
state: str = param.Selector(default="California", objects=state_options)
cmap: str = param.Selector(default=cc.fire, objects=cc.palette, label="cmap by Colorcet")
alpha: float = param.Number(default=0.8, bounds=(0, 1))
data = param.DataFrame()
def __init__(self, **params):
params["value"] = params.get("value", Map(layers=[], view_state={"longitude": -119.81446785010868, "latitude": 36.08305565437565, "zoom": 5}))
super().__init__(**params)
self.value.layout.width=self.value.layout.height="100%"
self.description = pn.Column(pn.pane.Markdown(description, margin=5), logo)
self.settings = pn.Column(
pn.widgets.Select.from_param(self.param.state, sizing_mode="stretch_width"),
pn.widgets.ColorMap.from_param(
self.param.cmap,
ncols=3,
swatch_width=100,
name="cmap by Colorcet",
sizing_mode="stretch_width",
),
pn.widgets.FloatSlider.from_param(
self.param.alpha, sizing_mode="stretch_width"
),
margin=5,
sizing_mode="fixed",
width=300,
)
self.view = pn.Column(
self._title, pn.pane.IPyWidget(self.value, sizing_mode="stretch_both")
)
self._layout = pn.Row(
pn.Column(self.settings, sizing_mode="fixed", width=300),
self.view,
sizing_mode="stretch_both",
)
def __panel__(self):
return self._layout
@param.depends("state", watch=True, on_init=True)
def _update_data(self):
self.data = gdf[gdf["state"] == self.state]
def _get_color(self):
palette = to_palette(self.cmap)
normalized_scale_rank = (self.data["scalerank"] - 3) / 9
return apply_continuous_cmap(normalized_scale_rank, palette, alpha=self.alpha)
@param.depends("data", watch=True)
def _update_value(self):
layer = PathLayer.from_geopandas(self.data, width_min_pixels=0.8)
layer.get_color = self._get_color()
self.value.layers = [layer]
self._fly_to_center()
def _fly_to_center(self):
computed_view_state = compute_view(self.value.layers)
self.value.fly_to(
**computed_view_state,
duration=1000,
)
@param.depends("cmap", "alpha", watch=True)
def _update_layer_get_color(self):
self.value.layers[0].get_color = self._get_color()
@param.depends("state")
def _title(self):
return f"# North America Roads: {self.state}"
viewer = StateViewer()
pn.template.FastListTemplate(
logo="https://panel.holoviz.org/_static/logo_horizontal_dark_theme.png",
title="Works with Lonboard",
sidebar=[viewer.description, viewer.settings],
main=[viewer.view],
main_layout=None,
).servable()