This week I’ve started running/jogging, and I’m using RunKeeper on my iPhone to track my progress.
RunKeeper stores all the GPS data from your runs. This data is displayed per run, including a nice map of your route. Most important data can be reached throught the web interface, things like pace (min/km or min/mile) and distance. The most rewarding thing in running is breaking your own records, and RunKeeper has a couple of records:
- Longest run (distance)
- Longest run (time)
- Most calories burned in a run
- Fastest average pace
- etc
As you can see, all those statistics are about single runs, what I’m missing are the following records:
Fastest 1 KM, 3 KM, 5K, 10K etc.
For example, when I’ve run a very fast 5.5 km run, I’d love to see this reflected as my 5K personal record, but right now it is lost because I’ve already done a slow 6 km run and a very fast 1 km sprint.
Export data
But luckily RunKeeper has a very useful option for us developers: Settings > Export data.
This results in a ZIP file with GPX files, raw GPS data with time and location!
JAXB
The first thing I did was download the XSD and generate the JAXB Java code:
$ xjc -p com.royvanrijn.running.gpx gpx.xsd
parsing a schema...
compiling a schema...
com/royvanrijn/running/gpx/BoundsType.java
com/royvanrijn/running/gpx/CopyrightType.java
com/royvanrijn/running/gpx/EmailType.java
com/royvanrijn/running/gpx/ExtensionsType.java
com/royvanrijn/running/gpx/GpxType.java
com/royvanrijn/running/gpx/LinkType.java
com/royvanrijn/running/gpx/MetadataType.java
com/royvanrijn/running/gpx/ObjectFactory.java
com/royvanrijn/running/gpx/PersonType.java
com/royvanrijn/running/gpx/PtType.java
com/royvanrijn/running/gpx/PtsegType.java
com/royvanrijn/running/gpx/RteType.java
com/royvanrijn/running/gpx/TrkType.java
com/royvanrijn/running/gpx/TrksegType.java
com/royvanrijn/running/gpx/WptType.java
com/royvanrijn/running/gpx/package-info.java
Now I can open the GPX files in Java and extract the GPS locations and time like this:
JAXBContext jc = JAXBContext.newInstance("com.royvanrijn.running.gpx");
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement<GpxType> root = (JAXBElement<GpxType>) unmarshaller.unmarshal(file);
List<TrkType> tracks = root.getValue().getTrk();
The next thing I did was translate the lat+long+time waypoints into ‘legs’ consisting of meters+seconds.
Those legs can be used to check for a record during longer runs, like this:
@Override
public void analyze(List<Leg> legs) {
List<Leg> cache = new ArrayList<Leg>();
double runningDistance = 0.0;
for(Leg leg:legs) {
//Add next leg to the tail:
cache.add(leg);
runningDistance += leg.getMeters();
//If possible remove from head:
while((runningDistance-cache.get(0).getMeters()) > targetDistance) {
runningDistance -= cache.remove(0).getMeters();
}
if(runningDistance > targetDistance) {
//Check if the current target distance time is a record:
checkTime(cache);
}
}
}
For example using a target of 5000 meters in a 5070 meter run, this analysis finds the following 5K times:
5000.135743886022 00:29:57
5001.356437683744 00:29:55
5013.145427605677 00:30:01
5009.98623847093 00:30:00
5000.938905254762 00:30:01
5001.8612669243685 00:30:03
5000.555676905546 00:30:05
5000.514815789608 00:30:07
5000.514815789608 00:30:07
The information from RunKeeper website is:
- Distance: 5.07 km
- Time: 30:38
- Pace: 6:03
But when analysing the data more accurately, it could have said:
- New personal record 3K: 00:16:46
- New personal record 5K: 00:29:55
I couldn’t believe this feature wasn’t available in RunKeeper… but after a lot of Googling it turns out a lot of other people are looking for this ‘most requested’ feature! With a little bit of Java (100 lines of code) you can get a pretty good result:
Done analyzing all runs:
Fastest 100m run: 00:00:13
Fastest 200m run: 00:00:48
Fastest 400m run: 00:02:01
Fastest 1500m run: 00:07:50
Fastest 3000m run: 00:16:46
Fastest 5000m run: 00:29:55
Fastest 10000m run: --:--:--
I’m now thinking of making a simple JavaScript application (no backend) that uses the RunKeeper export zip file as input and displays a lot of additional data. Are you interested in this? Please drop a comment and convince me to make this for you guys and girls!