Skip to content

samsung health gpx files - heart rates #48

@ag88

Description

@ag88

Samsung Health app is able to export a GPX file with heart rates for activities (e.g. bike)
https://worksmile.zendesk.com/hc/en-us/articles/17045018603281-Samsung-Health-eksport-plik%C3%B3w-gpx

However, when I tried gpxplotter, I noted that heart rates is not extracted.
It turns out the heart rates is formatted as follows in a track point

<gpx ...
xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1"
http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd
>
...
<trkpt lat="15.123" lon="60.123">
<ele>10.020</ele>
<time>2024-10-25T08:38:42Z</time>
<extensions>
<gpxtpx:TrackPointExtension>
<gpxtpx:hr>60</gpxtpx:hr>
</gpxtpx:TrackPointExtension>
</extensions>
</trkpt>

currently I'm extracting it like (file: gpxread.py)

def extract_sam_ht_hr(point):
    ext = point.getElementsByTagName("extensions")
    if len(ext) == 0:
        return 0
    ext = ext[0].getElementsByTagName("gpxtpx:TrackPointExtension")
    if len(ext) == 0:
        return 0    
    if len(ext[0].getElementsByTagName("gpxtpx:hr")) == 0:
        return 0
    hr = ext[0].getElementsByTagName("gpxtpx:hr")[0].firstChild.nodeValue
    return int(hr)

def get_point_data(point):
    """Get basic information from a track point.

    Parameters
    ----------
    point : object like :py:class:`xml.dom.minidom.Element`
        The point on the track we are extracting information from.

    """
    data = {
        "lat": float(point.getAttribute("lat")),
        "lon": float(point.getAttribute("lon")),
    }

    ele = extract_data(point, "ele", float)
    if ele is not None:
        data["elevation"] = ele
        
    hr = extract_sam_ht_hr(point)  #<-- called here
    #if not hr == 0:
    data["hr"] = hr

    for key, val in EXTRACT.items():
        value = extract_data(point, val["key"], val["formatter"])
        if value is not None:
            data[key] = value

    return data

apparently, heart rates is missing in the samsung health gpx in the trackpoint when the tracking is paused, i.e. no heartrates in certain trackpoints). if I omit them, the returned list lengths become uneven and it'd cause some issues with matplotlib pyplot etc. Hence, I decided to simply return 0 heart rates for those trackpoints. it is fairly 'intuitive' on a plot, but that it may cause some problems doing calcs. Nevertheless, 0 'makes sense' in this case as during a long pause, it is high before the pause, zero during the pause, and low after the pause, not 'interpolating' them makes it apparent that it is missing during the pause.
Apps can choose to handle that zero hr as they deem fit.

this may possibly 'co-exists' with other heart rate formats, if those formats are after all different and distinct.
i.e. that heart rates is presented as one format or the other but not both

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions