Skip to main content

reflex-react-globe-gl

react-globe.gl for Reflex: 3D globe data visualization (ThreeJS/WebGL) written in pure Python.

  • Complete API: every prop and callback of react-globe.gl 2.38 — globe, points, arcs, polygons, paths, heatmaps, hex bins, hexed polygons, tiles, particles, rings, labels, HTML elements, 3D objects and custom layers — plus animate_in, wait_for_globe_ready and renderer_config.
  • Reflex-friendly events: callbacks receive plain, JSON-safe dicts (the ThreeJS internals, DOM events and circular references are stripped in the browser).
  • Responsive: fills its container by default (no more window-sized canvas).
  • Declarative imperative API: camera (point_of_view), orbit controls (auto_rotate, …), animation_paused and globe_material_options are regular props bound to your state.
  • Actions for the imperative methods (fly_to, get_point_of_view, get_screen_coords, …) usable directly as event triggers or returned from event handlers.
  • Helpers to write accessor functions from Python: js, constant, attr, color_scale, tooltip, tile_url, three_mesh, three_material.

Installation

pip install reflex-react-globe-gl
# or
uv add reflex-react-globe-gl

Requires Python 3.11+ and reflex>=0.10.0. The npm packages (react-globe.gl@2.38.0, three@0.186.0) are installed automatically by Reflex the first time the app compiles.

Quick start

import reflex as rx
import reflex_react_globe_gl as rg

IMG = "https://cdn.jsdelivr.net/npm/three-globe/example/img"


class State(rx.State):
    cities: list[dict] = [
        {"name": "Lagos", "lat": 6.52, "lng": 3.38, "size": 0.3},
        {"name": "Paris", "lat": 48.86, "lng": 2.35, "size": 0.5},
        {"name": "Tokyo", "lat": 35.68, "lng": 139.69, "size": 0.8},
    ]
    selected: str = ""

    @rx.event
    def select(self, city: dict):
        self.selected = city["name"]
        return rg.fly_to("globe", city["lat"], city["lng"], altitude=1.2)


def index() -> rx.Component:
    return rx.box(
        rg.globe(
            id="globe",
            globe_image_url=f"{IMG}/earth-night.jpg",
            background_image_url=f"{IMG}/night-sky.png",
            points_data=State.cities,
            point_altitude="size",          # attribute name
            point_color=rg.constant("orange"),  # constant value
            point_radius=0.6,
            point_label="name",
            on_point_click=State.select,
            auto_rotate=True,
            auto_rotate_speed=0.4,
        ),
        rx.text("Selected: ", State.selected, position="absolute", top="1em", left="1em"),
        height="100vh",
        position="relative",
    )


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

Concepts

Sizing

By default the globe fills its container (width: 100%; height: 100%, observed with a ResizeObserver). Give the parent a height (e.g. height="100vh") or style the globe itself (style={"height": "600px"} sizes the container). Explicit pixel width / height props (rg.globe(..., height=600)) override the measured size.

Accessor props

Like upstream, accessor props (point_lat, arc_color, hex_altitude, …) accept:

Value Meaning Example
str attribute name read from each datum point_lat="latitude"
number / bool constant point_radius=0.5
JS function computed per datum point_altitude=rg.js("d => d.pop * 1e-7")

A plain string is always an attribute name, so constant strings (colors!) need rg.constant("red").

Accessor functions run in the browser. They can reference state vars through f-strings and are re-applied whenever those vars change:

polygon_cap_color=rg.js(
    f"d => d.properties.ADMIN === {State.hovered} ? 'steelblue' : 'rgba(200, 0, 0, 0.6)'"
),

Helpers:

