Reputation: 600
I want to find all pubs in a specific area using the Overpass API and selecting the area with geocodeArea.
Testing the following query on overpass-turbo.eu gives me the desired result:
{{geocodeArea:berlin}}->.searchArea;
(
node["amenity"="pub"](area.searchArea);
way["amenity"="pub"](area.searchArea);
relation["amenity"="pub"](area.searchArea);
);
out body;
>;
out skel qt;
But when I implement that query in python using overpy...
import overpy
api = overpy.Overpass()
result = api.query("""
{{geocodeArea:berlin}}->.searchArea;
(
node["amenity"="pub"](area.searchArea);
way["amenity"="pub"](area.searchArea);
relation["amenity"="pub"](area.searchArea);
);
out body;
>;
out skel qt;
""")
print("Amenities in nodes: %d" % len(result.nodes))
print("Amenities in ways: %d" % len(result.ways))
... I get the following error:
Traceback (most recent call last):
File "testOP.py", line 15, in <module>
""")
File "/usr/local/lib/python2.7/dist-packages/overpy/__init__.py", line 119, in query
msgs=msgs
overpy.exception.OverpassBadRequest: Error: line 2: parse error: Unknown type "{"
Error: line 2: parse error: An empty query is not allowed
Error: line 2: parse error: ';' expected - '{' found.
I guess that the problem has to do with the double curly braces, but so far escaping them and other variations didn't help.
Possible solution with Nominatim
Thanks to @scai I know now, that with {{geocodeArea:xxx}} overpass turbo only makes a geocode request. I decided to implement that in my program by myself using geopy and Nominatim:
from geopy.geocoders import Nominatim
import overpy
city_name = "berlin"
# Geocoding request via Nominatim
geolocator = Nominatim(user_agent="city_compare")
geo_results = geolocator.geocode(city_name, exactly_one=False, limit=3)
# Searching for relation in result set
for r in geo_results:
print(r.address, r.raw.get("osm_type"))
if r.raw.get("osm_type") == "relation":
city = r
break
# Calculating area id
area_id = int(city.raw.get("osm_id")) + 3600000000
# Excecuting overpass call
api = overpy.Overpass()
result = api.query("""
area(%s)->.searchArea;
(
node["amenity"="pub"](area.searchArea);
way["amenity"="pub"](area.searchArea);
relation["amenity"="pub"](area.searchArea);
);
out body;
""" % area_id)
# Printing no. of pubs in nodes and ways
print("Amenities in nodes: %d" % len(result.nodes))
print("Amenities in ways: %d" % len(result.ways))
The code ...
It's not a very clean solution and I wonder if it's possible to directly use the first result (which is mostly the city just as point) for my purposes. Hints are still welcome.
Upvotes: 9
Views: 4286
Reputation: 1216
You can achieve similar results using the area
filter instead of geocodeArea
. For your example:
area[name="Berlin"]->.searchArea;
(
node["amenity"="pub"](area.searchArea);
way["amenity"="pub"](area.searchArea);
relation["amenity"="pub"](area.searchArea);
);
out body;
>;
out skel qt;
This could work, but for other areas maybe you need to be more specific with the tags used in the area
filter, more information in the Language Guide for Overpass
Upvotes: 8
Reputation: 21469
{{geocodeArea: xxx }}
is a special feature of overpass turbo and not part of Overpass API. overpy uses Overpass API directly which means you can't use this keyword.
However {{geocodeArea: xxx }}
just tells overpass turbo to perform a geocoding request, i.e. transform an address into a geographic location. You can do the same, e.g. by making a call to Nominatim, Photon or any other geocoder.
Upvotes: 8