Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Using buildings, roads, places and boundaries to support spatial analytics projects

1. Why this page matters

Remote sensing imagery often needs context. A satellite image may show pixels, but your project may need buildings, roads, land-use polygons, administrative boundaries, reference samples or validation data to make the analysis meaningful.

In the previous page, you searched for raster imagery. This page focuses on vector and contextual data that can support the same project.

The next page explains how to document and cite both raster and vector sources.


2. Core idea

Vector data can support an SDS320 project in several roles:

RoleExample
Study area definitionboundary polygon, city extent, protected area
Contextroads, rivers, land use, buildings
Training databuilding footprints, road lines, labelled polygons
Validation dataindependent reference points or polygons
Interpretationadministrative units, population context, infrastructure
Visualisationmap overlays, labels, location context

The same vector dataset can be helpful for one project and misleading for another. You need to check completeness, date, geometry quality and licence.


3. Workflow

Step 1: Identify the role of vector data

Consider what you need the vector data for before downloading it.

Examples:

I need building footprints as context for interpreting model outputs.
I need administrative boundaries to summarise predicted change by district.
I need road data to compare detected linear features with mapped roads.

This avoids collecting vector layers that do not support the analysis.


Step 2: Choose a vector source

Possible sources include:

SourcePossible use
Overture MapsBuildings, places, transportation, divisions and base features.
OpenStreetMapRoads, buildings, amenities, land use and other volunteered map features.
National or regional open data portalsOfficial boundaries, cadastral layers, land-use data or infrastructure.
WRI / Global Nature Watch data platformsEnvironmental monitoring and forest-related context data.
Project-specific datasetsField data, labelled samples, provided training data or institutional data.

Step 3: Access Overture Maps data

The GeoAI source material shows Overture Maps as a source for building footprints and other vector data. Overture data can be useful for buildings, places, transportation and other contextual features.

The geoai package offers two ways to access Overture data. Both rely on the overturemaps package, which is installed automatically as a dependency of geoai in the SDS320 environment. Both can take a few minutes to run depending on the size of your bounding box and your network speed.

Option A: Download to a file

download_overture_buildings() uses the Overture Maps CLI to download building footprints for a bounding box and save them to disk:

import os
import geoai

bbox = (8.53, 47.37, 8.54, 47.38)  # example WGS84 bbox near Zurich

output_path = "buildings.geojson"

geoai.download_overture_buildings(
    bbox=bbox,
    output=output_path,
    overture_type="building",
)

full_path = os.path.abspath(output_path)
file_size_mb = os.path.getsize(full_path) / (1024 * 1024)

print(f"Buildings saved to {full_path}")
print(f"File size: {file_size_mb:.2f} MB")

The saved file size depends on the bounding box size and building density: a small test area like the one above is typically well under a megabyte, while a city-scale query can reach tens or hundreds of megabytes. Check the file size before scaling up your bounding box.

Option B: Load directly as a GeoDataFrame

For more flexibility, get_overture_data() returns the data directly as a GeoDataFrame, which is convenient for immediate inspection and filtering. It also supports other feature types beyond buildings, such as places, roads, land cover and water:

import geoai

bbox = (8.53, 47.37, 8.54, 47.38)  # example WGS84 bbox near Zurich

buildings = geoai.get_overture_data(
    overture_type="building",
    bbox=bbox,
    output="buildings.parquet",
)

print(f"Downloaded {len(buildings)} buildings")
buildings.head()

Step 4: Access OSM-style data

While Overture Maps is increasingly popular for building footprints, OpenStreetMap (OSM) remains a valuable source for roads, points of interest, land-use polygons and many other features maintained by a global community of volunteers. In GeoAI projects, OSM data is commonly used to generate training labels for tasks such as road extraction, building detection and land-use classification.

The quackosm library uses DuckDB to extract OSM data efficiently from PBF files, and leafmap.osm provides convenient wrapper functions around it. You can query by bounding box, by place name or by a custom geometry.

To query by bounding box, use quackosm_gdf_from_bbox() with an OSM tag filter:

