File size: 4,337 Bytes
a19fe56
 
c32e2b7
a19fe56
 
 
c32e2b7
a19fe56
ab6a63c
 
a19fe56
c32e2b7
 
a19fe56
 
c32e2b7
 
 
a19fe56
c32e2b7
a19fe56
 
c32e2b7
 
 
 
 
 
 
 
 
a19fe56
 
 
 
 
 
 
 
 
 
c32e2b7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a19fe56
 
c32e2b7
 
 
 
a19fe56
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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()