# 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.