import leafmap.osm as osm

bbox = (8.53, 47.37, 8.54, 47.38)  # example WGS84 bbox near Zurich

buildings_osm = osm.quackosm_gdf_from_bbox(bbox, tags={"building": True})

print(f"Downloaded {len(buildings_osm)} buildings")
buildings_osm.head()

To query by place name, use quackosm_gdf_from_place():

roads = osm.quackosm_gdf_from_place("Basel, Switzerland", tags={"highway": True})

print(f"Downloaded {len(roads)} road segments")
roads.head()

For more precise control over the query area, pass a Shapely geometry to quackosm_gdf_from_geometry():

from shapely.geometry import Polygon

polygon = Polygon([
    (8.53, 47.37),
    (8.54, 47.37),
    (8.54, 47.38),
    (8.53, 47.38),
])

natural = osm.quackosm_gdf_from_geometry(polygon, tags={"natural": True})

print(f"Downloaded {len(natural)} natural features")
natural.head()

The quackosm functions accept any valid OSM tag for filtering. Common tags for GeoAI work include building, landuse, natural, waterway, highway and amenity.


Step 5: Access Swiss geodata

If your project area is in Switzerland, the federal geoportal map.geo.admin.ch is backed by a set of free public REST APIs from swisstopo. Most endpoints need no API key, which makes them convenient for use, but swisstopo does enforce rate limits on high-frequency requests.

The relevant services are:

ServiceBase URLPurpose
Core REST APIapi3.geo.admin.chGeocoding, the “identify” endpoint (query features at a point), feature search, height/elevation lookup.
STAC catalogdata.geo.admin.chDownloadable datasets such as orthophotos, elevation models and 3D building data.
WMTS tile servicewmts.geo.admin.chMap tiles and imagery, and the basis for shareable map.geo.admin.ch links.

Because most of these endpoints are plain REST services, you can query them directly with requests, without a dedicated Python wrapper. The following example uses the “identify” endpoint with an envelope (bounding box) geometry to download the Suitability of roofs for the use of solar energy dataset, published by the Swiss Federal Office of Energy (SFOE), for a small residential quarter in Zurich, and loads the result directly into a GeoDataFrame:

import requests
import geopandas as gpd
from shapely.geometry import shape

identify_url = "https://api3.geo.admin.ch/rest/services/api/MapServer/identify"

bbox = "8.5470,47.3950,8.5490,47.3970"  # small quarter in Zurich, WGS84

response = requests.get(
    identify_url,
    params={
        "geometry": bbox,
        "geometryType": "esriGeometryEnvelope",
        "geometryFormat": "geojson",
        "sr": 4326,
        "layers": "all:ch.bfe.solarenergie-eignung-daecher",
        "tolerance": 0,
        "mapExtent": "8.50,47.35,8.60,47.45",
        "imageDisplay": "800,600,96",
        "returnGeometry": "true",
    },
)
response.raise_for_status()

results = response.json()["results"]

roofs = gpd.GeoDataFrame(
    [r["properties"] for r in results],
    geometry=[shape(r["geometry"]) for r in results],
    crs="EPSG:4326",
)

print(f"Downloaded {len(roofs)} roof facets")
roofs[["klasse_text", "flaeche", "stromertrag"]].head()

Each roof facet carries a suitability class (klasse_text, ranging from low to top suitability), its area in square metres (flaeche) and an estimated annual electricity yield in kWh (stromertrag). This dataset is only offered as a single whole-of-Switzerland download through the STAC catalog, so for a small project area, querying by bounding box like this is more practical than downloading the full national file.

You can also query features at a specific point using the “identify” endpoint. This is useful for contextual lookups, for example checking whether a location sits on a mapped hiking trail:

identify_url = "https://api3.geo.admin.ch/rest/services/api/MapServer/identify"

