developmentseed / lonboard

A Python library for fast, interactive geospatial vector data visualization in Jupyter.
https://developmentseed.org/lonboard/latest/
MIT License
575 stars 28 forks source link

Document that lonboard works with Panel #262

Closed MarcSkovMadsen closed 5 months ago

MarcSkovMadsen commented 9 months ago

I checked it out and HoloViz Panel seems to work great with lonboard via its Ipywidgets/ Anywidgets support.

This could be quite useful to document. Let me know if you would accept a PR. Thanks.

https://github.com/developmentseed/lonboard/assets/42288570/5e62605d-a6e0-433b-b190-b7901579ca4f


"""Panel data app based on https://developmentseed.org/lonboard/latest/examples/north-america-roads/"""
# pip install panel colorcet ipywidgets_bokeh geopandas palettable lonboard
import colorcet as cc
import geopandas as gpd

from lonboard import Map, PathLayer
from lonboard.colormap import apply_continuous_cmap
from palettable.palette import Palette

import panel as pn

url = "https://naciscdn.org/naturalearth/10m/cultural/ne_10m_roads_north_america.zip"
path = "ne_10m_roads_north_america.zip"

try:
    gdf = pn.state.as_cached(
        "ne_10m_roads_north_america", gpd.read_file, filename=path, engine="pyogrio"
    )
except:
    gdf = pn.state.as_cached(
        "ne_10m_roads_north_america", gpd.read_file, filename=url, engine="pyogrio"
    )

state_options = sorted(state for state in gdf["state"].unique() if state)

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)

def create_map(state="California", cmap=cc.fire, alpha=0.8):
    palette = to_palette(cmap)
    data = gdf[gdf["state"] == state]
    layer = PathLayer.from_geopandas(data, width_min_pixels=0.8)
    normalized_scale_rank = (data["scalerank"] - 3) / 9
    layer.get_color = apply_continuous_cmap(normalized_scale_rank, palette, alpha=alpha)
    map_ = Map(layers=[layer], _height=650)
    return map_

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."""

# THE PANEL APP
pn.extension("ipywidgets")
state = pn.widgets.Select(
    value="California",
    options=state_options,
    width=150,
    name="State",
    sizing_mode="stretch_width",
)
cmap = pn.widgets.ColorMap(
    value=cc.fire,
    options=cc.palette,
    ncols=3,
    swatch_width=100,
    name="cmap by Colorcet",
    sizing_mode="stretch_width",
)
alpha = pn.widgets.FloatSlider(
    value=0.8, start=0, end=1, name="Alpha", min_width=100, sizing_mode="stretch_width"
)
logo = pn.pane.Image(
    "https://github.com/developmentseed/lonboard/raw/main/assets/dalle-lonboard.jpg"
)
def title(state):
    return f"# North America Roads: {state}"

settings = pn.Column(state, cmap, alpha)
description = pn.Column(pn.pane.Markdown(description, margin=5), logo)
component = pn.Column(
    pn.bind(title, state=state),
    pn.panel(
        pn.bind(create_map, state=state, cmap=cmap, alpha=alpha.param.value_throttled),
        sizing_mode="stretch_both",
    ),
    sizing_mode="stretch_both",
)
pn.template.FastListTemplate(
    logo="https://panel.holoviz.org/_static/logo_horizontal_dark_theme.png",
    title="Works with LonBoard",
    main=[component],
    sidebar=[description, settings],
).servable()
kylebarron commented 9 months ago

Thanks for trying out lonboard! I'm not familiar with panel, but glad to see that it works! Happy to add that to the docs or whatever makes sense.

When you select a new colormap, alpha, anything... the map element fully reloads... that's pretty bad. In particular, that seems really bad because all the map data will be re-parsed and re-rendered from scratch (and maybe even re-downloaded?). lonboard's architecture assumes that you have a stateful jupyter widget on the JS side, and so changing a colormap or the alpha should not create a new map. In particular, if things are wired up correctly, changing the alpha should be instantaneous (especially if you link the alpha to the opacity attribute of the layer, instead of re-generating the colormap colors)

I'm not familiar with panel but there should be a way to persist an existing widget and mutate its state. You don't want to be creating a new map element from create_map each time.

kylebarron commented 5 months ago

There's a panel page in the "ecosystem" section of the Lonboard docs, so I'll close this: https://developmentseed.org/lonboard/latest/ecosystem/panel/

MarcSkovMadsen commented 3 months ago

Sorry. I never saw the question about in-place updates. I've added a PR to document this in https://github.com/developmentseed/lonboard/pull/539.

Thanks for adding the original example to the docs.