Skip to content

Commit

Permalink
remove settings module node/way tags/attrs
Browse files Browse the repository at this point in the history
  • Loading branch information
gboeing committed Feb 22, 2024
1 parent e4626be commit 54170cd
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 49 deletions.
46 changes: 25 additions & 21 deletions osmnx/_osm_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@
import geopandas as gpd


# default values for node/way elements' attrs required to meet OSM XML spec
ATTR_DEFAULTS = {
"changeset": "1",
"timestamp": utils.ts(template="{:%Y-%m-%dT%H:%M:%SZ}"),
"uid": "1",
"user": "OSMnx",
"version": "1",
"visible": "true",
}


class _OSMContentHandler(ContentHandler):
"""
SAX content handler for OSM XML.
Expand Down Expand Up @@ -186,16 +197,8 @@ def _save_graph_xml(
bounds = dict(zip(["minlon", "minlat", "maxlon", "maxlat"], coords))

# add default values (if missing) for required attrs to meet OSM XML spec
attr_defaults = {
"changeset": "1",
"timestamp": utils.ts(template="{:%Y-%m-%dT%H:%M:%SZ}"),
"uid": "1",
"user": "OSMnx",
"version": "1",
"visible": "true",
}
for gdf in (gdf_nodes, gdf_edges):
for col, value in attr_defaults.items():
for col, value in ATTR_DEFAULTS.items():
if col not in gdf.columns:
gdf[col] = value
else:
Expand All @@ -204,20 +207,18 @@ def _save_graph_xml(
# transform nodes gdf to meet OSM XML spec
# 1) reset index (osmid) then rename osmid, x, and y columns
# 2) round lat/lon coordinates
# 3) retain only node cols corresponding to configured node attrs and tags
# 3) drop unnecessary geometry column
gdf_nodes = gdf_nodes.reset_index().rename(columns={"osmid": "id", "x": "lon", "y": "lat"})
gdf_nodes[["lon", "lat"]] = gdf_nodes[["lon", "lat"]].round(PRECISION)
node_cols = list(set(settings.osm_xml_node_attrs) | set(settings.osm_xml_node_tags))
gdf_nodes = gdf_nodes[node_cols]
gdf_nodes = gdf_nodes.drop(columns=["geometry"])

# transform edges gdf to meet OSM XML spec
# 1) fill and convert oneway bools to strings
# 2) rename osmid column (but keep (u, v, k) index for processing)
# 3) retain only edge cols corresponding to configured edge attrs and tags
# 3) drop unnecessary geometry column
if "oneway" in gdf_edges.columns:
gdf_edges["oneway"] = gdf_edges["oneway"].fillna(ONEWAY).replace({True: "yes", False: "no"})
edge_cols = list(set(settings.osm_xml_way_attrs) | set(settings.osm_xml_way_tags))
gdf_edges = gdf_edges.rename(columns={"osmid": "id"})[edge_cols]
gdf_edges = gdf_edges.rename(columns={"osmid": "id"}).drop(columns=["geometry"])

# create parent XML element then add bounds, nodes, ways as sub elements
element = Element("osm", attrib={"version": API_VERSION, "generator": f"OSMnx {__version__}"})
Expand Down Expand Up @@ -249,20 +250,20 @@ def _add_nodes_xml(
-------
None
"""
node_attrs = set(settings.osm_xml_node_attrs)
node_tags = set(settings.osm_xml_node_tags)
node_tags = set(settings.useful_tags_node)
node_attrs = {"id", "lat", "lon"}.union(ATTR_DEFAULTS)

# convert gdf rows to generator of col:val dicts with null vals removed
rows = gdf_nodes.where(gdf_nodes.isna(), gdf_nodes.astype(str)).to_dict(orient="records")
nodes = ({k: v for k, v in d.items() if pd.notna(v)} for d in rows)

# add each node attr dict as a SubElement of parent
for node in nodes:
node_attr = {k: node[k] for k in node.keys() & node_attrs}
node_attr = {k: node[k] for k in node_attrs}
node_element = SubElement(parent, "node", attrib=node_attr)

# add each tag key:value dict as a SubElement of the node SubElement
for k in node.keys() & node_tags:
for k in node_tags.intersection(node):
node_tag = {"k": k, "v": node[k]}
_ = SubElement(node_element, "tag", attrib=node_tag)

Expand Down Expand Up @@ -296,10 +297,13 @@ def _add_ways_xml(
-------
None
"""
way_tags = set(settings.useful_tags_way)
way_attrs = list({"id"}.union(ATTR_DEFAULTS))

for osmid, way in gdf_edges.groupby("id"):
# STEP 1: add the way and its attrs as a "way" sub element of the
# parent element
attrs = way[settings.osm_xml_way_attrs].iloc[0].astype(str).to_dict()
attrs = way[way_attrs].iloc[0].astype(str).to_dict()
way_element = SubElement(parent, "way", attrib=attrs)

# STEP 2: add the way's edges' node IDs as "nd" sub elements of
Expand All @@ -316,7 +320,7 @@ def _add_ways_xml(
# sub element. if an agg function was provided for a tag, apply it
# to the values of the edges in the way. if no agg function was
# provided for a tag, just use the value from first edge in way.
for tag in settings.osm_xml_way_tags:
for tag in way_tags.intersection(way.columns):
if way_tags_agg is not None and tag in way_tags_agg:
value = way[tag].agg(way_tags_agg[tag])
else:
Expand Down
28 changes: 0 additions & 28 deletions osmnx/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,6 @@
nominatim_key : str | None
Your Nominatim API key, if you are using an API instance that requires
one. Default is `None`.
osm_xml_node_attrs : list[str]
Node attributes for saving .osm XML files with `save_graph_xml` function.
Default is `["id", "timestamp", "uid", "user", "version", "visible",
"changeset", "lat", "lon"]`.
osm_xml_node_tags : list[str]
Node tags for saving .osm XML files with `save_graph_xml` function.
Default is `["highway"]`.
osm_xml_way_attrs : list[str]
Edge attributes for saving .osm XML files with `save_graph_xml` function.
Default is `["id", "timestamp", "uid", "user", "version", "visible",
"changeset"]`.
osm_xml_way_tags : list[str]
Edge tags for for saving .osm XML files with `save_graph_xml` function.
Default is `["highway", "lanes", "maxspeed", "name", "oneway"]`.
overpass_endpoint : str
The base API url to use for Overpass queries. Default is
`"https://overpass-api.de/api"`.
Expand Down Expand Up @@ -169,20 +155,6 @@
memory: int | None = None
nominatim_endpoint: str = "https://nominatim.openstreetmap.org/"
nominatim_key: str | None = None
osm_xml_node_attrs: list[str] = [
"id",
"timestamp",
"uid",
"user",
"version",
"visible",
"changeset",
"lat",
"lon",
]
osm_xml_node_tags: list[str] = ["highway"]
osm_xml_way_attrs: list[str] = ["id", "timestamp", "uid", "user", "version", "visible", "changeset"]
osm_xml_way_tags: list[str] = ["highway", "lanes", "maxspeed", "name", "oneway"]
overpass_endpoint: str = "https://overpass-api.de/api"
overpass_rate_limit: bool = True
overpass_settings: str = "[out:json][timeout:{timeout}]{maxsize}"
Expand Down

0 comments on commit 54170cd

Please sign in to comment.