Skip to content

Commit

Permalink
Add ecosystem/integrations documentation (#350)
Browse files Browse the repository at this point in the history
### Change list

- Documentation for integrating with shiny, panel, geopandas,
geoarrow-rust, jupyter widgets
  • Loading branch information
kylebarron authored Feb 6, 2024
1 parent bf1794c commit bf843c0
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 147 deletions.
Binary file added assets/shiny-example.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions docs/ecosystem/geoarrow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# GeoArrow

[GeoArrow](https://geoarrow.org/) is an in-memory data structure for storing vector geospatial data and associated attributes. Lonboard uses GeoArrow internally and is the [primary reason why Lonboard is fast](../how-it-works.md#how-is-it-so-fast).

There's a burgeoning ecosystem of Python libraries that use GeoArrow internally. Creating Lonboard `Layer` objects from GeoArrow tables is the fastest way to visualize data, as no conversions are needed on the Python side.

## geoarrow-rust

[geoarrow-rust](https://geoarrow.org/geoarrow-rs/python/latest/) is a Python library implementing the GeoArrow specification with efficient spatial operations. This library has "rust" in the name because it is implemented based on the [GeoArrow Rust implementation](https://geoarrow.org/geoarrow-rs/).

```py
from geoarrow.rust.core import GeoTable, read_geojson
from lonboard import Map, PathLayer

path = "/path/to/file.geojson"
geo_table = read_geojson(path)

# Assuming the GeoJSON contains LineString or MultiLineString data
layer = PathLayer(table=geo_table)
m = Map(layer)
m
```

Refer to the [geoarrow-rust](https://geoarrow.org/geoarrow-rs/python/latest/) documentation for more information.
23 changes: 23 additions & 0 deletions docs/ecosystem/geopandas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# GeoPandas

[GeoPandas](https://geopandas.org/en/stable/) extends the Pandas data frame library to allow spatial operations on geospatial data.

All relevant Lonboard layer classes have a [`from_geopandas`](../api/layers/base-layer.md#lonboard.BaseArrowLayer.from_geopandas) method for `GeoDataFrame` input.

Some layer types, such as [`BitmapLayer`](../api/layers/bitmap-layer.md), don't have a `from_geopandas` method because the rendering isn't relevant to GeoPandas (i.e. GeoPandas doesn't store image data).

## Example

```py
import geodatasets
import geopandas as gpd
from lonboard import Map, SolidPolygonLayer

# New York City boroughs
gdf = gpd.read_file(geodatasets.get_path('nybb'))
layer = SolidPolygonLayer.from_geopandas(
gdf,
get_fill_color=[255, 0, 0],
)
m = Map(layer)
```
5 changes: 5 additions & 0 deletions docs/ecosystem/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Ecosystem

Lonboard aims to both integrate closely in the existing Python geospatial ecosystem and be future proof for the next generation of Python geospatial libraries.

The pages in this section outline various integrations. If there's a library you think Lonboard should integrate with or you want to document existing compatibility, [create an issue](https://github.com/developmentseed/lonboard/issues/new) to discuss.
5 changes: 5 additions & 0 deletions docs/ecosystem/jupyter-widgets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Jupyter Widgets

[Jupyter Widgets](https://ipywidgets.readthedocs.io/en/stable/) are interactive browser controls for Jupyter notebooks. While Lonboard's classes are themselves widgets, Jupyter Widgets' design means that widgets integrate with other widgets seamlessly.

For example, the `ipywidgets` Python library [includes many core widgets](https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20List.html) like sliders, dropdowns, color pickers, and file upload elements. Then you can [_link widgets together_](https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Events.html#linking-widgets). This means that your widget-based slider or chart can create events that change the display of a Lonboard map based on user input events.
108 changes: 108 additions & 0 deletions docs/ecosystem/panel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Panel

[Panel](https://panel.holoviz.org/) is a tool to build interactive web applications and dashboards using Python code.

Panel [has been reported to work](https://github.com/developmentseed/lonboard/issues/262) with Lonboard. However, it appears that Panel [does not support reactive updates](https://github.com/holoviz/panel/issues/5921) in the same way that [Shiny](./shiny) does, so the map will necessarily be recreated from scratch on every update.

## Example

This example was written by [@MarcSkovMadsen](https://github.com/MarcSkovMadsen) in [issue #262](https://github.com/developmentseed/lonboard/issues/262).

```py
"""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()
```
39 changes: 39 additions & 0 deletions docs/ecosystem/shiny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Shiny

[Shiny](https://shiny.posit.co/py/) is a tool to build interactive web applications and dashboards using Python code. Shiny [integrates with Jupyter Widgets](https://shiny.posit.co/py/docs/jupyter-widgets.html), which means that Lonboard is supported out-of-the-box.

Pay attention to the ["Efficient updates"](https://shiny.posit.co/py/docs/jupyter-widgets.html#efficient-updates) section of the Shiny documentation. This is the most efficient way to create a reactive map. Take care to not recreate the `Map` widget from scratch on updates, as that will send data from Python to the browser anew.


## Example

![](../assets/shiny-example.gif)

```py
import geopandas as gpd
from shiny import reactive
from shiny.express import input, ui
from shinywidgets import render_widget

from lonboard import Map, ScatterplotLayer

colors = {
"Red": [200, 0, 0],
"Green": [0, 200, 0],
"Blue": [0, 0, 200],
}

ui.input_select("color_select", "Color", choices=list(colors.keys()))


@render_widget
def map():
gdf = gpd.read_file(gpd.datasets.get_path("naturalearth_cities"))
layer = ScatterplotLayer.from_geopandas(gdf, radius_min_pixels=2)
return Map(layer)


@reactive.effect
def set_fill_color():
map.widget.layers[0].get_fill_color = colors[input.color_select()]
```
141 changes: 0 additions & 141 deletions examples/layers/bitmap-layer.ipynb

This file was deleted.

13 changes: 7 additions & 6 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,19 @@ nav:
- api/layers/arc-layer.md
- api/layers/text-layer.md
- api/experimental/traits.md
- Ecosystem:
- ecosystem/index.md
- ecosystem/geoarrow.md
- ecosystem/geopandas.md
- ecosystem/panel.md
- ecosystem/shiny.md

# - Caveats: caveats.md
- Performance: performance.md
- Changelog: CHANGELOG.md
- Alternatives: alternatives.md
- "How it works?": how-it-works.md

# - Ecosystem:
# - ecosystem/index.md
# - ecosystem/geopandas.md
# - ecosystem/geoarrow.md

watch:
- lonboard
- docs
Expand Down Expand Up @@ -121,7 +122,7 @@ plugins:
alias_type: "copy"
canonical_version: "latest"
- mkdocs-jupyter:
include_source: True
include_source: true
ignore: ["**/.ipynb_checkpoints/*.ipynb"]
- mkdocstrings:
enable_inventory: true
Expand Down

0 comments on commit bf843c0

Please sign in to comment.