Skip to main content

Reflex wrapper for react-map-gl (maplibre endpoint) — interactive MapLibre GL JS maps in pure Python.

Project description

reflex-mapgl-maplibre

Interactive MapLibre GL JS maps for Reflex, in pure Python. A thin, idiomatic wrapper around react-map-gl via its react-map-gl/maplibre endpoint — markers, popups, GeoJSON sources & layers, clustering, heatmaps, controls, feature interaction and imperative camera control, with no JavaScript or React required.

Status: beta (0.1.0). Core map, markers/popups, sources/layers, controls, multi-map provider and optional deck.gl/draw overlays are implemented, with a 58-test contract suite (100% wrapper coverage) and a demo app mapped to the upstream examples gallery. See specs/ for the full design.

Why

Reflex has no built-in map component. react-map-gl/maplibre is the standard React wrapper for MapLibre, but it is unreachable from Python without a wrapper. This package exposes it as Reflex components and ships a demo app that reproduces the upstream examples.

Install

uv add reflex-mapgl-maplibre      # or: pip install reflex-mapgl-maplibre

It pulls the npm packages react-map-gl and maplibre-gl into the compiled frontend automatically, and injects maplibre-gl/dist/maplibre-gl.css for you.

Quickstart

import reflex as rx
import reflex_mapgl_maplibre as mapgl

STYLE = "https://demotiles.maplibre.org/style.json"  # key-less basemap

def index() -> rx.Component:
    return mapgl.map(
        mapgl.navigation_control(position="top-right"),
        mapgl.marker(longitude=-122.4, latitude=37.8, color="#ef4444"),
        initial_view_state={"longitude": -122.4, "latitude": 37.8, "zoom": 11},
        map_style=STYLE,
        style={"width": "100%", "height": "100vh"},
    )

app = rx.App()
app.add_page(index)

Components

Factory Wraps Purpose
mapgl.map(...) Map (default export) Root map canvas, camera, style, events
mapgl.marker(...) Marker DOM marker at a lng/lat
mapgl.popup(...) Popup Floating info bubble
mapgl.source(...) Source Data source (GeoJSON, tiles, clustering)
mapgl.layer(...) Layer Style layer (circle/line/fill/symbol/heatmap/…)
mapgl.navigation_control(...) NavigationControl Zoom + compass
mapgl.geolocate_control(...) GeolocateControl Find my location
mapgl.fullscreen_control(...) FullscreenControl Fullscreen toggle
mapgl.scale_control(...) ScaleControl Scale bar
mapgl.attribution_control(...) AttributionControl Attribution box
mapgl.map_provider(...) MapProvider Multi-map / synced maps

Optional, heavier overlays live in reflex_mapgl_maplibre.advanced (deckgl_overlay, draw_control) and pull extra npm dependencies on demand.

Full contract: specs/api/component-api-v1.md.

Imperative camera control

map(...) returns an instance whose camera helpers produce event specs you can attach to any handler. The map needs an id:

m = mapgl.map(id="main", initial_view_state={...}, map_style=STYLE)

rx.button("Paris",    on_click=m.fly_to(2.35, 48.85, zoom=11))
rx.button("Fit area", on_click=m.fit_bounds([[-10, 36], [30, 60]], padding=40))

fly_to, ease_to, jump_to, fit_bounds are forwarded to the MapLibre MapRef (see Technical Design DD-003).

Examples (demo app)

The mapgl_maplibre_demo/ app maps the upstream examples gallery to one page each:

Page Example
/ Basic map
/controls Controls
/markers Markers & Popups
/geojson GeoJSON sources & layers
/clusters Clustering
/heatmap Heatmap
/interaction Click features → Reflex state
/animation Viewport animation (fly_to / fit_bounds)
/side-by-side Two maps under a MapProvider

Run it:

uv sync                       # create .venv with the wrapper + dev tools
cd mapgl_maplibre_demo
uv run reflex run             # the local wrapper is installed in editable mode

