Skip to content

Shiny

Input and output

Use output_maplibregl in the UI and render_maplibregl in the server section of your Shiny for Python app:

from shiny import App, ui
from maplibre import output_maplibregl, render_maplibregl, Map

app_ui = ui.page_fluid(
    ui.panel_title("MapLibre"),
    output_maplibregl("maplibre", height=600)
)


def server(input, output, session):
    @render_maplibregl
    def maplibre():
        m = Map()
        return m


app = App(app_ui, server)

Reactivity

Input events

MapLibre for Python provides the following reactive inputs:

  • input.{output_id}_clicked: Sends coordinates of the clicked location on the map.
  • input.{output_id}_feature_clicked: Sends the properties of the clicked feature and its layer id.
  • input.{output_id}_view_state: Sends the current view state. Fired when the view state is changed.

Map updates

Use MapContext to update your Map object.

Example

import json

from maplibre import (
    Layer,
    LayerType,
    Map,
    MapContext,
    output_maplibregl,
    render_maplibregl,
)
from maplibre.controls import NavigationControl
from maplibre.sources import GeoJSONSource
from shiny import App, reactive, render, ui

LAYER_ID = "earthquakes"
CIRCLE_RADIUS = 5

app_ui = ui.page_fluid(
    ui.panel_title("MapLibre for Python"),
    output_maplibregl("mapgl", height=600),
    ui.div("Click on the map to print the coords.", style="padding: 10px;"),
    ui.output_text_verbatim("coords", placeholder=True),
    ui.div("Click on a feature to print its props.", style="padding: 10px;"),
    ui.output_text_verbatim("props", placeholder=True),
    ui.div("Move map or zoom to update view state.", style="padding: 10px;"),
    ui.output_text_verbatim("view_state", placeholder=True),
    ui.input_slider("radius", "Radius", value=CIRCLE_RADIUS, min=1, max=10),
)

circle_layer = Layer(
    type=LayerType.CIRCLE,
    id=LAYER_ID,
    source=GeoJSONSource(
        data="https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson"
    ),
    paint={"circle-color": "yellow"},
)


def server(input, output, session):
    @render_maplibregl
    def mapgl():
        m = Map(zoom=3, pitch=40)
        m.add_control(NavigationControl())
        m.add_layer(circle_layer)
        return m

    @render.text
    def coords():
        return str(input.mapgl_clicked())

    @render.text
    def view_state():
        return json.dumps(input.mapgl_view_state(), indent=2)

    @render.text
    def props():
        return str(input.mapgl_feature_clicked())

    @reactive.Effect
    @reactive.event(input.radius)
    async def radius():
        async with MapContext("mapgl") as m:
            m.set_paint_property(LAYER_ID, "circle-radius", input.radius())


app = App(app_ui, server)

Run this example:

poetry run uvicorn docs.examples.getting_started.reactivity:app --reload