Skip to content

Instantly share code, notes, and snippets.

@spirrobe
Last active May 21, 2024 20:50
Show Gist options
  • Save spirrobe/7a512eeb83a7dfc20ae3f94871815367 to your computer and use it in GitHub Desktop.
Save spirrobe/7a512eeb83a7dfc20ae3f94871815367 to your computer and use it in GitHub Desktop.
A small function to get an altitude profile from Swisstopo based on their API
def get_swisstopo_elevation_profile(coords, # a path (2+ points in the form)
kind='csv',
# three heights are available for JSON
# COMB, DTM2, DTM25
which='COMB',
asnumpy=True,
quiet=True,
opts={"sr": None,
"nb_points": None,
"offset": None,
"distinct_points": True,
"callback": None,
}
):
"""
Call the swisstopo API for altitude data along a path.
Pass in a list or array of coordinates in EPSG 2056 (LV95) or 21781 (LV03)
to get altitude values along the provided path. For options see keywords or
parameters of call via swisstopo API.
Parameters
----------
coords : list or numpy array
The coordinates in either EPSG 2056 (LV95) or EPSG 21781 (LV03).
kind : str, optional
Which API backend should be queried. Available are json and csv.
If none of these are passed properly, fallback is csv.
The default is 'csv' (easier structure to parse).
which: str
If kind is json, three altitude values are available, DTM2, DTM25 and
COMB(INATION).
asnumpy : bool, optional
Whether to return a numpy array.
The default is True.
quiet : bool, optional
Whether to quiet the output (True) or not.
The default is True.
opts: dict
Further keywords than can be passed to the API call, see
https://api3.geo.admin.ch/services/sdiservices.html#profile
Returns
-------
list or numpy array
The returned points, in the form of distance along path, altitude,
coordinates.
"""
import requests
import numpy as np
if len(coords) > 5000:
print('Warning, number of coordinates exceeds swisstopo API'
'max number of points, reduce coords beforehand.')
return np.asarray([]) if asnumpy else []
payload = 'geom={"type":"LineString","coordinates":['
payload += ','.join([f"[{coord[0]},{coord[1]}]"
for coord in coords])
payload += ']'
opts = ','.join(['"'+str(key)+'"'+':'+'"'+str(opt)+'"'
for key, opt in opts.items()
if opt is not None])
if opts:
payload += ',' + opts
payload += '}'
kind = kind.lower()
if kind.lower() not in ['csv', 'json']:
if not quiet:
print('Only csv or json can be chosen, autoselecting csv')
kind = 'csv'
baseurl = "https://api3.geo.admin.ch/rest/services/profile." + kind
try:
profile = requests.get(baseurl, params=payload)
except ConnectionError:
if not quiet:
print('Connection timeout')
return np.asarray([]) if asnumpy else []
if profile.ok:
if not quiet:
print('Success')
else:
if not quiet:
print('Failed')
if kind == 'csv':
profile = profile.text.split('\r\n')
# Distance, Altitude, Easting, Northing -> not needed
# header = profile[0]
profile = list(map(lambda x: [float(j.strip('"'))
for j in x.split(';')],
profile[1:-1]))
elif kind == 'json':
profile = [[p['dist'], p['alts'][which],
p['easting'], p['northing']]
for p in profile.json()]
if asnumpy:
profile = np.asarray(profile)
return profile
if __name__ == '__main__':
# straightforward example usage
rw=[2611025.0, 2620975.0, 2633725.0]
hw=[1266400.0, 1256750.0, 1250000.0]
profile = get_swisstopo_elevation_profile(list(zip(rw, hw)))
import matplotlib.pyplot as plt
plt.fill_between(profile[:,0],
profile[:,1],
facecolor='grey',
edgecolor='k',
alpha=0.8)
plt.ylim(min(profile[:,1]), None)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment