Quickstart#

The main library function is gradeit().

The simplest way to use the package is to call gradeit() with a trace of points. This uses all of the defaults and should work well out of the box.

from gradeit import gradeit

trace = [
    (39.7392, -104.9903),
    (39.7402, -104.9903),
    (39.7412, -104.9903),
]
result = gradeit(trace)

Input#

A trace is a sequence of points and can have any of these forms. GradeIT detects the form:

import numpy as np
import pandas as pd

from gradeit import Coordinate, gradeit

lats = [39.7392, 39.7402, 39.7412]
lons = [-104.9903, -104.9903, -104.9903]

gradeit(pd.DataFrame({"latitude": lats, "longitude": lons}))  # DataFrame
gradeit(np.column_stack((lats, lons)))  # (n, 2) array, (lat, lon) rows
gradeit({"latitude": lats, "longitude": lons})  # mapping
gradeit(list(zip(lats, lons)))  # (lat, lon) pairs
gradeit([Coordinate.from_lat_lon(lat, lon) for lat, lon in zip(lats, lons)])  # Coordinate objects

Set the column names if your DataFrame uses different names:

import pandas as pd

from gradeit import gradeit

df = pd.DataFrame(
    {
        "lat": [39.7392, 39.7402, 39.7412],
        "lon": [-104.9903, -104.9903, -104.9903],
    }
)
gradeit(df, lat_col="lat", lon_col="lon")

Points must be in travel order. GradeIT calculates grade between consecutive points. You must provide at least two points. GradeIT does not change your input.

Output#

gradeit() returns a GradeResult. This frozen container has NumPy arrays:

from gradeit import gradeit

result = gradeit([(39.7392, -104.9903), (39.7402, -104.9903), (39.7412, -104.9903)])

result.elevation_ft_unfiltered  # raw DEM lookup, feet
result.grade_dec_unfiltered  # grade from the raw lookup, decimal rise/run
result.elevation_ft_filtered  # cleaned elevation, feet
result.grade_dec_filtered  # grade recomputed from the cleaned elevation
result.distances_ft  # distance from the previous point, feet
result.coordinates  # the parsed input coordinates

Grade is a decimal rise over run. Multiply it by 100 to get a percentage. distances_ft starts with 0.0.

To return the result as a Pandas dataframe or Python dictionary:

from gradeit import gradeit

result = gradeit([(39.7392, -104.9903), (39.7402, -104.9903), (39.7412, -104.9903)])

df = result.to_dataframe()  # needs gradeit[pandas]
d = result.to_dict()  # same columns, plain lists

Choosing an elevation model#

The default is USGSApi(), which pings the online USGS 3DEP service. This works right out of the box but it requires API calls. For better performance, download raster tiles and use USGSLocal:

from gradeit import USGSLocal, gradeit

trace = [(39.7392, -104.9903), (39.7402, -104.9903), (39.7412, -104.9903)]
result = gradeit(trace, elevation_model=USGSLocal("path/to/tiles"))

See Elevation Data to get the tiles.

See Custom Elevation Sources to develop a model for a custom data source.

Choosing a filter#

If you do not pass a filter, GradeIT uses Wood2014Filter. This is suitable for most traces:

from gradeit import gradeit

trace = [(39.7392, -104.9903), (39.7402, -104.9903), (39.7412, -104.9903)]
result = gradeit(trace)  # Wood2014Filter applied

To disable filtering or use more than one filter:

from gradeit import BridgeFilter, Wood2014Filter, gradeit

trace = [(39.7392, -104.9903), (39.7402, -104.9903), (39.7412, -104.9903)]

gradeit(trace, elevation_filter=None)  # raw only
gradeit(trace, elevation_filter=Wood2014Filter(savgol_window_ft=1200))
gradeit(
    trace,
    elevation_filter=[BridgeFilter(baseline_radius_ft=6000), Wood2014Filter()],
)

GradeIT applies filters in order. Each filter receives the output from the last filter. GradeIT calculates grade from the final elevation. If you have large bridge artifacts, put BridgeFilter first (see Bare-Earth Bridges). See Filters for all parameters. See How Filtration Works for filter behavior.

Next#

Your First Grade Profile runs all of this on a real trace.