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:
286
docs/GETTING_STARTED.md
Normal file
286
docs/GETTING_STARTED.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# Getting Started
|
||||
|
||||
This guide walks through installing `dpg-map`, creating a map widget, adding overlays, updating
|
||||
the map from runtime code, and configuring tile providers and caches.
|
||||
|
||||
## Requirements
|
||||
|
||||
`dpg-map` currently targets Python `>=3.14` and uses:
|
||||
|
||||
- Dear PyGui for the UI
|
||||
- Pillow for decoding tile images
|
||||
- Requests for tile HTTP requests
|
||||
- Platformdirs for the default disk cache location
|
||||
|
||||
The project is managed with `uv`.
|
||||
|
||||
## Install From This Repository
|
||||
|
||||
For development inside this repository:
|
||||
|
||||
```bash
|
||||
uv sync
|
||||
uv run python -c "import dpg_map as dpgm; print(dpgm.list_providers())"
|
||||
```
|
||||
|
||||
For another local app using this checkout:
|
||||
|
||||
```bash
|
||||
cd /path/to/your-app
|
||||
uv add --editable /home/hector/projects/dpg-map
|
||||
```
|
||||
|
||||
Then import it as:
|
||||
|
||||
```python
|
||||
import dpg_map as dpgm
|
||||
```
|
||||
|
||||
## Configure The Package
|
||||
|
||||
Configure package-wide defaults before creating maps:
|
||||
|
||||
```python
|
||||
dpgm.configure(
|
||||
user_agent="my-product/1.0 contact@example.com",
|
||||
cache_dir=".tile-cache",
|
||||
memory_cache_max_tiles=512,
|
||||
disk_cache_max_bytes=2_000_000_000,
|
||||
)
|
||||
```
|
||||
|
||||
Set an application-specific `user_agent` when using OpenStreetMap tiles. If no user agent is
|
||||
configured, `dpg-map` emits a runtime warning and uses a fallback package user agent.
|
||||
|
||||
## Create A Map
|
||||
|
||||
`map_widget(...)` is a Dear PyGui context manager. It creates a child window containing the map
|
||||
drawlist and installs internal render and input handlers.
|
||||
|
||||
```python
|
||||
from typing import Any
|
||||
|
||||
import dearpygui.dearpygui as _dpg
|
||||
import dpg_map as dpgm
|
||||
|
||||
dpg: Any = _dpg
|
||||
|
||||
dpgm.configure(user_agent="getting-started/0.1 contact@example.com")
|
||||
|
||||
dpg.create_context()
|
||||
dpg.create_viewport(title="dpg-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):
|
||||
dpgm.add_marker("start", lat=47.9029, lon=1.9093, label="Start")
|
||||
|
||||
dpg.setup_dearpygui()
|
||||
dpg.show_viewport()
|
||||
dpg.start_dearpygui()
|
||||
dpg.destroy_context()
|
||||
```
|
||||
|
||||
`map_widget(...)` must be called on the GUI thread inside an active Dear PyGui context.
|
||||
|
||||
## Tags And Map Scope
|
||||
|
||||
Each map has a `tag`. Runtime calls should pass `map_tag` when there may be more than one map:
|
||||
|
||||
```python
|
||||
dpgm.set_center(47.9029, 1.9093, map_tag="live-map")
|
||||
dpgm.update_marker("vehicle", lat=47.9030, lon=1.9098, map_tag="live-map")
|
||||
```
|
||||
|
||||
Inside a `with dpgm.map_widget(...)` block, overlay creation can omit `map_tag` because the map is
|
||||
the current map context:
|
||||
|
||||
```python
|
||||
with dpgm.map_widget(tag="live-map"):
|
||||
dpgm.add_marker("vehicle", lat=47.9029, lon=1.9093)
|
||||
```
|
||||
|
||||
Use explicit `map_tag` in callbacks, worker threads, and apps with multiple maps.
|
||||
|
||||
## Add Overlays
|
||||
|
||||
Markers:
|
||||
|
||||
```python
|
||||
dpgm.add_marker(
|
||||
"vehicle",
|
||||
lat=47.9029,
|
||||
lon=1.9093,
|
||||
label="Vehicle",
|
||||
show_label=True,
|
||||
color=(255, 80, 80, 255),
|
||||
radius=6,
|
||||
map_tag="map",
|
||||
)
|
||||
```
|
||||
|
||||
Polylines:
|
||||
|
||||
```python
|
||||
dpgm.add_polyline(
|
||||
"route",
|
||||
points=[(47.9029, 1.9093), (47.9050, 1.9150), (47.9080, 1.9180)],
|
||||
color=(80, 180, 255, 255),
|
||||
thickness=3,
|
||||
map_tag="map",
|
||||
)
|
||||
```
|
||||
|
||||
Trajectories:
|
||||
|
||||
```python
|
||||
dpgm.add_trajectory(
|
||||
"track",
|
||||
points=[],
|
||||
color=(255, 180, 60, 255),
|
||||
thickness=3,
|
||||
show_points=True,
|
||||
point_stride=10,
|
||||
map_tag="map",
|
||||
)
|
||||
```
|
||||
|
||||
Coordinates are `(lat, lon)` pairs in degrees. Latitude must be between `-90` and `90`;
|
||||
longitude must be between `-180` and `180`.
|
||||
|
||||
## Runtime Updates
|
||||
|
||||
Runtime public calls are intended to be safe from background threads. They update logical state
|
||||
and enqueue GUI-thread work instead of calling Dear PyGui directly.
|
||||
|
||||
```python
|
||||
dpgm.update_marker("vehicle", lat=current_lat, lon=current_lon, map_tag="map")
|
||||
dpgm.update_trajectory("track", points=tuple(track_points), map_tag="map")
|
||||
```
|
||||
|
||||
Overlay updates do not reset map center or zoom.
|
||||
|
||||
## View Control
|
||||
|
||||
```python
|
||||
dpgm.set_center(47.9029, 1.9093, map_tag="map")
|
||||
dpgm.set_zoom(15, map_tag="map")
|
||||
dpgm.set_view(center=(47.9029, 1.9093), zoom=15, map_tag="map")
|
||||
dpgm.fit_bounds(((47.89, 1.89), (47.92, 1.93)), map_tag="map")
|
||||
```
|
||||
|
||||
`set_zoom(...)` and `set_view(...)` clamp zoom to the active provider range.
|
||||
|
||||
Coordinate conversion helpers use map-local screen coordinates:
|
||||
|
||||
```python
|
||||
lat, lon = dpgm.screen_to_latlon(120, 80, map_tag="map")
|
||||
x, y = dpgm.latlon_to_screen(47.9029, 1.9093, map_tag="map")
|
||||
```
|
||||
|
||||
## Layers
|
||||
|
||||
Overlays belong to named layers. Layers can be shown, hidden, cleared, and ordered with
|
||||
`z_index`.
|
||||
|
||||
```python
|
||||
dpgm.add_layer("vehicles", z_index=80, map_tag="map")
|
||||
dpgm.add_marker("car-1", lat=47.9, lon=1.9, layer="vehicles", map_tag="map")
|
||||
|
||||
dpgm.hide_layer("vehicles", map_tag="map")
|
||||
dpgm.show_layer("vehicles", map_tag="map")
|
||||
dpgm.clear_layer("vehicles", map_tag="map")
|
||||
```
|
||||
|
||||
Default layers include `default`, `markers`, `lines`, and `trajectories`.
|
||||
|
||||
## Tile Providers
|
||||
|
||||
OpenStreetMap is registered by default as `osm`.
|
||||
|
||||
Custom providers use XYZ URL templates. Required template fields are `{z}`, `{x}`, and `{y}`.
|
||||
Optional fields are `{s}` for subdomain, `{r}` for retina suffix, and `{ext}` for file extension.
|
||||
|
||||
```python
|
||||
provider = dpgm.TileProvider(
|
||||
name="carto-light",
|
||||
url_template="https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
|
||||
subdomains=("a", "b", "c", "d"),
|
||||
attribution="(c) OpenStreetMap contributors (c) CARTO",
|
||||
file_extension="png",
|
||||
)
|
||||
|
||||
dpgm.register_provider(provider)
|
||||
dpgm.set_provider("carto-light", map_tag="map")
|
||||
```
|
||||
|
||||
Provider switching preserves overlays and center, clamps zoom to the new provider range, and
|
||||
invalidates stale tile loads from the previous provider.
|
||||
|
||||
## Cache
|
||||
|
||||
`dpg-map` uses:
|
||||
|
||||
- A memory cache for decoded runtime tiles
|
||||
- A persistent provider-namespaced disk cache
|
||||
|
||||
```python
|
||||
stats = dpgm.get_cache_stats(map_tag="map")
|
||||
print(stats.memory_tiles, stats.disk_bytes, stats.disk_path)
|
||||
|
||||
dpgm.clear_memory_cache(map_tag="map")
|
||||
dpgm.clear_disk_cache(provider="osm")
|
||||
```
|
||||
|
||||
`clear_memory_cache(...)` is routed through the renderer command queue so Dear PyGui textures are
|
||||
deleted on the GUI thread. `clear_disk_cache(...)` can clear all providers, one provider, or a
|
||||
map-scoped cache directory.
|
||||
|
||||
## Sizing
|
||||
|
||||
The map widget is a Dear PyGui child window containing a measured drawlist.
|
||||
|
||||
Common sizing modes:
|
||||
|
||||
- `width=-1`, `height=-1`: fill available space where Dear PyGui supports it
|
||||
- Positive `width` and `height`: fixed requested size
|
||||
- `autosize_x=True` or `autosize_y=True`: pass Dear PyGui autosize flags to the child
|
||||
- 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
|
||||
```
|
||||
|
||||
## Multiple Maps
|
||||
|
||||
Multiple maps can be used in the same Dear PyGui app. Give each map a distinct tag and pass
|
||||
`map_tag` for runtime updates.
|
||||
|
||||
```python
|
||||
with dpgm.map_widget(tag="live-map", center=(47.9, 1.9), zoom=15, width=-1, height=300):
|
||||
dpgm.add_marker("vehicle", lat=47.9, lon=1.9)
|
||||
|
||||
with dpgm.map_widget(tag="recap-map", center=(47.9, 1.9), zoom=13, width=-1, height=300):
|
||||
dpgm.add_trajectory("lap", points=[])
|
||||
|
||||
dpgm.update_marker("vehicle", lat=47.901, lon=1.902, map_tag="live-map")
|
||||
dpgm.update_trajectory("lap", points=lap_points, map_tag="recap-map")
|
||||
```
|
||||
|
||||
Pan, zoom, tile rendering, overlays, providers, and caches are isolated per map unless you choose
|
||||
to share global configuration.
|
||||
|
||||
## Diagnostics
|
||||
|
||||
Use `get_map_debug_state(...)` and `get_cache_stats(...)` while developing or troubleshooting:
|
||||
|
||||
```python
|
||||
debug = dpgm.get_map_debug_state(map_tag="map")
|
||||
stats = dpgm.get_cache_stats(map_tag="map")
|
||||
```
|
||||
|
||||
These snapshots are intended for diagnostics and logging, not as a stable serialization format.
|
||||
Reference in New Issue
Block a user