112 quackosm
Downloading and visualizing OpenStreetMap data with QuackOSM
QuackOSM is a high-performance library for reading OpenStreetMap data using DuckDB. It offers significant speed improvements over traditional methods and can handle large datasets efficiently.
Uncomment the following line to install leafmap and quackosm if needed.
# %pip install -U leafmap quackosm
import leafmap
import leafmap.osm as osm
Download OSM data by place name¶
The quackosm_gdf_from_place function downloads OSM data for a given place name. QuackOSM automatically finds and downloads the required PBF files.
# Download all OSM features for Monaco
gdf = osm.quackosm_gdf_from_place("Monaco")
print(f"Downloaded {len(gdf)} features")
gdf.head()
Visualize the data on an interactive map:
m = leafmap.Map()
m.add_gdf(gdf, layer_name="Monaco OSM")
m
Filter by OSM tags¶
You can filter OSM features by specifying tags. For example, download only buildings:
# Download only buildings in Monaco
buildings = osm.quackosm_gdf_from_place("Monaco", tags={"building": True})
print(f"Downloaded {len(buildings)} buildings")
buildings.head()
m = leafmap.Map()
m.add_gdf(buildings, layer_name="Buildings", style={"color": "red", "fillOpacity": 0.3})
m
Download roads and highways:
# Download roads in Monaco
roads = osm.quackosm_gdf_from_place("Monaco", tags={"highway": True})
print(f"Downloaded {len(roads)} road features")
roads.head()
m = leafmap.Map()
m.add_gdf(roads, layer_name="Roads", style={"color": "blue", "weight": 2})
m
Filter for specific tag values:
# Download restaurants and cafes
dining = osm.quackosm_gdf_from_place(
"Monaco", tags={"amenity": ["restaurant", "cafe", "bar"]}
)
print(f"Downloaded {len(dining)} dining establishments")
dining.head()
m = leafmap.Map()
m.add_gdf(dining, layer_name="Dining", style={"color": "green", "fillColor": "green"})
m
Download OSM data by bounding box¶
Use quackosm_gdf_from_bbox to download data for a specific bounding box:
# Bounding box for Vatican City area (west, south, east, north)
bbox = (12.445, 41.900, 12.460, 41.910)
# Download all features in the bounding box
gdf_bbox = osm.quackosm_gdf_from_bbox(bbox)
print(f"Downloaded {len(gdf_bbox)} features")
gdf_bbox.head()
m = leafmap.Map(center=[41.905, 12.4525], zoom=16)
m.add_gdf(gdf_bbox, layer_name="Vatican Area OSM")
m
Download only buildings in the bounding box:
buildings_bbox = osm.quackosm_gdf_from_bbox(bbox, tags={"building": True})
print(f"Downloaded {len(buildings_bbox)} buildings")
m = leafmap.Map(center=[41.905, 12.4525], zoom=16)
m.add_gdf(
buildings_bbox,
layer_name="Buildings",
style={"color": "orange", "fillOpacity": 0.5},
)
m
Download OSM data by geometry¶
Use quackosm_gdf_from_geometry to download data for a custom geometry:
from shapely.geometry import Polygon
# Create a custom polygon
coords = [(7.41, 43.73), (7.43, 43.73), (7.43, 43.75), (7.41, 43.75), (7.41, 43.73)]
polygon = Polygon(coords)
# Download natural features
natural = osm.quackosm_gdf_from_geometry(polygon, tags={"natural": True})
print(f"Downloaded {len(natural)} natural features")
natural.head()
m = leafmap.Map(center=[43.74, 7.42], zoom=14)
m.add_gdf(
natural, layer_name="Natural Features", style={"color": "green", "fillOpacity": 0.4}
)
m
Using WKT or GeoJSON geometry¶
You can also use WKT strings or GeoJSON dictionaries as geometry input:
# Using WKT string
wkt = "POLYGON ((7.41 43.73, 7.43 43.73, 7.43 43.75, 7.41 43.75, 7.41 43.73))"
leisure = osm.quackosm_gdf_from_geometry(wkt, tags={"leisure": True})
print(f"Downloaded {len(leisure)} leisure features")
m = leafmap.Map(center=[43.74, 7.42], zoom=14)
m.add_gdf(leisure, layer_name="Leisure", style={"color": "purple", "fillOpacity": 0.4})
m
Multiple layers on a single map¶
Let's combine multiple OSM layers on a single map:
# Download different feature types for Monaco
buildings = osm.quackosm_gdf_from_place("Monaco", tags={"building": True})
roads = osm.quackosm_gdf_from_place("Monaco", tags={"highway": True})
water = osm.quackosm_gdf_from_place("Monaco", tags={"natural": "water"})
print(f"Buildings: {len(buildings)}, Roads: {len(roads)}, Water: {len(water)}")
m = leafmap.Map()
# Add layers with different styles
if len(buildings) > 0:
m.add_gdf(
buildings,
layer_name="Buildings",
style={"color": "red", "fillOpacity": 0.3, "weight": 1},
)
if len(roads) > 0:
m.add_gdf(roads, layer_name="Roads", style={"color": "gray", "weight": 2})
if len(water) > 0:
m.add_gdf(water, layer_name="Water", style={"color": "blue", "fillOpacity": 0.5})
m.zoom_to_gdf(buildings)
m
Export to GeoParquet¶
QuackOSM can efficiently export data to GeoParquet format, which is optimized for cloud storage and analytical workflows:
# Export Monaco buildings to GeoParquet
# output_path = osm.quackosm_to_parquet(
# "Monaco",
# "monaco_buildings.parquet",
# tags={"building": True}
# )
# print(f"Saved to: {output_path}")
Common OSM tags¶
Here are some commonly used OSM tags for filtering:
| Category | Tag Examples |
|---|---|
| Buildings | {"building": True}, {"building": "residential"} |
| Roads | {"highway": True}, {"highway": ["primary", "secondary"]} |
| Water | {"natural": "water"}, {"waterway": True} |
| Land use | {"landuse": True}, {"landuse": ["residential", "commercial"]} |
| Amenities | {"amenity": True}, {"amenity": ["restaurant", "hospital"]} |
| Shops | {"shop": True}, {"shop": ["supermarket", "convenience"]} |
| Tourism | {"tourism": True}, {"tourism": ["hotel", "attraction"]} |
| Natural | {"natural": True}, {"natural": ["tree", "wood"]} |
| Leisure | {"leisure": True}, {"leisure": ["park", "playground"]} |
For a complete list of OSM tags, visit: https://wiki.openstreetmap.org/wiki/Map_features
Performance comparison¶
QuackOSM typically offers 2-10x faster performance compared to osmnx for large datasets, thanks to:
- DuckDB-based parallel processing
- Efficient caching of downloaded PBF files
- Optimized geometry operations
For very large areas, consider using the verbosity_mode="verbose" parameter to see progress information.