Elevation Query

5 minute read

Published:

If you are reading this page, probably you wanted to know the elevation of a point using its cooridnates. I found two useful APIs that you can use to call the elevation of a point on earth using its coordinates. Also, there are some other resources. For example, the elevation data using LiDAR for the whole state of Tennessee is available. You can learn more about it here. Please let me know if you find other useful APIs so that we can put all of them together and compare and contrast them. Let’s get to the two APIs we want to dicuss here.

USGS API

United States Geological Survey (USGS) provides a servcie that you can request the elevation of a coodinates. The pros is its free and you don’t need any keys and the cons is its relatively slow compared to the other alternative. Therefore, it can be a good option for extracting the elevation of a few points. You can use the following function to extract the elevation using latitude and longitude of the point. Also, you can define the unit of output. If the server for any reason doesnt return any values, we try one more time after 1 second, and we try maximum 10 times.

def request_elevation_usgs(lat,
                      lon,
                      units='Meters',
                      max_tries=10,
                      sec_btw_tries=1):
    '''
    
    This function is used to query elevation from usgs. The query should be one by one. 
    Parameters
    ----------
    lat : float
        The latitude of the point.
    lon : float
        The longitude of the point.
    units : string, optional
        The unit of interest for the elevation. The default is 'Meters'.
    max_tries : TYPE, optional
        The maximum number of iteration. The default is 10.
    sec_btw_tries : TYPE, optional
        The time interval between each iteration. The default is 1.

    Returns
    -------
    elevation : float
        The elevation of the point.
	'''
    usgs_url = r'https://nationalmap.gov/epqs/pqs.php?'
    usgs_params = {'output': 'json', 'x': lon, 'y': lat, 'units': units}
    for i in range(max_tries):
        try:
            usgs_request = requests.get(url=usgs_url,
                                        params=usgs_params)
            elevation = float(usgs_request.json()['USGS_Elevation_Point_Query_Service']['Elevation_Query']['Elevation'])
            break
        except Exception as e:
            print(e)
            elevation = None
            time.sleep(sec_btw_tries)
    return elevation

Google Maps Elevation API

Elevation API on GCP has 2 advantages: 1) it is fast 2) you can request multiple points at the same time (maximum 512). However, you need a GCP account and apikey. If you want to know the elevation of just one point, you can use the following function with an input which is a list of longitude and latitude, for instance [-90, 24]. If your goal is request the elevation of multiple points (to make it faster and cheaper), the input should be string of points seperated by a vertical line and comma seperated longitude and latitude, for istance "-73.998672, 40.714728 | 150.644,-34.397".

def request_elevation_gcp(List_Points):
    '''
    
    This function is used to query elevation from google maps. The query can be one by one or in batch. The unit of the output result is meter.
    To see how you can create and api key and setup your GCP please see the following links
    https://developers.google.com/maps/documentation/elevation/overview
    https://developers.google.com/maps/gmp-get-started
    
    Parameters
    ----------
    List_Points List or String: TYPE
        if list: it is a pair of longitude and latitude. For example [-90, 24]
        if string: it is seperated multiple pairs of longitude and latitude. For example "-73.998672, 40.714728 | 150.644,-34.397"

    Returns
    -------
    elevationArray : List
        It is a list including the elevation of the requested points.

    '''
  
    
    apikey = "your Key"
    url = "https://maps.googleapis.com/maps/api/elevation/json"
    
    
    if isinstance(List_Points,str):
        print('string (batch) mode')
        request_ = urllib.request.urlopen(url+"?locations="+List_Points+"&key="+apikey)
    
    elif len(List_Points)==2:
        print('single mode')
        lat=List_Points[1]
        lng=List_Points[0]
        request_ = urllib.request.urlopen(url+"?locations="+str(lat)+","+str(lng)+"&key="+apikey)
    else:
        'The input is not correct.'
    try:
        results = json.load(request_).get('results')
        if 0 < len(results):
            elevationArray = []
            for resultset in results:
                elevationArray.append(resultset['elevation'])
                #elevation = results[0].get('elevation')
            # ELEVATION
            return elevationArray
        else:
            print('HTTP GET Request failed.')
    except ValueError:
        print('JSON decode failed: '+str(request_))

The following figure and table compare the elevation extracted using the two afformentioned methods. As expected, for the same coordinates, even though the altitude is almost the same but not exactly.

No text
Fig.1 - Comparing the elevation extracted from USGS and Google Maps Elevation API

There is another take away from Fig. 1. I intentionally choose two roadways with an unleveled intersection (bridge). As you can see the point 4 from the left figure and point 5 from the right figure have almost the same altitude; no matter if you use USGS or Google Maps Elevation API. Fig. 2 shows the 3D view of this intersection and its topology when you use Google Maps Elevation API. You may have noticed by now, these APIs act like an Injective Function. In other words, for each pair of longitude and latitude, they return just one elevation. While it may not be always accurate. In the example above there is a bridge and we want to know the elevation of a pair of coordinates on it. However, for the exact some coordinates, two different elevations exist 1) the elevation of the deck of the bridge 2) the elevation of the land under the bridge. This caveat becomes more important when you want to know the elevation of a roadway including a bridge, a tunnel, or an unleveled intersection.

No text
Fig.2 - Elevation extracted from Google Maps Elevation API

As you can see in the figure below, it seems Google Maps is aware of it, and somehow it is taken care of. However, when you extract the elevation using Google Maps Elevation API, it always gives you the ground elevation (not the bridge). You can read more about it here.

No text
Fig.3 - Elevation manually extracted from from Google Maps App

I hope that was a useful and succint explanation about how to extract elevation, and you can use it in your projects.