apartment search with openrouteservice

In this example, we’d like to showcase one way to go about finding an apartment based on data.

In this notebook we'll provide an example for using different openrouteservice API's to help you look for an apartment.

In [ ]:
mkdir ors-apartment
conda create -n ors-apartment python=3.6 shapely
cd ors-apartment
pip install openrouteservice ortools folium
In [1]:
import folium

from openrouteservice import client

We have just moved to San Francisco with our kids and are looking for the perfect location to get a new home. Our geo intuition tells us we have to look at the data to come to this important decision. So we decide to geek it up a bit.

Apartment isochrones

There are three different suggested locations for our new home. Let's visualize them and the 15 minute walking radius on a map:

In [7]:
api_key = 'your_key' #Provide your personal API key
clnt = client.Client(key=api_key) 
# Set up folium map
map1 = folium.Map(tiles='Stamen Toner', location=([37.738684, -122.450523]), zoom_start=12)

# Set up the apartment dictionary with real coordinates
apt_dict = {'first': {'location': [-122.430954, 37.792965]},
            'second': {'location': [-122.501636, 37.748653]},
            'third': {'location': [-122.446629, 37.736928]}

# Request of isochrones with 15 minute footwalk.
params_iso = {'profile': 'foot-walking',
              'intervals': [900], # 900/60 = 15 mins
              'segments': 900,
              'attributes': ['total_pop'] # Get population count for isochrones

for name, apt in apt_dict.items():
    params_iso['locations'] = [apt['location']] # Add apartment coords to request parameters
    apt['iso'] = clnt.isochrones(**params_iso) # Perform isochrone request
    folium.features.GeoJson(apt['iso']).add_to(map1) # Add GeoJson to map
    folium.map.Marker(list(reversed(apt['location'])), # reverse coords due to weird folium lat/lon syntax
                 ).add_to(map1) # Add apartment locations to map


POIs around apartments

For the ever-styled foodie parents we are, we need to have the 3 basic things covered: kindergarten, supermarket and hair dresser. Let's see what options we got around our apartments:

In [8]:
# Common request parameters
params_poi = {'request': 'pois',
              'sortby': 'distance'}

# POI categories according to 
# https://github.com/GIScience/openrouteservice-docs#places-response
categories_poi = {'kindergarten': [153],
                  'supermarket': [518],
                  'hairdresser': [395]}

for name, apt in apt_dict.items():
    apt['categories'] = dict() # Store in pois dict for easier retrieval
    params_poi['geojson'] = apt['iso']['features'][0]['geometry']
    print("\n{} apartment".format(name))
    for typ, category in categories_poi.items():
        params_poi['filter_category_ids'] = category
        apt['categories'][typ] = dict()
        apt['categories'][typ]['geojson']= clnt.places(**params_poi)['features'] # Actual POI request
        print("\t{}: {}".format(typ, # Print amount POIs
first apartment
	kindergarten: 1
	supermarket: 8
	hairdresser: 10

second apartment
	kindergarten: 3
	supermarket: 1
	hairdresser: 4

third apartment
	kindergarten: 1
	supermarket: 3
	hairdresser: 2

So, all apartments meet all requirements. Seems like we have to drill down further.

Routing from apartments to POIs

To decide on a place, we would like to know from which apartment we can reach all required POI categories the quickest. So, first we look at the distances from each apartment to the respective POIs.

In [11]:
# Set up common request parameters
params_route = {'profile': 'foot-walking',
               'format_out': 'geojson',
               'geometry': 'true',
               'format': 'geojson',
               'instructions': 'false',

# Set up dict for font-awesome
style_dict = {'kindergarten': 'child',
              'supermarket': 'shopping-cart',
              'hairdresser': 'scissors'

# Store all routes from all apartments to POIs
for apt in apt_dict.values():
    for cat, pois in apt['categories'].items():
        pois['durations'] = []
        for poi in pois['geojson']:
            poi_coords = poi['geometry']['coordinates']
            # Perform actual request
            params_route['coordinates'] = [apt['location'],
            json_route = clnt.directions(**params_route)
            poi_duration = json_route['features'][0]['properties']['summary']['duration']
            pois['durations'].append(poi_duration) # Record durations of routes

Quickest route to all POIs

Now, we only need to determine which apartment is closest to all POI categories.

In [12]:
# Sum up the closest POIs to each apartment
for name, apt in apt_dict.items():
    apt['shortest_sum'] = sum([min(cat['durations']) for cat in apt['categories'].values()])
    print("{} apartments: {} mins".format(name,
first apartments: 37.098333333333336 mins
second apartments: 40.325 mins
third apartments: 35.315000000000005 mins

We got a winner!

Finally, it looks like the 3rd apartment is the one where we would need to walk the shortest amount of time to reach a kindergarten, supermarket and a hair dresser. Let's pack those boxes and welcome to San Francisco.