2025-09-23 15:53:15 +01:00
{
"cells": [
{
"cell_type": "code",
2025-09-26 16:37:46 +01:00
"execution_count": 2,
2025-09-23 15:53:15 +01:00
"id": "63f43af5",
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import seaborn as sns\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np"
]
},
{
"cell_type": "code",
2025-09-26 16:37:46 +01:00
"execution_count": 3,
2025-09-23 15:53:15 +01:00
"id": "b0ee2af1",
"metadata": {},
"outputs": [
2025-09-23 19:20:36 +01:00
{
"name": "stdout",
"output_type": "stream",
"text": [
"Smoothed columns created:\n",
2025-09-23 20:36:24 +01:00
"['VO2(ml/min)_smoothed', 'VCO2(ml/min)_smoothed', 'HR(bpm)_smoothed', 'VT(l)_smoothed', 'BF(bpm)_smoothed', 'VE(l/min)_smoothed', 'VO2 Pulse_smoothed', 'VO2 Breath_smoothed', 'CHO_smoothed', 'FAT_smoothed']\n"
2025-09-23 19:20:36 +01:00
]
},
2025-09-23 17:14:36 +01:00
{
"name": "stderr",
"output_type": "stream",
"text": [
2025-09-26 16:37:46 +01:00
"/tmp/ipykernel_393367/3054964805.py:3: FutureWarning: errors='ignore' is deprecated and will raise in a future version. Use to_numeric without passing `errors` and catch exceptions explicitly instead\n",
2025-09-23 17:14:36 +01:00
" df = df.apply(pd.to_numeric, errors='ignore')\n"
]
2025-09-23 15:53:15 +01:00
}
],
"source": [
"df = pd.read_csv('data/Pnoe_20250729_1550-Moran_Keirstyn.csv', delimiter=';')\n",
2025-09-23 17:14:36 +01:00
"# Convert all columns to numeric where possible, coercing errors to NaN\n",
"df = df.apply(pd.to_numeric, errors='ignore')\n",
2025-09-23 18:47:10 +01:00
"df['VO2 Pulse'] = df['VO2(ml/min)'] / df['HR(bpm)'] # VO2 Pulse in mL/beat\n",
"df['VO2 Breath'] = df['VO2(ml/min)'] / df['BF(bpm)'] # VO2 per Breath in mL/breath\n",
2025-09-23 20:36:24 +01:00
"df['CHO'] = df['EE(kcal/min)'] * df['CARBS(%)']/100\n",
"df['FAT'] = df['EE(kcal/min)'] * df['FAT(%)']/100\n",
2025-09-23 19:20:36 +01:00
"# Smooth key columns using rolling window\n",
"window_size = 10\n",
"\n",
"# List of columns to smooth\n",
2025-09-23 20:36:24 +01:00
"columns_to_smooth = ['VO2(ml/min)', 'VCO2(ml/min)', 'HR(bpm)', 'VT(l)', 'BF(bpm)', 'VE(l/min)', 'VO2 Pulse', 'VO2 Breath', 'CHO', 'FAT']\n",
2025-09-23 19:20:36 +01:00
"\n",
"# Apply smoothing to each column\n",
"for col in columns_to_smooth:\n",
" if col in df.columns:\n",
" df[f'{col}_smoothed'] = df[col].rolling(window=window_size).mean()\n",
"\n",
"print(\"Smoothed columns created:\")\n",
"print([col for col in df.columns if '_smoothed' in col])"
2025-09-23 15:53:15 +01:00
]
},
{
"cell_type": "code",
2025-09-26 16:37:46 +01:00
"execution_count": 4,
2025-09-23 18:47:10 +01:00
"id": "fbd292c3",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
2025-09-24 08:35:29 +01:00
"22.369999999999997\n"
2025-09-23 18:47:10 +01:00
]
}
],
"source": [
"print(df['VO2 Pulse'].max())"
]
},
{
"cell_type": "code",
2025-09-26 16:37:46 +01:00
"execution_count": 5,
2025-09-23 15:53:15 +01:00
"id": "ef8bc7ac",
"metadata": {},
"outputs": [
{
"data": {
2025-09-23 20:36:24 +01:00
"image/png": "iVBORw0KGgoAAAANSUhEUgAABeAAAAHWCAYAAAAfLimnAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQAA01xJREFUeJzs3Xd0VOXWwOHfmZ5k0nuFhN577yqCggoqKFjAwvW79sa1XK9iRez12hUVsYBSrigIKEjvvSchvfdMymTK+f4YCERakCSThP2slbXIzCl7JoczZ/bZ734VVVVVhBBCCCGEEEIIIYQQQghRpzTuDkAIIYQQQgghhBBCCCGEaI4kAS+EEEIIIYQQQgghhBBC1ANJwAshhBBCCCGEEEIIIYQQ9UAS8EIIIYQQQgghhBBCCCFEPZAEvBBCCCGEEEIIIYQQQghRDyQBL4QQQgghhBBCCCGEEELUA0nACyGEEEIIIYQQQgghhBD1QBLwQgghhBBCCCGEEEIIIUQ9kAS8EEIIIYQQQgghhBBCCFEPJAEvhBBCCCFEE6MoCjNmzHB3GEIIIYQQQohzkAS8EEIIIYQQfzF79mwURan+0el0REZGMnXqVNLT090dXr1Yv349M2bMoKioyN2hCCGEEEII0Wzo3B2AEEIIIYQQjdVzzz1HbGwslZWVbNy4kdmzZ7N27Vr27t2LyWRyW1wVFRXodHV7Kb9+/XqeffZZpk6dip+fX51uWwghhBBCiIuVJOCFEEIIIYQ4gyuuuILevXsDcOeddxIUFMSsWbNYvHgxEydOdFtctUn+l5WV4eXl1QDRnJmqqlRWVuLh4eHWOIQQQgghhHAXaUEjhBBCCCFELQ0ZMgSAhISE6scOHjzI9ddfT0BAACaTid69e7N48eIa69lsNp599lnatGmDyWQiMDCQwYMHs3z58uplpk6ditlsJjExkVGjRuHl5UVERATPPfccqqrW2N5fe8DPmDEDRVHYv38/kydPxt/fn8GDBwOwe/dupk6dSlxcHCaTibCwMG6//Xby8/NrrD99+nQAYmNjq1vvJCUlAWC323n++edp1aoVRqORli1b8uSTT2K1WmvE1bJlS8aOHcuyZcvo3bs3Hh4efPTRRwwbNoxu3bqd9j1t164do0aNqs3bL4QQQgghRJMjFfBCCCGEEELU0vGEtL+/PwD79u1j0KBBREZG8vjjj+Pl5cUPP/zAuHHj+PHHHxk/fjzgSnDPnDmTO++8k759+1JSUsLWrVvZvn07I0eOrN6+w+Fg9OjR9O/fn1deeYWlS5fyzDPPYLfbee65584Z34QJE2jTpg0vvfRSddJ++fLlJCYmcttttxEWFsa+ffv4+OOP2bdvHxs3bkRRFK699loOHz7Mt99+y5tvvklQUBAAwcHBgKv6/8svv+T666/nkUceYdOmTcycOZMDBw6wYMGCGjEcOnSISZMmcddddzFt2jTatWuH2Wxm2rRp7N27l86dO1cvu2XLFg4fPsxTTz31N/8iQgghhBBCNG6SgBdCCCGEEOIMiouLycvLo7Kykk2bNvHss89iNBoZO3YsAA888AAxMTFs2bIFo9EIwN13383gwYN57LHHqhPwS5Ys4corr+Tjjz8+6/4qKysZPXo077zzTvW2rrrqKmbNmsX9999fnRg/k27dujF37twaj91999088sgjNR7r378/kyZNYu3atQwZMoSuXbvSs2dPvv32W8aNG0fLli2rl921axdffvkld955J5988kn1NkNCQnjttdf4448/GDFiRPXy8fHxLF26tEZVe48ePbjvvvuYM2cOL7/8cvXjc+bMwcvLi2uvvfasr0sIIYQQQoimSlrQCCGEEEIIcQaXXXYZwcHBREdHc/311+Pl5cXixYuJioqioKCA33//nYkTJ1JaWkpeXh55eXnk5+czatQojhw5Qnp6OgB+fn7s27ePI0eOnHOf9957b/W/FUXh3nvvpaqqihUrVpxz3f/7v/875bGT+69XVlaSl5dH//79Adi+ffs5t/nLL78A8PDDD9d4/HhSf8mSJTUej42NPaWljK+vL9dccw3ffvttdWW+w+Hg+++/Z9y4cW7vVS+EEEIIIUR9kQS8EEIIIYQQZ/D++++zfPly5s+fz5VXXkleXl51pXt8fDyqqvKf//yH4ODgGj/PPPMMADk5OQA899xzFBUV0bZtW7p06cL06dPZvXv3KfvTaDTExcXVeKxt27bAifY3ZxMbG3vKYwUFBTzwwAOEhobi4eFBcHBw9XLFxcXn3GZycjIajYbWrVvXeDwsLAw/Pz+Sk5PPGQPArbfeSkpKCmvWrAFgxYoVZGdnc8stt5wzBiGEEEIIIZoqaUEjhBBCCCHEGfTt25fevXsDMG7cOAYPHszkyZM5dOgQTqcTgEcfffSMk4geT1oPHTqUhIQEFi1axG+//cann37Km2++yYcffsidd95ZZ/GeXO1+3MSJE1m/fj3Tp0+ne/fumM1mnE4no0ePrn4NtaEoyt+OAWDUqFGEhoYyZ84chg4dypw5cwgLC+Oyyy6rdQxCCCGEEEI0NZKAF0IIIYQQoha0Wi0zZ85kxIgRvPfee9x+++0A6PX6WiWRAwICuO2227jtttuwWCwMHTqUGTNm1EjAO51OEhMTq6veAQ4fPgxQoy97bRUWFrJy5UqeffZZnn766erHT9cK50wJ9hYtWuB0Ojly5AgdOnSofjw7O5uioiJatGhRq1i0Wi2TJ09m9uzZzJo1i4ULFzJt2jS0Wu15viohhBBCCCGaDmlBI4QQQgghRC0NHz6cvn378tZbb+Hj48Pw4cP56KOPyMzMPGXZ3Nzc6n/n5+fXeM5sNtO6dWusVusp67333nvV/1ZVlffeew+9Xs+ll1563vEeT24f77t+3FtvvXXKssf7sBcVFdV4/MorrzztOm+88QYAY8aMqXU8t9xyC4WFhdx1111YLBZuvvnmWq8rhBBCCCFEUyQV8EIIIYQQQpyH6dOnM2HCBGbPns3777/P4MGD6dKlC9OmTSMuLo7s7Gw2bNhAWloau3btAqBjx44MHz6cXr16ERAQwNatW5k/f36NCVcBTCYTS5cuZcqUKfTr149ff/2VJUuW8OSTTxIcHHzesfr4+DB06FBeeeUVbDYbkZGR/Pbbbxw9evSUZXv16gXAv//9b2688Ub0ej1XXXUV3bp1Y8qUKXz88ccUFRUxbNgwNm/ezJdffsm4ceMYMWJErePp0aMHnTt3Zt68eXTo0IGePXue92sSQgghhBCiKZEEvBBCCCGEEOfh2muvpVWrVrz22mtMmzaNrVu38uyzzzJ79mzy8/MJCQmhR48eNVq+3H///SxevJjffvsNq9VKixYteOGFF5g+fXqNbWu1WpYuXco///lPpk+fjre3N88880yNbZ2vuXPnct999/H++++jqiqXX345v/76KxERETWW69OnD88//zwffvghS5cuxel0cvToUby8vPj000+Ji4tj9uzZLFiwgLCwMJ544onqyWbPx6233sq//vUvmXxVCCGEEEJcFBT1r+NRhRBCCCGEEA1u6tSpzJ8/H4vF4u5Q6tXbb7/NQw89RFJSEjExMe4ORwghhBBCiHolPeCFEEIIIYQQDUJVVT777DOGDRsmyXchhBBCCHFRkBY0QgghhBBCiHpVVlbG4sWL+eOPP9izZw+LFi1yd0hCCCGEEEI0CEnACyGEEEIIIepVbm4ukydPxs/PjyeffJKrr77a3SEJIYQQQgjRINzagmbmzJn06dMHb29vQkJCGDduHIcOHTrrOrNnz0ZRlBo/JpOpgSIWQgghhBCifsyePbvZ9n9v2bIlqqpSWFjIiy++6O5whBBCCCFEM1ZaWsqDDz5IixYt8PDwYODAgWzZssVt8bg1Ab969WruueceNm7cyPLly7HZbFx++eWUlZWddT0fHx8yMzOrf5KTkxsoYiGEEEIIIYQQQgghhBCN1Z133sny5cv5+uuv2bNnD5dffjmXXXYZ6enpbolHUVVVdcueTyM3N5eQkBBWr17N0KFDT7vM7NmzefDBBykqKmrY4IQQQgghhBB
2025-09-23 15:53:15 +01:00
"text/plain": [
"<Figure size 1800x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
2025-09-23 18:17:06 +01:00
"first_unique_phase = df.drop_duplicates(subset='PHASE')\n",
"phase_times = first_unique_phase['T(sec)'].tolist()\n",
"\n",
2025-09-23 15:53:15 +01:00
"plt.figure(figsize=(18, 5))\n",
"ax1 = plt.subplot()\n",
"\n",
2025-09-23 19:20:36 +01:00
"\n",
2025-09-23 15:53:15 +01:00
"# Plot VT with step-like appearance\n",
2025-09-23 19:20:36 +01:00
"line1 = sns.lineplot(data=df, x='T(sec)', y='VT(l)_smoothed', label='VT (L)')\n",
2025-09-23 15:53:15 +01:00
"ax1.set_xlabel('Time (sec)')\n",
"ax1.set_ylabel('VT (L)')\n",
"ax1.set_title('Respiratory')\n",
"ax1.grid(True, alpha=0.1)\n",
2025-09-23 20:36:24 +01:00
"ax1.set_ylim(0, 2.5)\n",
2025-09-23 15:53:15 +01:00
"\n",
"# Plot speed as step function on secondary y-axis\n",
"ax2 = ax1.twinx()\n",
"ax1.set_xticks(np.arange(0, df['T(sec)'].max() + 200, 200))\n",
"line2 = sns.lineplot(data=df, x='T(sec)', y='Speed', color='green', ax=ax2, \n",
" drawstyle='steps-post', linewidth=2, label='Speed')\n",
"ax2.set_ylabel('Speed')\n",
2025-09-23 20:36:24 +01:00
"ax2.set_ylim(0, 9)\n",
2025-09-23 15:53:15 +01:00
"\n",
"# Remove default legends first\n",
"ax1.get_legend().remove()\n",
"ax2.get_legend().remove()\n",
"\n",
"# Combine legends from both axes in the top left\n",
"lines1, labels1 = ax1.get_legend_handles_labels()\n",
"lines2, labels2 = ax2.get_legend_handles_labels()\n",
"ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')\n",
"\n",
"# Add colored background regions if you have phase information\n",
"ax1.axvspan(0, phase_times[1], alpha=0.2, color='lightblue')\n",
"ax1.axvspan(phase_times[1], phase_times[2], alpha=0.2, color='purple')\n",
"ax1.axvspan(phase_times[2], phase_times[3], alpha=0.2, color='lightgreen')\n",
"ax1.axvspan(phase_times[3], df['T(sec)'].max(), alpha=0.2, color='blue')\n",
"\n",
2025-09-26 16:37:46 +01:00
"plt.savefig('graphs/respiratory.png')\n",
2025-09-23 15:53:15 +01:00
"plt.show()"
]
},
{
"cell_type": "code",
2025-09-24 08:35:29 +01:00
"execution_count": 5,
2025-09-23 18:17:06 +01:00
"id": "06244aa2",
2025-09-23 15:53:15 +01:00
"metadata": {},
2025-09-23 17:14:36 +01:00
"outputs": [
{
"data": {
2025-09-23 18:17:06 +01:00
"image/png": "iVBORw0KGgoAAAANSUhEUgAABdEAAAMfCAYAAAA5Z570AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3Xd4U9X/B/B3uvekA0rpADrYyChLKbJBNggypIIgSxFEvg6mICCIIojgzwEIyJSlKEvZm8oeZXSwSinQ0kF37u+PY1aTdKRJB7xfz5Mnyb3nnnNucnPTfnLu58gkSZJARERERERERERERERazMq6A0RERERERERERERE5RWD6EREREREREREREREejCITkRERERERERERESkB4PoRERERERERERERER6MIhORERERERERERERKQHg+hERERERERERERERHowiE5EREREREREREREpAeD6EREREREREREREREejCITkRERERERERERESkB4PoRERUYv7+/pDJZJDJZJgxY0ZZd0dp5cqVyn7JZDKNdeHh4crlERERyuWxsbEa2xw4cKB0O10E+vpOVNGU13NHeXPq1Cl07twZ7u7uMDMzU75mycnJZd21CnHOpKIr6HuzNLYvz2bMmKHcL39//7LuTomV5/MKERFRecQgOhFRBXDgwAGNf0r13SpSQDX/P9q6Ai/qweL8/7A+r/+oPy8BcvXgqPrNzs4OgYGBGDBgAPbv31/W3TSp/J/b2NjYUms7IiKizD8fJQ2QmzLArv76hIeHG7VuY3vw4AE6d+6MXbt24cmTJ5AkqVjbP3nyBFOmTEHDhg3h6OgIKysreHp6IjQ0FL169cLMmTNx584dE/WeFIryXa1+zJfH4/J5/d41NX1/s9nY2MDPzw8DBgzAoUOHSrVPJT2vEBERvYgsyroDREREptKkSRMsWLCgWNu4ublpbFO9enVjd6vERo8ejddeew0AUKdOnTLuTfFkZGQgJiYGMTEx2LBhA77//nuMHDmyrLtFZeTTTz/F06dPAQAtWrQo496UT7t378aTJ08AiGDc2LFj4efnBwCwtbUtcNu4uDi0atUKd+/e1ViemJiIxMREXLt2Ddu2bUP9+vXh6+trUP8qwjmTqDzKysrC7du3cfv2bWzYsAGzZ8/Gp59+Wiptl+S8QkRE9KJiEJ2IqALq378/GjdurLW8ogVUTa127dqoXbt2sbZxcnLCpEmTTNQj4+jfv39Zd6FYAgMDMXr0aGRnZ+PChQvYuHGjctTbJ598grfffhtmZs/PxXEpKSlwcnIq625UCCNGjCjrLpR7cXFxysc+Pj5YsmRJkbf93//+pwygW1hYoF+/fqhVqxYkSUJ0dDSOHTuG69evl6h/FeGcSVReNG7cGP3794dcLseNGzewevVqZGVlAQCmTp2KLl26oGHDhiZpOy8vD1lZWbCzsyvRecVQ/G4kIqIKTyIionJv//79EgDlbcWKFcUqHxMTo7Hez89PuW769Ola2587d0566623pMDAQMnGxkayt7eXGjRoIH3++edSWlqaVvnC6tNlxYoVGn3cv3+/VpnWrVsr1/v5+UmSJEkxMTEa2+m6KfqQvw19dQ8dOlS5PH/96v0qrF318jk5OdKUKVOkzp07S4GBgZKzs7NkYWEhubm5Sa1atZIWL14sZWdnK+uePn16oXUr3kd9fVeIioqSRo0aJQUFBUm2traSra2tVLNmTWnkyJHS1atXtcoPHTpUWV/r1q2l+/fvSyNGjJC8vb0lKysrKSQkRPq///u/Qt9TderHROvWrTXW9e/fX2O/4uPjtbZ/8OCB9PHHH0v169eXHBwcJGtra6l69erSmDFjpLi4uEL34d69e9LQoUMlT09PydraWmrYsKG0bt06nX199uyZ9NVXX0ktWrSQXFxcJEtLS8nT01Pq3LmztGHDBq3y+T9fN27ckBYsWCCFhIRIVlZWUo8ePQp9L3W9b8ak/nrkP/YNfb8TExOlDz74QKpVq5ZkZ2cnWVpaSl5eXlKTJk2ksWPHSsePH9fZtq6bgq5zR3G2L+i8mH8/JUn7nFDQZ1iSJCkvL0/65ZdfpPbt20seHh6SpaWlVKlSJalLly7Szp07DXpvNm/eLHXp0kXy8vKSLC0tJRcXF6l58+bSl19+KaWnpyvL5T/O8t/yf650cXV1VZafMWOGzjJXrlzR+o6QJHEO++mnn6T27dtLnp6eyn0PCwvTqKugc6bCjh07pO7du0ve3t7KfW7Tpo20Zs0aSS6Xa5TVVd+6deukpk2bSra2tpKLi4vUt29f6fbt2zr35+rVq9KYMWOk0NBQyd7eXrK1tZUCAgKk/v37S6dPn9Yoa4r3V5+ifP4LOm9KkiQ9ffpUmjNnjtS0aVPJyclJsrS0lHx9faWhQ4dKly5d0iofHR0tjR8/XmrVqpVUtWpVyc7OTrKyspKqVKkivfbaa9KOHTu0ttH1vVmS793s7Gzpiy++kIKDgyUrKyvJx8dH+uCDD6TMzMwiv3b79++Xhg0bJjVs2FB5nrK1tZWqV68uRURESBcuXNDapiTfaxcuXJC6du0qOTo6So6OjlLHjh2lyMhIje9pxd8kRVHQe//DDz9orJ86darG+pJ+F8bFxUmDBw+WPD09JZlMJm3durVY55Winq907euKFSukbdu2Sc2bN5fs7e0lZ2dnSZK0j5Hk5GTp3Xfflby9vSU7OzspPDxcOnnypCRJknTr1i2pT58+kouLi+Tg4CB17NhRunjxola78+fPl3r06CHVrFlTcnV1lSwsLCRnZ2epSZMm0uzZs3X+7Zq/r3v27JHCw8Mle3t7ycHBQerUqZPOz5UkSdKdO3ekyZMnSw0aNJAcHR0la2trydfXV+rRo4e0Z88erfLFOQcSEVH5xSA6EVEFUJpB9O+++06ysLDQ+w9WrVq1tIKeDKJrl09NTS20bLt27aTc3FxJkowXRN+4caNkY2Ojtw5ra2utYLL6P92BgYFS5cqVdW77008/Fem9laSCg0ETJ05UrjMzM9MKphw7dkyqVKmS3n1wdnaWDh06pHcfgoKCJB8fH53bLly4UGO7+Ph4qXbt2gW+7n369JFycnKU2+T/fL388ssazytSEL2o73dGRoYUHBxc4D7973//09m2rptCeQ6iP3v2TGrXrl2BZSdOnFjk9yQ3N1d6/fXXC6wvNDRUun//viRJxgmiOzo6KssPGDCgyIHLx48fS02aNCnwM6hQ0DkzLy9PGjJkSIH70a9fP+V5UFd9rVq10rldzZo1pYyMDI1+//jjj5KVlZXetr7++mtlWWO/v4Upyue/oPPm9evXJX9/f719tba2ljZu3Kixze+//17o8T5z5kyNbYwdRO/YsaPO8kOGDCnya/fBBx8U2LaVlZW0d+9ejW0M/V47ffq05ODgoFXOxsZGatu2rfK5sYLoly5d0lg/YsQI5bqSfhfWrFlT8vb21timqEH04p6vdO1r/u9GfUH0Ro0a6Xy9t2/fLrm5uWmtc3d3lx4+fKjRrru7e4F9rVu3rpSamqq3ry1btpRkMlmR2tq5c6fGuTX/bfz48cqyhpwDiYio/GI6FyKiCmjXrl149OiR1vL+/fsbnNcWAI4dO4Zx48ZBLpcDAJo1a4ZOnTohNTUVq1atwqNHj3DlyhW8+eab2LNnj8HtlIQi/+6ZM2ewYcMG5XL1nLymyq2cP796Xl4e5s2bh+TkZACAg4ODMqeoTCZDYGAgmjVrBh8fH7i6uiInJwfXrl3Dpk2bkJubi3379uG3337D66+/jg4dOsDBwQHLli1DdHQ0ANVl3+r7XpCbN29iyJAhykvD3d3dMXToUMhkMuX7l5WVhaFDh6JRo0aoWbOmVh3R0dGwsbHB6NGjYWtri2XLliEjIwMAMH/+fAwbNsywFw9ATk6OMp2LQo8ePWBtba18npKSgp49eyqPbz8/P/Tv3x+2trbYvHkzLl++jKdPn6JPnz64ceMGnJ2dtdq5fv06nJ2dMWHCBMhkMvz888/K9+ijjz5C9+7dUaNGDQDAoEGDcPnyZeW2ffv2Ra1atbB3714
2025-09-23 17:14:36 +01:00
"text/plain": [
2025-09-23 18:17:06 +01:00
"<Figure size 1500x800 with 2 Axes>"
2025-09-23 17:14:36 +01:00
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
2025-09-23 18:17:06 +01:00
"\n",
"# Group by speed and calculate mean for numeric columns only\n",
2025-09-23 17:14:36 +01:00
"speed_groups = df.groupby('Speed').mean(numeric_only=True).round(1)\n",
"\n",
"# Drop the first and last row from speed_groups\n",
"speed_groups = speed_groups.iloc[1:-1]\n",
"\n",
"# Filter data to only include speeds in the desired range\n",
"filtered_data = speed_groups[(speed_groups.index >= 3.5) & (speed_groups.index <= 7.5)]\n",
"\n",
2025-09-23 18:17:06 +01:00
"# Create figure with specific size\n",
"plt.figure(figsize=(15, 8))\n",
"plt.style.use('default')\n",
2025-09-23 17:14:36 +01:00
"\n",
2025-09-23 18:17:06 +01:00
"# Create stage labels and positions\n",
"stage_labels = [f'Stage {i}' for i in range(1, len(filtered_data) + 1)]\n",
"x_positions = np.arange(len(filtered_data))\n",
2025-09-23 17:14:36 +01:00
"\n",
2025-09-23 17:18:10 +01:00
"# Calculate fat and carbs energy expenditure from percentages\n",
"fat_ee = filtered_data['EE(kcal/min)'] * filtered_data['FAT(%)'] / 100\n",
"carbs_ee = filtered_data['EE(kcal/min)'] * filtered_data['CARBS(%)'] / 100\n",
"\n",
2025-09-23 18:17:06 +01:00
"# Create the main axis for the stacked bars\n",
"ax1 = plt.gca()\n",
"\n",
"# Create stacked bar chart with colors\n",
"bars_fat = ax1.bar(x_positions, fat_ee, color='#1f77b4', alpha=0.8, width=0.6, label='Fat')\n",
"bars_carbs = ax1.bar(x_positions, carbs_ee, bottom=fat_ee, color='#ff7f0e', alpha=0.8, width=0.6, label='Carbs')\n",
"\n",
"# Set labels and formatting for primary axis\n",
"ax1.set_xlabel('', fontsize=12)\n",
"ax1.set_ylabel('Fuel (kcal/min)', fontsize=12)\n",
"ax1.set_ylim(0, 20)\n",
"\n",
"# Add individual values on each bar segment\n",
"for i, (fat_val, carb_val, total_val) in enumerate(zip(fat_ee, carbs_ee, filtered_data['EE(kcal/min)'])):\n",
" if fat_val > 0.3: # Fat value\n",
" ax1.text(i, fat_val/2, f'{fat_val:.1f}', ha='center', va='center',\n",
" fontsize=9, fontweight='bold', color='white')\n",
" if carb_val > 0.3: # Carbs value\n",
" ax1.text(i, fat_val + carb_val/2, f'{carb_val:.1f}', ha='center', va='center',\n",
" fontsize=9, fontweight='bold', color='white')\n",
" # Total EE\n",
" ax1.text(i, total_val + 0.5, f'{total_val:.1f} kcal', ha='center', va='bottom',\n",
" fontsize=10, fontweight='bold', color='black')\n",
"\n",
"# Add speed labels below x-axis\n",
"for i, speed in enumerate(filtered_data.index):\n",
" ax1.text(i, -1.5, f'{speed:.1f} mph', ha='center', va='top', fontsize=9)\n",
" ax1.text(i, -2.8, f'{speed*1.609:.1f} min/km', ha='center', va='top', fontsize=8, color='gray')\n",
"\n",
"# Create secondary y-axis for heart rate\n",
"ax2 = ax1.twinx()\n",
"\n",
"# Plot heart rate line (no manual offset)\n",
"hr_line = ax2.plot(x_positions, filtered_data['HR(bpm)'],\n",
" marker='o', linewidth=3, markersize=8, color='red', label='Heart Rate')\n",
"\n",
"# Set heart rate axis formatting\n",
"ax2.set_ylabel('Heart Rate (bpm)', fontsize=12, color='red')\n",
"ax2.tick_params(axis='y', labelcolor='red')\n",
"\n",
"# Dynamically adjust HR axis to float above bars\n",
"max_bar_height = max(filtered_data['EE(kcal/min)'])\n",
"ax2.set_ylim(0, 220) # ensures HR line is above bars\n",
2025-09-23 17:18:10 +01:00
"\n",
"\n",
2025-09-23 18:17:06 +01:00
"# Add HR values above the points\n",
"for i, hr in enumerate(filtered_data['HR(bpm)']):\n",
" ax2.text(i, hr + 10, f'{int(hr)}bpm', ha='center', va='bottom',\n",
" fontsize=10, fontweight='bold', color='red')\n",
2025-09-23 17:14:36 +01:00
"\n",
2025-09-23 18:17:06 +01:00
"# Set x-axis formatting\n",
"ax1.set_xticks(x_positions)\n",
"ax1.set_xticklabels(stage_labels, fontsize=11)\n",
2025-09-23 17:14:36 +01:00
"\n",
2025-09-23 18:17:06 +01:00
"# Add title\n",
"plt.suptitle('Fuel Utilization Report - Institute of Science, Health and Performance',\n",
" fontsize=14, fontweight='bold', y=0.95)\n",
"\n",
"# Create legend\n",
2025-09-23 17:14:36 +01:00
"lines1, labels1 = ax1.get_legend_handles_labels()\n",
"lines2, labels2 = ax2.get_legend_handles_labels()\n",
2025-09-23 18:17:06 +01:00
"ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left',\n",
" frameon=True, fancybox=True, shadow=True)\n",
2025-09-23 17:14:36 +01:00
"\n",
2025-09-23 18:17:06 +01:00
"# Add grid\n",
"ax1.grid(True, alpha=0.3, linestyle='-', linewidth=0.5)\n",
"ax1.set_axisbelow(True)\n",
"\n",
"# Adjust layout\n",
2025-09-23 17:14:36 +01:00
"plt.tight_layout()\n",
2025-09-23 18:17:06 +01:00
"plt.subplots_adjust(bottom=0.1, top=0.9)\n",
"plt.show()\n"
2025-09-23 17:14:36 +01:00
]
2025-09-23 17:18:10 +01:00
},
{
"cell_type": "code",
2025-09-24 08:35:29 +01:00
"execution_count": 6,
2025-09-23 17:18:10 +01:00
"id": "8a1878a0",
"metadata": {},
2025-09-23 18:47:10 +01:00
"outputs": [
{
"data": {
2025-09-23 19:20:36 +01:00
"image/png": "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+fTTT53PW6VKlWjatGmquoqiULhwYZeEm6IozJo1i4oVK+Lh4UHBggUZOHAgN2/edDm2ePHidOjQgTVr1lCjRg08PT35+OOPM3UN6fnvGh63p+jbsmULw4cPJygoiICAAAYOHIjFYiEmJobevXsTGBhIYGAgr7/+OqqqprrOzFyTEEIIIYR4vEjCQwghhBACx7RWNpuN7777zqX8xo0brFmzhs6dOzs/5fzLL7/g4eFB9+7d02wrPDycBg0a8Ndff5GcnJzueSMjIylQoMADx337BvrtqbYexksvvcT8+fPp2rUr8+bN49VXX8XT09MlIfPXX3/RqFEj4uLiGDduHJMmTSImJoZmzZqxc+fOBz633W7n+vXrqR5p3bxMSkqicePGfPXVV/Tu3ZsPP/yQ+vXrM2rUKEaOHOlSd/bs2VSvXp2JEycyadIk9Ho9Tz/9NL/++muqdv/66y9eeeUVevTowezZs6lZs6bz0/SdO3fmyy+/5Msvv6RLly73fX1nz54FIDAw8L7j+/LLLzGZTDRs2NAZw8CBAwG4evUqderUYe3atQwdOpTZs2dTqlQp+vfvz6xZs+47ToA///yTf//9l+eff545c+bQs2dPvvnmG9q1a5fqpjNA9+7diY+PZ/LkyXTv3p0lS5Y4pwG77YUXXmDWrFm0atWKKVOmYDAYaN++fabiCQsLw263p5pC6V5u3rxJu3btiIiIYNq0aRQpUoRBgwa5JIEURaFjx468//77PPnkk8yZM4dOnToxc+ZMevTo4dLee++9R+/evSldujQzZsxgxIgRrFu3jkaNGhETE+Ost2jRIgYOHEhISAjTpk2jfv36dOzYMc3EyH/9/vvv2O32NEeY3da7d29sNhurV68GoEePHmzatInIyEiXelu2bOHy5cv07NnTWTZw4EBee+016tevz+zZs3n++edZunQprVu3TrU2yPHjx3nmmWdo2bIls2fPplq1ahnG/6CGDRvGyZMnmTBhAh07dmThwoWMGTOGJ598ErvdzqRJk2jQoAHTp09P9fO/n2sSQgghhBCPEVUIIYQQQqg2m00NDQ1V69at61K+YMECFVDXrFnjLAsICFCrVq2abnvDhw9XAfXgwYP3rLNp0yZVo9GoY8aMyTC+xYsXq4C6du1a9dq1a+qFCxfUb775Rs2fP7/q6empXrx4UVVVVW3cuLHauHHjVMf36dNHDQsLcykD1HHjxjm3/f391SFDhtwzBkVR1NKlS6utW7dWFUVxliclJanh4eFqy5YtM7yOtDRu3FgF0n1Mnz7dWf+dd95Rvb291RMnTri08+abb6o6nU49f/68S2x3s1gsaqVKldRmzZq5lAOqVqtV//nnH5fya9eupXqe0rN+/XoVUD/77DP12rVr6uXLl9XVq1erpUqVUjUajbpz506X+pmNz9vbW+3Tp0+q8/Xv318NDQ1Vr1+/7lLes2dP1d/fP1X7mZHWMV9//bUKqJs2bXKWjRs3TgXUfv36udTt3Lmzmj9/fuf2/v37VUAdPHiwS71nn302U89tZGSkGhQUpAJquXLl1JdeekldtmyZGhMTk6ru7b70wQcfOMvMZrNarVo1NTg4WLVYLKqqquqXX36parVadfPmzS7H3/5937p1q6qqqnr27FlVp9Op7733nku9Q4cOqXq93ll
2025-09-23 18:47:10 +01:00
"text/plain": [
"<Figure size 1800x500 with 3 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"first_unique_phase = df.drop_duplicates(subset='PHASE')\n",
"phase_times = first_unique_phase['T(sec)'].tolist()\n",
"\n",
"plt.figure(figsize=(18, 5))\n",
"ax1 = plt.subplot()\n",
"\n",
"# Plot VO2 Pulse\n",
2025-09-23 19:20:36 +01:00
"#\n",
"line1 = sns.lineplot(data=df, x='T(sec)', y='VO2 Pulse_smoothed', label='VO2 Pulse (mL/beat)', color='blue')\n",
2025-09-23 18:47:10 +01:00
"ax1.set_xlabel('Time (sec)')\n",
"ax1.set_ylabel('VO2 Pulse (mL/beat)')\n",
"ax1.set_title('VO2 Pulse, Heart Rate, and Speed Over Time')\n",
"ax1.set_ylim(0, df['VO2 Pulse'].max())\n",
"ax1.grid(True, alpha=0.1)\n",
"\n",
"# Create second y-axis for heart rate\n",
2025-09-23 19:20:36 +01:00
"#\n",
2025-09-23 18:47:10 +01:00
"ax2 = ax1.twinx()\n",
2025-09-23 19:20:36 +01:00
"line2 = sns.lineplot(data=df, x='T(sec)', y='HR(bpm)_smoothed', color='red', ax=ax2, \n",
2025-09-23 18:47:10 +01:00
" linewidth=2, label='Heart Rate (bpm)')\n",
"ax2.set_ylabel('Heart Rate (bpm)', color='red')\n",
"ax2.tick_params(axis='y', labelcolor='red')\n",
"\n",
"# Create third y-axis for speed\n",
"ax3 = ax1.twinx()\n",
"ax3.spines['right'].set_position(('outward', 60))\n",
2025-09-23 19:20:36 +01:00
"\n",
2025-09-23 18:47:10 +01:00
"line3 = sns.lineplot(data=df, x='T(sec)', y='Speed', color='green', ax=ax3, \n",
" drawstyle='steps-post', linewidth=2, label='Speed')\n",
"ax3.set_ylabel('Speed', color='green')\n",
"ax3.tick_params(axis='y', labelcolor='green')\n",
"\n",
"ax1.set_xticks(np.arange(0, df['T(sec)'].max() + 200, 200))\n",
"\n",
"# Remove default legends first\n",
"if ax1.get_legend():\n",
" ax1.get_legend().remove()\n",
"if ax2.get_legend():\n",
" ax2.get_legend().remove()\n",
"if ax3.get_legend():\n",
" ax3.get_legend().remove()\n",
"\n",
"# Combine legends from all axes in the top left\n",
"lines1, labels1 = ax1.get_legend_handles_labels()\n",
"lines2, labels2 = ax2.get_legend_handles_labels()\n",
"lines3, labels3 = ax3.get_legend_handles_labels()\n",
"ax1.legend(lines1 + lines2 + lines3, labels1 + labels2 + labels3, loc='upper left')\n",
"\n",
"# Add colored background regions if you have phase information\n",
"ax1.axvspan(0, phase_times[1], alpha=0.2, color='lightblue')\n",
"ax1.axvspan(phase_times[1], phase_times[2], alpha=0.2, color='purple')\n",
"ax1.axvspan(phase_times[2], phase_times[3], alpha=0.2, color='lightgreen')\n",
"ax1.axvspan(phase_times[3], df['T(sec)'].max(), alpha=0.2, color='blue')\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
2025-09-24 08:35:29 +01:00
"execution_count": 7,
2025-09-23 18:47:10 +01:00
"id": "7361fb05",
"metadata": {},
"outputs": [
{
"data": {
2025-09-23 19:20:36 +01:00
"image/png": "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
2025-09-23 18:47:10 +01:00
"text/plain": [
"<Figure size 1800x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"first_unique_phase = df.drop_duplicates(subset='PHASE')\n",
"phase_times = first_unique_phase['T(sec)'].tolist()\n",
"\n",
"plt.figure(figsize=(18, 5))\n",
"ax1 = plt.subplot()\n",
"\n",
"# Plot VT with step-like appearance\n",
2025-09-23 19:20:36 +01:00
"line1 = sns.lineplot(data=df, x='T(sec)', y='VO2 Breath_smoothed', label='VO2 per Breath (mL/breath)')\n",
2025-09-23 18:47:10 +01:00
"ax1.set_xlabel('Time (sec)')\n",
"ax1.set_ylabel('VO2 per Breath (mL/breath)')\n",
"ax1.set_title('VO2 per Breath and Speed Over Time')\n",
"ax1.grid(True, alpha=0.1)\n",
"\n",
"# Plot speed as step function on secondary y-axis\n",
"ax2 = ax1.twinx()\n",
"ax1.set_xticks(np.arange(0, df['T(sec)'].max() + 200, 200))\n",
"line2 = sns.lineplot(data=df, x='T(sec)', y='Speed', color='green', ax=ax2, \n",
" drawstyle='steps-post', linewidth=2, label='Speed')\n",
"ax2.set_ylabel('Speed')\n",
"\n",
"# Remove default legends first\n",
"ax1.get_legend().remove()\n",
"ax2.get_legend().remove()\n",
"\n",
"# Combine legends from both axes in the top left\n",
"lines1, labels1 = ax1.get_legend_handles_labels()\n",
"lines2, labels2 = ax2.get_legend_handles_labels()\n",
"ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')\n",
"\n",
"# Add colored background regions if you have phase information\n",
"ax1.axvspan(0, phase_times[1], alpha=0.2, color='lightblue')\n",
"ax1.axvspan(phase_times[1], phase_times[2], alpha=0.2, color='purple')\n",
"ax1.axvspan(phase_times[2], phase_times[3], alpha=0.2, color='lightgreen')\n",
"ax1.axvspan(phase_times[3], df['T(sec)'].max(), alpha=0.2, color='blue')\n",
"\n",
"plt.show()"
]
2025-09-23 19:08:30 +01:00
},
{
"cell_type": "code",
2025-09-24 08:35:29 +01:00
"execution_count": 8,
2025-09-23 19:08:30 +01:00
"id": "c89478ff",
"metadata": {},
2025-09-23 20:36:24 +01:00
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABeQAAAHWCAYAAAAWxYndAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3Xd4VGXax/HvtEx679SE3osIiFRFEUXFgl2wrGV17W1117bru6xtV13L2tayllXsClZUQKSIiCC9hUB678m08/4xZCSSkASSTMrvs1eudc4585z7ZJ6EyX3uuR+TYRgGIiIiIiIiIiIiIiLSqsz+DkBEREREREREREREpCtQQl5EREREREREREREpA0oIS8iIiIiIiIiIiIi0gaUkBcRERERERERERERaQNKyIuIiIiIiIiIiIiItAEl5EVERERERERERERE2oAS8iIiIiIiIiIiIiIibUAJeRERERERERERERGRNqCEvIiIiIiIiIiIiIhIG1BCXkRERETkNy655BJ69+7t7zBa1csvv4zJZCItLc3fofjNfffdh8lk8ncYIiIiItKFKCEvIiIiIgDs3LmTq666itTUVAIDAwkPD+fYY4/l8ccfp6qqyndc7969mTVrVr1jfPvtt5hMJt55552D9m3cuJGLLrqIbt26YbfbSU5O5sILL2Tjxo2tdk2tzePx8OqrrzJu3Diio6MJCwujf//+zJ07l5UrV/o7vBa1fPlyzjjjDBISErDb7fTu3ZurrrqK9PR0f4dWR+/evTGZTI1+vfzyy/4OVURERES6IKu/AxARERER/1u4cCFz5szBbrczd+5chg4disPh4LvvvuO2225j48aNPPfcc4c9/nvvvcf5559PdHQ0l19+OSkpKaSlpfHiiy/yzjvv8L///Y8zzjijBa+obVx//fU89dRTnH766Vx44YVYrVa2bt3Kp59+SmpqKuPHj/d3iC3iX//6FzfccAOpqalcd911JCUlsXnzZl544QXeeustFi1axIQJE/wdJgCPPfYY5eXlvseLFi3izTff5J///CexsbG+7RMmTOCiiy7ij3/8oz/CFBEREZEuSgl5ERERkS5u9+7dnHfeefTq1Yuvv/6apKQk375rr72WHTt2sHDhwsMef+fOnVx88cWkpqaydOlS4uLifPtuuOEGJk2axMUXX8z69etJTU09omtpSzk5OTz99NNcccUVB92seOyxx8jLy/NTZC1r+fLl3HjjjUycOJHPPvuM4OBg377f//73HHvssZx99tls3LiRqKioNouroqKCkJCQg7bPnj27zuPs7GzefPNNZs+eXW8bIqtVfxKJiIiISNtRyxoRERGRLu6hhx6ivLycF198sU4yvlbfvn254YYbDnv8hx9+mMrKSp577rk6yXiA2NhYnn32WSoqKnjooYcOOY7D4eCee+7hqKOOIiIigpCQECZNmsQ333xT57i0tDRMJhOPPPIIzz33HH369MFut3P00Ufzww8/HDTuBx98wNChQwkMDGTo0KG8//77Tbqu3bt3YxgGxx577EH7TCYT8fHxvse1/dqXLl3KVVddRUxMDOHh4cydO5eioqKDnv/pp58yadIkQkJCCAsL45RTTqm3tc+WLVs4++yziY6OJjAwkDFjxvDRRx8ddNzGjRs57rjjCAoKonv37jzwwAN4PJ4mXedf//pXTCYTr7zySp1kPECfPn146KGHyMrK4tlnnwXgkUcewWQysWfPnoPGuvPOOwkICKhzzatWreKkk04iIiKC4OBgpkyZwvLly+s8r7bX+6ZNm7jggguIiopi4sSJTYr/UOrrIW8ymfjDH/7AggULGDx4MEFBQRxzzDFs2LABgGeffZa+ffsSGBjI1KlT6+3B35RrEhEREZGuSQl5ERERkS7u448/JjU1tVktR5xOJ/n5+Qd9lZSU1Dt+7969mTRpUr1jTZ48md69ezdahV9aWsoLL7zA1KlTefDBB7nvvvvIy8tjxowZrFu37qDj33jjDR5++GGuuuoqHnjgAdLS0jjzzDNxOp2+Y7744gvOOussTCYT8+fPZ/bs2Vx66aWsWbOm0e9Br169AFiwYAGVlZWNHg/whz/8gc2bN3Pfffcxd+5cXn/9dWbPno1hGL5j/vvf/3LKKacQGhrKgw8+yN13382mTZuYOHFineTvxo0bGT9+PJs3b+aPf/wjjz76KCEhIcyePbvOTYXs7GymTZvGunXr+OMf/8iNN97Iq6++yuOPP95ovJWVlSxevJhJkyaRkpJS7zHnnnsudrudTz75BIBzzjkHk8nE22+/fdCxb7/9NieeeKKvkv7rr79m8uTJlJaWcu+99/K3v/2N4uJijjvuOFavXn3Q8+fMmUNlZSV/+9vfuOKKKxqN/3AtW7aMW265hXnz5nHfffexefNmZs2axVNPPcUTTzzBNddcw2233caKFSu47LLL6jy3udckIiIiIl2MISIiIiJdVklJiQEYp59+epOf06tXLwM45NeCBQsMwzCM4uLiJo1/2mmnGYBRWlra4DEul8uoqamps62oqMhISEgwLrvsMt+23bt3G4ARExNjFBYW+rZ/+OGHBmB8/PHHvm0jR440kpKSjOLiYt+2L774wgCMXr16Nfq9mDt3rgEYUVFRxhlnnGE88sgjxubNmw867qWXXjIA46ijjjIcDodv+0MPPWQAxocffmgYhmGUlZUZkZGRxhVXXFHn+dnZ2UZERESd7ccff7wxbNgwo7q62rfN4/EYEyZMMPr16+fbduONNxqAsWrVKt+23NxcIyIiwgCM3bt3N3h969atMwDjhhtuOOT3Yfjw4UZ0dLTv8THHHGMcddRRdY5ZvXq1ARivvvqqL9Z+/foZM2bMMDwej++4yspKIyUlxTjhhBN82+69914DMM4///xDxlGfhx9+uMHrrB33QIBht9vrHP/ss88agJGYmFhnjt555511xm7ONYmIiIhI16QKeREREZEurLS0FICwsLBmPW/cuHF8+eWXB3098sgjdY4rKytr0vi1+2vjqY/FYiEgIAAAj8dDYWEhLpeLMWPGsHbt2oOOP/fcc+v0NK+t0N+1axcAWVlZrFu3jnnz5hEREeE77oQTTmDw4MGHjLfWSy+9xJNPPklKSgrvv/8+t956K4MGDeL4448nIyPjoOOvvPJKbDab7/Hvf/97rFYrixYtAuDLL7+kuLiY888/v84nDywWC+PGjfO15yksLOTrr7/mnHPOoayszHdcQUEBM2bMYPv27b7zL1q0iPHjxzN27FjfeePi4rjwwgsbvb7mvH4HvnbnnnsuP/74Izt37vRte+utt7Db7Zx++ukArFu3ju3bt3PBBRdQUFDgu4aKigqOP/54li5delBbnauvvrrRmFvC8ccfX6ff/Lhx4wA466yz6nwvarfXzqnDuSYRERER6Vq0gpGIiIhIFxYeHg78mnhtqtjYWKZPn37Q9t8ukFmbvGxs/KYmfl955RUeffRRtmzZUqf1TH3tVHr27FnncW1yvrZ/eW2P8379+h303AEDBtSb5P8ts9nMtddey7XXXktBQQHLly/n3//+N59++innnXcey5Ytq3P8b88VGhpKUlKSrxXN9u3bATjuuOPqPV/t67Vjxw4Mw+Duu+/m7rvvrvfY3NxcunXrxp49e3yJ499eY2Oa8/od+NrNmTOHm2++mbfeeou77roLwzBYsGABM2fO9F1D7bXOmzevwXFLSkrq3FRpqG1OS/vt3Km9YdOjR496t9fOqcO5JhERERHpWpSQFxEREenCwsPDSU5O5pdffmmV8SMiIkhKSmL9+vWHPG79+vV069bNl6ytz2uvvcYll1zC7Nmzue2224iPj8disTB//vw6ldi1LBZLveMYB/Rrb0kxMTGcdtppnHbaaUydOpUlS5awZ88eX6/5pqitnv7vf/9LYmLiQftrb3jUHnfrrbcyY8aMesfq27dvcy+h3jGsVushX7+amhq2bt3KmDFjfNuSk5OZNGkSb7/9NnfddRcrV64kPT2dBx980HdM7TU8/PDDjBw5st6xQ0ND6zwOCgo6gqtpuobmTmN
"text/plain": [
"<Figure size 1800x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
2025-09-23 19:08:30 +01:00
"source": [
"first_unique_phase = df.drop_duplicates(subset='PHASE')\n",
"phase_times = first_unique_phase['T(sec)'].tolist()\n",
"\n",
"plt.figure(figsize=(18, 5))\n",
"ax1 = plt.subplot()\n",
"\n",
2025-09-23 20:36:24 +01:00
"df['CHO']\n",
2025-09-23 19:08:30 +01:00
"# Plot VT with step-like appearance\n",
2025-09-23 20:36:24 +01:00
"line1 = sns.lineplot(data=df, x='T(sec)', y='CHO_smoothed', label='CHO (kcal/min)')\n",
2025-09-23 19:08:30 +01:00
"ax1.set_xlabel('Time (sec)')\n",
2025-09-23 20:36:24 +01:00
"ax1.set_ylabel('CHO (g/min)')\n",
"ax1.set_title('CHO and Speed Over Time')\n",
2025-09-23 19:08:30 +01:00
"ax1.grid(True, alpha=0.1)\n",
"\n",
"# Plot speed as step function on secondary y-axis\n",
"ax2 = ax1.twinx()\n",
"ax1.set_xticks(np.arange(0, df['T(sec)'].max() + 200, 200))\n",
2025-09-23 20:36:24 +01:00
"line2 = sns.lineplot(data=df, x='T(sec)', y='FAT_smoothed', color='green', ax=ax2, label='FAT (kcal/min)')\n",
"ax2.set_ylabel('FAT (kcal/min)')\n",
"\n",
"ax2.set_ylim(0, 15) # ensures HR line is above bars\n",
2025-09-23 19:08:30 +01:00
"\n",
"# Remove default legends first\n",
"ax1.get_legend().remove()\n",
"ax2.get_legend().remove()\n",
"\n",
"# Combine legends from both axes in the top left\n",
"lines1, labels1 = ax1.get_legend_handles_labels()\n",
"lines2, labels2 = ax2.get_legend_handles_labels()\n",
"ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')\n",
"\n",
"# Add colored background regions if you have phase information\n",
"ax1.axvspan(0, phase_times[1], alpha=0.2, color='lightblue')\n",
"ax1.axvspan(phase_times[1], phase_times[2], alpha=0.2, color='purple')\n",
"ax1.axvspan(phase_times[2], phase_times[3], alpha=0.2, color='lightgreen')\n",
"ax1.axvspan(phase_times[3], df['T(sec)'].max(), alpha=0.2, color='blue')\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
2025-09-24 08:35:29 +01:00
"execution_count": 22,
2025-09-23 19:08:30 +01:00
"id": "1db16040",
"metadata": {},
"outputs": [
{
"data": {
2025-09-23 19:20:36 +01:00
"image/png": "iVBORw0KGgoAAAANSUhEUgAABkkAAAHWCAYAAADTgW69AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3Xd8FEUbwPHf1fQCIYUSQgg19E5ooYpIEQEpooAgUqW9imKjKCBYAJUiiqACKiioiNJ7b9J7r0ko6eXqvn8cOTiSkABpwPP1cx/udmdnnt1MTthnZ0alKIqCEEIIIYQQQgghhBBCCCHEU0ad1wEIIYQQQgghhBBCCCGEEELkBUmSCCGEEEIIIYQQQgghhBDiqSRJEiGEEEIIIYQQQgghhBBCPJUkSSKEEEIIIYQQQgghhBBCiKeSJEmEEEIIIYQQQgghhBBCCPFUkiSJEEIIIYQQQgghhBBCCCGeSpIkEUIIIYQQQgghhBBCCCHEU0mSJEIIIYQQQgghhBBCCCGEeCpJkkQIIYQQQgghhBBCCCGEEE8lSZIIIYQQQgg7lUrFmDFj8joM8RR7Gvpg48aNady4cV6HkadKlChBr1698joMIYQQQgghJEkihBBCCJGedu3a4erqSnx8fIZlunfvjl6v5+bNm/ZtFy9epH///pQoUQInJyf8/Pxo3749W7duTXP88ePHGTlyJFWrVsXDw4PChQvTunVr9uzZk6UY582bh0qlsr+cnZ0pU6YMgwcPJjIy8sFPOh9p3LgxFStWTHff+fPnUalUfPbZZ7kclU1SUhJjxoxhw4YNWSq/YcMGh5+TRqPBz8+PTp06cezYsYeOY8KECfzxxx8Pffzj7vr16wwdOpRy5crh4uKCn58ftWvX5u233yYhISGvw8s2JpOJL7/8klq1auHh4YG7uzu1atXiyy+/xGQy5XV4dvf28/u9hBBCCCGEyE+0eR2AEEIIIUR+1L17d5YtW8bSpUvp0aNHmv1JSUn8+eefPPvss/j4+ACwdetWnnvuOQBee+01QkNDiYiIYN68eTRs2JBp06bxxhtv2Ov47rvvmDNnDh07dmTgwIHExsbyzTffULduXVasWEHz5s2zFOu4ceMIDg4mJSWFLVu2MHPmTP755x8OHz6Mq6trNlwNcbekpCTGjh0L8ECjAYYMGUKtWrUwmUwcPHiQWbNmsWHDBg4fPkxAQMADxzFhwgQ6depE+/btH/jYx92tW7eoWbMmcXFx9O7dm3LlynHz5k0OHjzIzJkzGTBgAO7u7nkd5iNLTEykdevWbNy4kTZt2tCrVy/UajUrVqxg6NChLFmyhOXLl+Pm5pbXoVK+fHl++uknh22jRo3C3d2d9957L035EydOoFbLM3tCCCGEECLvSZJECCGEECId7dq1w8PDg4ULF6abJPnzzz9JTEyke/fuAERHR9OpUydcXFzYunUrISEh9rIjRoygZcuWDBs2jBo1alCvXj0AunXrxpgxYxxu5vbu3Zvy5cszZsyYLCdJWrVqRc2aNQFbcsbHx4cvvviCP//8k27duj30NRCOrFYrRqPxoY9v2LAhnTp1sn8uW7YsAwYM4Mcff2TkyJHZEeJTY86cOVy8eJGtW7faf59SxcXFodfr8yiy7DVixAg2btzIV199xeDBg+3bBwwYwPTp0xk8eDBvvvkmM2fOzLWYFEUhJSUFFxcXh+3+/v68/PLLDts++eQTChUqlGY7gJOTU47GKYQQQgghRFbJoztCCCGEEOlwcXGhQ4cOrF27lqioqDT7Fy5ciIeHB+3atQPgm2++ISIigk8//dQhQZJa1w8//IBKpWLcuHH27TVq1EjztLuPjw8NGzZ8pGmYmjZtCsC5c+eAjNc/6NWrFyVKlLhvXfHx8QwbNsxh+rAWLVqwb98+h3I7d+7k2WefxcvLC1dXV8LDw9OdYiwnxcTEMGzYMAIDA3FycqJUqVJMmjQJq9XqUO6zzz6jXr16+Pj44OLiQo0aNfjtt9/S1KdSqRg8eDALFiygQoUKODk5MWvWLHx9fQEYO3asffqgh1lDo2HDhgCcOXPmgeNTqVQkJiba+5VKpXJY3+HKlSv07t0bf39/nJycqFChAt9///0Dx5jq4MGD9OrVi5IlS+Ls7ExAQAC9e/d2mGoOYMyYMahUKk6fPk2vXr3w9vbGy8uLV199laSkJIeyBoOB4cOH4+vra/9dunz5cpbiOXPmDBqNhrp166bZ5+npibOzs/1z6tRte/fupV69eri4uBAcHMysWbPSHGswGBg9ejSlSpXCycmJwMBARo4cicFgSFN2/vz51KhRAxcXFwoWLEjXrl25dOlSmnKzZ88mJCQEFxcXateuzebNm7N0jpcvX2bOnDk0bdrUIUGSatCgQTRp0oTvvvvOft0qVqxIkyZN0pS1Wq0ULVrUIUlntVqZOnUqFSpUwNnZGX9/f/r160d0dLTDsSVKlKBNmzasXLmSmjVr4uLiwjfffJOlc7ife9ckSZ0+cMuWLQwZMgRfX1+8vb3p168fRqORmJgYevToQYECBShQoAAjR45EUZQ055mVcxJCCCGEEOJukiQRQgghhMhA9+7dMZvNLFq0yGH7rVu3WLlyJS+88IL9aeply5bh7OxM586d060rODiYBg0asG7dOpKTk+/bbkREBIUKFXrouFNvuqdOA/Yo+vfvz8yZM+nYsSMzZszgzTffxMXFxSGJs27dOho1akRcXByjR49mwoQJxMTE0LRpU3bt2vXQbVssFm7cuJHmld4Nz6SkJMLDw5k/fz49evTgyy+/pH79+owaNYoRI0Y4lJ02bRrVqlVj3LhxTJgwAa1Wy4svvsjy5cvT1Ltu3TqGDx9Oly5dmDZtGrVq1bI/tf/CCy/w008/8dNPP9GhQ4cHPr/z588DUKBAgQeO76effsLJyYmGDRvaY+jXrx8AkZGR1K1blzVr1jB48GCmTZtGqVKl6NOnD1OnTn3gOAFWr17N2bNnefXVV/nqq6/o2rUrv/zyC88991yaG9UAnTt3Jj4+nokTJ9K5c2fmzZtnn6Is1WuvvcbUqVN55pln+OSTT9DpdLRu3TpL8QQFBWGxWNJM75SR6OhonnvuOWrUqMHkyZMpVqwYAwYMcEgcWa1W2rVrx2effUbbtm356quvaN++PVOmTKFLly4O9Y0fP54ePXpQunRpvvjiC4YNG8batWtp1KgRMTEx9nJz5syhX79+BAQEMHnyZOrXr0+7du3STabc699//8VisaQ7ki1Vjx49MJvNrFixAoAuXbqwadMmIiIiHMpt2bKFq1ev0rVrV/u2fv368dZbb1G/fn2mTZvGq6++yoIFC2jZsmWatU5OnDhBt27daNGiBdOmTaNq1aqZxv+w3njjDU6dOsXYsWNp164ds2fP5oMPPqBt27ZYLBYmTJhAgwYN+PTTT9P8/B/knIQQQgghhLBThBBCCCFEusxms1K4cGElLCzMYfusWbMUQFm5cqV9m7e3t1KlSpX71jdkyBAFUA4ePJhhmU2bNikqlUr54IMPMo1v7ty5CqCsWbNGuX79unLp0iXll19+UXx8fBQXFxfl8uXLiqIoSnh4uBIeHp7m+J49eypBQUEO2wBl9OjR9s9eXl7KoEGDMozBarUqpUuXVlq2bKlYrVb79qSkJCU4OFhp0aJFpueRnvDwcAW47+vTTz+1l//oo48UNzc35eTJkw71vPPOO4pGo1EuXrzoENvdjEajUrFiRaVp06YO2wFFrVYrR44ccdh+/fr1NNfpftavX68Ayvfff69cv35duXr1qrJixQqlVKlSikqlUnbt2uVQPqvxubm5KT179kzTXp8+fZTChQsrN27ccNjetWtXxcvLK039WZHeMT///LMCKJs2bbJvGz16tAIovXv3dij7wgsvKD4+PvbP+/fvVwBl4MCBDuVeeumlLF3biIgIxdfXVwGUcuXKKf3791cWLlyoxMTEpCmb2pc+//xz+zaDwaBUrVpV8fPzU4xGo6IoivLTTz8parVa2bx5s8Pxqb/vW7duVRRFUc6fP69oNBpl/PjxDuUOHTqkaLVa+3a
2025-09-23 19:08:30 +01:00
"text/plain": [
"<Figure size 1800x500 with 3 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"first_unique_phase = df.drop_duplicates(subset='PHASE')\n",
"phase_times = first_unique_phase['T(sec)'].tolist()\n",
"\n",
"plt.figure(figsize=(18, 5))\n",
"ax1 = plt.subplot()\n",
"\n",
"# Plot VO2 Pulse\n",
2025-09-23 19:20:36 +01:00
"line1 = sns.lineplot(data=df, x='T(sec)', y='VCO2(ml/min)_smoothed', label='VCO2 (ml/min)', color='blue')\n",
2025-09-23 19:08:30 +01:00
"ax1.set_xlabel('Time (sec)')\n",
"ax1.set_ylabel('VO2 Pulse (mL/beat)')\n",
"ax1.set_title('VO2 Pulse, Heart Rate, and Speed Over Time')\n",
"ax1.set_ylim(0, df['VCO2(ml/min)'].max())\n",
"ax1.grid(True, alpha=0.1)\n",
"\n",
"# Create second y-axis for heart rate\n",
"ax2 = ax1.twinx()\n",
2025-09-23 19:20:36 +01:00
"line2 = sns.lineplot(data=df, x='T(sec)', y='HR(bpm)_smoothed', color='red', ax=ax2, \n",
2025-09-23 19:08:30 +01:00
" linewidth=2, label='Heart Rate (bpm)')\n",
"ax2.set_ylabel('Heart Rate (bpm)', color='red')\n",
"ax2.tick_params(axis='y', labelcolor='red')\n",
"\n",
"# Create third y-axis for speed\n",
"ax3 = ax1.twinx()\n",
"ax3.spines['right'].set_position(('outward', 60))\n",
2025-09-23 19:20:36 +01:00
"line3 = sns.lineplot(data=df, x='T(sec)', y='BF(bpm)_smoothed', color='green', ax=ax3, linewidth=2, label='BF (bpm)')\n",
2025-09-23 19:08:30 +01:00
"ax3.set_ylabel('BF (bpm)', color='green')\n",
"ax3.tick_params(axis='y', labelcolor='green')\n",
"\n",
"ax1.set_xticks(np.arange(0, df['T(sec)'].max() + 200, 200))\n",
"\n",
"# Remove default legends first\n",
"if ax1.get_legend():\n",
" ax1.get_legend().remove()\n",
"if ax2.get_legend():\n",
" ax2.get_legend().remove()\n",
"if ax3.get_legend():\n",
" ax3.get_legend().remove()\n",
"\n",
"# Combine legends from all axes in the top left\n",
"lines1, labels1 = ax1.get_legend_handles_labels()\n",
"lines2, labels2 = ax2.get_legend_handles_labels()\n",
"lines3, labels3 = ax3.get_legend_handles_labels()\n",
"ax1.legend(lines1 + lines2 + lines3, labels1 + labels2 + labels3, loc='upper left')\n",
"\n",
"# Add colored background regions if you have phase information\n",
"ax1.axvspan(0, phase_times[1], alpha=0.2, color='lightblue')\n",
"ax1.axvspan(phase_times[1], phase_times[2], alpha=0.2, color='purple')\n",
"ax1.axvspan(phase_times[2], phase_times[3], alpha=0.2, color='lightgreen')\n",
"ax1.axvspan(phase_times[3], df['T(sec)'].max(), alpha=0.2, color='blue')\n",
"\n",
"plt.show()"
]
2025-09-24 08:35:29 +01:00
},
{
"cell_type": "code",
2025-09-24 09:57:15 +01:00
"execution_count": 31,
2025-09-24 08:35:29 +01:00
"id": "52642f49",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>MeasurementDate</th>\n",
" <th>Comment</th>\n",
" <th>ExternalDeviceId</th>\n",
" <th>ExternalPatientId</th>\n",
" <th>FirstName</th>\n",
" <th>LastName</th>\n",
" <th>BirthDate</th>\n",
" <th>Age</th>\n",
" <th>Ethnicity</th>\n",
" <th>Gender</th>\n",
" <th>...</th>\n",
" <th>Child_XC</th>\n",
" <th>Child_XC_Unit</th>\n",
" <th>Child_BIVA_ZRh</th>\n",
" <th>Child_BIVA_ZXcH</th>\n",
" <th>Child_PhA</th>\n",
" <th>Child_PhA_Unit</th>\n",
" <th>Child_REE_Kcal</th>\n",
" <th>Child_REE_MJ</th>\n",
" <th>Child_TEE_Kcal</th>\n",
" <th>Child_TEE_MJ</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>2025-09-05T14:56:27.0000000Z</td>\n",
" <td>NaN</td>\n",
" <td>10000001583275_0055003f5631501320313557</td>\n",
" <td>LD5163301170</td>\n",
" <td>Lucy</td>\n",
" <td>Dibenedetto</td>\n",
" <td>1997-08-28T00:00:00.0000000Z</td>\n",
" <td>28</td>\n",
" <td>Caucasian</td>\n",
" <td>Female</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2025-09-03T13:16:22.0000000Z</td>\n",
" <td>NaN</td>\n",
" <td>10000001583275_0055003f5631501320313557</td>\n",
" <td>NS6479273340</td>\n",
" <td>Niyanta</td>\n",
" <td>Shah</td>\n",
" <td>1985-03-11T00:00:00.0000000Z</td>\n",
" <td>40</td>\n",
" <td>Other</td>\n",
" <td>Female</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>2025-09-03T13:14:23.0000000Z</td>\n",
" <td>NaN</td>\n",
" <td>10000001583275_0055003f5631501320313557</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>1985-03-11T00:00:00.0000000Z</td>\n",
" <td>40</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>2025-08-27T20:57:32.0000000Z</td>\n",
" <td>NaN</td>\n",
" <td>10000001583275_0055003f5631501320313557</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>1996-04-05T00:00:00.0000000Z</td>\n",
" <td>29</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>2025-08-20T14:01:13.0000000Z</td>\n",
" <td>NaN</td>\n",
" <td>10000001583275_0055003f5631501320313557</td>\n",
" <td>MW4167267833</td>\n",
" <td>Monica</td>\n",
" <td>Wong</td>\n",
" <td>1985-02-17T00:00:00.0000000Z</td>\n",
" <td>40</td>\n",
" <td>Asian</td>\n",
" <td>Female</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>58</th>\n",
" <td>2025-04-10T14:10:28.0000000Z</td>\n",
" <td>NaN</td>\n",
" <td>10000001583275_0055003f5631501320313557</td>\n",
" <td>6473915195</td>\n",
" <td>Tristan</td>\n",
" <td>Walsh</td>\n",
" <td>1995-12-01T00:00:00.0000000Z</td>\n",
" <td>29</td>\n",
" <td>Caucasian</td>\n",
" <td>Female</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>59</th>\n",
" <td>2025-04-02T21:19:51.0000000Z</td>\n",
" <td>NaN</td>\n",
" <td>10000001583275_0055003f5631501320313557</td>\n",
" <td>WSC4168020667</td>\n",
" <td>Scott</td>\n",
" <td>Christie</td>\n",
" <td>1968-08-19T00:00:00.0000000Z</td>\n",
" <td>56</td>\n",
" <td>Caucasian</td>\n",
" <td>Male</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>60</th>\n",
" <td>2025-04-02T15:23:54.0000000Z</td>\n",
" <td>NaN</td>\n",
" <td>10000001583275_0055003f5631501320313557</td>\n",
" <td>6478809838</td>\n",
" <td>Lauren</td>\n",
" <td>Karatanevski</td>\n",
" <td>1984-07-07T00:00:00.0000000Z</td>\n",
" <td>40</td>\n",
" <td>Caucasian</td>\n",
" <td>Female</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>61</th>\n",
" <td>2025-03-26T15:47:42.0000000Z</td>\n",
" <td>NaN</td>\n",
" <td>10000001583275_0055003f5631501320313557</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>2002-07-10T00:00:00.0000000Z</td>\n",
" <td>22</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>62</th>\n",
" <td>2025-03-19T15:10:21.0000000Z</td>\n",
" <td>NaN</td>\n",
" <td>10000001583275_0055003f5631501320313557</td>\n",
" <td>6478809838</td>\n",
" <td>Lauren</td>\n",
" <td>Karatanevski</td>\n",
" <td>1984-07-07T00:00:00.0000000Z</td>\n",
" <td>40</td>\n",
" <td>Caucasian</td>\n",
" <td>Female</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>63 rows × 147 columns</p>\n",
"</div>"
],
"text/plain": [
" MeasurementDate Comment \\\n",
"0 2025-09-05T14:56:27.0000000Z NaN \n",
"1 2025-09-03T13:16:22.0000000Z NaN \n",
"2 2025-09-03T13:14:23.0000000Z NaN \n",
"3 2025-08-27T20:57:32.0000000Z NaN \n",
"4 2025-08-20T14:01:13.0000000Z NaN \n",
".. ... ... \n",
"58 2025-04-10T14:10:28.0000000Z NaN \n",
"59 2025-04-02T21:19:51.0000000Z NaN \n",
"60 2025-04-02T15:23:54.0000000Z NaN \n",
"61 2025-03-26T15:47:42.0000000Z NaN \n",
"62 2025-03-19T15:10:21.0000000Z NaN \n",
"\n",
" ExternalDeviceId ExternalPatientId FirstName \\\n",
"0 10000001583275_0055003f5631501320313557 LD5163301170 Lucy \n",
"1 10000001583275_0055003f5631501320313557 NS6479273340 Niyanta \n",
"2 10000001583275_0055003f5631501320313557 NaN NaN \n",
"3 10000001583275_0055003f5631501320313557 NaN NaN \n",
"4 10000001583275_0055003f5631501320313557 MW4167267833 Monica \n",
".. ... ... ... \n",
"58 10000001583275_0055003f5631501320313557 6473915195 Tristan \n",
"59 10000001583275_0055003f5631501320313557 WSC4168020667 Scott \n",
"60 10000001583275_0055003f5631501320313557 6478809838 Lauren \n",
"61 10000001583275_0055003f5631501320313557 NaN NaN \n",
"62 10000001583275_0055003f5631501320313557 6478809838 Lauren \n",
"\n",
" LastName BirthDate Age Ethnicity Gender ... \\\n",
"0 Dibenedetto 1997-08-28T00:00:00.0000000Z 28 Caucasian Female ... \n",
"1 Shah 1985-03-11T00:00:00.0000000Z 40 Other Female ... \n",
"2 NaN 1985-03-11T00:00:00.0000000Z 40 NaN NaN ... \n",
"3 NaN 1996-04-05T00:00:00.0000000Z 29 NaN NaN ... \n",
"4 Wong 1985-02-17T00:00:00.0000000Z 40 Asian Female ... \n",
".. ... ... ... ... ... ... \n",
"58 Walsh 1995-12-01T00:00:00.0000000Z 29 Caucasian Female ... \n",
"59 Christie 1968-08-19T00:00:00.0000000Z 56 Caucasian Male ... \n",
"60 Karatanevski 1984-07-07T00:00:00.0000000Z 40 Caucasian Female ... \n",
"61 NaN 2002-07-10T00:00:00.0000000Z 22 NaN NaN ... \n",
"62 Karatanevski 1984-07-07T00:00:00.0000000Z 40 Caucasian Female ... \n",
"\n",
" Child_XC Child_XC_Unit Child_BIVA_ZRh Child_BIVA_ZXcH Child_PhA \\\n",
"0 NaN NaN NaN NaN NaN \n",
"1 NaN NaN NaN NaN NaN \n",
"2 NaN NaN NaN NaN NaN \n",
"3 NaN NaN NaN NaN NaN \n",
"4 NaN NaN NaN NaN NaN \n",
".. ... ... ... ... ... \n",
"58 NaN NaN NaN NaN NaN \n",
"59 NaN NaN NaN NaN NaN \n",
"60 NaN NaN NaN NaN NaN \n",
"61 NaN NaN NaN NaN NaN \n",
"62 NaN NaN NaN NaN NaN \n",
"\n",
" Child_PhA_Unit Child_REE_Kcal Child_REE_MJ Child_TEE_Kcal Child_TEE_MJ \n",
"0 NaN NaN NaN NaN NaN \n",
"1 NaN NaN NaN NaN NaN \n",
"2 NaN NaN NaN NaN NaN \n",
"3 NaN NaN NaN NaN NaN \n",
"4 NaN NaN NaN NaN NaN \n",
".. ... ... ... ... ... \n",
"58 NaN NaN NaN NaN NaN \n",
"59 NaN NaN NaN NaN NaN \n",
"60 NaN NaN NaN NaN NaN \n",
"61 NaN NaN NaN NaN NaN \n",
"62 NaN NaN NaN NaN NaN \n",
"\n",
"[63 rows x 147 columns]"
]
},
2025-09-24 09:57:15 +01:00
"execution_count": 31,
2025-09-24 08:35:29 +01:00
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_2 = pd.read_excel('data/SECA body comp for all patients.xlsx')\n",
"df_2"
]
},
{
"cell_type": "code",
2025-09-24 09:57:15 +01:00
"execution_count": 36,
2025-09-24 08:35:29 +01:00
"id": "2056096d",
"metadata": {},
"outputs": [
{
"data": {
2025-09-24 09:57:15 +01:00
"image/png": "iVBORw0KGgoAAAANSUhEUgAABLAAAAEiCAYAAADptysgAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQAANzVJREFUeJzt3Xl0VdX9/vHnZiQhEGbCFEIgEQiCBARBRSiogAIiY+sQtBVBsFoG4adFUNoKUlAKLVarURegODGpaAWBqkQmCfNsGCWADGFOQrJ/f7ByvjlkDhk24f1a6y65Z599zr73wya5j/uc6zHGGAEAAAAAAACW8irtAQAAAAAAAAC5IcACAAAAAACA1QiwAAAAAAAAYDUCLAAAAAAAAFiNAAsAAAAAAABWI8ACAAAAAACA1QiwAAAAAAAAYDUCLAAAAAAAAFiNAAsAAAAAAABWI8ACAKAM8Hg82T58fHwUHByspk2b6pFHHtGSJUtKZXwTJkxwjevdd98tlfPm9rjllltKZEz5tWLFilzHW6FCBTVp0kR/+MMftGbNmtIeLgrp3LlzWrx4scaMGaOOHTsqMjJSlSpVkp+fn0JCQtSlSxe98cYbSklJybb/2rVrNXXqVD344INq3ry5QkJC5Ofnp+DgYLVs2VIjR47Uzz//XGTjPX/+vBo1apTl7+O+ffuy7Ltz504NHDhQNWrUkK+vr+rWrasnnnhCiYmJOR47LCxMHo9HL7/8cpGNGQBQNhBgAQBQhqWlpenMmTPavn27Zs+ere7du+vxxx8v7WGVae+++67rg/2ECROK5Tznzp3Tjh079Pbbb+u2227T2LFji+U8ZVFJ1Sg/vvrqK/Xs2VOvvvqqVq5cqd27dyspKUmpqak6evSoli1bpqFDh6ply5Y6ePBglv6dOnXSqFGjNH/+fG3evFlHjx5Vamqqzpw5o/j4eE2bNk1RUVGaM2dOkYx39OjR2rt3b5777d69W23bttW8efN04sQJ1ahRQ4cPH9Z//vMf3XbbbTp58mSWPn/+85+1f/9+RUVF8fcZAJCFT2kPAAAAFL1u3bopMDBQqampio+P14EDB5y22NhY9evXT926dSvFEZaO+vXrq3Xr1tm2NWjQoIRHUzCBgYFOzc6ePau1a9fq1KlTkiRjjCZPnqzIyEgCyutYQECAWrVqpQoVKmjTpk06fPiw07Zt2zYNGDBAq1atyrF/06ZN1aBBAx05ckQ//fSTs/3SpUsaNGiQbrnlFkVFRRV6fN98841mzZqVr33/+te/KikpSZK0cOFC3X///Zo5c6aefvpp7d+/XzNnztSLL77o7L9u3TrNmDFDXl5eeuutt+Tn51focQIAyiYCLAAAyqB//etfCgsLkySlpqbqjjvucF1mtmzZshsywOrYsWOJXb5Y1KpXr65PPvnEeX7ixAl17NhRW7Zscbb9/e9/J8C6DkVGRmrs2LEaOHCgAgICJF2Zt8OHD9ebb77p7BcXF6eNGzeqRYsWzraAgAANHTpUw4YNc+a8JC1dulTdu3dXamqqJOny5cv6z3/+o9dee61QY0xKSnL+bgUHB8vj8ej06dM57r927VpJUuXKlXX//fdLkh599FE9/fTTkuT69ygtLU2DBw9WWlqahg0bpnbt2hVqjACAso1LCAEAKON8fX3VoUMH17aLFy9mu++5c+c0Y8YMdenSRTVr1nTupdO8eXP98Y9/1Pbt23M8z8mTJ/WnP/1J9evXl7+/v0JDQzVs2DAdO3Ysxz6rVq1yXcr10EMPZbtfz549XftlDm2Kw/fff68//elP6tSpkxo2bKjKlSs79xO7+eabNXToUG3cuNHVJ+OytMcee8y1/aWXXiqWy9WqVq2qESNGuLZt375d586dc227ePGi3njjDd17772u+yO1bt1aL730kk6cOJHt8TOPOSwsTCkpKXr11VfVvHlzlS9fXh6Px7W/MUaLFi3SwIED1bBhQwUFBSkgIEChoaHq1q1bjit3vvvuO8XExCgiIkJBQUEqV66cGjRooJiYGCcEudqgQYNc41uxYoU2bNig/v37q0aNGvL391ejRo00btw4JScnO/1Kukb5cdddd2nLli167LHHnPBKujJvX3/9dfn4uP9/844dO1zPN27cqClTprjCK0nq0qWL+vfvn2vfgnj66ad16NAhSdKMGTMUHBxc6GNd7bXXXtOGDRtUt25dvfLKK0V2XABAGWMAAMB1T5LrkZCQ4LSlpKSYtm3butpjY2OzHCM+Pt6EhYVlOVbmh4+Pj/n73/+epe+hQ4dMeHh4tn1q1aplfve73+V4/vbt2zvb/fz8TGJiouvYv/76q/H19XX2ueOOO/L9vowfP9513piYmHz1GzZsWK7vgyTj7e1t3n77badPbGxsnn0kmfHjx+drDMuXL3f1q1+/fpZ9vvjiiyzH/+WXX5z2bdu2mcjIyFzHExISYlatWpXl2FfXsHPnzln6Zjh27Ji56667cj3P1eNPTU01jz32WK59PB6PGTduXJaxxcTEuPZ76KGHjLe3d7bHeOCBB4qtRiWhWrVqrrEtWbIk331HjRrl6jtgwIBCjWH+/PnOMR588EFjjDH169fP8d8cY4wZNGiQ07Z48WJjjDEzZsxwtr388svGGGMSEhJMYGCgkWQWLVpUqPEBAG4MXEIIAEAZ9NRTTykwMFCXL19WfHy89u/f77Tdeeed+t3vfufa/9dff9W9996ro0ePOtuqVq2q6OhoHT58WNu2bZN05TKkUaNGKSQkxLVaatCgQa5vOvP19VXbtm11+fJlrV27VnPnzs1xrKNHj1bv3r0lSSkpKXrrrbf05z//2WmfN2+ecxmUJA0ZMqSgb4djxYoV6tu3b7Ztw4cPV8eOHZ3nXl5eioyMVPXq1VW5cmWlpqZq3759ziq0jMudunXrplq1aiksLEx9+vTR/v37tW7dOuc4TZo0UdOmTZ3nmf98rTLf50i68r5XrVpVknTq1Cndc889zqoZSWrUqJFuuukmHT161BljYmKievTooU2bNql27drZnufIkSM6cuSIypcvr+joaJUrV85ZHZWWlqbu3bu7XrN05bK4Ro0a6ezZs1naJOmZZ55RbGys87xChQpq27atvLy8tGrVKp07d07GGE2cOFG1a9fOte5z5syRv7+/br/9dp06dUqbN2922hYsWKBVq1apffv2pVKja7F69Wr9+uuvzvPAwEC1bds2X33T0tKyfOvob37zmwKP4fjx43ryySclSTVq1NAbb7yRr37PP/+85s+fr6SkJPXq1UshISH65ZdfJF25F92wYcMkSUOHDtWFCxfUr18/9ejRo8DjAwDcQEo7QQMAANdO+VhVIsk0bNjQ7N27N0v/sWPHuvZr27atOXXqlNM+ceJEV3udOnVMWlqaMcaYdevWudp8fX1NXFyc03fJkiXG4/HkuAIrLS3NtUqobt26JjU11WnPvEKrWrVq5tKlS/l+X65egZXbI/OYdu/ebU6fPp3tMWfOnOnqN2vWLFf71at8CruaJ7cVWGfPnjUfffSRqVixomufrl27Ovv8+c9/drVNmjTJdfy5c+e62ocPH+5qv/r9ueWWW8yhQ4ec9ow6vPPOO679AgICnBU3mcf7/vvvO8937txpvLy8nD5t2rQxSUlJTvvRo0dNvXr1nPaqVaua5ORkp/3qFVjBwcEmPj4+x/aXXnrJNZ6iqlFxOnHihGnatKlrnC+88EK++48ZM8bVt1GjRubChQsFHseDDz7oHGPBggXO9rxWYBljzI4dO0z//v1N9erVjY+Pj6ldu7b5wx/+YI4cOWKM+b+/g5UqVXK2LViwwDz88MOmU6dOpnfv3mbmzJnm4sWLBR43AKDsYQUWAAA3kL1796p58+ZavHixOnXq5GxftGiRa78JEyaoUqVKzvOxY8dq1qxZzgqKw4cP66efflLr1q31zTffuPr26dNHt912m/O8a9eu6ty5s5YuXZrtmLy8vDRy5EhnlcehQ4e0YMEC9e3bVwkJCa5vXRs0aJD8/f0L9+ILIDw8XJ988onmzZun+Ph4JSYm6uLFizLGZNn3Wu4
2025-09-24 08:35:29 +01:00
"text/plain": [
"<Figure size 1200x300 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"body_fat_chart = {\n",
" \"male\": {\n",
" \"20-39\": {\n",
2025-09-24 09:57:15 +01:00
" \"bad\": [(0, 5), (25, 50)],\n",
" \"okay\": [(5, 10), (20, 25)],\n",
" \"good\": [(10, 20)]\n",
2025-09-24 08:35:29 +01:00
" },\n",
" \"40-59\": {\n",
2025-09-24 09:57:15 +01:00
" \"bad\": [(0, 5), (30, 50)],\n",
" \"okay\": [(5, 10), (20, 30)],\n",
" \"good\": [(10, 20)]\n",
2025-09-24 08:35:29 +01:00
" },\n",
" \"60-79\": {\n",
2025-09-24 09:57:15 +01:00
" \"bad\": [(0, 5), (30, 50)],\n",
" \"okay\": [(5, 10), (20, 25)],\n",
" \"good\": [(10, 25)]\n",
2025-09-24 08:35:29 +01:00
" }\n",
" },\n",
" \"female\": {\n",
" \"20-39\": {\n",
" \"bad\": [(0, 15), (40, 50)],\n",
" \"okay\": [(15, 20), (35, 40)],\n",
" \"good\": [(20, 35)]\n",
" },\n",
" \"40-59\": {\n",
" \"bad\": [(0, 20), (40, 50)],\n",
" \"okay\": [(20, 25), (35, 40)],\n",
" \"good\": [(25, 35)]\n",
" },\n",
" \"60-79\": {\n",
" \"bad\": [(0, 20), (40, 50)],\n",
" \"okay\": [(20, 25), (35, 40)],\n",
" \"good\": [(25, 35)]\n",
" }\n",
" }\n",
"}\n",
2025-09-24 09:57:15 +01:00
"\n",
2025-09-24 08:35:29 +01:00
"def create_body_fat_visualization(gender, age, body_fat_percentage):\n",
" # Determine age group\n",
" if 20 <= age <= 39:\n",
" age_group = \"20-39\"\n",
" elif 40 <= age <= 59:\n",
" age_group = \"40-59\"\n",
" elif 60 <= age <= 79:\n",
" age_group = \"60-79\"\n",
" else:\n",
" return \"Age out of range (20-79)\"\n",
" \n",
" # Get ranges for the specific gender and age group\n",
" ranges = body_fat_chart[gender.lower()][age_group]\n",
" \n",
" # Create figure\n",
" fig, ax = plt.subplots(figsize=(12, 3))\n",
" \n",
" # Define colors for different categories\n",
2025-09-24 09:57:15 +01:00
" colors = {'bad': '#ff6b6b', 'okay': '#ffeb3b', 'good': '#90ee90'}\n",
2025-09-24 08:35:29 +01:00
" \n",
" # Create the horizontal segments\n",
" bar_height = 0.4\n",
" y_position = 0\n",
" \n",
" # Plot each category's ranges\n",
" for category, ranges_list in ranges.items():\n",
" for range_tuple in ranges_list:\n",
" start, end = range_tuple\n",
" width = end - start\n",
" ax.barh(y_position, width, left=start, height=bar_height, \n",
2025-09-24 09:57:15 +01:00
" color=colors[category], alpha=0.9, edgecolor='black', linewidth=0.5)\n",
2025-09-24 08:35:29 +01:00
" \n",
" # Add the user's body fat percentage marker (triangle pointing down)\n",
2025-09-24 09:57:15 +01:00
" ax.plot(body_fat_percentage, y_position + bar_height / 2 + 0.05, 'v', markersize=15, color='black')\n",
2025-09-24 08:35:29 +01:00
" \n",
" # Customize the chart\n",
" ax.set_xlim(0, 50)\n",
2025-09-24 09:57:15 +01:00
" ax.set_ylim(-1, 1)\n",
" ax.set_xlabel('')\n",
2025-09-24 08:35:29 +01:00
" ax.set_title(f'Body Fat Percent - {body_fat_percentage:.1f}%', fontsize=16, fontweight='bold', pad=20)\n",
" \n",
2025-09-24 09:57:15 +01:00
" # Add age group and gender label on the left side\n",
" ax.text(-5, y_position, f'{age_group}\\n({gender[0].upper()})', ha='center', va='center', fontsize=12)\n",
" \n",
" # Adjust x-axis ticks to match the image\n",
" ax.set_xticks(range(0, 51, 5))\n",
" ax.set_xticklabels([f'{i}%' for i in range(0, 51, 5)])\n",
" \n",
" # Draw vertical lines for the tick marks\n",
" for tick in range(0, 51, 5):\n",
" ax.plot([tick, tick], [y_position - bar_height / 2, y_position - bar_height / 2 - 0.1], color='black', linewidth=1.5)\n",
2025-09-24 08:35:29 +01:00
" \n",
" # Remove y-axis and top/right spines\n",
" ax.set_yticks([])\n",
" ax.spines['left'].set_visible(False)\n",
" ax.spines['right'].set_visible(False)\n",
" ax.spines['top'].set_visible(False)\n",
2025-09-24 09:57:15 +01:00
" ax.spines['bottom'].set_visible(False)\n",
2025-09-24 08:35:29 +01:00
" \n",
" plt.tight_layout()\n",
2025-09-24 09:57:15 +01:00
" plt.savefig('graphs/page_1_body_fat.png')\n",
2025-09-24 08:35:29 +01:00
" plt.show()\n",
"\n",
"# Create the chart using Keirstyn's data\n",
"gender = 'female'\n",
2025-09-24 09:57:15 +01:00
"age = 25\n",
"fat_percentage = 22.4\n",
2025-09-24 08:35:29 +01:00
"create_body_fat_visualization(gender, age, fat_percentage)"
]
},
{
"cell_type": "code",
2025-09-26 16:37:46 +01:00
"execution_count": null,
2025-09-24 08:35:29 +01:00
"id": "bf55717b",
"metadata": {},
"outputs": [
{
"data": {
2025-09-24 09:57:15 +01:00
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAxkAAAKXCAYAAADuLofjAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQAAlwlJREFUeJzs3Xd4VGX6xvHvmUklPUDovUlHEURBpSlYwY5lLVh27d3V3VVsa/m5urZ1XQv2tSzYQAER6QpSpUnvnYSWhNQ55/fHIYEhATLJJGfOzP25rrkgM2dmniST5Nzzvs/7GpZlWYiIiIiIiASJx+kCREREREQkvChkiIiIiIhIUClkiIiIiIhIUClkiIiIiIhIUClkiIiIiIhIUClkiIiIiIhIUClkiIiIiIhIUClkiIiIiIhIUClkiIiIiIhIUClkiEhYeP/99zEMw+8iEqgjX0Pvv/9+lR5Pr0sRiVRRThcgIqGnb9++TJ06tdzbPB4PtWrVom7dupxwwgkMGDCA66+/ntq1a9dwle6wefNmPvnkE6ZPn87SpUvJysoiLy+P5ORkWrRoQY8ePTj//PMZPHgwXq/X6XKlAh5//HG/j4cOHUq3bt0cqUVEJFQpZIhIQEzTJCcnh5ycHNatW8e4ceN46qmnGD16NAMGDHC6vJCxf/9+7rvvPj744AOKi4vL3L579252797NvHnzePPNN+nevTtz5851oFIJ1BNPPOH3cfPmzRUyRESOoJAhIlW2b98+rrjiCtasWUNKSorT5Thu3bp1DBw4kLVr11b4PpmZmdVYkVTUunXr/D6uU6dOlR7v0ksvpW/fvlV6DBERN1LIEJEKKTn58vl8/P7779x9991+J9FZWVmMHz+eK664wqkSQ8K+ffs455xzygSM1NRU7rzzTs466yzq169Pbm4uy5cvZ8KECXzxxRcOVStHat68eVAfLzExkcTExKA+poiIG6jxW0QqpHnz5jRv3pxWrVpx/vnn8/TTT5c5Zv369Ue9/9atW3n88cfp06cPdevWJSYmhpSUFDp27Mgtt9zCL7/8ctwavvvuO84++2zS09NJSEiga9euvPDCCxQWFh7zfh999JFf421ycjK5ubnlHnvnnXf6HXvaaacdt67DPf3006xYscLvug4dOrB06VKefPJJTj/9dNq0aUO3bt0YNmwY7733Hhs3buSWW24p9/Esy2LMmDFcddVVtG7dmqSkJGJjY2nQoAFnn302L7/8Mvv37y/3vuvXry/TdDxlyhQ2bdrEzTffTJMmTYiPj6dt27Y89thjfl+TmTNnMmTIEDIyMoiPj6dTp04888wzFBQUlPtczZs393uexx9/HJ/PxxtvvMEpp5xCcnIySUlJnHrqqYwcORLLso75dVy1ahUPPvggPXr0oHbt2kRHR5Oens6JJ57I3XffzdKlS496X8uy+PLLL7n00ktp3bo1CQkJREdHU69ePTp16sTFF1/Mc889x8yZM8vc92iN34d/LY90ww03+N3n8KASSOP3nj17eOGFFxg4cCD169cnNjaWpKQk2rRpwx/+8AcmTJhw1Ps+/vjj5dYwZ84chg0bRoMGDYiNjaVJkybccsstbNmy5aiPJSISFJaIyBHOPPNMC/C7HOnTTz8tc8x//vOfch/vX//6lxUbG1vm+CMvV155pZWdnV3uYzz00ENHvd/JJ59s/fOf/zxqzQUFBVa9evX8bnv77bfLPIfP57Pq16/vd9w777xT4a9bdna2FRcX53f/6Ohoa8WKFRV+jMNt2rTJOu200477datTp441fvz4Mvdft25dmWOfffZZKzk5udzHOfHEE62cnBzrlVdesTweT7nHnHXWWZbP5yvzXM2aNfM77v777y/3dVRyueSSS6zCwsIyj+Pz+ay//e1vR33+kothGNa9995rFRUV+d3fNE3rsssuO+7XDLDatWtX5vmPPOa999476tfyaJdmzZqVPt5777133J8ly7Ks0aNHW6mpqcd97AEDBlg7duwoc/8RI0aUqeH5558/6texYcOG1ubNm8utRUQkGBQyRKSM8k4O161bZ61bt85avXq19d1331mtW7f2uz0qKsrasGFDmcd6/fXXK3xyBliDBw+2iouL/R6jvBO1Iy+1atU65sncY4895ndbz549y9Q6efJkv2MSEhKOGnrK8/XXX5epYdiwYRW+/+GysrKstm3bVvjrFh0dbU2ePNnvMco7MTYM45iP07dv3+MeM3LkyDL1HhkyoqOjj1vzn//85zKPc//99wf0ern55pv97j9q1KgK3zdUQsY333xz3FB1+KUkDB7uyJBxvO8hYF1zzTVHe/mJiFSZpkuJSIW0aNGCFi1a0Lp1a8477zxWr15deltUVBT/+te/aNq0qd99Nm/ezAMPPOB3XWpqKv/5z3/47bff+O677+jevbvf7ePHj+ejjz4q/bioqIhHHnnE75ioqCiefvpp5s+fz4QJEzjttNM4cODAMeu/9dZbiYmJKf34119/ZdGiRX7HfP75534fX3755QHNp1+wYEGZ6yq74tZjjz3GypUr/a676KKLmDRpEvPmzeOpp54iKupQW11RURE333xzuStZHc6yLG644QYWLlzIlClTaNWqld/tU6ZMwbIsHn74YZYsWcJXX31Famqq3zGffPLJcesvKiqiXbt2fPXVVyxatIj//Oc/JCUl+R3z4osv+k3bmTt3Li+++KLfMY0bN+a///0vixcvZtSoUbRs2dLv9rfffpspU6aUfnzk0stnn302U6ZMYeXKlSxevJjvvvuOp59+mn79+vl9/Y6ncePGrFu3rkxjOMALL7xQetu6deuYMWNGhR83NzeXW265BdM0S6+LjY3lhRdeYP78+UycOJFBgwb53WfBggW88MILx3xcy7Lwer08/fTTLFmyhG+//ZaGDRv6HTNq1CiKiooqXKuISEAcDjkiEoKONc2lvMutt95a5p1Vy7KsJ598ssyxP/74o98x2dnZVp06dY46yvD999+XeYwnn3zS7zEOHDhgZWRkHPcd46uvvtrv9ttuu630tuLi4jKPMWPGjIC+brfddluZGsaNGxfQY1iWZeXn55cZmTn99NPLHPfss8+Web7vv/++9Pby3n0/8cQTLdM0S4959dVXyxwzdOhQv+e55557/G6vU6dOmVqOHMmIjY21tm7d6nfM6NGjyzzXP/7xj9Lbhw8f7nebx+MpM9Vsw4YNZUZJLr/88tLbb731Vr/bPvvss6N+nffv31/muiPrKxnJCPSYEscbyfjwww/L3H7kFL3i4mKrQ4cOfsfUq1fP7/t45EgGYD388MN+j/O///2vzDFLliw5au0iIlWhkQwRqbJ///vf9OjRg+3bt/tdf+S7yq1atSrzzn5iYiJXXXWV33Vz584tHZmYPXt2mecbPny438fx8fFlHqM8d911l9/Hn3zySenzTJ48mZ07d5be1q5dO3r37n3cx6wOc+bMKTMyc/PNN5c57o9//GOZ66ZNm3bMx77mmmv8mo9btGhR5phrr73W7+O2bdv6fbxnz55jPgfAOeecQ4MGDfyuGzp0KOnp6X7XzZo1q/T/R75e+vbtW+a5mzZtyjnnnON33eGf85EjYzfddBNXXHEFTz75JJ999hmLFi3C5/MBlBlZccKRn3NcXFyZr7/X6+Wmm27yu27Hjh1lRrqOdMcdd/h9fMIJJ5Q5piLfSxGRylDIEJEKseweLkzTZOvWrTzzzDN+t5csa3u4rVu3+n185FSXo11vmiY7duwAKP23RGxsbJlpH1D+yfKRevbsSa9evUo/3rdvX+nysUcuI3tkkKmIunXrlrlu8+bNAT/OkV83oMy0JoC0tLQyU5nKu+/hjvxa16pVq8wxR34t4+Pj/T4uOUk/lvK+Hx6Ph2bNmvldd3gwPbL28j5nKPs57Nixo7Sma665hp49e5belpOTwxdffMGIESO48sor6dq1K2lpaVx77bWsWrXquJ9HdTvyc27SpAnR0dFljivvZ+dY3+vExEQaNWrkd92R30fguNPrREQqSyFDRAJiGAYNGjTgkUceYciQIX63jRo1ir1
2025-09-24 08:35:29 +01:00
"text/plain": [
"<Figure size 800x800 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Filter df_2 for Keirstyn Moran\n",
"keirstyn_data = df_2[df_2['LastName'].str.contains('Moran', case=False, na=False)]\n",
"# Get the fat mass percentage for Keirstyn\n",
"fat_percentage = keirstyn_data['Adult_FMP'].iloc[0]\n",
2025-09-24 09:57:15 +01:00
"weight_kg = keirstyn_data['Weight'].iloc[0]\n",
2025-09-24 08:35:29 +01:00
"age = keirstyn_data['Age'].iloc[0]\n",
"gender = keirstyn_data['Gender'].iloc[0]\n",
"lean_percentage = 100 - fat_percentage\n",
"\n",
"# Create donut chart\n",
2025-09-24 09:57:15 +01:00
"fat_mass_lbs = 27.6\n",
"lean_mass_lbs = 95.4\n",
2025-09-24 08:35:29 +01:00
"\n",
2025-09-24 09:57:15 +01:00
"# Calculate percentages from the provided weights\n",
"total_weight = fat_mass_lbs + lean_mass_lbs\n",
"fat_percentage = (fat_mass_lbs / total_weight) * 100\n",
"lean_percentage = (lean_mass_lbs / total_weight) * 100\n",
2025-09-24 08:35:29 +01:00
"\n",
2025-09-24 09:57:15 +01:00
"# Data for the chart\n",
"sizes = [fat_percentage, lean_percentage]\n",
"labels = ['Fat Mass (27.6lbs)', 'Lean Mass (95.4lbs)']\n",
"colors = ['#fde3ac', '#ff9966'] # Light yellow/tan and orange from the image\n",
"\n",
"plt.figure(figsize=(8, 8))\n",
"# Create the donut chart\n",
"wedges, texts, autotexts = plt.pie(sizes,\n",
" autopct='%1.1f%%',\n",
" startangle=90,\n",
" wedgeprops=dict(width=0.5, edgecolor='w'),\n",
" colors=colors)\n",
"\n",
"# Customize the text for labels and percentages\n",
"for i, (text, autotext) in enumerate(zip(texts, autotexts)):\n",
" # Set the label text to be the full label, not just the percentage\n",
" text.set_text(labels[i])\n",
" text.set_fontsize(14)\n",
" text.set_color('black')\n",
"\n",
" # Position the percentage text inside the donut\n",
" autotext.set_fontsize(14)\n",
" autotext.set_color('black')\n",
"\n",
"# Set the title\n",
"plt.title('Body Composition', fontsize=18, fontweight='bold')\n",
"plt.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle\n",
"plt.savefig('graphs/page_1_body_composition.png')\n",
2025-09-24 08:35:29 +01:00
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "21c1c0a5",
"metadata": {},
"outputs": [],
"source": []
2025-09-23 15:53:15 +01:00
}
],
"metadata": {
"kernelspec": {
"display_name": "report_generation",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}