<jupyter_start><jupyter_text>Make PositionsThe positions in the GPX file occur approximately every eight hours. To get a smoother animation that allows the progression of the weather to be seen more frequent positions are required. This notebook takes the original fixes and then interpolates between the points to get hourly positions. Various interpolation techniques are possible; a simple linear interpolation based on the bearing and distance between fixes will be tried first.<jupyter_code>from geographiclib.geodesic import Geodesic
from geopy import distance
import gpxpy
import pandas as pd
gpx_file = 'yblog-1589101179046.gpx'
with open(gpx_file) as fh:
    gpx = gpxpy.parse(fh)
data = gpx.tracks[0].segments[0].points
print(data[0])
df = pd.DataFrame(columns=['lat', 'lon', 'time'])

# Skip the first entry as it was just a test one week before we departed
for point in data[1:]: 
    df = df.append({'lon': point.longitude, 'lat' : point.latitude, 'time' : point.time}, ignore_index=True)
print(df[:10])
print(df[-3:])

ms_to_knot = 1.944
geod = Geodesic.WGS84
hourly = pd.DataFrame(columns=['lat', 'lon', 'time', 'bearing', 'speed', 'src'])
# src is a character with meanings: f: fix
#                                   i: interpolated between fixes
#                                   m: manually inserted point (e.g. when 
#                                      tracker was off in port)
seconds_in_hour = 60**2
for orig_index in range(len(df.index) - 1):
    l = geod.InverseLine(
        df.loc[orig_index]['lat'],
        df.loc[orig_index]['lon'],
        df.loc[orig_index + 1]['lat'],
        df.loc[orig_index + 1]['lon'],
    )
    start_time = df.iloc[orig_index]['time']
    start_time_hour = start_time.replace(minute=0, second=0, microsecond=0)
    end_time = df.iloc[orig_index + 1]['time']
    end_time_hour = end_time.replace(minute=0, second=0, microsecond=0)
    time_delta_hours = int((end_time_hour - start_time_hour).total_seconds() / 
                           seconds_in_hour)
    time_delta = (end_time - start_time).total_seconds()
    speed = (l.s13 / time_delta) * ms_to_knot
    for i in range(time_delta_hours):
        g = l.Position(
            (l.s13 / time_delta_hours) * i, 
            Geodesic.STANDARD | Geodesic.LONG_UNROLL
        )
        hourly = hourly.append({
            'time': start_time_hour + pd.Timedelta(hours=i),
            'lat': g['lat2'],
            'lon': g['lon2'],
            'bearing': g['azi2'] if  g['azi2'] >= 0 else 360 +  g['azi2'],
            'speed': speed,
            'src': 'f' if i == 0 else 'i',
        }, ignore_index=True)
print(hourly[:24])
print(hourly[-24:])
output_name = 'hourly_positions.json'
with open(output_name, 'w') as fh:
    hourly.to_json(fh)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12401150251617542, 'fraction_numerical': 0.020488856937455068, 'mean_word_length': 3.00431654676259, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '249493', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 955, 'n_tokens_neox': 894, 'n_words': 247, 'path': 'make_positions.ipynb', 'repo_name': 'jonseddon/elinca', 'size': '2782'}