Helper Produces
rg.js("d => …") any JS expression (supports embedded state vars)
rg.constant(value) () => value
rg.attr("properties.NAME", default) nested attribute accessor
rg.color_scale("d.sumWeight", "YlOrRd", (0, 1e7), "sqrt") value → color (15 palettes or a list of hex colors; linear, sqrt, log, pow; any argument may be a state var)
rg.tooltip("<b>{name}</b><br/>{properties.POP_EST}") HTML tooltip from a template (values are escaped)
rg.tile_url("https://tile.openstreetmap.org/{z}/{x}/{y}.png") globe_tile_engine_url builder
rg.three_mesh("OctahedronGeometry", [1.5, 0], "MeshLambertMaterial", {"color": "cyan"}) object_three_object / custom_three_object factory
rg.three_material("MeshLambertMaterial", {...}) material for tile_material, polygon_cap_material, …

Inside rg.js you can use the global window.ReflexGlobe namespace, which exposes THREE, colorScale, PALETTES and get(id) (the globe handle, e.g. for getCoords).

Events

All layer callbacks are exposed with snake_case names (on_point_click, on_arc_hover, on_hex_polygon_right_click, on_custom_layer_click, …) plus on_globe_ready, on_globe_click, on_globe_right_click and on_zoom. Handlers receive JSON-safe values and may accept only a prefix of the arguments:

Trigger Handler arguments
on_<layer>_click, on_<layer>_right_click (datum, coords, event) — coords = {lat, lng, altitude}, event = {clientX, clientY, button, shiftKey, …}
on_<layer>_hover (datum_or_None, previous_or_None)
on_globe_click, on_globe_right_click (coords, event)
on_zoom (pov) — {lat, lng, altitude}, throttled by zoom_throttle_ms (150 ms)
on_html_element_click (datum, event) — markers created with html_markup
on_html_element_hover (datum_or_None)

Keys starting with __ and keys listed in event_data_exclude (default ["geometry"], so GeoJSON geometries are not shipped over the websocket on every hover) are removed from datums; arrays are capped at 2000 items. Regular DOM events (on_click, on_mouse_move, …) go to the container.

Reflex extensions

Prop Description
point_of_view / pov_transition_ms declarative camera {lat, lng, altitude}; the camera moves when it changes
auto_rotate, auto_rotate_speed, enable_zoom, enable_rotate, enable_pan orbit controls shortcuts
controls_options any OrbitControls attribute (minDistance, maxDistance, zoomSpeed, …)
animation_paused pause / resume the render loop
globe_material_options attributes applied to the globe MeshPhongMaterial (color, emissive, emissiveIntensity, shininess, bumpScale, opacity, transparent, wireframe, …)
html_markup attribute or JS function returning an HTML string per html_elements_data item (simpler than html_element), enables on_html_element_click/hover
event_data_exclude keys stripped from event datums
zoom_throttle_ms throttle interval of on_zoom
globe_tile_engine_max_level max zoom level of the slippy-map engine

Imperative actions

Give the globe an id and use the actions (they are rx.call_script event specs):

rx.button("Tokyo", on_click=rg.fly_to("globe", 35.68, 139.69, altitude=1.2, transition_ms=1500))
rx.button("Where am I?", on_click=rg.get_point_of_view("globe", State.receive_pov))
Action Upstream method
fly_to / point_of_view(id, lat, lng, altitude, transition_ms) pointOfView(pov, ms)
get_point_of_view(id, callback) pointOfView()
pause_animation(id), resume_animation(id) pauseAnimation(), resumeAnimation()
set_controls(id, **options) controls() attributes
clear_tile_cache(id) globeTileEngineClearCache()
get_screen_coords(id, lat, lng, alt, callback=…) getScreenCoords()
to_globe_coords(id, x, y, callback=…) toGlobeCoords()
get_coords(id, lat, lng, alt, callback=…) getCoords()
get_globe_radius(id, callback=…) getGlobeRadius()
run_js(id, code) anything else: globe and THREE are in scope (globe.scene(), globe.lights(), globe.camera(), globe.renderer(), globe.postProcessingComposer())

