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.