How can I find POIs using overpass in a city, starting from latitude and longitude?

Hi,
I’m trying to develop an application that finds POIs of a city like museums, user input is country name and city name, this get translated to latitude and longitude using nominatim service, I would like to write a query for overpass that starting from those cohordinates lists me all pois inside the city.
ieg: users enter England, London and gets a list of museums in London city boundaries. I choosed to use both country and city names for locating the starting point to avoid city duplication.
Is it possible to do so?

I’m doing some exeperiments using overpass-turbo to try to find the right query before putting in my software, anyway I still haven’t found something that gives me results I would like and in a reasonable time.

This is my current overpass query:

is_in(41.8933203,12.4829321)->.a;
area(area.a)[boundary=administrative] ->.fi;
area(area.fi)[admin_level=8]->.city;
node(area.city)['amenity'='museum'];
out;

I accept any kind of suggestion.

best regards,
magowiz

You do know Overpass Turbo has a geocoder, don‘t you?

{{geocodeArea:London}}->.searchArea;
nwr["tourism"="museum"] (area.searchArea);
1 Like

Please note usage policy of server that you will be using ( Overpass API - OpenStreetMap Wiki )

In case of wider use of that app you may need to run own server

1 Like

Under the hood, overpass turbo simply calls Nominatim, then replaces the .searchArea by whatever was returned by Nominatim (also adds some special offset value for areas). OP probably can’t include overpass turbo in their app, and needs to implement something similar.

Your query is not valid, Overpass API doesn’t support area in area queries like this one here:

area(area.a)[boundary=administrative] ->.fi;

Essentially it means, the (area.a) is being ignored, and you’re processing all areas worldwide (!).

One way to specify these filters would be:

is_in(41.8933203,12.4829321)->.all_areas;
area.all_areas[boundary=administrative][admin_level=8]->.city;
nw(area.city)[tourism=museum];
out center;

This works without querying Nominatim, but may not work depending on how admin boundaries are mapped.

BTW: I also changed amenity=museum to tourism=museum, as that’s the correct tagging for a museum (overpass turbo wizard fixed that already, see above). Also, I added ways in the result, as not every museum is mapped as a node. And finally, I returned the center point for each POI. You might want to include relations as well, ymmv.

3 Likes

Hi all,
thank you for your responses: I meanwhile found something that works, I didn’t know I can use two different concentric areas, since user input is country and city I found this suitable:

area[name="France"];
rel[name="Paris"](area);
map_to_area;
(
   node["tourism"="museum"](area);
   way["tourism"="museum"](area);
   relation["tourism"="museum"](area);
);
out;

In any case if you find that for any reason my query is not optimized like yours let me know, I found a similar example in “area” part of official documentation and I tried to adapt it.

I’m using overpy which is a python library that performs overpass api queries, I cannot use overpass turbo specific syntax

@Mateusz_Konieczny for what is usage of mine app I plan to place a request every new travel, so I mean I need to plan a travel to Paris and I will lookup openstreetmap once to get all pois, that will be cached and saved locally, I don’t know if this could be a wider use, in any case I will found a solution

@mmd in terms of performance do you think that using is_in instead of query I proposed, is better?

Thanks again for the information you gave to me.
Should I mark this as solved? Since we have here 2 working queries.

Oh well, this query doesn’t work as expected: the query for way and relations doesn’t return any results, as the area has been overwritten by the “node” statement.

map_to_area;
(
   node["tourism"="museum"](area);
   way["tourism"="museum"](area);     // <<<<<< area is no longer available -> empty result!
   relation["tourism"="museum"](area);  // <<<<<< area is no longer available -> empty result!

To fix this issue I’m assigning the result of map_to_area to a named inputset, and use this inputset in subsequent steps instead:

area[name="France"];
rel[name="Paris"](area);
map_to_area -> .searchArea;
(
  node["tourism"="museum"](area.searchArea);
  way["tourism"="museum"](area.searchArea);
  rel["tourism"="museum"](area.searchArea);
);  
out center;

To make the query more readable, I’m merging the node, way and relation query into a single nwr, which does exactly the same.

area[name="France"];
rel[name="Paris"](area);
map_to_area -> .searchArea;
nwr["tourism"="museum"](area.searchArea);
out center;

“out;” is a bit pointless (sic!) for ways and relations, as the query won’t return any geometry data.

As an alternative, you can choose between one of the following:

  • out center; to get a center point for ways/relations
  • out geom; or
  • (._;>;);out;

ok thank you very much for your contribute, seeing what you proposed I changed a bit mine final query

this is my python code that generates query:
TOURIST_ATTRACTIONS is a list of possible tourism values I use in or, in the clause, I choose to get with out both meta and geom to be sure I get: latitude and longitude (so I can generate a osm link) and also few information like opening hours when available. But also in this case correct me if I’m wrong.

cl_tags = '|'.join(TOURIST_ATTRACTIONS)
clause = f'nwr["tourism"~"{cl_tags}"](area.searchArea);'
query = f"""
                        area[name={self.country_name}];
                        rel[name="{self.city_name}"](area);
                        map_to_area ->.searchArea;
                        {clause}
                        out meta geom;
                    """

Maybe you could add ^ and $ to your regular expressions for exact string matches:

nwr["tourism"~"^(hotel|museum)$"];

You put {self.city_name} in quotation marks, but you left them out for the country name {self.country_name}. I would use them everywhere to avoid issues with countries like “United States of America”.

If a user can provide any of these values as input, don’t forget to sanitize / escape values as needed.

perfect, thank you for suggestions:
here it is the code:

cl_tags = '|'.join(TOURIST_ATTRACTIONS)
        clause = f'nwr["tourism"~"^({cl_tags})$"](area.searchArea);'
        query = f"""
                        area[name="{self.country_name}"];
                        rel[name="{self.city_name}"](area);
                        map_to_area ->.searchArea;
                        {clause}
                        out meta geom;
                    """
        result = self.overpass_api.query(query)

I agree with you that user input needs somehow to get sanitized, since location is the most important thing on my app I spent a little more effort to avoid free input and in the same time give user possibility to easily choose: user inserts letters (part of name of a city for example), I perform then a query on another library (countryinfo) to fetch only valid values, so I prevent user to insert not valid values, he/she is able only to search and select across valid combinations.