Jovian
⭐️
Sign In
Learn data science and machine learning by building real-world projects on Jovian

Open Route Services - Tutorials


ors_service_image


Credits - https://openrouteservice.org/

import Packages

In [1]:
import requests
import plotly.graph_objects as go

OpenRouteService Token

  1. Create an account by visiting openrouteservice.org.

  2. Navigate to Dashboard and create a free token.

  3. Got to API interactive examples for the documentation to understand in what ways you can use this token.

  4. Copy the API token into an empty text file.

In [2]:
with open(file='ors_token.txt', mode='r') as file:
    api_key = file.read()

Mapbox Token

  1. Create an account by visiting mapbox.com.

  2. Navigate to your account (account.mapbox.com).

  3. Create a free token by clicking the button Create a token.

  4. Copy the API token into an empty text file.

In [3]:
with open(file='mapbox_token.txt', mode='r') as file:
    mapbox_api = file.read()

ScatterMapBox

  1. Create a class called MapPlotter to visualize the geo-data.

  2. Private methods -

    • _global_scattermap()
    • _global_linemap()
    • _global_layout()
  3. Public methods -

    • plot_point() - to plot a point on the map.
    • plot_directions() - to plot route directions between from point to to point.
    • plot_polygons() - to plot polygons on the map (isochrones).
    • plot_pois() - to plot POIs (point of interst) between from point to to point.
In [4]:
class MapPlotter:
    def __init__(self, mapbox_api, map_style):
        self.mapbox_api = mapbox_api
        self.map_style = map_style
    
    def _global_scattermap(self, lat, lon, place, color):
        if isinstance(lat, list) and isinstance(lon, list):
            lats = lat
            lons = lon
        else:
            lats = [lat]
            lons = [lon]
        place = '' if not place else place.title()
        
        trace = go.Scattermapbox(
            lat=lats,
            lon=lons,
            mode='markers',
            marker=dict(
                size=10,
                color=color
            ),
            text=place,
            hoverinfo='text'
        )
        return trace
    
    def _global_linemap(self, set_coords):
        lons, lats = set_coords
        
        trace = go.Scattermapbox(
            lat=lats,
            lon=lons,
            mode='lines',
            line=dict(
                width=2,
            ),
            text='',
            hoverinfo='text'
        )
        return trace
    
    def _global_layout(self, center_lat, center_lon, zoom):
        layout = go.Layout(
            autosize=True,
            height=600,
            hovermode='closest',
            showlegend=False,
            mapbox=dict(
                accesstoken=self.mapbox_api,
                bearing=0,
                center=dict(
                    lat=center_lat,
                    lon=center_lon
                ),
                pitch=0,
                zoom=zoom,
                style=self.map_style
            ),
            margin=dict(l=40, r=40, t=40, b=40)
        )
        return layout
    
    def plot_point(self, place, coords, zoom):
        lon, lat = coords
        
        trace = self._global_scattermap(lat=lat, lon=lon, place=place, color='red')
        layout = self._global_layout(center_lat=lat, center_lon=lon, zoom=zoom)
        
        fig = go.Figure(data=[trace], layout=layout)
        fig.show()
        
        return None
    
    def plot_directions(self, start, end, start_coords, end_coords, direction_coords, zoom):
        dlons, dlats = direction_coords
        slon, slat = start_coords
        elon, elat = end_coords
        
        trace1 = self._global_scattermap(lat=slat, lon=slon, place=start, color='red')
        trace2 = self._global_scattermap(lat=elat, lon=elon, place=end, color='green')
        trace3 = self._global_linemap(set_coords=direction_coords)
        layout = self._global_layout(center_lat=slat, center_lon=elon, zoom=zoom)
        
        fig = go.Figure(data=[trace3, trace1, trace2], layout=layout)
        fig.show()
        
        return None
    
    def plot_polygons(self, start, end, start_coords, end_coords, polygon_coords, zoom):
        slon, slat = start_coords
        elon, elat = end_coords
        
        trace_list = []
        trace1 = self._global_scattermap(lat=slat, lon=slon, place=start, color='red')
        trace2 = self._global_scattermap(lat=elat, lon=elon, place=end, color='red')
        for (idx, set_coords) in polygon_coords.items():
            trace_idx = self._global_linemap(set_coords=set_coords)
            trace_list.append(trace_idx)
        trace_list.extend([trace1, trace2])
        layout = self._global_layout(center_lat=slat, center_lon=elon, zoom=zoom)
        
        fig = go.Figure(data=trace_list, layout=layout)
        fig.show()
        
        return None
    
    def plot_pois(self, start, end, start_coords, end_coords, point_coords, zoom):
        slon, slat = start_coords
        elon, elat = end_coords
        
        trace1 = self._global_scattermap(lat=slat, lon=slon, place=start, color='red')
        trace2 = self._global_scattermap(lat=elat, lon=elon, place=end, color='red')
        
        if point_coords:
            plons, plats = point_coords
            trace3 = self._global_scattermap(lat=plats, lon=plons, place=None, color='blue')
            trace_list = [trace1, trace2, trace3]
        else:
            trace3 = None
            trace_list = [trace1, trace2]
        
        layout = self._global_layout(center_lat=slat, center_lon=elon, zoom=zoom)
        
        fig = go.Figure(data=trace_list, layout=layout)
        fig.show()
        
        return None

