Search code examples
pythonjsoncoordinatesgeopandas

Python: Obtaining elevation from latitude and longitude values


Firstly, there is code for this question. However, it seems to only be suitable for the US. As stated on their website (https://nationalmap.gov/epqs/) when unable to find value it will return -1000000, which is my case.

I'm trying to obtain elevation in Sweden.

Using this sample data:

lat = [57.728905, 57.728874, 57.728916, 57.728836, 57.728848]
lon = [11.949309, 11.949407, 11.949470, 11.949342, 11.949178]

# create df
df = pd.DataFrame({'lat': lat, 'lon': lon})

How can I make the code below adaptable to global grounds and not just limited to the US? Or at least, is there a way I could focus it on Sweden? Shouldn't the USGS have global data?

def make_remote_request(url: str, params: dict):
   """
   Makes the remote request
   Continues making attempts until it succeeds
   """

   count = 1
   while True:
       try:
           response = requests.get((url + urllib.parse.urlencode(params)))
       except (OSError, urllib3.exceptions.ProtocolError) as error:
           print('\n')
           print('*' * 20, 'Error Occured', '*' * 20)
           print(f'Number of tries: {count}')
           print(f'URL: {url}')
           print(error)
           print('\n')
           count += 1
           continue
       break

   return response


def elevation_function(x):
   url = 'https://nationalmap.gov/epqs/pqs.php?'
   params = {'x': x[1],
             'y': x[0],
             'units': 'Meters',
             'output': 'json'}
   result = make_remote_request(url, params)
   return result.json()['USGS_Elevation_Point_Query_Service']['Elevation_Query']['Elevation']

To run the function:

df['elevation'] = df.apply(elevation_function, axis=1)


# Print output
df

Source code: Obtain elevation from latitude longitude coordinates with a simple python script

UPDATE:

Using the suggestions in the accepted answer and adding time.sleep(1) in the elevation function allowed me to get elevation data to all the observations. Note that this API only allows 100 locations per request. Hence, for a higher number of rows, it must be broken down into different requests.


Solution

  • I've been using the api from opentopodata.org to obtain elevation values. You could use the EU-DEM dataset which covers entire sweden. An API request is as simple as the following:

    https://api.opentopodata.org/v1/eudem25m?locations=57.728905,11.949309
    

    Another elevation API can be found at https://open-elevation.com/. A request looks very similar:

    https://api.open-elevation.com/api/v1/lookup?locations=57.728905,11.949309
    

    therefore adapting your elevation_function:

    def elevation_function(x):
       url = 'https://api.opentopodata.org/v1/eudem25m?'
       # url = 'https://api.open-elevation.com/api/v1/lookup?'
       params = {'locations': f"{x[0]},{x[1]}"}
       result = make_remote_request(url, params)
       return result.json()['results'][0]['elevation']