Personal blog written from scratch using Node.js, Bootstrap, and MySQL. https://jrtechs.net
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

741 lines
24 KiB

  1. Let's do a deep dive and start visualizing my life using Fitbit and
  2. Matplotlib.
  3. # What is Fitbit
  4. [Fitbit](https://www.fitbit.com) is a fitness watch that tracks your sleep, heart rate, and activity.
  5. Fitbit is able to track your steps, however, it is also able to detect multiple types of activity
  6. like running, walking, "sport" and biking.
  7. # What is Matplotlib
  8. [Matplotlib](https://matplotlib.org/) is a python visualization library that enables you to create bar graphs, line graphs, distributions and many more things.
  9. Being able to visualize your results is essential to any person working with data at any scale.
  10. Although I like [GGplot](https://ggplot2.tidyverse.org/) in R more than Matplotlib, Matplotlib is still my go to graphing library for Python.
  11. # Getting Your Fitbit Data
  12. There are two main ways that you can get your Fitbit data:
  13. - Fitbit API
  14. - Data Archival Export
  15. Since connecting to the API and setting up all the web hooks can be a
  16. pain, I'm just going to use the data export option because this is
  17. only for one person. You can export your data here:
  18. [https://www.fitbit.com/settings/data/export](https://www.fitbit.com/settings/data/export).
  19. ![Data export on fitbit's website](media/vis_my_life/dataExport.png)
  20. The Fitbit data archive was very organized and kept meticulous records
  21. of everything. All of the data was organized in separate JSON files
  22. labeled by date. Fitbit keeps around 1MB of data on you per day; most
  23. of this data is from the heart rate sensors. Although 1MB of data may
  24. sound like a ton of data, it is probably a lot less if you store it in
  25. formats other than JSON. When I downloaded the compressed file it was
  26. 20MB, but when I extracted it, it was 380MB! I've only been using
  27. Fitbit for 11 months at this point.
  28. ![compressed data](media/vis_my_life/compression.png)
  29. ## Sleep
  30. Sleep is something fun to visualize. No matter how much of it you get
  31. you still feel tired as a college student. In the "sleep_score" folder
  32. of the exported data you will find a single CSV file with your resting
  33. heart rate and Fitbit's computed sleep scores. Interesting enough,
  34. this is the only file that comes in the CSV format, everything else is
  35. JSON file.
  36. We can read in all the data using a single liner with the
  37. [Pandas](https://pandas.pydata.org/) python library.
  38. ```python
  39. import matplotlib.pyplot as plt
  40. import pandas as pd
  41. sleep_score_df = pd.read_csv('data/sleep/sleep_score.csv')
  42. ```
  43. ```python
  44. print(sleep_score_df)
  45. ```
  46. sleep_log_entry_id timestamp overall_score \
  47. 0 26093459526 2020-02-27T06:04:30Z 80
  48. 1 26081303207 2020-02-26T06:13:30Z 83
  49. 2 26062481322 2020-02-25T06:00:30Z 82
  50. 3 26045941555 2020-02-24T05:49:30Z 79
  51. 4 26034268762 2020-02-23T08:35:30Z 75
  52. .. ... ... ...
  53. 176 23696231032 2019-09-02T07:38:30Z 79
  54. 177 23684345925 2019-09-01T07:15:30Z 84
  55. 178 23673204871 2019-08-31T07:11:00Z 74
  56. 179 23661278483 2019-08-30T06:34:00Z 73
  57. 180 23646265400 2019-08-29T05:55:00Z 80
  58. composition_score revitalization_score duration_score \
  59. 0 20 19 41
  60. 1 22 21 40
  61. 2 22 21 39
  62. 3 17 20 42
  63. 4 20 16 39
  64. .. ... ... ...
  65. 176 20 20 39
  66. 177 22 21 41
  67. 178 18 21 35
  68. 179 17 19 37
  69. 180 21 21 38
  70. deep_sleep_in_minutes resting_heart_rate restlessness
  71. 0 65 60 0.117330
  72. 1 85 60 0.113188
  73. 2 95 60 0.120635
  74. 3 52 61 0.111224
  75. 4 43 59 0.154774
  76. .. ... ... ...
  77. 176 88 56 0.170923
  78. 177 95 56 0.133268
  79. 178 73 56 0.102703
  80. 179 50 55 0.121086
  81. 180 61 57 0.112961
  82. [181 rows x 9 columns]
  83. With the Pandas library you can generate Matplotlib graphs. Although
  84. you can directly use Matplotlib, the wrapper functions using Pandas
  85. makes it easier to use.
  86. ## Sleep Score Histogram
  87. ```python
  88. sleep_score_df.hist(column='overall_score')
  89. ```
  90. array([[<matplotlib.axes._subplots.AxesSubplot object at 0x7fc2c0a270d0>]],
  91. dtype=object)
  92. ![png](media/vis_my_life/output_7_1.png)
  93. ## Heart Rate
  94. Fitbit keeps their calculated heart rates in the sleep scores file
  95. rather than heart. Knowing your resting heart rate is useful because
  96. it is a good indicator of your overall health.
  97. ![](media/vis_my_life/restingHeartRate.jpg)
  98. ```python
  99. sleep_score_df.hist(column='resting_heart_rate')
  100. ```
  101. array([[<matplotlib.axes._subplots.AxesSubplot object at 0x7fc2917a6090>]],
  102. dtype=object)
  103. ![png](media/vis_my_life/output_9_1.png)
  104. ## Resting Heart Rate Time Graph
  105. Using the pandas wrapper we can quickly create a heart rate graph over
  106. time.
  107. ```python
  108. sleep_score_df.plot(kind='line', y='resting_heart_rate', x ='timestamp', legend=False, title="Resting Heart Rate(BPM)")
  109. ```
  110. <matplotlib.axes._subplots.AxesSubplot at 0x7fc28f609b50>
  111. ![png](media/vis_my_life/output_11_1.png)
  112. However, as we notice with the graph above, the time axis is wack. In
  113. the pandas data frame everything was stored as a string timestamp. We
  114. can convert this into a datetime object by telling pandas to parse the
  115. date as it reads it.
  116. ```python
  117. sleep_score_df = pd.read_csv('data/sleep/sleep_score.csv', parse_dates=[1])
  118. sleep_score_df.plot(kind='line', y='resting_heart_rate', x ='timestamp', legend=False, title="Resting Heart Rate(BPM)")
  119. ```
  120. <matplotlib.axes._subplots.AxesSubplot at 0x7fc28f533510>
  121. ![png](media/vis_my_life/output_13_1.png)
  122. To fully manipulate the graphs, we need to use some matplotlib code to
  123. do things like setting the axis labels or make multiple plots right
  124. next to each other. We can create grab the current axis being used by
  125. matplotlib by using plt.gca().
  126. ```python
  127. ax = plt.gca()
  128. sleep_score_df.plot(kind='line', y='resting_heart_rate', x ='timestamp', legend=False, title="Resting Heart Rate Graph", ax=ax, figsize=(10, 5))
  129. plt.xlabel("Date")
  130. plt.ylabel("Resting Heart Rate (BPM)")
  131. plt.show()
  132. #plt.savefig('restingHeartRate.svg')
  133. ```
  134. ![png](media/vis_my_life/output_15_0.png)
  135. The same thing can be done with sleep scores. It is interesting to
  136. note that the sleep scores rarely vary anything between 75 and 85.
  137. ```python
  138. ax = plt.gca()
  139. sleep_score_df.plot(kind='line', y='overall_score', x ='timestamp', legend=False, title="Sleep Score Time Series Graph", ax=ax)
  140. plt.xlabel("Date")
  141. plt.ylabel("Fitbit's Sleep Score")
  142. plt.show()
  143. ```
  144. ![png](media/vis_my_life/output_17_0.png)
  145. Using Pandas we can generate a new column with a specific date
  146. attribute like year, day, month, or weekday. If we add a new column
  147. for weekday, we can then group by weekday and collapse them all into a
  148. single column by summing or averaging the value.
  149. ```python
  150. temp = pd.DatetimeIndex(sleep_score_df['timestamp'])
  151. sleep_score_df['weekday'] = temp.weekday
  152. print(sleep_score_df)
  153. ```
  154. sleep_log_entry_id timestamp overall_score \
  155. 0 26093459526 2020-02-27 06:04:30+00:00 80
  156. 1 26081303207 2020-02-26 06:13:30+00:00 83
  157. 2 26062481322 2020-02-25 06:00:30+00:00 82
  158. 3 26045941555 2020-02-24 05:49:30+00:00 79
  159. 4 26034268762 2020-02-23 08:35:30+00:00 75
  160. .. ... ... ...
  161. 176 23696231032 2019-09-02 07:38:30+00:00 79
  162. 177 23684345925 2019-09-01 07:15:30+00:00 84
  163. 178 23673204871 2019-08-31 07:11:00+00:00 74
  164. 179 23661278483 2019-08-30 06:34:00+00:00 73
  165. 180 23646265400 2019-08-29 05:55:00+00:00 80
  166. composition_score revitalization_score duration_score \
  167. 0 20 19 41
  168. 1 22 21 40
  169. 2 22 21 39
  170. 3 17 20 42
  171. 4 20 16 39
  172. .. ... ... ...
  173. 176 20 20 39
  174. 177 22 21 41
  175. 178 18 21 35
  176. 179 17 19 37
  177. 180 21 21 38
  178. deep_sleep_in_minutes resting_heart_rate restlessness weekday
  179. 0 65 60 0.117330 3
  180. 1 85 60 0.113188 2
  181. 2 95 60 0.120635 1
  182. 3 52 61 0.111224 0
  183. 4 43 59 0.154774 6
  184. .. ... ... ... ...
  185. 176 88 56 0.170923 0
  186. 177 95 56 0.133268 6
  187. 178 73 56 0.102703 5
  188. 179 50 55 0.121086 4
  189. 180 61 57 0.112961 3
  190. [181 rows x 10 columns]
  191. ```python
  192. print(sleep_score_df.groupby('weekday').mean())
  193. ```
  194. sleep_log_entry_id overall_score composition_score \
  195. weekday
  196. 0 2.483733e+10 79.576923 20.269231
  197. 1 2.485200e+10 77.423077 20.423077
  198. 2 2.490383e+10 80.880000 21.120000
  199. 3 2.483418e+10 76.814815 20.370370
  200. 4 2.480085e+10 79.769231 20.961538
  201. 5 2.477002e+10 78.840000 20.520000
  202. 6 2.482581e+10 77.230769 20.269231
  203. revitalization_score duration_score deep_sleep_in_minutes \
  204. weekday
  205. 0 19.153846 40.153846 88.000000
  206. 1 19.000000 38.000000 83.846154
  207. 2 19.400000 40.360000 93.760000
  208. 3 19.037037 37.407407 82.592593
  209. 4 19.346154 39.461538 94.461538
  210. 5 19.080000 39.240000 93.720000
  211. 6 18.269231 38.692308 89.423077
  212. resting_heart_rate restlessness
  213. weekday
  214. 0 58.576923 0.139440
  215. 1 58.538462 0.142984
  216. 2 58.560000 0.138661
  217. 3 58.333333 0.135819
  218. 4 58.269231 0.129791
  219. 5 58.080000 0.138315
  220. 6 58.153846 0.147171
  221. ## Sleep Score Based on Day
  222. ```python
  223. ax = plt.gca()
  224. sleep_score_df.groupby('weekday').mean().plot(kind='line', y='overall_score', ax = ax)
  225. plt.ylabel("Sleep Score")
  226. plt.title("Sleep Scores on Varying Days of Week")
  227. plt.show()
  228. ```
  229. ![png](media/vis_my_life/output_22_0.png)
  230. ## Sleep Score Based on Days of Week
  231. ```python
  232. ax = plt.gca()
  233. sleep_score_df.groupby('weekday').mean().plot(kind='line', y='resting_heart_rate', ax = ax)
  234. plt.ylabel("Resting heart rate (BPM)")
  235. plt.title("Resting Heart Rate Varying Days of Week")
  236. plt.show()
  237. ```
  238. ![png](media/vis_my_life/output_24_0.png)
  239. # Calories
  240. Fitbit keeps all of their calorie data in JSON files representing
  241. sequence data at 1 minute increments. To extrapolate calorie data we
  242. need to group by day and then sum the days to get the total calories
  243. burned per day.
  244. ```python
  245. calories_df = pd.read_json("data/calories/calories-2019-07-01.json", convert_dates=True)
  246. ```
  247. ```python
  248. print(calories_df)
  249. ```
  250. dateTime value
  251. 0 2019-07-01 00:00:00 1.07
  252. 1 2019-07-01 00:01:00 1.07
  253. 2 2019-07-01 00:02:00 1.07
  254. 3 2019-07-01 00:03:00 1.07
  255. 4 2019-07-01 00:04:00 1.07
  256. ... ... ...
  257. 43195 2019-07-30 23:55:00 1.07
  258. 43196 2019-07-30 23:56:00 1.07
  259. 43197 2019-07-30 23:57:00 1.07
  260. 43198 2019-07-30 23:58:00 1.07
  261. 43199 2019-07-30 23:59:00 1.07
  262. [43200 rows x 2 columns]
  263. ```python
  264. import datetime
  265. calories_df['date_minus_time'] = calories_df["dateTime"].apply( lambda calories_df :
  266. datetime.datetime(year=calories_df.year, month=calories_df.month, day=calories_df.day))
  267. calories_df.set_index(calories_df["date_minus_time"],inplace=True)
  268. print(calories_df)
  269. ```
  270. dateTime value date_minus_time
  271. date_minus_time
  272. 2019-07-01 2019-07-01 00:00:00 1.07 2019-07-01
  273. 2019-07-01 2019-07-01 00:01:00 1.07 2019-07-01
  274. 2019-07-01 2019-07-01 00:02:00 1.07 2019-07-01
  275. 2019-07-01 2019-07-01 00:03:00 1.07 2019-07-01
  276. 2019-07-01 2019-07-01 00:04:00 1.07 2019-07-01
  277. ... ... ... ...
  278. 2019-07-30 2019-07-30 23:55:00 1.07 2019-07-30
  279. 2019-07-30 2019-07-30 23:56:00 1.07 2019-07-30
  280. 2019-07-30 2019-07-30 23:57:00 1.07 2019-07-30
  281. 2019-07-30 2019-07-30 23:58:00 1.07 2019-07-30
  282. 2019-07-30 2019-07-30 23:59:00 1.07 2019-07-30
  283. [43200 rows x 3 columns]
  284. ```python
  285. calories_per_day = calories_df.resample('D').sum()
  286. print(calories_per_day)
  287. ```
  288. value
  289. date_minus_time
  290. 2019-07-01 3422.68
  291. 2019-07-02 2705.85
  292. 2019-07-03 2871.73
  293. 2019-07-04 4089.93
  294. 2019-07-05 3917.91
  295. 2019-07-06 2762.55
  296. 2019-07-07 2929.58
  297. 2019-07-08 2698.99
  298. 2019-07-09 2833.27
  299. 2019-07-10 2529.21
  300. 2019-07-11 2634.25
  301. 2019-07-12 2953.91
  302. 2019-07-13 4247.45
  303. 2019-07-14 2998.35
  304. 2019-07-15 2846.18
  305. 2019-07-16 3084.39
  306. 2019-07-17 2331.06
  307. 2019-07-18 2849.20
  308. 2019-07-19 2071.63
  309. 2019-07-20 2746.25
  310. 2019-07-21 2562.11
  311. 2019-07-22 1892.99
  312. 2019-07-23 2372.89
  313. 2019-07-24 2320.42
  314. 2019-07-25 2140.87
  315. 2019-07-26 2430.38
  316. 2019-07-27 3769.04
  317. 2019-07-28 2036.24
  318. 2019-07-29 2814.87
  319. 2019-07-30 2077.82
  320. ```python
  321. ax = plt.gca()
  322. calories_per_day.plot(kind='hist', title="Calorie Distribution", legend=False, ax=ax)
  323. plt.show()
  324. ```
  325. ![png](media/vis_my_life/output_30_0.png)
  326. ```python
  327. ax = plt.gca()
  328. calories_per_day.plot(kind='line', y='value', legend=False, title="Calories Per Day", ax=ax)
  329. plt.xlabel("Date")
  330. plt.ylabel("Calories")
  331. plt.show()
  332. ```
  333. ![png](media/vis_my_life/output_31_0.png)
  334. ## Calories Per Day Box Plot
  335. Using this data we can turn this into a boxplot to make it easier to
  336. visualize the distribution of calories burned during the month of
  337. July.
  338. ```python
  339. ax = plt.gca()
  340. ax.set_title('Calorie Distribution for July')
  341. ax.boxplot(calories_per_day['value'], vert=False,manage_ticks=False, notch=True)
  342. plt.xlabel("Calories Burned")
  343. ax.set_yticks([])
  344. plt.show()
  345. ```
  346. ![png](media/vis_my_life/output_33_0.png)
  347. # Steps
  348. Fitbit is known for taking the amount of steps someone takes per day.
  349. Similar to calories burned, steps taken is stored in time series data
  350. at 1 minute increments. Since we are interested at the day level data,
  351. we need to first remove the time component of the dataframe so that we
  352. can group all the data by date. Once we have everything grouped by
  353. date, we can sum and produce steps per day.
  354. ```python
  355. steps_df = pd.read_json("data/steps-2019-07-01.json", convert_dates=True)
  356. steps_df['date_minus_time'] = steps_df["dateTime"].apply( lambda steps_df :
  357. datetime.datetime(year=steps_df.year, month=steps_df.month, day=steps_df.day))
  358. steps_df.set_index(steps_df["date_minus_time"],inplace=True)
  359. print(steps_df)
  360. ```
  361. dateTime value date_minus_time
  362. date_minus_time
  363. 2019-07-01 2019-07-01 04:00:00 0 2019-07-01
  364. 2019-07-01 2019-07-01 04:01:00 0 2019-07-01
  365. 2019-07-01 2019-07-01 04:02:00 0 2019-07-01
  366. 2019-07-01 2019-07-01 04:03:00 0 2019-07-01
  367. 2019-07-01 2019-07-01 04:04:00 0 2019-07-01
  368. ... ... ... ...
  369. 2019-07-31 2019-07-31 03:55:00 0 2019-07-31
  370. 2019-07-31 2019-07-31 03:56:00 0 2019-07-31
  371. 2019-07-31 2019-07-31 03:57:00 0 2019-07-31
  372. 2019-07-31 2019-07-31 03:58:00 0 2019-07-31
  373. 2019-07-31 2019-07-31 03:59:00 0 2019-07-31
  374. [41116 rows x 3 columns]
  375. ```python
  376. steps_per_day = steps_df.resample('D').sum()
  377. print(steps_per_day)
  378. ```
  379. value
  380. date_minus_time
  381. 2019-07-01 11285
  382. 2019-07-02 4957
  383. 2019-07-03 13119
  384. 2019-07-04 16034
  385. 2019-07-05 11634
  386. 2019-07-06 6860
  387. 2019-07-07 3758
  388. 2019-07-08 9130
  389. 2019-07-09 10960
  390. 2019-07-10 7012
  391. 2019-07-11 5420
  392. 2019-07-12 4051
  393. 2019-07-13 15980
  394. 2019-07-14 23109
  395. 2019-07-15 11247
  396. 2019-07-16 10170
  397. 2019-07-17 4905
  398. 2019-07-18 10769
  399. 2019-07-19 4504
  400. 2019-07-20 5032
  401. 2019-07-21 8953
  402. 2019-07-22 2200
  403. 2019-07-23 9392
  404. 2019-07-24 5666
  405. 2019-07-25 5016
  406. 2019-07-26 5879
  407. 2019-07-27 19492
  408. 2019-07-28 4987
  409. 2019-07-29 9943
  410. 2019-07-30 3897
  411. 2019-07-31 166
  412. ## Steps Per Day Histogram
  413. After the data is in the form that we want, graphing the data is
  414. straight forward. Two added things I like to do for normal box plots
  415. is to set the displays to horizontal add the notches.
  416. ```python
  417. ax = plt.gca()
  418. ax.set_title('Steps Distribution for July')
  419. ax.boxplot(steps_per_day['value'], vert=False,manage_ticks=False, notch=True)
  420. plt.xlabel("Steps Per Day")
  421. ax.set_yticks([])
  422. plt.show()
  423. ```
  424. ![png](media/vis_my_life/output_38_0.png)
  425. Wrapping that all into a single function we get something like this:
  426. ```python
  427. def readFileIntoDataFrame(fName):
  428. steps_df = pd.read_json(fName, convert_dates=True)
  429. steps_df['date_minus_time'] = steps_df["dateTime"].apply( lambda steps_df :
  430. datetime.datetime(year=steps_df.year, month=steps_df.month, day=steps_df.day))
  431. steps_df.set_index(steps_df["date_minus_time"],inplace=True)
  432. return steps_df.resample('D').sum()
  433. def graphBoxAndWhiskers(data, title, xlab):
  434. ax = plt.gca()
  435. ax.set_title(title)
  436. ax.boxplot(data['value'], vert=False, manage_ticks=False, notch=True)
  437. plt.xlabel(xlab)
  438. ax.set_yticks([])
  439. plt.show()
  440. ```
  441. ```python
  442. graphBoxAndWhiskers(readFileIntoDataFrame("data/steps-2020-01-27.json"), "Steps In January", "Steps Per Day")
  443. ```
  444. ![png](media/vis_my_life/output_41_0.png)
  445. That is cool, but, what if we could view the distribution for each
  446. month in the same graph? Based on the two previous graphs, my step
  447. distribution during July looked distinctly different from my step
  448. distribution in January. The first difficultly would be to read in
  449. all the files since Fitbit creates a new file for every month. The
  450. next thing would be to group them by month and then graph it.
  451. ```python
  452. import os
  453. files = os.listdir("data")
  454. print(files)
  455. ```
  456. ['steps-2019-04-02.json', 'steps-2019-08-30.json', 'steps-2020-02-26.json', 'steps-2019-10-29.json', 'steps-2019-07-01.json', 'steps-2020-01-27.json', 'steps-2019-07-31.json', 'steps-2019-06-01.json', 'steps-2019-09-29.json', '.ipynb_checkpoints', 'steps-2019-12-28.json', 'steps-2019-05-02.json', 'calories', 'steps-2019-11-28.json', 'sleep']
  457. ```python
  458. dfs = []
  459. for file in files: # this can take 15 seconds
  460. if "steps" in file: # finds the steps files
  461. dfs.append(readFileIntoDataFrame("data/" + file))
  462. ```
  463. ```python
  464. stepsPerDay = pd.concat(dfs)
  465. graphBoxAndWhiskers(stepsPerDay, "Steps Per Day Last 11 Months", "Steps per Day")
  466. ```
  467. ![png](media/vis_my_life/output_45_0.png)
  468. ```python
  469. print(type(stepsPerDay['value'].to_numpy()))
  470. print(stepsPerDay['value'].keys())
  471. stepsPerDay['month'] = pd.DatetimeIndex(stepsPerDay['value'].keys()).month
  472. stepsPerDay['week_day'] = pd.DatetimeIndex(stepsPerDay['value'].keys()).weekday
  473. print(stepsPerDay)
  474. ```
  475. <class 'numpy.ndarray'>
  476. DatetimeIndex(['2019-04-03', '2019-04-04', '2019-04-05', '2019-04-06',
  477. '2019-04-07', '2019-04-08', '2019-04-09', '2019-04-10',
  478. '2019-04-11', '2019-04-12',
  479. ...
  480. '2019-12-19', '2019-12-20', '2019-12-21', '2019-12-22',
  481. '2019-12-23', '2019-12-24', '2019-12-25', '2019-12-26',
  482. '2019-12-27', '2019-12-28'],
  483. dtype='datetime64[ns]', name='date_minus_time', length=342, freq=None)
  484. value month week_day
  485. date_minus_time
  486. 2019-04-03 510 4 2
  487. 2019-04-04 11453 4 3
  488. 2019-04-05 12684 4 4
  489. 2019-04-06 12910 4 5
  490. 2019-04-07 3368 4 6
  491. ... ... ... ...
  492. 2019-12-24 5779 12 1
  493. 2019-12-25 4264 12 2
  494. 2019-12-26 4843 12 3
  495. 2019-12-27 9609 12 4
  496. 2019-12-28 2218 12 5
  497. [342 rows x 3 columns]
  498. ## Graphing Steps by Month
  499. Now that we have columns for the total amount of steps per day and the
  500. months, we can plot all the data on a single plot using the group by
  501. operator in the plotting library.
  502. ```python
  503. ax = plt.gca()
  504. ax.set_title('Steps Distribution for July\n')
  505. stepsPerDay.boxplot(column=['value'], by='month',ax=ax, notch=True)
  506. plt.xlabel("Month")
  507. plt.ylabel("Steps Per Day")
  508. plt.show()
  509. ```
  510. ![png](media/vis_my_life/output_48_0.png)
  511. ```python
  512. ax = plt.gca()
  513. ax.set_title('Steps Distribution By Week Day\n')
  514. stepsPerDay.boxplot(column=['value'], by='week_day',ax=ax, notch=True)
  515. plt.xlabel("Week Day")
  516. plt.ylabel("Steps Per Day")
  517. plt.show()
  518. ```
  519. ![png](media/vis_my_life/output_49_0.png)
  520. ## Future Work
  521. Moving forward with this I would like to do more visualizations with
  522. sleep data and heart rate.