Skip to content

Commit f11f196

Browse files
authored
Merge pull request #29 from khink/percentage-in-zones
Calculate percentage spent in each HR zone
2 parents 9275f95 + b3d22eb commit f11f196

6 files changed

Lines changed: 3577 additions & 3 deletions

File tree

README.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ Basic usage example::
7777
Compatibility
7878
-------------
7979

80-
* Python 2.7 or 3.6+
80+
* Python 3.6+, see `tox.ini`_.
81+
82+
.. _tox.ini: tox.ini
8183

8284
License
8385
-------

tcxparser/exceptions.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class TcxParserException(Exception):
2+
"""A generic error to raise when parsing a tcx file fails"""
3+
pass
4+
5+
6+
class NoHeartRateDataError(Exception):
7+
8+
def __init__(self):
9+
self.message = "The tcx file contains no heart rate data."
10+
super().__init__(self.message)

tcxparser/tcxparser.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import time
88
from lxml import objectify
99

10+
from .exceptions import NoHeartRateDataError
11+
1012
namespace = 'http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2'
1113

1214

@@ -98,6 +100,44 @@ def hr_min(self):
98100
"""Minimum heart rate of the workout"""
99101
return min(self.hr_values())
100102

103+
def hr_percent_in_zones(self, zones):
104+
"""Percentage of workout spent in each heart rate zone.
105+
106+
Given these user's heart rate zones:
107+
zones = {
108+
"Z0": (0, 119),
109+
"Z1": (120, 199),
110+
"Z2": (200, 240),
111+
}
112+
113+
Then `self.hr_percent_in_zones(zones)` would return something like:
114+
{
115+
"Z0": 5,
116+
"Z1": 95,
117+
"Z2": 0,
118+
}
119+
120+
Correct calculation relies on evenly spaced measurement times.
121+
"""
122+
hr_values = self.hr_values()
123+
if not hr_values:
124+
raise NoHeartRateDataError
125+
126+
# Initialize a dictionary with one item for each zone
127+
per_zone = dict.fromkeys(zones.keys(), 0)
128+
129+
# count number of HR measurements per zone
130+
for hr in hr_values:
131+
for zone_name, zone_boundaries in zones.items():
132+
if hr >= zone_boundaries[0] and hr <= zone_boundaries[1]:
133+
per_zone[zone_name] += 1
134+
135+
# convert counts to percentages
136+
nr_hr_values = len(hr_values)
137+
for name, count in per_zone.items():
138+
per_zone[name] = round(100 * count / nr_hr_values)
139+
return per_zone
140+
101141
@property
102142
def pace(self):
103143
"""Average pace (mm:ss/km for the workout"""

0 commit comments

Comments
 (0)