Performance tips

  • Keep large datasets in state and load them in on_load; data identity is preserved between renders, so layers are only rebuilt when the data actually changes.
  • Accessors without state vars are stabilized automatically; accessors that embed state vars are re-applied when the component re-renders. To switch between a few fixed functions, prefer rx.cond / rx.match over embedding the var (see the tiles demo).
  • hex_bin_merge=True, points_merge=True and enable_pointer_interaction=False trade interactivity for speed on very large datasets.

Demo app

react_globe_gl_demo/ is a multi-page Reflex app that exercises the whole API:

Page Features
World population hex bins from 11k cells, state-driven resolution / altitude / palette, hover & click
Countries choropleth, elevated and hexed polygons, labels, hover highlight, click → details + fly-to
Arcs & rings animated dashed arcs, "emit arcs on click" orchestrated by a backend background task, ripple rings
Cities & markers labels / points / HTML markers, declarative camera bound to state, rings around the selection
Heatmap & hexbins volcano heatmap, hex bins and points on the same dataset
Objects, particles & paths ThreeJS meshes (objects layer), custom layer, particle clouds, animated paths, satellites moved from the backend
Tiles & map engine slippy-map tile engine (OSM, CARTO, ESRI) and the tiles layer with custom materials
Globe playground globe images, atmosphere, graticules, material, orbit controls, pause, fly-to and query actions
git clone https://github.com/ecrespo/reflex-react-globe-gl
cd reflex-react-globe-gl
uv venv && uv pip install -e ".[dev]"
cd react_globe_gl_demo
uv run reflex run

Globe textures are loaded from jsDelivr. To serve them locally, copy the images from three-globe/example/img into react_globe_gl_demo/assets/img/ and run with GLOBE_IMG_BASE=/img uv run reflex run.

Development

uv pip install -e ".[dev]"
uv run pytest                      # Python + JS wrapper tests (the latter need Node 24)
# regenerate the .pyi stubs (Reflex 0.10 removed `reflex component build`), then build sdist + wheel
PYTHONPATH=. uv run --python 3.13 python -m reflex_base.utils.pyi_generator custom_components/reflex_react_globe_gl
uv build

Project layout:

custom_components/reflex_react_globe_gl/
├── react_globe_gl.py   # the Globe component (all props / events)
├── globe_wrapper.js    # React wrapper around react-globe.gl (sizing, events, registry…)
├── helpers.py          # js / constant / color_scale / tooltip / tile_url / three_mesh…
└── actions.py          # fly_to / get_point_of_view / set_controls / run_js…
react_globe_gl_demo/    # demo app
tests/                  # pytest suite

Credits

License

MIT © Ernesto Crespo

Metadata

Release files for reflex-react-globe-gl 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for reflex-react-globe-gl 0.2.0
File Size Uploaded Provenance
reflex_react_globe_gl-0.2.0.tar.gz 50.6 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for reflex-react-globe-gl 0.2.0
File Interpreter ABI Platform
reflex_react_globe_gl-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 91.7 kB

Release files / reflex_react_globe_gl-0.2.0.tar.gz

Download URL reflex_react_globe_gl-0.2.0.tar.gz
Size 50.6 kB
Tags Source
SHA-256 checksum
How to use checksums
13c55cb145f8bdfbe8ce96ae81a33962967ac3b643c2f395ac3be63df63ef656
BLAKE2b-256 checksum
How to use checksums
c2d03cda0d4d67cbfe3d4523df8d2c53408512de941c890a64d647ffd6683282
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Release files / reflex_react_globe_gl-0.2.0-py3-none-any.whl

Download URL reflex_react_globe_gl-0.2.0-py3-none-any.whl
Size 41.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3e8653fa47a6dd0f1ed1c6263fe56153fc28fe41ada0bc2db16c86a28177ed6b
BLAKE2b-256 checksum
How to use checksums
01ea209a5a3d491a50d5465ff4ecc97e96fb9d9862ed95f0fdc83ef053ef2654
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Security for reflex-react-globe-gl 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for reflex_react_globe_gl-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page