Elevation Query
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.

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.

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.

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