This guide has 2 routes. Pick one, or read both. Each route is complete on its own.
OpenStreetMap, usually shortened to OSM, is a map of the world that volunteers build and anyone may use. It is often the best free source of roads, buildings, hospitals, schools, rivers and land use for a district, and it is the quickest way to get a base layer for a project.
This guide shows two routes to the same data. Route A uses QuickOSM, a plugin that adds a form to QGIS. Route B uses a short Python script. In both you say what you want with a key and a value, and where you want it with an area.
How OSM describes a feature
Every feature in OSM has tags, and a tag is a key and a value. A hospital has the key amenity and the value hospital, written amenity=hospital. A main road has highway=primary. A building has building=yes. A river has waterway=river. The OSM wiki page Map features lists the common ones, and it is worth keeping open when you plan a query.
A feature can also be one of three shapes. A node is a point, such as a shop. A way is a line, such as a road, or a closed line that makes a polygon, such as a building. A relation groups other features, for example a large multipolygon lake with an island. When you download, you get up to three layers, one for each shape, because the same tag can appear on a point and on a polygon. A hospital might be mapped as a point in one town and as a building outline in the next.
Licence
OSM data is open under the Open Database Licence (ODbL). You may use it freely, including commercially, as long as you credit OpenStreetMap contributors and share any changed version of the database under the same licence. For a map or a report, write "© OpenStreetMap contributors" near the figure. The copyright page of OSM, linked in the sources, gives the exact wording.
Route A: QuickOSM in QGIS
- Install QuickOSM. Open Plugins > Manage and Install Plugins, search for
QuickOSM, and click Install Plugin. - Open Vector > QuickOSM > QuickOSM.
- The first time, a message about the OSM licence appears. Click I understand the copyrights, access to the plugin.
- On the Quick query tab, type the Key
amenityand the Valuehospital. - Choose the area. In lets you type a place name such as
Jagraon. Canvas Extent uses the part of the map that you see on the screen, which is the better choice for a district that has no clear place name, or when you want a particular box. - Click Run query.
QuickOSM adds up to three layers to the project, one for points, one for lines and one for multipolygons, depending on how the features are mapped in your area. Layers with no features are not added. Open the attribute table to see the tags, such as name. The step-by-step version with screenshots is in the QGIS tutorial on capturing data.
To keep the result, right-click the layer, choose Export > Save Features As, and pick GeoPackage.
If you leave the Value empty, QuickOSM downloads every feature that has the key. building with no value gives every building, and that can be a very large download for a city. Start with a small area.
Route B: Python and the Overpass API
Overpass is the service that answers questions about OSM data. You send it a query and it sends back the features. A query has four parts: the output format, the kind of feature, the tag, and the box.
You need Python with requests, geopandas and shapely.
import requests
# Step 1: the service address, and a name for your script. Overpass refuses requests that do not say who is asking.
OVERPASS = "https://overpass-api.de/api/interpreter"
HEADERS = {"User-Agent": "timeandspatial-guide/1.0 (write your email address here)"}
def overpass(query):
# Step 2: send the query and return the list of features from the answer
reply = requests.post(OVERPASS, data={"data": query}, headers=HEADERS, timeout=120)
reply.raise_for_status()
return reply.json()["elements"]
# Step 3: the box. Overpass wants south, west, north, east, which is a different order from many other tools.
south, west, north, east = 30.74, 75.40, 30.84, 75.55 # a box of about 14 km by 11 km near Jagraon, Punjab
# Step 4: every hospital in the box, as a point. Features mapped as areas are reduced to their centre.
query = f'[out:json][timeout:60]; nwr["amenity"="hospital"]({south},{west},{north},{east}); out center;'
hospitals = overpass(query)
print(len(hospitals), "hospitals found")
print(hospitals[0]["type"], "|", hospitals[0]["tags"].get("name"))
33 hospitals found
node | Gupta Hospital, Kothe Baggu
Read the query piece by piece. [out:json] asks for the answer as JSON. nwr means nodes, ways and relations, so all three shapes. ["amenity"="hospital"] is the tag. The four numbers are the box. out center; asks for one point for every feature, which suits a list of places. The Overpass wiki page in the sources lists everything else you can ask.
Overpass is a shared service. The rules are: say who you are, ask for small areas, and do not send the same query many times a minute. A request that is too large or too frequent is refused with an error 429 or a timeout.
Turn the answer into a GeoPackage
import geopandas as gpd
# Step 1: build one row for each feature, with a point and its name and type
rows = []
for item in hospitals:
lat = item.get("lat") or item["center"]["lat"] # nodes carry lat and lon, areas carry a centre
lon = item.get("lon") or item["center"]["lon"]
tags = item.get("tags", {})
rows.append({"osm_type": item["type"], "osm_id": item["id"], "name": tags.get("name"), "operator": tags.get("operator"), "lon": lon, "lat": lat})
# Step 2: a GeoDataFrame, which is a table with a geometry column. OSM coordinates are longitude and latitude, EPSG:4326.
hospital_points = gpd.GeoDataFrame(rows, geometry=gpd.points_from_xy([r["lon"] for r in rows], [r["lat"] for r in rows]), crs="EPSG:4326")
print(hospital_points[["osm_type", "name"]].head())
# Step 3: save the layer into a GeoPackage
hospital_points.to_file("jagraon_osm.gpkg", layer="hospitals", driver="GPKG")
osm_type name
0 node Gupta Hospital, Kothe Baggu
1 node Jain Hospital
2 node Ayush Speech and Autism Centre
3 node Karan Singla Surgical and General Hospital
4 node Sharma Hospital
Roads: lines instead of points
Roads are ways, so ask for their geometry. The query asks for the main road classes only. Asking for every highway returns tracks and footpaths too, and the answer is much larger.
from shapely.geometry import LineString
# Step 1: main roads in the box, as lines. "out geom" returns the coordinates of every vertex.
road_classes = "motorway|trunk|primary|secondary|tertiary"
query = f'[out:json][timeout:60]; way["highway"~"^({road_classes})$"]({south},{west},{north},{east}); out geom;'
ways = overpass(query)
print(len(ways), "road segments found")
# Step 2: turn each way into a line. A way carries its vertices as a list of points.
roads = gpd.GeoDataFrame(
[{"osm_id": w["id"], "highway": w["tags"]["highway"], "name": w["tags"].get("name")} for w in ways],
geometry=[LineString([(p["lon"], p["lat"]) for p in w["geometry"]]) for w in ways],
crs="EPSG:4326",
)
# Step 3: check the result. Reproject to the UTM zone of the place (metres) so that lengths mean something.
roads_utm = roads.to_crs(32643)
roads["length_km"] = roads_utm.length / 1000
print(roads.groupby("highway")["length_km"].sum().round(1))
# Step 4: save the layer next to the hospitals
roads.to_file("jagraon_osm.gpkg", layer="roads", driver="GPKG")
190 road segments found
highway
secondary 40.9
tertiary 203.5
trunk 36.8
Name: length_km, dtype: float64
A length in degrees is meaningless, which is why the check reprojects first. Always measure length and area in a projected CRS. The same file now holds two layers, hospitals and roads. QGIS shows both when you open it.
How complete is the data?
OSM is as good as its volunteers. Main roads in a district are usually mapped well. Buildings, small shops and land use vary a lot from place to place. A hospital that is missing from the layer is not proof that it does not exist, and a layer with many features is not proof of a good survey. Compare a count with an official source when it matters, and say in your report that OSM is the source and when you downloaded it, because the map changes every day.
Common mistakes
- Giving Overpass the box in the wrong order. It wants south, west, north, east, and many tools use west, south, east, north.
- Leaving out the
User-Agentand getting a refusal. - Asking for a whole city's buildings in one query and getting a timeout. Cut the area into pieces.
- Forgetting that a feature can come back as a point, a line or a polygon, and keeping only one layer.
- Measuring length in degrees.
- Using the data without the credit "© OpenStreetMap contributors".

