The Map Widget

Guitares includes an interactive web-based map widget powered by either MapLibre GL (open-source, recommended) or Mapbox GL (requires an API token). The map is embedded in the Qt window via a QWebEngineView and communicates with Python through a bidirectional bridge.

Adding the map widget

Add the map to your YAML config like any other element:

- style: map
  id: map
  position: {x: 10, y: 180, width: -10, height: -10}
  module: map_callbacks
  map_style: osm
  map_lat: 0.0
  map_lon: 0.0
  map_zoom: 2

Map element keys

Key

Type

Default

Description

id

str

Unique ID — required to access the map object later

map_style

str

"osm"

Initial basemap style (see basemap styles below)

map_lat

float

0.0

Initial map center latitude

map_lon

float

0.0

Initial map center longitude

map_zoom

float

2

Initial zoom level

map_projection

str

"mercator"

Map projection: "mercator" or "globe"

Accessing the map object

The map object becomes available after the map has finished loading. Use the map_ready callback (triggered automatically) to store a reference:

# map_callbacks.py
from app import app

def map_ready(*args):
    element = app.gui.window.find_element_by_id("map")
    app.map = element.widget

    # Set up layers
    main = app.map.add_layer("main")
    main.add_layer("polygons", type="polygon")

def map_moved(*args):
    # Called when the user pans or zooms
    pass

Map navigation methods

Method

Description

map.fly_to(lon, lat, zoom)

Animate the map to a location

map.fit_bounds(lon1, lat1, lon2, lat2)

Zoom to fit a bounding box

map.set_layer_style(style)

Change the basemap style

map.set_projection(projection)

Switch between "mercator" and "globe"

map.set_terrain(enabled, exaggeration)

Enable or disable 3D terrain

map.click_point(callback)

Register a one-shot click handler that returns (lon, lat)

map.take_screenshot(path)

Save the current map view as a PNG

Basemap styles (MapLibre)

Style name

Description

"osm"

OpenStreetMap (default)

"satellite"

Satellite imagery

"topo"

Topographic map

Layer system

All map data is organized into a tree of layers. There are two kinds of layer objects:

  • Container layers — grouping nodes with no visual output, created with add_layer(id)

  • Data layers — visual layers with a type, created with add_layer(id, type="...")

Creating layers

# Container layer
main = app.map.add_layer("main")

# Data layers inside the container
main.add_layer("grid", type="polygon")
main.add_layer("boundaries", type="line")
main.add_layer("stations", type="circle")

Available layer types

Type

Description

polygon

Filled/outlined polygons from a GeoDataFrame

polygon_selector

Polygons with click-selection support

line

Polylines from a GeoDataFrame

line_selector

Polylines with click-selection support

circle

Point circles from a GeoDataFrame or coordinate lists

circle_selector

Circles with click-selection support

choropleth

Attribute-colored polygons (colored by a data column)

heatmap

Heatmap from point data

draw

Interactive drawing layer (polygon, polyline, rectangle)

marker

PNG icon markers at point locations

raster

Raster image overlay (numpy array + extent)

raster_image

Direct image overlay

raster_tile

Tile-based raster (URL template)

image

Generic image overlay

cyclone_track

Specialized storm track visualization

Setting layer data

Call set_data() on a data layer to pass it new content. The input type depends on the layer type:

import geopandas as gpd

# Polygon / line / circle layers: pass a GeoDataFrame
gdf = gpd.read_file("boundaries.geojson")
app.map.layer["main"].layer["boundaries"].set_data(gdf)

# Raster layer: pass a numpy array and extent
app.map.layer["main"].layer["flood_depth"].set_data(
    data=depth_array,         # 2D numpy array
    x0=lon_min, y0=lat_min,
    x1=lon_max, y1=lat_max
)

Layer styling

Layer appearance is controlled by attributes set directly on the layer object before or after set_data():

layer = app.map.layer["main"].layer["polygons"]
layer.fill_color = "blue"
layer.fill_opacity = 0.5
layer.line_color = "black"
layer.line_width = 1.0

Common style attributes:

Attribute

Description

fill_color

Fill color (color name, hex string, or "transparent")

fill_opacity

Fill opacity (0.0 – 1.0)

line_color

Outline/line color

line_width

Line width in pixels

circle_radius

Circle radius in pixels (circle layers)

hover_color

Color when the mouse hovers over a feature

selected_color

Color when a feature is selected

Layer visibility

layer.set_visible(True)   # show
layer.set_visible(False)  # hide

Draw layer

The draw layer lets users draw features interactively on the map. The drawn features are stored as a GeoDataFrame accessible via layer.gdf.

draw = app.map.layer["main"].layer["drawing"]

# Start drawing
draw.draw_polygon()
draw.draw_polyline()
draw.draw_rectangle()

# Stop drawing and switch to select mode
draw.stop_drawing()

# Access drawn features
gdf = draw.gdf   # GeoDataFrame with all drawn features

Map event callbacks

The map module in your YAML config can define callback functions that are called for map events:

Function name

When called

map_ready

Map has loaded and is ready; set up layers here

map_moved

User panned or zoomed the map

mouse_moved

Mouse cursor moved over the map (receives lon, lat)

Click and selection events are delivered to Python via the layer’s callback attributes:

layer = app.map.layer["main"].layer["polygons"]
layer.callback_click = my_click_callback   # called with feature index

Using Mapbox

To use Mapbox GL instead of MapLibre, set map_engine="mapbox" when creating the GUI:

self.gui = GUI(self, config_file="myapp.yml", map_engine="mapbox")

You must also place a file named mapbox_token.txt in the same directory as your config file, containing your Mapbox public access token on a single line.

Mapbox supports additional basemap styles:

map_style: mapbox://styles/mapbox/streets-v12
map_style: mapbox://styles/mapbox/satellite-v9
map_style: mapbox://styles/mapbox/outdoors-v12
map_style: mapbox://styles/mapbox/light-v11
map_style: mapbox://styles/mapbox/dark-v11