<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/the-gamification-of-fitbit-how-an-api-provided-the-next-level-of-training/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://towardsdatascience.com/the-gamification-of-fitbit-how-an-api-provided-the-next-level-of-training-eaf7b267af00?source=rss-459e62b88a2a------2"> Stories by Matt.0 on Medium</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<blockquote><p><strong>“Anyone can look for fashion in a boutique or history in a museum. The creative explorer looks for history in a hardware store and fashion in an airport” — Robert Wieder</strong></p></blockquote>
<figure><img alt="" src="https://i0.wp.com/cdn-images-1.medium.com/max/390/1*8RLsDiMctQXxopZbPkrbDg.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<p>As much as I like Medium for it’s ability to reach an audience I prefer the customization afforded by github.io. <strong>If you want to see a far-fancier version of this post please </strong><a rel="nofollow" href="https://moldach.github.io/fitbit-project/" target="_blank"><strong>visit this page instead</strong></a><strong>.</strong></p>
<h3>Project Inspiration</h3>
<p>You may, or may not, have heard of the term gamification but chances are you’ve experienced it.</p>
<p>Gamification is the application of game-design elements, and game principles, in non-game contexts. The idea is, if you use elements of games, like linking rules and rewards into a feedback system, you can make (almost) any activity motivating and fun.</p>
<p>Gamification is the concept behind <strong>eLearning</strong>. In elementary school I remember all the students wanted to play <a rel="nofollow" href="https://classicreload.com/oregon-trail.html" target="_blank">The Oregon Trail</a> in computer class. I also remember another game where you had to solve math problems before something hit the floor. Okay, maybe it wasn’t the most thrilling introduction to gamification but I remember it nonetheless.</p>
<p>At some point in my career, I got tired of using nano and decided to I wanted to try to learn Vim.</p>
<figure><img alt="" src="https://i2.wp.com/cdn-images-1.medium.com/max/492/1*AmTt7JNbFu1jFMNsPyQu-A.jpeg?w=456&ssl=1" data-recalc-dims="1"></figure>
<p>It was then that I discovered two very enjoyable examples of gamification:</p>
<ul>
<li><a rel="nofollow" href="https://vim-adventures.com/" target="_blank">Vim Adventures</a> is kind of like Zelda for Gameboy where you have to move through the environment and solve riddles – except with Vim commands! You can <a rel="nofollow" href="https://www.youtube.com/watch?v=zGk_ipjk9uw" target="_blank">watch it being played on Twitch here</a>.</li>
</ul>
<figure><img alt="" src="https://i2.wp.com/cdn-images-1.medium.com/max/1024/1*Okxo0zg6qVP04FoAXae8pw.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<ul>
<li><a rel="nofollow" href="https://www.shortcutfoo.com/" target="_blank">shortcutFoo</a> teaches you shortcuts for Vim, Emacs, Command Line, Regex <em>etc.</em> via <strong>interval training</strong>, which is essentially spaced repetition. This helps you memorize shortcuts more efficiently.</li>
</ul>
<figure><img alt="" src="https://i2.wp.com/cdn-images-1.medium.com/max/893/1*5ud55u_gAzfpMCsi0kOs8A.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<p>Today, I enjoy eLearning-gamification on platforms like <a rel="nofollow" href="https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=2ahUKEwiQm7ib677eAhUovlkKHRr-BygQFjAAegQIAhAC&url=https%3A%2F%2Fwww.duolingo.com%2F&usg=AOvVaw0GVHP2wYuntJMUTG1EDY5y" target="_blank">DuoLingo</a>, and <a rel="nofollow" href="https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=2ahUKEwiQm7ib677eAhUovlkKHRr-BygQFjAAegQIAhAC&url=https%3A%2F%2Fwww.duolingo.com%2F&usg=AOvVaw0GVHP2wYuntJMUTG1EDY5y" target="_blank">DataCamp</a>.</p>
<p>I’ve also recently started to participate in a Kaggle competition, “<a rel="nofollow" href="https://www.kaggle.com/c/pubg-finish-placement-prediction" target="_blank">PUBG Finish Placement Prediction</a>”. Kaggle is a Google owned hangout for data science enthusiasts where they can use machine learning to solve predictive analytics problems for cash and clout. Similar to chess there are so-called <strong>Kaggle Grandmasters</strong>.</p>
<h3>The Quest</h3>
<p>Our laboratory studies perinatal influences on the biological embedding of early adversity of mental health outcomes. We combine genetic, epigenetic and epidemiological approaches to identify pregnant women who’s offspring may potentially be at risk for adverse mental health outcomes.</p>
<blockquote><p><em>My supervisor approached me with a challenge; how feasible would it be to access biometric data from 200 Fitbits?</em></p></blockquote>
<p><strong>So I bought myself a Fitbit Charge2 fitness tracker and hit the gym!</strong></p>
<p>At some point I think we both realized that this project was going to be a big undertaking. Perhaps R isn’t really intended to do large scale real-time data management from API services. It’s great for static files, or static endpoints, but if you’re working with multiple participants a dedicated solution like <a rel="nofollow" href="https://www.fitabase.com/" target="_blank">Fitabase</a> may work the best – or so they claim.</p>
<p>Nonetheless, I wanted to try out a bunch of cool new things in R like making a personal website using blogdown, using gganimate with Rokemon, accessing the fitbit API with httr as well as adding a background image with some custom CSS/HTML. Is there possibly a better way to possibly gamify my leaRning curve – I think not.</p>
<p><strong>The following was my attempt at e-learning </strong><strong>gamification for </strong><strong>R.</strong></p>
<p>I used the <a rel="nofollow" href="https://bookdown.org/yihui/blogdown/" target="_blank">blogdown</a> package to allow me to write blog posts as R Markdown documents, knitting everything to a nice neat static website that I can push online. It was a nice opportunity to learn a bit about pandoc, Hugo, CSS/HTML lurking beneath the server side code. I decided to go with the <a rel="nofollow" href="https://themes.gohugo.io/academic/" target="_blank">Academic theme</a> for <a rel="nofollow" href="https://gohugo.io/" target="_blank">Hugo</a>, pull in as much data as I could from the Fitbit API, clean it up, and then perform some exploratory data analysis. In the process, I generated some cool animated sprites and use video game inspired visualizations.</p>
<figure><img alt="" src="https://i1.wp.com/cdn-images-1.medium.com/max/400/1*Iv2UzWmwJOtzbUQD-cFofg.gif?w=456&ssl=1" data-recalc-dims="1"></figure>
<h3>Setting up a Fitbit Developer Account</h3>
<p>Fitbit uses <a rel="nofollow" href="https://dev.fitbit.com/build/reference/web-api/oauth2/" target="_blank"><strong>OAuth 2.0</strong></a><strong> Access</strong> Token for making HTTP request to the Fitbit API. You need to set up an account to use the API and include your token in R. Instead of reading the <a rel="nofollow" href="https://dev.fitbit.com/build/reference/web-api/basics/#app-registration" target="_blank">FITBIT DEV HELP</a> section I would direct the reader to better more-concise instructions <a rel="nofollow" href="https://obrl-soil.github.io/fitbit-api-r/" target="_blank">here</a>.</p>
<p>Now that you have an account we’re ready to do stuff in R.</p>
<p>Set your token up:</p>
<pre># You Found A Secret Area!<br>token = &quot;yourToken&quot;</pre>
<h3>Using the fitbitr package</h3>
<p>I had never made an HTTP request before and although the process is officially documented <a rel="nofollow" href="https://moldach.github.io/fitbit-project/(https://dev.fitbit.com/build/reference/web-api/oauth2/)" target="_blank">here</a> it can be a <em>tad</em> overwhelming. Therefore, I initially resorted to using an R package built to access the R API, under-the-hood, called fitbitr.</p>
<p>Unfortunately this would limit me to only accessing some basic user information, heart rate and step count data.</p>
<h3>Getting Basic User Info</h3>
<p>The first function in this package sends a GET request to the Get Profile <a rel="nofollow" href="https://dev.fitbit.com/build/reference/web-api/user/#get-profile" target="_blank">resource URL</a>.</p>
<pre># Extracting Resources</pre>
<pre># Get userInfo<br>user_info &lt;- fitbitr::getUserInfo(token)</pre>
<pre># Hailing a Chocobo!</pre>
<pre># What is my stride length in meters?<br>strideLengthWalking &lt;- user_info$strideLengthWalking</pre>
<p>My stride length is 68.5.</p>
<p><em>Stride length is measured from heel to heel and determines how far you walk with each step. On average, a man’s walking stride length is 2.5 feet, or 30 inches, while a woman’s average stride length is 2.2 feet, or 26.4 inches, according to this </em><a rel="nofollow" href="https://livehealthy.chron.com/average-walking-stride-length-7494.html" target="_blank"><em>report</em></a><em>.</em></p>
<pre># Hitting 80 MPH</pre>
<pre># What is my running stride length<br>strideLengthRunning &lt;- user_info$strideLengthRunning</pre>
<p>My running stride length is 105.5.</p>
<p><em>The Fitbit uses your </em><em>sex and </em><em>height by default to gauge your stride length which could potentially be inaccurate.</em></p>
<pre># Looking for the fourth chaos emerald </pre>
<pre># What is my average daily steps?<br>averageDailySteps &lt;- user_info$averageDailySteps</pre>
<p>My average daily steps is 14214.</p>
<p>Considering that the daily recommended steps is 10,000 I’d say that’s acceptable. That being said, there’s always room for improvement.</p>
<h3>Accessing heart rate and footsteps with the fitbitr pacakge</h3>
<p>I’m going to grab a week’s worth of data for a very preliminary EDA.</p>
<pre># Smashing buttons</pre>
<pre>days &lt;- c(&quot;Sunday&quot;, &quot;Monday&quot;, &quot;Tuesday&quot;, &quot;Wednesday&quot;, &quot;Thursday&quot;, &quot;Friday&quot;, &quot;Saturday&quot;)</pre>
<pre>monday_heart &lt;- getTimeSeries(token, type = &quot;heart&quot;, activityDetail = &quot;1min&quot;, date = &quot;2018-08-20&quot;, startTime = &quot;00:00&quot;, endTime = &quot;23:59&quot;)<br>monday_heart %&lt;>% mutate(date = &quot;2018-08-20&quot;)<br>monday_steps &lt;- getTimeSeries(token, type = &quot;steps&quot;, activityDetail = &quot;1min&quot;, date = &quot;2018-08-20&quot;)<br>monday_steps %&lt;>% mutate(date = &quot;2018-08-20&quot;)<br>monday &lt;- monday_heart %>% full_join(monday_steps)<br>monday %&lt;>% mutate(week_date = &quot;Monday&quot;)<br>monday %&lt;>% mutate(day_of_week = &quot;1&quot;)</pre>
<pre>tuesday_heart &lt;- getTimeSeries(token, type = &quot;heart&quot;, activityDetail = &quot;1min&quot;, date = &quot;2018-08-21&quot;)<br>tuesday_heart %&lt;>% mutate(date = &quot;2018-08-21&quot;)<br>tuesday_steps &lt;- getTimeSeries(token, type = &quot;steps&quot;, activityDetail = &quot;1min&quot;, date = &quot;2018-08-21&quot;)<br>tuesday_steps %&lt;>% mutate(date = &quot;2018-08-21&quot;)<br>tuesday &lt;- tuesday_heart %>% full_join(tuesday_steps)<br>tuesday %&lt;>% mutate(week_date = &quot;Tuesday&quot;)<br>tuesday %&lt;>% mutate(day_of_week = &quot;2&quot;)</pre>
<pre>wednesday_heart &lt;- getTimeSeries(token, type = &quot;heart&quot;, activityDetail = &quot;1min&quot;, date = &quot;2018-08-22&quot;)<br>wednesday_heart %&lt;>% mutate(date = &quot;2018-08-22&quot;)<br>wednesday_steps &lt;- getTimeSeries(token, type = &quot;steps&quot;, activityDetail = &quot;1min&quot;, date = &quot;2018-08-22&quot;)<br>wednesday_steps %&lt;>% mutate(date = &quot;2018-08-22&quot;)<br>wednesday &lt;- wednesday_heart %>% full_join(wednesday_steps)<br>wednesday %&lt;>% mutate(week_date = &quot;Wednesday&quot;)<br>wednesday %&lt;>% mutate(day_of_week = &quot;3&quot;)</pre>
<pre>thursday_heart &lt;- getTimeSeries(token, type = &quot;heart&quot;, activityDetail = &quot;1min&quot;, date = &quot;2018-08-23&quot;)<br>thursday_heart %&lt;>% mutate(date = &quot;2018-08-23&quot;)<br>thursday_steps &lt;- getTimeSeries(token, type = &quot;steps&quot;, activityDetail = &quot;1min&quot;, date = &quot;2018-08-23&quot;)<br>thursday_steps %&lt;>% mutate(date = &quot;2018-08-23&quot;)<br>thursday &lt;- thursday_heart %>% full_join(thursday_steps)<br>thursday %&lt;>% mutate(week_date = &quot;Thursday&quot;)<br>thursday %&lt;>% mutate(day_of_week = &quot;4&quot;)</pre>
<pre>friday_heart &lt;- getTimeSeries(token, type = &quot;heart&quot;, activityDetail = &quot;1min&quot;, date = &quot;2018-08-24&quot;)<br>friday_heart %&lt;>% mutate(date = &quot;2018-08-24&quot;)<br>friday_steps &lt;- getTimeSeries(token, type = &quot;steps&quot;, activityDetail = &quot;1min&quot;, date = &quot;2018-08-24&quot;)<br>friday_steps %&lt;>% mutate(date = &quot;2018-08-24&quot;)<br>friday &lt;- friday_heart %>% full_join(friday_steps)<br>friday %&lt;>% mutate(week_date = &quot;Friday&quot;)<br>friday %&lt;>% mutate(day_of_week = &quot;5&quot;)</pre>
<pre>saturday_heart &lt;- getTimeSeries(token, type = &quot;heart&quot;, activityDetail = &quot;1min&quot;, date = &quot;2018-08-24&quot;)<br>saturday_heart %&lt;>% mutate(date = &quot;2018-08-24&quot;)<br>saturday_steps &lt;- getTimeSeries(token, type = &quot;steps&quot;, activityDetail = &quot;1min&quot;, date = &quot;2018-08-24&quot;)<br>saturday_steps %&lt;>% mutate(date = &quot;2018-08-24&quot;)<br>saturday &lt;- saturday_heart %>% full_join(saturday_steps)<br>saturday %&lt;>% mutate(week_date = &quot;Saturday&quot;)<br>saturday %&lt;>% mutate(day_of_week = &quot;6&quot;)</pre>
<pre>week &lt;- monday %>% bind_rows(tuesday) %>% bind_rows(wednesday) %>% bind_rows(thursday) %>% bind_rows(friday) %>% bind_rows(saturday)<br>        <br>week$date &lt;- as.Date(week$date)</pre>
<h3>Summary Statistics</h3>
<pre># Opening pod bay doors</pre>
<pre>week %>% <br>        group_by(type) %>% <br>                summarise(<br>                        total = sum(value),<br>                        minimum = min(value),<br>                        mean = mean(value),<br>                        median = median(value),<br>                        maximum = max(value),<br>                        max_time = max(time)<br>                        ) %>%<br>        knitr::kable(digits = 3) %>% <br>        kable_styling(full_width = F)</pre>
<figure><img alt="" src="https://i0.wp.com/cdn-images-1.medium.com/max/720/1*TFqP9E4gxIHqo9IKlgSERg.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<h3>Exploratory Data Analysis</h3>
<p>Since this is a post about gamification I decided to do something fun with my exploratory data visualizations. I wanted to use the Rokemon package which allows me to set the theme of ggplot2 (and ggplot2 extensions) to Game Boy and Game Boy Advance themes! When convenient, I’ve combined plots with cowplot.</p>
<p>Let’s take a quick look at the relationship and distribution of heart rate and step count.</p>
<pre># Doing the thing...</pre>
<pre>g &lt;- week %>% <br>        spread(type, value) %>% <br>        rename(hear_rate = &quot;heart rate&quot;) %>% <br>        na.omit() %>% <br>        ggplot(aes(steps, hear_rate)) + geom_point() + geom_smooth(method=&quot;lm&quot;, se=F, colour = &quot;#DE7243&quot;) </pre>
<pre>gb &lt;- g + theme_gameboy()<br>gba &lt;- g + theme_gba()</pre>
<pre>plot_grid(gb, gba, labels = c(&quot;&quot;, &quot;&quot;), align = &quot;h&quot;)</pre>
<figure><img alt="" src="https://i1.wp.com/cdn-images-1.medium.com/max/1024/1*tL7RuSmO6g0rBWYmjqiCjw.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<p>Alternatively, we could get a better look at the data by adding marginal density plots to the scatterplots with the ggMarginal() function from the ggExtra package.</p>
<figure><img alt="" src="https://i2.wp.com/cdn-images-1.medium.com/max/1024/1*awEEdUUu0qsU31Cgwb9RSQ.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<h3>Weekly trends</h3>
<p>Let’s take a quick look at the distribution of the contiguous variables to get a better idea than the mean and median.</p>
<pre># Loading..... Wait, what else were you expecting?</pre>
<pre>annotations_steps &lt;- data_frame(<br>        x = c(45, 100, 165),<br>        y = c(0.01, 0.01, 0.01),<br>        label = c('walking pace', 'brisk walking pace', 'running pace'),<br>        type = c('steps', 'steps', 'steps')<br>)</pre>
<pre>g &lt;- week %>% <br>  ggplot(aes(value)) + <br>  geom_density(fill = &quot;#DE7243&quot;) +<br>  geom_text(data = annotations_steps, aes(x = x, y = y, label = label), angle = -30, hjust = 1) +<br>  facet_grid(.~type, scales = 'free_x') + <br>  labs(title = 'Heart Rate and Steps-per-minute over two months',<br>       subtitle = 'Data gathered from Fitbit Charge2')</pre>
<pre>g + theme_gameboy()<br>g + theme_gba()</pre>
<figure><img alt="" src="https://i1.wp.com/cdn-images-1.medium.com/max/1024/1*H2NbPNizSKZqPZSwlCGaWQ.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<figure><img alt="" src="https://i0.wp.com/cdn-images-1.medium.com/max/1024/1*Avm4lYB5WP_Tze6PFwW_5A.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<p>Heart rate is a little right-skewed, probably due to sleep and sedentary work. Similarly, for step count you see that only a small bump under brisk walking pace from when I skateboarded to work.</p>
<h3>Exercise patterns</h3>
<p>This week I didn’t work out so I thought I’d at least look at when I was on my way to work. The figure below shows blue for heart rate/min and orange is the number of steps/min.</p>
<pre># You are carrying too much to be able to run</pre>
<pre>between_six_nine &lt;- function(time) time > 7*60*60 &amp; time &lt; 10*60*60</pre>
<pre>is_weekday &lt;- function(day_of_week) day_of_week %in% 1:6</pre>
<pre>week$week_date_f &lt;- factor(week$week_date, levels=c(&quot;Monday&quot;,&quot;Tuesday&quot;,&quot;Wednesday&quot;, &quot;Thursday&quot;, &quot;Friday&quot;, &quot;Saturday&quot;))</pre>
<pre>g &lt;- week %>% <br>        filter(between_six_nine(time) &amp; is_weekday(day_of_week)) %>% <br>        spread(type, value) %>% <br>        ggplot(aes(x = time)) +<br>        geom_bar(aes(y = steps), color = '#DE7243', alpha = 0.3, stat = 'identity') + <br>        geom_line(aes(y = `heart rate`), color = '#E3F24D', size = 0.8) + <br>        facet_grid(~week_date_f) +<br>        scale_x_continuous(breaks=c(27000, 30000, 33000, 36000), labels=c(&quot;7am&quot;, &quot;8am&quot;, &quot;9am&quot;, &quot;10am&quot;))</pre>
<pre>g + theme_gameboy()<br>g + theme_gba()</pre>
<figure><img alt="" src="https://i2.wp.com/cdn-images-1.medium.com/max/1024/1*D3D8lvHds59v4HbWaKULOA.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<figure><img alt="" src="https://i1.wp.com/cdn-images-1.medium.com/max/1024/1*4xcR0gCR0-SQI5vmxo1hzg.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<p>My activity has been pretty much the same all week since I skateboard to work every morning.</p>
<h3>Most active time</h3>
<pre># 60% of the time, it loads ALL the time</pre>
<pre>step_counts &lt;- week %>% <br>  filter(type == 'steps') %>% <br>  group_by(day_of_week) %>% <br>  summarise(<br>    type = last(type), <br>    avg_num_steps = sprintf('avg num steps: %3.0f', sum(value)/52)<br>  )</pre>
<pre>g &lt;- week %>%<br>        ggplot(aes(x= value, y = fct_rev(factor(day_of_week)))) +<br>        geom_density_ridges(scale = 2.5, fill = &quot;#DE7243&quot;) +<br>        geom_text(data = step_counts, nudge_y = 0.15, hjust = 0, <br>            aes(x = 85, y = fct_rev(factor(day_of_week)), label = avg_num_steps)) +<br>        scale_y_discrete(breaks=1:6, labels = c(&quot;Monday&quot;, &quot;Tuesday&quot;, &quot;Wednesday&quot;, &quot;Thursday&quot;, &quot;Friday&quot;, &quot;Saturday&quot;)) +<br>        facet_grid(.~type, scales = &quot;free&quot;) +<br>        labs(x = '', y = &quot;Day of the Week&quot;) </pre>
<pre>g + theme_gameboy()<br>g + theme_gba()</pre>
<figure><img alt="" src="https://i0.wp.com/cdn-images-1.medium.com/max/1024/1*5Z0waiTSvovqTlZC-9ud5g.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<figure><img alt="" src="https://i1.wp.com/cdn-images-1.medium.com/max/1024/1*rFddnm9WhH2-fWaB2lii5Q.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<p>The distribution of steps per-minute was pretty constant because as I said I didn’t work-out; this likely reflects me shuffling to get tea.</p>
<p>It looks like Monday was the day I got my heart rate up the most, the bimodal peak is probably when I was running around looking for a rental property.</p>
<h3>Accessing the Fitbit API directly with the httr package</h3>
<p>Eventually, I found an excellent <a rel="nofollow" href="https://obrl-soil.github.io/fitbit-api-r/" target="_blank">tutorial</a> by <a rel="nofollow" href="https://github.com/obrl-soil" target="_blank">obrl-soil</a> which introduced me to the httr package and gave me the confidence I needed to peruse the <a rel="nofollow" href="https://dev.fitbit.com/build/reference/web-api/" target="_blank">Fitbit DEV web API reference</a>. Now I was able to gain access to far more sources of data.</p>
<h3>What data is available?</h3>
<p>A brief overview of what data is available from the Fitbit API:</p>
<pre># Your Boko Club is badly damaged</pre>
<pre># make a kable table for data you can access from Fitbit API<br>dt01 &lt;- data.frame(Scope = c(&quot;activity&quot;,<br>                             &quot;heartrate&quot;,<br>                             &quot;location&quot;,<br>                             &quot;nutrition&quot;,<br>                             &quot;profile&quot;,<br>                             &quot;settings&quot;,<br>                             &quot;sleep&quot;,<br>                             &quot;social&quot;,<br>                             &quot;weight&quot;),<br>                   Description = c(&quot;The activity scope includes activity data and exercise log related features, such as steps, distance, calories burned, and active minutes&quot;,<br>                                   &quot;The heartrate scope includes the continuous heart rate data and related analysis&quot;,<br>                                   &quot;The location scope includes the GPS and other location data&quot;,<br>                                   &quot;The nutrition scope includes calorie consumption and nutrition related features, such as food/water logging, goals, and plans&quot;,<br>                                   &quot;The profile scope is the basic user information&quot;,<br>                                   &quot;The settings scope includes user account and device settings, such as alarms&quot;,<br>                                   &quot;The sleep scope includes sleep logs and related sleep analysis&quot;,<br>                                   &quot;The social scope includes friend-related features, such as friend list, invitations, and leaderboard&quot;,<br>                                   &quot;The weight scope includes weight and related information, such as body mass index, body fat percentage, and goals&quot;)<br>)</pre>
<pre>dt01 %>%<br>  kable(&quot;html&quot;) %>%<br>  kable_styling(full_width = F) %>%<br>  column_spec(1, bold = T, border_right = T) %>%<br>  column_spec(2, width = &quot;30em&quot;, background = &quot;#E3F24D&quot;)</pre>
<figure><img alt="" src="https://i0.wp.com/cdn-images-1.medium.com/max/777/1*xj5DbVpOv9ypbHhPocCW9Q.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<p>What are the units of measurement?</p>
<pre># Loading Cutscenes You Can't Skip</pre>
<pre># make a Kable table or measurement information<br>dt03 &lt;- data.frame(unitType = c(&quot;duration&quot;,<br>                                &quot;distance&quot;,<br>                                &quot;elevation&quot;,<br>                                &quot;height&quot;,<br>                                &quot;weight&quot;,<br>                                &quot;body measurements&quot;,<br>                                &quot;liquids&quot;,<br>                                &quot;blood glucose&quot;),<br>                   unit = c(&quot;milliseconds&quot;,<br>                            &quot;kilometers&quot;,<br>                            &quot;meters&quot;,<br>                            &quot;centimeters&quot;,<br>                            &quot;kilograms&quot;,<br>                            &quot;centimeters&quot;,<br>                            &quot;milliliters&quot;,<br>                            &quot;millimoles per liter&quot;))<br>dt03 %>%<br>  kable(&quot;html&quot;) %>%<br>  kable_styling(full_width = F) %>%<br>  column_spec(1, bold = T, border_right = T) %>%<br>  column_spec(2, width = &quot;30em&quot;, background = &quot;#E3F24D&quot;)</pre>
<figure><img alt="" src="https://i0.wp.com/cdn-images-1.medium.com/max/756/1*T3BNmCI84G5ee8NnBXbybQ.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<p>Define a function for turning a json list into a dataframe.</p>
<pre># Inserting last-minute subroutines into program...</pre>
<pre># json-as-list to dataframe (for simple cases without nesting!)<br>jsonlist_to_df &lt;- function(data = NULL) {<br>    purrr::transpose(data) %>%<br>    purrr::map(., unlist) %>%<br>    as_tibble(., stringsAsFactors = FALSE)<br>}</pre>
<h3>Investigating my 10Km run</h3>
<p>GET request to retrieve minute-by-minute heart rate data for my 10km run.</p>
<pre># Preparing for the mini-boss</pre>
<pre>get_workout &lt;- function(date = NULL, start_time = NULL, end_time = NULL, <br>                         token = Sys.getenv('FITB_AUTH')) {<br>GET(url =<br>        paste0('https://api.fitbit.com/1/user/-/activities/heart/date/',<br>        date, '/1d/1min/time/', start_time, '/', end_time, '.json'), <br>        add_headers(Authorization = paste0(&quot;Bearer &quot;, token)))<br>}</pre>
<pre># Get the workout for my 10Km run <br>got_workout &lt;- get_workout(date = '2018-10-21', start_time = '09:29', end_time = '10:24')</pre>
<pre>workout &lt;- content(got_workout)</pre>
<pre># summary</pre>
<pre>workout[['activities-heart']][[1]][['heartRateZones']] &lt;- jsonlist_to_df(workout[['activities-heart']][[1]][['heartRateZones']])</pre>
<pre># the dataset<br>workout[['activities-heart-intraday']][['dataset']] &lt;- jsonlist_to_df(workout[['activities-heart-intraday']][['dataset']])</pre>
<pre># format the time <br>workout$`activities-heart-intraday`$dataset$time &lt;- as.POSIXlt(workout$`activities-heart-intraday`$dataset$time, format = '%H:%M:%S')<br>lubridate::date(workout$`activities-heart-intraday`$dataset$time) &lt;- '2018-10-21'</pre>
<pre># find time zone<br># grep(&quot;Canada&quot;, OlsonNames(), value=TRUE)<br>lubridate::tz(workout$`activities-heart-intraday`$dataset$time) &lt;- 'Canada/Eastern'</pre>
<p>Let’s take a look at the summary for my 10Km run:</p>
<pre># Farming Hell Cows</pre>
<pre>workout$`activities-heart`[[1]]$heartRateZones %>% kable() %>% kable_styling(full_width = F)</pre>
<figure><img alt="" src="https://i1.wp.com/cdn-images-1.medium.com/max/716/1*6K4-HyAJVhifc8w0wqVaKw.png?w=456&ssl=1" data-recalc-dims="1"></figure>
<p><a rel="nofollow" href="https://obrl-soil.github.io/fitbit-api-r/" target="_blank">obrl-soil</a> used the MyZone Efforts Points <a rel="nofollow" href="https://myzone.org/the-zones/" target="_blank">(MEPS)</a> which is calculated minute-by-minute as a percentage of max heart rate. It measures the effort put in – The more points the better. Another example of gamification in action.</p>
<pre># Looting a chest</pre>
<pre>meps_max &lt;- function(age = NULL) { 207 - (0.7 * age) }</pre>
<p>Mine is 186.</p>
<p>Now is we create a tribble with 4 heart ranges showing the lower and higher bounds and use the mutate() function from above to calculate what my max heart rate is (with lower and upper bounds).</p>
<pre># Taking the hobbits to Isengard</pre>
<pre>my_MEPS &lt;- tribble(~MEPS, ~hr_range, ~hr_lo, ~hr_hi, <br>                       1,  '50-59%',   0.50,   0.59,<br>                       2,  '60-69%',   0.60,   0.69,<br>                       3,  '70-79%',   0.70,   0.79,<br>                       4,    '>=80',   0.80,   1.00) %>%<br>  mutate(my_hr_low = floor(meps_max(30) * hr_lo),<br>         my_hr_hi  = ceiling(meps_max(30) * hr_hi))<br>my_MEPS</pre>
<pre>## # A tibble: 4 x 6<br>##    MEPS hr_range hr_lo hr_hi my_hr_low my_hr_hi<br>##   </pre>