{ "nbformat": 4, "nbformat_minor": 5, "metadata": { "colab": { "provenance": [] }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" } }, "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Chapter 1 - Daily Heart Rate Distribution\n", "\n", "This notebook runs in demo mode by default, using generated minute-level heart-rate data. Replace the demo data cell with a Garmin export or API pull when working with your own data." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "\n", "np.random.seed(7)\n", "minutes = pd.date_range(\"2026-01-01\", periods=24 * 60 * 14, freq=\"min\")\n", "hour = minutes.hour.to_numpy()\n", "\n", "base = 58 + 5 * np.sin(2 * np.pi * (hour - 6) / 24)\n", "movement = np.where((hour >= 8) & (hour <= 20), np.random.gamma(1.8, 4.0, len(minutes)), 0)\n", "training = np.zeros(len(minutes))\n", "for day in range(14):\n", " start = day * 24 * 60 + 17 * 60\n", " duration = 35 + (day % 4) * 10\n", " training[start:start + duration] = np.linspace(35, 80, duration)\n", "heart_rate = np.clip(base + movement + training + np.random.normal(0, 3, len(minutes)), 42, 185)\n", "\n", "hr = pd.DataFrame({\"timestamp\": minutes, \"heart_rate\": heart_rate.round(0).astype(int)})\n", "hr.head()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "bins = [0, 60, 70, 80, 90, 100, 120, 140, 160, 220]\n", "labels = [\"<60\", \"60-69\", \"70-79\", \"80-89\", \"90-99\", \"100-119\", \"120-139\", \"140-159\", \"160+\"]\n", "hr[\"zone\"] = pd.cut(hr[\"heart_rate\"], bins=bins, labels=labels, right=False)\n", "distribution = (\n", " hr.groupby(\"zone\", observed=False)\n", " .size()\n", " .rename(\"minutes\")\n", " .reset_index()\n", ")\n", "distribution[\"hours\"] = (distribution[\"minutes\"] / 60).round(1)\n", "distribution[\"percent\"] = (distribution[\"minutes\"] / distribution[\"minutes\"].sum() * 100).round(1)\n", "distribution" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import plotly.express as px\n", "\n", "fig = px.bar(distribution, x=\"zone\", y=\"hours\", title=\"Daily Life Heart-Rate Distribution\")\n", "fig.update_layout(xaxis_title=\"Heart-rate band (bpm)\", yaxis_title=\"Hours across sample\")\n", "fig.show()\n", "print(\"Notebook completed.\")" ] } ] }