Basemaps use key-less styles (MapLibre demotiles, CARTO). For MapTiler styles, pass map_style="https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY".

Development & publishing (Reflex custom component, uv)

This repo follows the Reflex custom-components layout (custom_components/, a demo app, and a publishable pyproject.toml) and uses uv as the package manager.

# 1. Set up the dev environment (creates .venv, installs the wrapper editable
#    plus the dev group: build, twine, pytest, pytest-cov, ruff).
uv sync

# 2. Quality gates.
uv run ruff check custom_components tests
uv run pytest                      # 58 tests, 100% wrapper coverage

# 3. Build the component (regenerates the .pyi type stubs and the dist/ artifacts:
#    .whl + .tar.gz). `python -m reflex` keeps the repo root importable so the
#    stub generator can resolve `custom_components.*`.
uv run python -m reflex component build

# 4. Validate the distribution metadata for PyPI.
uv run twine check dist/*

# 5. Publish (requires a PyPI account + API token; see prerequisites docs).
uv publish                         # or: uv run twine upload dist/*
#   TestPyPI first:  uv publish --publish-url https://test.pypi.org/legacy/

reflex component build produces the same dist/ artifacts; uv build works too (both invoke the setuptools backend). The published wheel ships the .pyi stubs and a py.typed marker (PEP 561) for IDE autocomplete.

To list the component on the Reflex gallery after publishing: reflex component share.

Project layout

reflex-mapgl-maplibre/
├── custom_components/reflex_mapgl_maplibre/   # the wrapper package
│   ├── base.py        # shared base: library, CSS, NoSSR
│   ├── map.py         # Map root + imperative camera helpers
│   ├── markers.py     # Marker, Popup
│   ├── sources.py     # Source, Layer
│   ├── controls.py    # Navigation/Geolocate/Fullscreen/Scale/Attribution
│   ├── provider.py    # MapProvider
│   └── advanced.py    # deck.gl overlay & draw control (optional deps)
├── mapgl_maplibre_demo/                       # demo Reflex app
├── specs/                                     # SDD artifacts (see specs/README.md)
├── tests/                                     # compile/contract tests
└── scripts/create_github_repo.sh

Design docs (SDD)

This project is spec-driven. See specs/README.md: PRD · Component API Spec · Technical Design · Phases · Implementation Plan · Tasks · Upstream Analysis (examples catalog).

Compatibility

  • Python ≥ 3.10, Reflex ≥ 0.9
  • Frontend: react-map-gl@^8.1.1, maplibre-gl@^5

License

MIT. Upstream react-map-gl and maplibre-gl are MIT-licensed; this wrapper is published with attribution.

Credits

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

reflex_mapgl_maplibre-0.1.0.tar.gz (23.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

reflex_mapgl_maplibre-0.1.0-py3-none-any.whl (25.9 kB view details)

Uploaded Python 3

File details

Details for the file reflex_mapgl_maplibre-0.1.0.tar.gz.

File metadata

  • Download URL: reflex_mapgl_maplibre-0.1.0.tar.gz
  • Upload date:
  • Size: 23.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for reflex_mapgl_maplibre-0.1.0.tar.gz
Algorithm Hash digest
SHA256 040d73e8e98d364804fc1a02378c274d020cab19a5267f2bdcc557658a1e9953
MD5 d4134b7238c46ac31a38b5a8504ee27f
BLAKE2b-256 6d915aff5b847bb512d67ac68f92c3c569f4079eaf7ea4489539daa5d97f48e2

See more details on using hashes here.

File details

Details for the file reflex_mapgl_maplibre-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for reflex_mapgl_maplibre-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 461880d9c642bfea5a3bb3e324996c9e4e472396ad8f9321b137da4054e769ca
MD5 0c135e489042937496d5de1a4666be18
BLAKE2b-256 4704dc3f94325b2c3fd1b5039e08e435d4b8d273e5a68062daa2e6caf97b97f1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page