Extractors

In [5]:
extract_longitude = lambda coords : coords[0]
extract_latitude = lambda coords : coords[1]

OpenRouteService class

  1. Create a class called OpenRouteServices to fetch geo-data from open-route-service API.

  2. Inherits a class called MapPlotter to visualize the data.

  3. Public methods -

    • get_geocode() - to fetch the geo-coordinates of a place name.
    • get_directions() - to fetch the route directions coordinate values from one point to another point.
    • get_isochrones() - to fetch polygons to visualize the isochrones.
    • get_pois() - to fetch the POIs coordinate values from one point to another point.
In [6]:
class OpenRouteService(MapPlotter):
    def __init__(self, api_key, mapbox_api, map_style):
        self.api_key = api_key
        self.mapbox_api = mapbox_api
        self.map_style = map_style
        self.headers = {
            'Accept': 'application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8',
        }
    
    def get_geocode(self, place, with_plot=False):
        url = 'https://api.openrouteservice.org/geocode/search?api_key={}&text={}'
        url = url.format(
            self.api_key,
            place
        )
        
        req = requests.get(url=url, headers=self.headers)
        print('Geocode response status - {} : {} {}'.format(place, req.status_code, req.reason))
        
        if (req.status_code == 200):
            req_data = req.json()
            features = req_data['features']
            # format - [longitude, latitude]
            coords = features[0]['geometry']['coordinates']
            
            if with_plot:
                self.plot_point(place=place, coords=coords, zoom=10)
                return None
            return coords
        
        return None
    
    def get_directions(self, start, end, mode='driving-car', with_plot=False):
        start_coords = self.get_geocode(place=start)
        end_coords = self.get_geocode(place=end)
        
        url = 'https://api.openrouteservice.org/v2/directions/{}?api_key={}&start={},{}&end={},{}'
        url = url.format(
            mode,
            self.api_key,
            start_coords[0],
            start_coords[1],
            end_coords[0],
            end_coords[1]
        )
        req = requests.get(url=url, headers=self.headers)
        print('Directions response status : ', req.status_code, req.reason)
        
        if (req.status_code == 200):
            req_data = req.json()
            features = req_data['features']
            directions = features[0]['geometry']['coordinates']
            lons = list(map(extract_longitude, directions))
            lats = list(map(extract_latitude, directions))
            # format - [longitude, latitude]
            direction_coords = [lons, lats]
            
            if with_plot:
                self.plot_directions(
                    start=start,
                    end=end,
                    start_coords=start_coords,
                    end_coords=end_coords,
                    direction_coords=direction_coords,
                    zoom=4
                )
                return None
            return direction_coords
        
        return None
    
    def get_isochrones(self, start, end, mode='driving-car', with_plot=False):
        start_coords = self.get_geocode(place=start)
        end_coords = self.get_geocode(place=end)
        
        body = {
            'locations' : [start_coords, end_coords],
            'range' : [300, 200]
        }
        self.headers['Authorization'] = self.api_key
        self.headers['Content-Type'] = 'application/json; charset=utf-8'
        
        url = 'https://api.openrouteservice.org/v2/isochrones/{}'.format(mode)
        req = requests.post(url=url, json=body, headers=self.headers)
        print('Isochrones response status : ', req.status_code, req.reason)
        
        if (req.status_code == 200):
            req_data = req.json()
            features = req_data['features']
            polygons = [each_f['geometry']['coordinates'] for each_f in features]
            polygon_coords = [
                # format - [longitude, latitude]
                [list(map(extract_longitude, p[0])), list(map(extract_latitude, p[0]))]
                for p in polygons
            ]
            polygon_coords = dict(enumerate(polygon_coords))
            
            if with_plot:
                self.plot_polygons(
                    start=start,
                    end=end,
                    start_coords=start_coords,
                    end_coords=end_coords,
                    polygon_coords=polygon_coords,
                    zoom=10
                )
                return None
            return polygon_coords
        
        return None
    
    def get_pois(self, start, end, with_plot=False):
        start_coords = self.get_geocode(place=start)
        end_coords = self.get_geocode(place=end)
        
        body = {
            'request' : 'pois',
            'geometry' : {
                'bbox' : [start_coords, end_coords],
                'geojson' : {
                    'type' : 'Point',
                    'coordinates' : start_coords
                },
                'buffer' : 200
            }
        }
        self.headers['Authorization'] = self.api_key
        self.headers['Content-Type'] = 'application/json; charset=utf-8'
        
        url = 'https://api.openrouteservice.org/pois'
        req = requests.post(url=url, json=body, headers=self.headers)
        print('POIs response status : ', req.status_code, req.reason)
        
        if (req.status_code == 200):
            req_data = req.json()
            features = req_data[0]['features']
            points = [each_f['geometry']['coordinates'] for each_f in features]
            lons = list(map(extract_longitude, points))
            lats = list(map(extract_latitude, points))
            # format - [longitude, latitude]
            point_coords = [lons, lats]
            
            if with_plot:
                self.plot_pois(
                    start=start,
                    end=end,
                    start_coords=start_coords,
                    end_coords=end_coords,
                    point_coords=point_coords,
                    zoom=10
                )
                return None
            return point_coords
        
        point_coords = None
        self.plot_pois(
            start=start,
            end=end,
            start_coords=start_coords,
            end_coords=end_coords,
            point_coords=point_coords,
            zoom=10
        )
        
        return None

Object Creation

In [7]:
ors = OpenRouteService(api_key=api_key, mapbox_api=mapbox_api, map_style='outdoors')

Geocode

In [8]:
ors.get_geocode(place='lucknow', with_plot=True)
Geocode response status - lucknow : 200 OK

Directions

In [9]:
ors.get_directions(start='goa', end='delhi', with_plot=True)
Geocode response status - goa : 200 OK Geocode response status - delhi : 200 OK Directions response status : 200 OK

Isochrones

In [10]:
ors.get_isochrones(start='chikkaballapur', end='doddaballapura', with_plot=True)
Geocode response status - chikkaballapur : 200 OK Geocode response status - doddaballapura : 200 OK Isochrones response status : 200 OK

POIs

In [11]:
ors.get_pois(start='chikkaballapur', end='doddaballapura', with_plot=True)
Geocode response status - chikkaballapur : 200 OK Geocode response status - doddaballapura : 200 OK POIs response status : 400 Bad Request

End