Release v1.0.0
This is the first releas of dpg-map, an AI coded dearpygui map widget built due to a lack of time to build it myself. It features multi-widget abilities, with layers, overlays etc
This commit is contained in:
168
README.md
168
README.md
@@ -1,30 +1,34 @@
|
||||
# dpg-map
|
||||
|
||||
`dpg-map` is a Dear PyGui map widget for XYZ raster tiles and geographic overlays.
|
||||
|
||||
The rebuilt beta exposes a stable public import:
|
||||
`dpg-map` is a Dear PyGui widget for interactive XYZ raster maps, tile caching, and
|
||||
geographic overlays.
|
||||
|
||||
```python
|
||||
import dpg_map as dpgm
|
||||
```
|
||||
|
||||
The widget is built for telemetry dashboards and internal tools that need maps inside normal
|
||||
Dear PyGui layouts. Runtime updates are thread-safe: marker, trajectory, view, provider, and
|
||||
cache calls update logical state or enqueue renderer work, while Dear PyGui draw calls stay on
|
||||
the GUI thread.
|
||||
|
||||
## Install
|
||||
|
||||
Use `uv` for development and dependency management:
|
||||
For local development:
|
||||
|
||||
```bash
|
||||
uv sync
|
||||
uv run pytest
|
||||
```
|
||||
|
||||
From another local project, add this package as an editable dependency:
|
||||
From another local project:
|
||||
|
||||
```bash
|
||||
uv add --editable ../dpg-map
|
||||
uv run python -c "import dpg_map as dpgm; print(dpgm.list_providers())"
|
||||
```
|
||||
|
||||
## Basic Map
|
||||
## Minimal Example
|
||||
|
||||
```python
|
||||
from typing import Any
|
||||
@@ -37,7 +41,7 @@ dpg: Any = _dpg
|
||||
dpgm.configure(user_agent="my-app/0.1 contact@example.com")
|
||||
|
||||
dpg.create_context()
|
||||
dpg.create_viewport(title="Map", width=1000, height=700)
|
||||
dpg.create_viewport(title="Map", width=900, height=600)
|
||||
|
||||
with dpg.window(label="Map", width=-1, height=-1):
|
||||
with dpgm.map_widget(tag="map", center=(47.9029, 1.9093), zoom=15, width=-1, height=-1):
|
||||
@@ -49,128 +53,36 @@ dpg.start_dearpygui()
|
||||
dpg.destroy_context()
|
||||
```
|
||||
|
||||
## Sizing
|
||||
|
||||
The widget is a Dear PyGui `child_window` containing a measured drawlist. The child keeps the requested Dear PyGui sizing intent while the drawlist uses concrete measured pixels.
|
||||
|
||||
Supported sizing modes:
|
||||
|
||||
- `width=0` and `height=0` keep Dear PyGui default sizing.
|
||||
- `width=-1` and `height=-1` fill available space where Dear PyGui supports it.
|
||||
- Positive dimensions request fixed sizes.
|
||||
- `autosize_x` and `autosize_y` are passed to the child window.
|
||||
- Hidden layouts preserve the last non-zero measured size until visible again.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
uv run python examples/sizing_window.py
|
||||
uv run python examples/sizing_child.py
|
||||
uv run python examples/sizing_table.py
|
||||
uv run python examples/hidden_tab.py
|
||||
```
|
||||
|
||||
## Live Updates
|
||||
|
||||
Runtime overlay updates are safe to call from background threads. They update logical state and enqueue renderer commands; Dear PyGui drawing, texture, handler, and viewport calls stay on the GUI thread.
|
||||
|
||||
Live marker update:
|
||||
|
||||
```python
|
||||
dpgm.add_marker("vehicle", lat=47.9029, lon=1.9093, map_tag="map")
|
||||
dpgm.update_marker("vehicle", lat=current_lat, lon=current_lon, map_tag="map")
|
||||
```
|
||||
|
||||
Live trajectory update:
|
||||
|
||||
```python
|
||||
dpgm.add_trajectory("track", points=[], map_tag="map")
|
||||
dpgm.update_trajectory("track", points=tuple(points), map_tag="map")
|
||||
```
|
||||
|
||||
Stress examples:
|
||||
|
||||
```bash
|
||||
uv run python examples/markers_live_thread.py
|
||||
uv run python examples/trajectory_live_thread.py
|
||||
```
|
||||
|
||||
## Providers
|
||||
|
||||
OpenStreetMap is registered as `osm` by default. Custom XYZ providers can be registered and selected at runtime:
|
||||
|
||||
```python
|
||||
provider = dpgm.TileProvider(
|
||||
name="custom",
|
||||
url_template="https://example.com/{z}/{x}/{y}.png",
|
||||
attribution="Tiles (c) Example",
|
||||
)
|
||||
dpgm.register_provider(provider)
|
||||
dpgm.set_provider("custom", map_tag="map")
|
||||
```
|
||||
|
||||
Provider switching preserves overlays and center, clamps zoom to the new provider range, increments the tile generation, and ignores stale tile results from the previous provider.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
uv run python examples/custom_provider.py
|
||||
```
|
||||
|
||||
## Cache
|
||||
|
||||
Tiles use an in-memory cache and a persistent provider-namespaced disk cache.
|
||||
|
||||
```python
|
||||
dpgm.configure(
|
||||
user_agent="my-app/0.1 contact@example.com",
|
||||
cache_dir=".tile-cache",
|
||||
memory_cache_max_tiles=512,
|
||||
disk_cache_max_bytes=2_000_000_000,
|
||||
)
|
||||
|
||||
stats = dpgm.get_cache_stats(map_tag="map")
|
||||
dpgm.clear_memory_cache(map_tag="map")
|
||||
dpgm.clear_disk_cache(provider="osm")
|
||||
```
|
||||
|
||||
`disk_cache_max_bytes=None` disables the disk size limit. Memory cache clears are routed through the renderer command queue so texture deletion happens on the GUI thread. Disk cache clears can target all providers or a single provider namespace.
|
||||
|
||||
Cache example:
|
||||
|
||||
```bash
|
||||
uv run python examples/cache_stress.py
|
||||
```
|
||||
|
||||
## OpenStreetMap Usage
|
||||
|
||||
The default OpenStreetMap provider requires attribution and should use an application-specific `User-Agent`.
|
||||
|
||||
```python
|
||||
dpgm.configure(user_agent="my-product/1.0 contact@example.com")
|
||||
```
|
||||
|
||||
If no user agent is configured, `dpg-map` emits a runtime warning and falls back to a package user agent. Applications are responsible for displaying provider attribution in accordance with provider terms; the renderer draws the provider attribution text on the map.
|
||||
|
||||
## Thread-Safety Contract
|
||||
|
||||
Public runtime functions are intended to be callable from non-GUI threads unless explicitly documented otherwise. They acquire map locks briefly, update logical state, and/or enqueue commands.
|
||||
|
||||
Thread-safe runtime areas include:
|
||||
|
||||
- view updates: `set_center`, `set_zoom`, `set_view`, `fit_bounds`
|
||||
- overlay updates: `add_marker`, `update_marker`, `update_trajectory`, `delete_overlay`
|
||||
- layer updates: `add_layer`, `show_layer`, `hide_layer`, `clear_layer`
|
||||
- provider/cache updates: `set_provider`, `clear_memory_cache`, `clear_disk_cache`
|
||||
|
||||
`map_widget(...)` creates Dear PyGui items and must be used on the GUI thread inside an active Dear PyGui context.
|
||||
|
||||
## Examples
|
||||
Run the bundled example:
|
||||
|
||||
```bash
|
||||
uv run python examples/basic_map.py
|
||||
uv run python examples/cache_stress.py
|
||||
uv run python examples/custom_provider.py
|
||||
uv run python examples/markers_live_thread.py
|
||||
uv run python examples/trajectory_live_thread.py
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Getting Started](docs/GETTING_STARTED.md)
|
||||
- [Examples](docs/EXAMPLES.md)
|
||||
- [API Reference](docs/API_REFERENCE.md)
|
||||
|
||||
Internal rebuild notes, implementation plans, and agent logs live in [codex/](codex/).
|
||||
|
||||
## Highlights
|
||||
|
||||
- OpenStreetMap provider registered by default as `osm`
|
||||
- Custom XYZ tile providers
|
||||
- Pan and cursor-centered zoom
|
||||
- Markers, polylines, and live trajectories
|
||||
- Overlay layers with visibility and z-order controls
|
||||
- Memory tile cache and provider-namespaced disk cache
|
||||
- Multiple independent map widgets in one Dear PyGui app
|
||||
- Background-thread runtime updates for telemetry workloads
|
||||
|
||||
## Project Commands
|
||||
|
||||
```bash
|
||||
uv run pytest
|
||||
uv run ruff check .
|
||||
uv run ruff format --check .
|
||||
uv run pyright
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user