Frequently asked questions#
Answers to questions that come up often (click a question to expand it). If yours isn’t here, search the issue tracker or open a new issue.
Reading data#
How do I read a large scale extract without running out of memory?
Pyrosm reads with its out-of-core engine by default, which decodes the file in a single streaming pass with bounded peak memory, spilling intermediate data to disk instead of holding the whole file at once, so large files covering e.g. whole countries can be read as they are:
osm = OSM("country.osm.pbf")
buildings = osm.get_buildings()
Reads, crops and merges choose how many threads to use by the size of the data
(workers="auto", the default): one for less than about 20 MB, more for larger files. Pass
workers=N for a fixed count, for example workers=1 to stay on one core when several pyrosm
jobs already run side by side. The threads need no if __name__ == "__main__": guard. Setting the
environment variable PYROSM_DECODE_BACKEND=processes switches to worker processes, as earlier
versions used; with it the default is one process, and on macOS and Windows a parallel read from
a script needs the guard, and without it falls back to a single process with a warning. The
processes setting is deprecated: it warns, and it will be removed in a future release. If you
need it, please tell us why in an issue.
Other ways to lower memory use: read only the area you need with a bounding_box (or crop the
file first with to_pbf()), keep fewer tag columns with tags_to_keep=[...] on the feature
call, and drop the element metadata columns with keep_metadata=False.
How do I get OSM data for a specific place or bounding box?
Download an extract by place name (geocoded) or by bounding box, then read it — and/or read
only a sub-area of a file with bounding_box:
from pyrosm import OSM, get_data, get_data_by_area, get_data_by_bbox
fp = get_data("Helsinki") # an extract by place name
# fp = get_data_by_bbox(bbox=[minx, miny, maxx, maxy]) # an extract for a bounding box
# fp = get_data_by_area(area) # the smallest extract containing an area
osm = OSM(fp, bounding_box=[minx, miny, maxx, maxy]) # read only this area of the file
For an area on a national border, get_data_by_area() finds the smallest single extract that
contains it, or with strategy="smallest_total" a set of extracts merged into one file when
their total download is smaller, and merge_pbf() combines overlapping extracts yourself. See
Downloading data and
Saving, cropping and merging data for more.
How does bounding_box keep features that are at the edge of the box (“intersects” or “within”)?
It is intersects, and the features are kept whole, not clipped. A way, building or
other area is included as long as at least one of its nodes is inside the box, and it is
returned with its complete geometry — so a building that is half inside and half outside the
box comes back as the whole building, with vertices beyond the box edge. (Internally pyrosm
selects “complete ways”, like osmconvert --complete-ways.)
A relation (a multipolygon or boundary) that straddles the box is the exception: by
default it is assembled from only the member ways that fall inside the box, so it has a
partial geometry. Pass complete_relations=True to fetch each such relation’s full member
set so its geometry is complete:
from pyrosm import OSM
osm = OSM("city.osm.pbf", bounding_box=bbox, complete_relations=True)
buildings = osm.get_buildings()
What coordinate reference system are the results in, and how do I reproject?
pyrosm returns GeoDataFrames in WGS84 (EPSG:4326) — longitude/latitude in degrees, matching the OSM source. Reproject with GeoPandas, e.g. to a metric CRS before measuring distances or areas:
buildings = osm.get_buildings().to_crs(epsg=3067) # a metric CRS (here ETRS-TM35FIN)
A CRSError when importing or first using pyrosm almost always means a broken pyproj/PROJ
install in your environment, not a pyrosm problem — reinstall pyproj (conda-forge recommended).
Filtering#
How does custom_filter combine multiple keys and values — AND or OR?
custom_filter is OR: an element is kept if it matches any of the given criteria.
Several values for one key match any of them, and several keys are combined with OR as well.
True means “any value for this key”.
# kept if it is a building OR carries any amenity tag:
osm.get_data_by_custom_criteria(custom_filter={"building": True, "amenity": True})
# kept if highway is residential OR primary:
osm.get_data_by_custom_criteria(custom_filter={"highway": ["residential", "primary"]})
Pass filter_type="exclude" to drop the matching elements instead of keeping them. See
Custom filters.
get_boundaries() returns only administrative areas — how do I get other boundary types?
get_boundaries() returns only boundary=administrative areas by default. For other
types, pass boundary_type:
osm.get_boundaries(boundary_type="all") # every boundary type
osm.get_boundaries(boundary_type="postal_code") # e.g. postal-code areas
Two things related to filtering that are good to understand:
name=filters by the area’s name, not by its boundary type — e.g.get_boundaries(name="Helsinki")searches names, it does not select a type.A neighbourhood/suburb mapped as an area is usually tagged
boundary=place(e.g.place=suburb), so it is not an administrative boundary. Useboundary_type="all", or query theplacetag directly:osm.get_data_by_custom_criteria(custom_filter={"place": ["suburb", "neighbourhood"]})
Networks and graphs#
Are the network types the same as in OSMnx?
Yes. network_type follows the way filters of OSMnx,
so reading a network with pyrosm selects the same streets as the equivalent OSMnx query,
and the OSMnx names work as network types as well:
pyrosm |
OSMnx |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
driving leaves out the service roads (alleys, driveways, parking aisles). Use
driving+service when those matter for reachability, for example when routing to
individual buildings.
A network exported with to_graph(..., graph_type="networkx") is OSMnx-compatible as
well: the node and edge attributes are named as OSMnx expects, so its functions work on
the graph directly.
How do I find street intersections and their coordinates?
Build a graph with to_graph(..., simplify_kwargs={"edge_attrs_differ": None}). This
simplification reduces the network to its topological nodes — every node is a real intersection
or a dead-end (the default one also keeps the nodes where the speed limit or road class
changes) — and each node carries
x/y (longitude/latitude in EPSG:4326), a Point geometry, and a street_count (how many
streets meet there). Keep the nodes where three or more streets meet:
import geopandas as gpd
from pyrosm import OSM, get_data
osm = OSM(get_data("Helsinki"))
nodes, edges = osm.get_network(network_type="driving", nodes=True)
G = osm.to_graph(
nodes, edges, graph_type="networkx", simplify_kwargs={"edge_attrs_differ": None}
)
intersections = gpd.GeoDataFrame(
[
{"osmid": n, "lon": d["x"], "lat": d["y"],
"street_count": d["street_count"], "geometry": d["geometry"]}
for n, d in G.nodes(data=True)
if d["street_count"] >= 3
],
crs="EPSG:4326",
)
street_count == 1 marks dead-ends. Use network_type="walking" or "cycling" to count
crossings for those modes instead.
Installation#
How should I install pyrosm, and what if installation fails?
Install it with pip, which installs prebuilt wheels, so nothing is compiled:
pip install pyrosm
or from conda-forge (with mamba/micromamba or conda):
mamba install -c conda-forge pyrosm
Wheels are published for CPython 3.11–3.15 on glibc-based Linux (x86_64 and aarch64), macOS (Intel and Apple silicon) and Windows on x86_64. Elsewhere pip builds pyrosm from source, which needs a C compiler; see Installation for musl-based Linux (Alpine) and Windows on ARM, where GeoPandas’ dependency pyogrio needs building too.