Created
July 20, 2022 13:01
-
-
Save N-M-T/826dc11435a6c7ab6f61cb843e274a3e to your computer and use it in GitHub Desktop.
Minimal example to extract fit and invisible timestamps
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from datetime import datetime, timedelta | |
from typing import Dict, Union, Optional, Tuple | |
import numpy as np | |
import pandas as pd | |
import fitdecode | |
# The names of the columns we will use in our points DataFrame. For the data we will be getting | |
# from the FIT data, we use the same name as the field names to make it easier to parse the data. | |
POINTS_COLUMN_NAMES = [ | |
"latitude", | |
"longitude", | |
"altitude", | |
"timestamp", | |
"heart_rate", | |
"cadence", | |
"speed", | |
] | |
def get_fit_point_data( | |
frame: fitdecode.records.FitDataMessage, | |
) -> Optional[Dict[str, Union[float, int, str, datetime]]]: | |
"""Extract some data from an FIT frame representing a track point | |
and return it as a dict. | |
""" | |
data: Dict[str, Union[float, int, str, datetime]] = {} | |
if not (frame.has_field("position_lat") and frame.has_field("position_long")): | |
# Frame does not have any latitude or longitude data. We will ignore these frames in order to keep things | |
# simple, as we did when parsing the TCX file. | |
return None | |
else: | |
data["latitude"] = frame.get_value("position_lat") / ((2 ** 32) / 360) | |
data["longitude"] = frame.get_value("position_long") / ((2 ** 32) / 360) | |
for field in POINTS_COLUMN_NAMES[3:]: | |
if frame.has_field(field): | |
data[field] = frame.get_value(field) | |
return data | |
def get_dataframes(fname: str) -> pd.DataFrame: | |
"""Takes the path to a FIT file (as a string) and returns Pandas | |
DataFrame: one containing individual points. | |
""" | |
points_data = [] | |
with fitdecode.FitReader(fname) as fit_file: | |
for frame in fit_file: | |
if isinstance(frame, fitdecode.records.FitDataMessage): | |
if frame.name == "record": | |
single_point_data = get_fit_point_data(frame) | |
if single_point_data is not None: | |
points_data.append(single_point_data) | |
# Create DataFrames from the data we have collected. If any information is missing from a particular | |
# point, it will show up as a null value or "NaN" in the DataFrame. | |
return pd.DataFrame(points_data, columns=POINTS_COLUMN_NAMES) | |
def get_pupil_timestamps(fname: str) -> pd.DataFrame: | |
df = pd.read_csv(fname) | |
ns_ts = df["timestamp [ns]"] | |
# convert utc nanoseconds to datetime | |
# TODO: modify this conversion | |
return pd.DataFrame([datetime.utcfromtimestamp(x / 1e9) for x in ns_ts]) | |
if __name__ == "__main__": | |
# from sys import argv | |
fname_fit = "/Users/neilthomas/Downloads/eye-tracking-run.FIT" # Path to FIT file | |
points_df = get_dataframes(fname_fit) | |
fname_pl = "/Users/neilthomas/Documents/raw-data-export/running_rd-4a40d94d/gaze.csv" # Path to Invisible data | |
ts_pl = get_pupil_timestamps(fname_pl) | |
print("\nGarmin ts:") | |
print(points_df["timestamp"]) | |
print("\nPL ts:") | |
print(ts_pl) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment