#!/usr/bin/env python3 import pandas as pd import numpy as np from geopy import distance import plotly.express as px # At the time of this writing the latest git version of gpx-converter # is required (the default pip version 1.7.4 does not enable to save altitudes) from gpx_converter import Converter # Self-explanatory text print('This script takes a circular GPX route as input') print('and makes it possible to change the starting point') print('and/or to invert the loop direction.') print(' ') print('It also generates an HTML file with the elevation profile.') print(' ') print('If you wish to change the starting point,') print('you will need to identify the exact coordinates') print('of the new starting point in the original GPX file.') print('For instance, by using a GPX viewer.') print(' ') # Input and files prompts igpx = input('Input GPX file name (whith full path) : ').strip() ogpx = input('Output GPX file name (whith full path) : ').strip() # Read the original GPX file df = Converter(input_file=igpx).gpx_to_dataframe() df.drop_duplicates(keep=False, inplace=True) df = df.round(decimals = 6) # Direction of the loop prompt idir = input('Would you like to invert the direction of the loop? (y/n) : ').strip() # Invert the direction of the loop if required if idir.lower() == ('yes') or idir.lower() == ('y'): df = df.iloc[::-1].reset_index(drop=True) # Starting point prompt isp = input('Would you like to change the starting poing? (y/n) : ').strip() # Alter the starting point if required if isp.lower() == ('yes') or isp.lower() == ('y'): lat = input('Latitude of the new starting point (exactly as in the input file) : ').strip() lon = input('Longitude of the new starting point (exactly as in the input file) : ').strip() idx = df.index[(df['latitude'] == round(float(lat), 6)) & (df['longitude'] == round(float(lon), 6))].values[0] df1 = df.iloc[:idx, :] df2 = df.iloc[idx:, :] df3 = df2.iloc[0].to_frame().T df = df2.append([df1, df3], ignore_index=True) # Save the new GPX file Converter.dataframe_to_gpx(input_df=df, lats_colname='latitude', longs_colname='longitude', alts_colname='altitude', output_file=ogpx) # Calculate distances between coordinates # We use the Karney (2013) algorithm as implemented in GeoPy # with an a posteriori Euclidean altitude correction def eukarney(lat1, lon1, alt1, lat2, lon2, alt2): p1 = (lat1, lon1) p2 = (lat2, lon2) karney = distance.distance(p1, p2).m return np.sqrt(karney**2 + (alt2 - alt1)**2) df['lat_shift'] = df['latitude'].shift().fillna(df['latitude']) df['lon_shift'] = df['longitude'].shift().fillna(df['longitude']) df['alt_shift'] = df['altitude'].shift().fillna(df['altitude']) df['distances'] = df.apply(lambda x: eukarney(x['latitude'], x['longitude'], x['altitude'], x['lat_shift'], x['lon_shift'], x['alt_shift']), axis=1).fillna(0) df['distance'] = df['distances'].cumsum().round(decimals = 0).astype(int) # Plot elevation profile fig = px.line(df, x = 'distance', y = 'altitude', title = 'Elevation profile of the route') fig.update_traces(line_color='#008000', line_width=3.0) fig.write_html(ogpx + '.html')