Skip to content

Enhancer Reference

OpenTopoElevationEnhancer(url='https://api.opentopodata.org/', dataset='eudem25m', interpolation='cubic', skip_checks=False)

Bases: ElevationEnhancer

Use the/a OpenTopoData API (https://opentopodata.org) to enhance a GPX track with elevation information.

Setup the enhancer via a opentopodata rest api.

Parameters:

Name Type Description Default
url str

REST api entrypoint url, defaults to "https://api.opentopodata.org/"

'https://api.opentopodata.org/'
dataset str

Dataset of elevation data , defaults to "eudem25m"

'eudem25m'
interpolation str

Interpolation method, defaults to "cubic"

'cubic'
skip_checks bool

If true, health checks will be skipped on initialization, defaults to False

False

Raises:

Type Description
APIHealthCheckFailedError

If connection can not established

APIHealthCheckFailedError

Any other error on health check

APIDataNotAvailableError

Dataset is not available at the endpoint

Source code in geo_track_analyzer/enhancer.py
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def __init__(
    self,
    url: str = "https://api.opentopodata.org/",
    dataset: str = "eudem25m",
    interpolation: str = "cubic",
    skip_checks: bool = False,
) -> None:
    """
    Setup the enhancer via a opentopodata rest api.

    :param url: REST api entrypoint url, defaults to "https://api.opentopodata.org/"
    :param dataset: Dataset of elevation data , defaults to "eudem25m"
    :param interpolation: Interpolation method, defaults to "cubic"
    :param skip_checks: If true, health checks will be skipped on initialization,
        defaults to False
    :raises APIHealthCheckFailedError: If connection can not established
    :raises APIHealthCheckFailedError: Any other error on health check
    :raises APIDataNotAvailableError: Dataset is not available at the endpoint
    """
    self.base_url = url
    self.url = f"{url}/v1/{dataset}"
    self.interpolation = interpolation

    if not skip_checks:
        logger.debug("Doing server health check")
        try:
            resp = requests.get(f"{self.base_url}/health")
        except requests.exceptions.ConnectionError as e:
            raise APIHealthCheckFailedError(str(e))
        if resp.status_code != 200:
            raise APIHealthCheckFailedError(resp.text)

        logger.debug("Doing dataset check")
        resp = requests.get(f"{self.base_url}/datasets")
        if resp.status_code != 200:
            raise APIHealthCheckFailedError(resp.text)
        datasets = [ds["name"] for ds in resp.json()["results"]]
        if dataset not in datasets:
            raise APIDataNotAvailableError("Dataset %s not available" % dataset)

enhance_track(track, inplace=False)

Main method to enhance a passed GPX track with elevation information

Parameters:

Name Type Description Default
track GPXTrack

Track to be enhanced.

required

Returns:

Type Description
GPXTrack

The enhanced track

Source code in geo_track_analyzer/enhancer.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
def enhance_track(self, track: GPXTrack, inplace: bool = False) -> GPXTrack:
    """
    Main method to enhance a passed GPX track with elevation information

    :param track: Track to be enhanced.

    :returns: The enhanced track
    """
    if inplace:
        track_ = track
    else:
        track_ = track.clone()

    for segment in track_.segments:
        request_coordinates = []
        for point in segment.points:
            request_coordinates.append((point.latitude, point.longitude))

        elevations = self.get_elevation_data(request_coordinates)
        for point, elevation in zip(segment.points, elevations):
            point.elevation = elevation

    return track_

get_elevation_data(input_coordinates, split_requests=None)

Send a post request to the api endoint to query elevation data for the passed input coordinates

Parameters:

Name Type Description Default
input_coordinates list[tuple[float, float]]

list of latitude, longitude tuples for which the elevation should be determined.

required
split_requests None | int

Optionally split request into multiple requires to get around size restrictions, defaults to None

None

Returns:

Type Description
list[float]

A list of Elevations for the passed coordinates.

Raises:

Type Description
APIResponseError

Any none 200 response form the endpoint

Source code in geo_track_analyzer/enhancer.py
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
def get_elevation_data(
    self,
    input_coordinates: list[tuple[float, float]],
    split_requests: None | int = None,
) -> list[float]:
    """Send a post request to the api endoint to query elevation data
    for the passed input coordinates

    :param input_coordinates: list of latitude, longitude tuples for which the
        elevation should be determined.

    :param split_requests: Optionally split request into multiple requires to get
        around size restrictions, defaults to None
    :raises APIResponseError: Any none 200 response form the endpoint

    :returns: A list of Elevations for the passed coordinates.
    """
    logger.debug("Getting elevation data")
    if split_requests is None:
        split_input_coord = [input_coordinates]
    else:
        split_input_coord = [
            input_coordinates[i : i + split_requests]
            for i in range(0, len(input_coordinates), split_requests)
        ]

    ret_elevations = []
    for coords in split_input_coord:
        locations = ""
        for latitude, longitude in coords:
            locations += f"{latitude},{longitude}|"

        locations = locations[:-1]
        resp = requests.post(
            self.url,
            data={
                "locations": locations,
                "interpolation": self.interpolation,
            },
        )

        if resp.status_code == 200:
            result_data = resp.json()
            for res in result_data["results"]:
                ret_elevations.append(res["elevation"])

        else:
            raise APIResponseError(resp.text)

    return ret_elevations

OpenElevationEnhancer(url='https://api.open-elevation.com')

Bases: ElevationEnhancer

Use the/a OpenElevation API (https://open-elevation.com) to enhance a GPX track with elevation information.

Setup the enhancer via the url of the rest api of open-elevation

Parameters:

Name Type Description Default
url str

URL of the API gateway

'https://api.open-elevation.com'
Source code in geo_track_analyzer/enhancer.py
176
177
178
179
180
181
182
183
184
185
186
def __init__(self, url: str = "https://api.open-elevation.com") -> None:
    """
    Setup the enhancer via the url of the rest api of open-elevation

    :param url: URL of the API gateway
    """
    self.url = f"{url}/api/v1/lookup"

    self.headers: Mapping[str, str] = CaseInsensitiveDict()
    self.headers["Accept"] = "application/json"
    self.headers["Content-Type"] = "application/json"

enhance_track(track, inplace=False)

Main method to enhance a passed GPX track with elevation information

Parameters:

Name Type Description Default
track GPXTrack

Track to be enhanced.

required

Returns:

Type Description
GPXTrack

The enhanced track

Source code in geo_track_analyzer/enhancer.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
def enhance_track(self, track: GPXTrack, inplace: bool = False) -> GPXTrack:
    """
    Main method to enhance a passed GPX track with elevation information

    :param track: Track to be enhanced.

    :returns: The enhanced track
    """
    if inplace:
        track_ = track
    else:
        track_ = track.clone()

    for segment in track_.segments:
        request_coordinates = []
        for point in segment.points:
            request_coordinates.append((point.latitude, point.longitude))

        elevations = self.get_elevation_data(request_coordinates)
        for point, elevation in zip(segment.points, elevations):
            point.elevation = elevation

    return track_

get_elevation_data(input_coordinates)

Send a POST request to the Open-Elevation API specified in the init.

Parameters:

Name Type Description Default
input_coordinates list[tuple[float, float]]

list of latitude, longitude tuples for which the elevation should be determined.

required

Returns:

Type Description
list[float]

A list of Elevations for the passed coordinates.

Source code in geo_track_analyzer/enhancer.py
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def get_elevation_data(
    self, input_coordinates: list[tuple[float, float]]
) -> list[float]:
    """
    Send a POST request to the Open-Elevation API specified in the init.

    :param input_coordinates: list of latitude, longitude tuples for which the
        elevation should be determined.

    :returns: A list of Elevations for the passed coordinates.
    """
    data: Dict = {"locations": []}
    for latitude, longitude in input_coordinates:
        data["locations"].append({"latitude": latitude, "longitude": longitude})

    resp = requests.post(self.url, headers=self.headers, data=json.dumps(data))

    if resp.status_code == 200:
        result_data = resp.json()
        ret_elevations = []
        for res in result_data["results"]:
            ret_elevations.append(float(res["elevation"]))

        return ret_elevations
    else:
        raise APIResponseError(resp.text)

get_enhancer(name)

Get a Enhance object for a specific enpoint by passing a distinct name

Parameters:

Name Type Description Default
name EnhancerType

Name of enhancer. Chose OpenTopoElevation or OpenElevation

required

Returns:

Type Description
Type[Enhancer]

An Enhancer object

Raises:

Type Description
NotImplementedError

If an invalid name is passed

Source code in geo_track_analyzer/enhancer.py
216
217
218
219
220
221
222
223
224
225
226
227
228
def get_enhancer(name: EnhancerType) -> Type[Enhancer]:
    """Get a Enhance object for a specific enpoint by passing a distinct name

    :param name: Name of enhancer. Chose OpenTopoElevation or OpenElevation
    :raises NotImplementedError: If an invalid name is passed
    :return: An Enhancer object
    """
    if name == EnhancerType.OPENTOPOELEVATION:
        return OpenTopoElevationEnhancer
    elif name == EnhancerType.OPENELEVATION:
        return OpenElevationEnhancer
    else:
        raise NotImplementedError("Can not return Enhancer for name %s" % name)