response = requests.get(
    identify_url,
    params={
        "geometry": "8.5480,47.3980",
        "geometryType": "esriGeometryPoint",
        "sr": 4326,
        "layers": "all:ch.swisstopo.swisstlm3d-wanderwege",
        "tolerance": 200,
        "mapExtent": "8.50,47.35,8.60,47.45",
        "imageDisplay": "800,600,96",
    },
)
response.raise_for_status()

results = response.json()["results"]
print(f"Found {len(results)} nearby trail segments")
if results:
    print(results[0]["attributes"])

A third pattern is feature search: querying a layer’s attributes by name instead of by location. The following example searches the swisstopo district-boundary layer for districts named “Bern”:

find_url = "https://api3.geo.admin.ch/rest/services/api/MapServer/find"

response = requests.get(
    find_url,
    params={
        "layer": "ch.swisstopo.swissboundaries3d-bezirk-flaeche.fill",
        "searchText": "Bern",
        "searchField": "name",
        "returnGeometry": "false",
    },
)
response.raise_for_status()

for feature in response.json()["results"]:
    print(feature["attributes"]["name"], feature["attributes"]["flaeche"], "ha")

Project check: direct API access is convenient for small, targeted lookups, such as a single quarter or a handful of points. For bulk downloads over a larger area, prefer the STAC catalog or an official bulk-download tool instead of looping over the REST API.


Step 6: Access global datasets

Alongside the specific sources above, a growing number of platforms curate global environmental and urban monitoring datasets, each with its own interactive map viewer. These are worth browsing manually first, since not every platform offers a convenient API, and a manual download through the browser is sometimes the most practical route into a project.

PlatformWhat it offersExplore
World Resources Institute (WRI) Data ExplorerA long-established, broad catalogue of curated environmental and socioeconomic datasets covering forests, water, cities, climate and land use.wri.org/data
Global Nature WatchA newer WRI platform for near-real-time, satellite-based monitoring of forest and land-cover change worldwide.globalnaturewatch.org/map
Fields of the World (FTW)A benchmark and interactive inference app for machine-learning-derived agricultural field boundaries, useful as training data or comparison in cropland-mapping projects.fieldsofthe.world
Global Building Atlas (GBA)AI-generated global building footprints and height data, viewable through a Google Earth Engine app.sat-io.earthengine.app/view/gba

A few more platforms worth knowing about:


Step 7: Check vector data quality

After loading vector data, inspect it before using it.

print("Rows:", len(buildings))
print("CRS:", buildings.crs)
print("Geometry types:", buildings.geom_type.value_counts())
print("Bounds:", buildings.total_bounds)

Also map a small sample with your imagery or basemap. Check whether the data align spatially and whether obvious features are missing.


Step 8: Save vector data

For project work, prefer robust and reproducible formats.

Common choices include:

FormatUse
GeoPackageGood general-purpose local vector format.
GeoParquetEfficient for larger vector datasets and modern cloud workflows.
GeoJSONEasy to inspect and share for small datasets.
ShapefileStill common, but has quite some practical limitations.

Record which format you used and why.


4. Python reactivation

Vector data workflows often use familiar GeoPandas operations:

# Inspect columns
buildings.columns

# Select useful columns
selected = buildings[["geometry"]].copy()

# Check approximate feature count
len(selected)

If you calculate areas, make sure the data are in a projected CRS with metre-based units.

# Example only: use a suitable CRS for your own study area
buildings_projected = buildings.to_crs("EPSG:2056")
buildings_projected["area_m2"] = buildings_projected.area

5. Common pitfalls

PitfallHow to avoid it
Treating vector data as complete truthCheck completeness and source limitations.
Ignoring CRSConfirm that vector and raster data align before analysis.
Using huge vector datasets too earlyStart with a small bounding box.
Using building footprints as labels without checking qualityInspect alignment with imagery.
Forgetting licence and attributionRecord provider and reuse conditions.
Saving only processed dataPreserve notes about original source and access route.

6. Mini task

Find one vector or contextual dataset for your project.

Write:

Dataset:
Provider:
Feature type:
Role in project:
Access method:
CRS:
Format:
Quality concern:
Licence or attribution note:
Decision:

7. Key takeaways