Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
New feature: Retrieving OSM POIs with osmnx? #116
first of all, awesome work with the package! Highly useful and needed.
I was wondering if there would be interest to include separate functionalities to retrieve OpenStreetMap POIs with osmnx? I am currently starting to write such functionalities for my own project, and I think I will be using osmnx as a basis for fetching Points of interest from OpenStreetMap (such as restaurants etc.). I know that it is possible to work with other infrastructures than roads, but if I have understood correctly that function works only with graphs, not with point data such as POIs.
If you think this would be interesting, I would be happy to help implementing these functions.
P.S. FYI: I introduce osmnx also with the fully open GIS course (Lesson 7) that can be found here http://autogis.github.io.
Nice, I think having POIs included in OSMnx would be a nice addition! And yes, I think a separate module would be good, and it could be written e.g. into
Basically the idea could be that you can pass a list of amenities to a function
I actually already wrote a first version of module with this style (only
Should the module provide information about what amenities are available?
The function searches now amenities from
How should we deal with the amenities that are of type
Should the functions return two GeoDataFrames where first one are the points and the second one contains edges? There are for example a lot of
And then the last thing, how should the functions deal with relations?
These can be fairly tricky to handle. Any ideas?
Okey, so these are some of the thoughts that I have now after testing a little bit what kind of amenities are returned by the Overpass. I would really appreciate all the thoughts and ideas from you about this, as you know the best how you want to develop the package.
I need to be cleaning my code a little bit and implement some of the missing features, but after that I will push my changes to a fork I made where you can take a look https://github.com/HTenkanen/osmnx.
I now wrote a
Please take a look, and try it out. E.g. following should work:
>>> import osmnx as ox >>> place = "Kamppi, Helsinki, Finland" >>> ox.available_amenities >>> selected_amenities = ['restaurant', 'bar', 'cafe'] >>> poi_gdf = ox.pois_from_place(place=place, amenities=selected_amenities) >>> poi_gdf['name'].head() 60062502 Kabuki 60068035 Cafe Java 60133792 Ateljé Finne 62965963 Empire Plaza 62967659 Ravintola Pääposti Name: name, dtype: object
@HTenkanen this is looking like a great start! A few ideas regarding your questions:
I'm not sure if the module needs to provide information about which amenities are available, as this would create a maintenance task on the OSMnx side... is it possible to just provide a link in the docstring to an authoritative documentation source from OSM?
Regarding amenities of type "way"... we could return a GeoDataFrame with both node-based and way-based amenities as individual rows. The former would have point geometries, and the latter would have polygon or multipolygon geometries. Would that work? If not, I'd be inclined to take the centroid of the way-based amenity to convert it to a point.
Regarding relations, do you have any examples? What kinds of amenities are these, and must they be handled as relations?
@gboeing Thanks for your thoughts!
I now implemented your ideas and now the poi-functions return a single GeoDataFrame consisting of
Regarding your question about relations, there are quite many cases where for example a school consists of many Polygons and hence those are dealt with a relation. And it is typically the case that the individual 'way' elements do not contain any attribute information about the school (like name, address, etc) as those attributes are assigned to the 'relation' element. Hence, in these cases it is necessary to handle the relation and create a MultiPolygon object having all the attributes. I have now wrote a function called
I also modularized the code a bit, and I think there are few functions that could be used directly e.g. in
Overall, I think the poi-module is now almost there, but it still needs some tests, documentation and a look from you.
Now e.g. following should work:
>>> import osmnx as ox >>> place = "Manhattan Island, Manhattan, New York City, New York, United States of America" >>> all_pois = ox.pois_from_place(place=place) >>> len(all_pois) 13182 >>> all_pois['amenity'].value_counts() bicycle_parking 3443 restaurant 2119 parking 768 cafe 762 school 611 place_of_worship 595 fast_food 529 bar 385 bank 345 bicycle_rental 342 drinking_water 334 bench 308 post_box 258 embassy 212 pharmacy 202 pub 147 theatre 132 ... # Get restaurants from Manhattan, New York >>> restaurants = ox.pois_from_place(place=place, amenities=['restaurant']) >>> restaurants['element_type'].value_counts() node 1941 way 179 relation 2 Name: element_type, dtype: int64 # Get schools from Manhattan, New York >>> schools = os.pois_from_place(place=place, amenities=['school'] >>> schools['name'].head() 42473959 NaN 42883022 NaN 357544551 All Hallows School 357544577 All Saints High School 357548361 High School for Health Profesion and Human Ser... Name: name, dtype: object >>> schools.plot(markersize=2)
# Get all Universities from Boston area (with 2 km buffer to cover also Cambridge) >>> boston_q = "Boston, Massachusetts, United States of America" >>> boston_poly = ox.gdf_from_place(boston_q, buffer_dist=2000) >>> universities = ox.pois_from_polygon(boston_poly.geometry.values, amenities=['university']) >>> list(universities.name.unique()) [nan, 'Picower Institute for Learning and Memory (MIT)', 'McGovern Institute for Brain Research (MIT)', 'Boston ollege', 'Boston College (Newton Campus)', 'Harvard Business School', 'John F Kennedy School of overnment', 'Radcliffe Institute for Advanced Studies', 'Soldiers Field Park Apartments', 'MIT Museum', 'Winthrop House', '250 Mt Vernon St @ Geiger Gibson Health Center', 'Boston University School of edicine', 'Citibank', 'Cambridge Innovation Center', 'Harvard Law School', 'Rubinstein Hall', 'Boston niversity', 'Suffolk University', 'Conant Hall', 'Longfellow Building', 'Putnam Building', 'Quincy College', 'Engineering Science Lab', 'Lowell Lecture Hall', 'Littauer Center', 'Memorial Hall', 'University Hall', 'Sever all', 'Boylston Hall', 'Myles Standish Hall', 'Stone Hearth', 'Swiss Bakers', 'Benjamin Franklin Institute of echnology', 'Randolph Hall', 'Lehman Dudley House', '7/11', 'Byerly Hall', 'Divinity Hall', 'Smith Campus enter', 'CGIS South', 'Tufts University Hirsh Health Sciences Library', 'Mather House', '38 Oxford', 'Farlow', 'Radcliffe University', 'CGIS Knafel', 'Phillips Brooks House', 'Holden Chapel', 'Vanserg Building', 'Biological aboratory', 'Larsen Building', 'Buckingham House', 'Gutman Building', 'Claverly Hall', 'Knowles Center', 'Tufts University Dowling Hall', 'Blackstone South', 'Harvard University Information Systems', 'Pforzheimer ouse', 'Emerson Hall', 'Currier House', 'Tufts Dental School', 'Mount Ida College', 'Teele Hall', 'Harvard Ed ortal', 'Hastings Building', 'Robinson Hall', 'University Herbaria', 'Harvard Hall', 'White Hall', 'Eliot House', 'Harvard University', 'Radcliffe Institute at Harvard University', 'Radcliffe Gym', 'Agassiz House', 'Boston ollege (Brighton Campus)', 'Boston College - Newton Campus', 'Harvard University Northwest Building', 'University of Massachusetts Boston', 'Harvard Medical School', 'Harvard School of Public Health', Harvard chool of Dental Medicine', '25 Travis Street', 'Northeastern University', 'Boston University Medical Campus', 'Leverett House', 'Quincy House', 'Cabot House', 'Dunster House', 'Lowell House', 'Harvard Science Center', 'Massachusetts Institute of Technology', 'Westmorely Hall', 'Kirkland House', 'Tufts University'] >>> universities.name.value_counts().head() Suffolk University 8 Harvard University 7 Boston University 7 Boston University Medical Campus 3 University of Massachusetts Boston 3 Name: name, dtype: int64 >>> universities.plot(alpha=0.7)
@gboeing Hi! Sorry for silence, have been busy with funding proposals and teaching last couple of weeks. I try to finish this up and make a pull request in a week or so. I leave the main readme.md documentation for you as I don't know how you would like to present this stuff. How does that sound?
By the way having a generic filter that you are discussing in #90 sounds really good and useful, and it was actually wished from few persons who I taught these stuff today. So that indeed would be a nice feature. E.g. related to buildings, being able to fetch buildings from an area that were built in 1954, or between years 2000-2015 are examples of such filtering that might be highly useful, and should be possible to do with OverpassAPI.
added a commit
Apr 11, 2018
Great work guys! I've tried using the code, but it doesn't work for me. I'm not sure whether I've made a mistake or maybe something on osm's side has updated.
When I try to run this code:
import osmnx as ox gdf = ox.pois_from_place(place='Kamppi, Helsinki, Finland')
I'm receiving these errors:
JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Exception: Server returned no JSON data.
Am I doing something wrong, or is something wrong in the code?
Amazing stuff! I've been loving these modules. I am getting stuck with a particular part of the OSM POIs module. I was wondering if you had any suggestions.
For some reason whenever I try to use a distance parameter higher than 500 I get the following error.
The error occurs at this line.
For my current project, I really would like to run it at 1000.
I can post more code if necessary.
@gboeing My apologies for the long response. I was away for the weekend.
Also, I apologize if this is a bit more than minimal...
@claytongroth I don't see any OSMnx error. I had to change your code snippet to turn it into a working example that reproduces the error you mentioned (this took some guesswork as your snippet works fine out of the box).
import osmnx as ox point = (43.073051, -89.401230) dist = 1000 G = ox.graph_from_point(point, distance=dist, network_type='walk') pois = ox.pois_from_point(point, distance=dist) POIshapes = pois['geometry'].representative_point()
This throws a geopandas ValueError as you're calling
When I run @gboeing's above code with
When I run the above code with
@gboeing What do you think about generalizing the
For example, let's say you want to get all features with an
Since there are a lot of POIs without consistent amenity tags (e.g., parks), this generalization was necessary for me to retrieve a broad array of POI types and seemed like low hanging fruit.
A **kwargs parameter in the
Thanks @HTenkanen and @gboeing for pointing out #190! Yes, my implementation is surprisingly similar, dictionaries and all. The biggest difference seems to be @HTenkanen's use of booleans to specify all or no values for a given tag key. I really like this;
What this means in practice is that a tag dictionary like the one below, which is supposed to exclude any element with a
For example, if I use this dictionary to query Piedmont, CA, I end up with a couple of stray elements with
One the one hand, the API is supposed to facilitate this sort of query, so maybe it makes sense to assume it will someday and include the functionality. On the other hand, I don't want to lead people into thinking it will work perfectly.
I still think
@mmd-osm do you have any insights on this?
@chesterharvey if you're still experiencing this issue, could you produce an MWE in Overpass QL?
Sorry @gboeing, I let this slide for a while. I'm opening a PR now. My modified