2025-09-23 15:53:15 +01:00
{
"cells": [
{
"cell_type": "code",
2025-09-23 17:14:36 +01:00
"execution_count": 34,
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-23 17:14:36 +01:00
"execution_count": 35,
2025-09-23 15:53:15 +01:00
"id": "b0ee2af1",
"metadata": {},
"outputs": [
{
2025-09-23 17:14:36 +01:00
"name": "stdout",
"output_type": "stream",
"text": [
"Column names and data types after conversion:\n",
"T(sec) float64\n",
"PHASE object\n",
"HR(bpm) float64\n",
"VO2(ml/min) float64\n",
"VCO2(ml/min) float64\n",
"RER float64\n",
"VE(l/min) float64\n",
"FEO2 float64\n",
"FECO2 float64\n",
"FETO2 int64\n",
"FETCO2 int64\n",
"PETO2 (mmHg) int64\n",
"PETCO2(mmHg) int64\n",
"FIO2 float64\n",
"FICO2 float64\n",
"VT(l) float64\n",
"BF(bpm) float64\n",
"EE(kcal/day) float64\n",
"EE(kcal/min) float64\n",
"CARBS(kcal) float64\n",
"CARBS(%) float64\n",
"FAT(kcal) float64\n",
"FAT(%) float64\n",
"MET float64\n",
"CUMULATIVE EE(kcal) float64\n",
"BP(kPa) float64\n",
"Watts float64\n",
"Speed float64\n",
"dtype: object\n",
"\n",
"First few rows:\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_3000/3236648660.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",
" 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",
"\n",
"# Display column names and data types to verify conversion\n",
"print(\"Column names and data types after conversion:\")\n",
"print(df.dtypes)\n",
"print(\"\\nFirst few rows:\")"
2025-09-23 15:53:15 +01:00
]
},
{
"cell_type": "code",
2025-09-23 17:14:36 +01:00
"execution_count": 36,
2025-09-23 15:53:15 +01:00
"id": "98da3827",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Phase transition times: [3.0, 54.0, 233.0, 1733.0]\n"
]
}
],
"source": [
"first_unique_phase = df.drop_duplicates(subset='PHASE')\n",
"phase_times = first_unique_phase['T(sec)'].tolist()\n",
"print(f\"Phase transition times: {phase_times}\")"
]
},
{
"cell_type": "code",
2025-09-23 17:14:36 +01:00
"execution_count": 37,
2025-09-23 15:53:15 +01:00
"id": "ef8bc7ac",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABeAAAAHWCAYAAAAfLimnAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzsnXeYJFW9/t+qzjM9OW5OhA0ssOQkoCKgGBDBK6iABL1XzPfCFb1KUhFQMMBPQJRVEVRQZBVB8pJZ4uacd3Zy6uncFX5/VJ2qU9XVcTrM7Hw/z7MPzEx31+kKp0695z3vV1BVVQVBEARBEARBEARBEARBEARBECVFrHYDCIIgCIIgCIIgCIIgCIIgCOJAhAR4giAIgiAIgiAIgiAIgiAIgigDJMATBEEQBEEQBEEQBEEQBEEQRBkgAZ4gCIIgCIIgCIIgCIIgCIIgygAJ8ARBEARBEARBEARBEARBEARRBkiAJwiCIAiCIAiCIAiCIAiCIIgyQAI8QRAEQRAEQRAEQRAEQRAEQZQBEuAJgiAIgiAIgiAIgiAIgiAIogyQAE8QBEEQBEEQBEEQBEEQBEEQZYAEeIIgCIIgCIKYZAiCgOuvv77azSAIgiAIgiAIIgckwBMEQRAEQRCEjeXLl0MQBOOf2+3GjBkzcOmll6Krq6vazSsLr776Kq6//nqMjIxUuykEQRAEQRAEccDgrnYDCIIgCIIgCGKicuONN2LevHmIx+N4/fXXsXz5crz88stYt24d/H5/1doVi8Xgdpd2KP/qq6/ihhtuwKWXXorGxsaSfjZBEARBEARBTFVIgCcIgiAIgiCIDHz4wx/GMcccAwC44oor0NrailtuuQUrVqzApz/96aq1Kx/xPxKJoLa2tgKtyYyqqojH4wgEAlVtB0EQBEEQBEFUC4qgIQiCIAiCIIg8ed/73gcA2L59u/G7TZs24fzzz0dzczP8fj+OOeYYrFixwvK+VCqFG264AQcffDD8fj9aWlpwyimn4OmnnzZec+mllyIYDGLHjh0466yzUFtbi+nTp+PGG2+EqqqWz7NnwF9//fUQBAEbNmzARRddhKamJpxyyikAgDVr1uDSSy/F/Pnz4ff70dnZicsuuwyDg4OW91999dUAgHnz5hnRO7t27QIASJKEm266CQsWLIDP58PcuXPxne98B4lEwtKuuXPn4qMf/Sj+/e9/45hjjkEgEMA999yD0047DUcccYTjPj300ENx1lln5bP7CYIgCIIgCGLSQQ54giAIgiAIgsgTJkg3NTUBANavX4+TTz4ZM2bMwLe//W3U1tbiL3/5C84991z89a9/xSc/+UkAmsB9880344orrsBxxx2HUCiEt956C++88w4+9KEPGZ8vyzLOPvtsnHDCCbj11lvx5JNP4rrrroMkSbjxxhtztu+CCy7AwQcfjB/96EeGaP/0009jx44d+MIXvoDOzk6sX78e9957L9avX4/XX38dgiDgvPPOw5YtW/DQQw/hjjvuQGtrKwCgra0NgOb+/93vfofzzz8f//3f/4033ngDN998MzZu3IhHH33U0obNmzfjwgsvxJe+9CVceeWVOPTQQxEMBnHllVdi3bp1OOyww4zXvvnmm9iyZQv+7//+r8gjQhAEQRAEQRATGxLgCYIgCIIgCCIDo6OjGBgYQDwexxtvvIEbbrgBPp8PH/3oRwEAX//61zF79my8+eab8Pl8AIAvf/nLOOWUU/C///u/hgD/+OOP4yMf+QjuvfferNuLx+M4++yz8Ytf/ML4rI997GO45ZZb8LWvfc0QxjNxxBFH4MEHH7T87stf/jL++7//2/K7E044ARdeeCFefvllvO9978Phhx+Oo446Cg899BDOPfdczJ0713jt6tWr8bvf/Q5XXHEFfv3rXxuf2d7ejp/85Cd4/vnn8f73v994/bZt2/Dkk09aXO3Lli3DV7/6VTzwwAP48Y9/bPz+gQceQG1tLc4777ys34sgCIIgCIIgJisUQUMQBEEQBEEQGTjjjDPQ1taGWbNm4fzzz0dtbS1WrFiBmTNnYmhoCM899xw+/elPY2xsDAMDAxgYGMDg4CDOOussbN26FV1dXQCAxsZGrF+/Hlu3bs25za985SvG/wuCgK985StIJpN45plncr73P//zP9N+x+evx+NxDAwM4IQTTgAAvPPOOzk/81//+hcA4Fvf+pbl90zUf/zxxy2/nzdvXlqkTENDAz7xiU/goYceMpz5sizjz3/+M84999yqZ9UTBEEQBEEQRLkgAZ4gCIIgCIIgMnDXXXfh6aefxiOPPIKPfOQjGBgYMJzu27Ztg6qq+N73voe2tjbLv+uuuw4A0NfXBwC48cYbMTIygkMOOQRLly7F1VdfjTVr1qRtTxRFzJ8/3/K7Qw45BIAZf5ONefPmpf1uaGgIX//619HR0YFAIIC2tjbjdaOjozk/c/fu3RBFEQcddJDl952dnWhsbMTu3btztgEALr74YuzZswcvvfQSAOCZZ55Bb28vPv/5z+dsA0EQBEEQBEFMViiChiAIgiAIgiAycNxxx+GYY44BAJx77rk45ZRTcNFFF2Hz5s1QFAUA8D//8z8Zi4gy0frUU0/F9u3b8dhjj+Gpp57CfffdhzvuuAN33303rrjiipK1l3e7Mz796U/j1VdfxdVXX40jjzwSwWAQiqLg7LPPNr5DPgiCUHQbAOCss85CR0cHHnjgAZx66ql44IEH0NnZiTPOOCPvNhAEQRAEQRDEZIMEeIIgCIIgCILIA5fLhZtvvhnvf//7ceedd+Kyyy4DAHg8nrxE5ObmZnzhC1/AF77wBYTDYZx66qm4/vrrLQK8oijYsWOH4XoHgC1btgCAJZc9X4aHh/Hss8/ihhtuwPe//33j905ROJkE9jlz5kBRFGzduhWLFi0yft/b24uRkRHMmTMnr7a4XC5cdNFFWL58OW655Rb8/e9/x5VXXgmXy1XgtyIIgiAIgiCIyQNF0BAEQRAEQRBEnpx++uk47rjj8LOf/Qz19fU4/fTTcc8996C7uzvttf39/cb/Dw4OWv4WDAZx0EEHIZFIpL3vzjvvNP5fVVXceeed8Hg8+OAHP1hwe5m4zXLXGT/72c/SXsty2EdGRiy//8hHPuL4nttvvx0AcM455+Tdns9//vMYHh7Gl770JYTDYXzuc5/L+70EQRAEQRAEMRkhBzxBEARBEARBFMDVV1+NCy64AMuXL8ddd92FU045BUuXLsWVV16J+fPno7e3F6+99hr27duH1atXAwAWL16M008/HUcffTSam5vx1ltv4ZFHHrEUXAUAv9+PJ598EpdccgmOP/54PPHEE3j88cfxne98B21tbQW3tb6+HqeeeipuvfVWpFIpzJgxA0899RR27tyZ9tqjjz4aAPDd734Xn/nMZ+DxePCxj30MRxxxBC655BLce++9GBkZwWmnnYZVq1bhd7/7Hc4991y8//3vz7s9y5Ytw2GHHYaHH34YixYtwlFHHVXwdyIIgiAIgiCIyQQJ8ARBEARBEARRAOeddx4WLFiAn/zkJ7jyyivx1ltv4YYbbsDy5csxODiI9vZ2LFu2zBL58rWvfQ0rVqzAU089hUQigTlz5uAHP/gBrr76astnu1wuPPnkk/iv//ovXH311airq8N1111n+axCefDBB/HVr34Vd911F1RVxZlnnoknnngC06dPt7zu2GOPxU033YS7774bTz75JBRFwc6dO1FbW4v77rsP8+fPx/Lly/Hoo4+is7MT1157rVFsthAuvvhiXHPNNVR8lSAIgiAIgpgSCKp9PSpBEARBEARBEBXn0ksvxSOPPIJwOFztppSVn//85/jmN7+JXbt2Yfbs2dVuDkEQBEEQBEGUFcqAJwiCIAiCIAiiIqiqit/85jc47bTTSHwnCIIgCIIgpgQUQUMQBEEQBEEQRFmJRCJYsWIFnn/+eaxduxaPPfZYtZtEEARBEARBEBWBBHiCIAiCIAiCIMpKf38/LrroIjQ2NuI73/kOPv7xj1e7SQRBEARBEARRESgDniAIgiAIgiAIgiAIgiAIgiDKAGXAEwR
"text/plain": [
"<Figure size 1800x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.figure(figsize=(18, 5))\n",
"ax1 = plt.subplot()\n",
"\n",
"# Plot VT with step-like appearance\n",
"line1 = sns.lineplot(data=df, x='T(sec)', y='VT(l)', label='VT (L)')\n",
"ax1.set_xlabel('Time (sec)')\n",
"ax1.set_ylabel('VT (L)')\n",
"ax1.set_title('Respiratory')\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()"
]
},
{
"cell_type": "code",
2025-09-23 17:14:36 +01:00
"execution_count": 45,
"id": "033cee9a",
2025-09-23 15:53:15 +01:00
"metadata": {},
2025-09-23 17:14:36 +01:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Data grouped by Speed (numeric columns only):\n"
]
},
{
"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>T(sec)</th>\n",
" <th>HR(bpm)</th>\n",
" <th>VO2(ml/min)</th>\n",
" <th>VCO2(ml/min)</th>\n",
" <th>RER</th>\n",
" <th>VE(l/min)</th>\n",
" <th>FEO2</th>\n",
" <th>FECO2</th>\n",
" <th>FETO2</th>\n",
" <th>FETCO2</th>\n",
" <th>...</th>\n",
" <th>EE(kcal/day)</th>\n",
" <th>EE(kcal/min)</th>\n",
" <th>CARBS(kcal)</th>\n",
" <th>CARBS(%)</th>\n",
" <th>FAT(kcal)</th>\n",
" <th>FAT(%)</th>\n",
" <th>MET</th>\n",
" <th>CUMULATIVE EE(kcal)</th>\n",
" <th>BP(kPa)</th>\n",
" <th>Watts</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Speed</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>3.5</th>\n",
" <td>142.4</td>\n",
" <td>96.1</td>\n",
" <td>1046.2</td>\n",
" <td>854.9</td>\n",
" <td>0.8</td>\n",
" <td>28.3</td>\n",
" <td>0.2</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>...</td>\n",
" <td>7230.0</td>\n",
" <td>5.0</td>\n",
" <td>0.2</td>\n",
" <td>39.4</td>\n",
" <td>0.3</td>\n",
" <td>60.6</td>\n",
" <td>5.5</td>\n",
" <td>8.8</td>\n",
" <td>99.5</td>\n",
" <td>95.7</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4.0</th>\n",
" <td>320.8</td>\n",
" <td>109.3</td>\n",
" <td>1423.6</td>\n",
" <td>1271.0</td>\n",
" <td>0.9</td>\n",
" <td>38.7</td>\n",
" <td>0.2</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>...</td>\n",
" <td>10008.1</td>\n",
" <td>7.0</td>\n",
" <td>0.4</td>\n",
" <td>64.1</td>\n",
" <td>0.2</td>\n",
" <td>35.9</td>\n",
" <td>7.5</td>\n",
" <td>27.3</td>\n",
" <td>99.5</td>\n",
" <td>112.4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4.5</th>\n",
" <td>501.8</td>\n",
" <td>139.4</td>\n",
" <td>1991.2</td>\n",
" <td>1862.2</td>\n",
" <td>0.9</td>\n",
" <td>56.0</td>\n",
" <td>0.2</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>...</td>\n",
" <td>14132.4</td>\n",
" <td>9.8</td>\n",
" <td>0.6</td>\n",
" <td>78.0</td>\n",
" <td>0.2</td>\n",
" <td>22.0</td>\n",
" <td>10.5</td>\n",
" <td>52.3</td>\n",
" <td>99.5</td>\n",
" <td>123.8</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5.0</th>\n",
" <td>685.6</td>\n",
" <td>153.2</td>\n",
" <td>2216.6</td>\n",
" <td>2098.0</td>\n",
" <td>0.9</td>\n",
" <td>64.3</td>\n",
" <td>0.2</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>...</td>\n",
" <td>15771.4</td>\n",
" <td>11.0</td>\n",
" <td>0.7</td>\n",
" <td>80.7</td>\n",
" <td>0.2</td>\n",
" <td>19.3</td>\n",
" <td>11.7</td>\n",
" <td>85.1</td>\n",
" <td>99.5</td>\n",
" <td>135.2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5.5</th>\n",
" <td>862.6</td>\n",
" <td>163.1</td>\n",
" <td>2303.3</td>\n",
" <td>2198.3</td>\n",
" <td>1.0</td>\n",
" <td>69.9</td>\n",
" <td>0.2</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>...</td>\n",
" <td>16579.3</td>\n",
" <td>11.5</td>\n",
" <td>0.7</td>\n",
" <td>86.3</td>\n",
" <td>0.1</td>\n",
" <td>13.7</td>\n",
" <td>12.2</td>\n",
" <td>118.3</td>\n",
" <td>99.5</td>\n",
" <td>151.9</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>5 rows × 26 columns</p>\n",
"</div>"
],
"text/plain": [
" T(sec) HR(bpm) VO2(ml/min) VCO2(ml/min) RER VE(l/min) FEO2 \\\n",
"Speed \n",
"3.5 142.4 96.1 1046.2 854.9 0.8 28.3 0.2 \n",
"4.0 320.8 109.3 1423.6 1271.0 0.9 38.7 0.2 \n",
"4.5 501.8 139.4 1991.2 1862.2 0.9 56.0 0.2 \n",
"5.0 685.6 153.2 2216.6 2098.0 0.9 64.3 0.2 \n",
"5.5 862.6 163.1 2303.3 2198.3 1.0 69.9 0.2 \n",
"\n",
" FECO2 FETO2 FETCO2 ... EE(kcal/day) EE(kcal/min) CARBS(kcal) \\\n",
"Speed ... \n",
"3.5 0.0 0.0 0.0 ... 7230.0 5.0 0.2 \n",
"4.0 0.0 0.0 0.0 ... 10008.1 7.0 0.4 \n",
"4.5 0.0 0.0 0.0 ... 14132.4 9.8 0.6 \n",
"5.0 0.0 0.0 0.0 ... 15771.4 11.0 0.7 \n",
"5.5 0.0 0.0 0.0 ... 16579.3 11.5 0.7 \n",
"\n",
" CARBS(%) FAT(kcal) FAT(%) MET CUMULATIVE EE(kcal) BP(kPa) Watts \n",
"Speed \n",
"3.5 39.4 0.3 60.6 5.5 8.8 99.5 95.7 \n",
"4.0 64.1 0.2 35.9 7.5 27.3 99.5 112.4 \n",
"4.5 78.0 0.2 22.0 10.5 52.3 99.5 123.8 \n",
"5.0 80.7 0.2 19.3 11.7 85.1 99.5 135.2 \n",
"5.5 86.3 0.1 13.7 12.2 118.3 99.5 151.9 \n",
"\n",
"[5 rows x 26 columns]"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Group by speed and calculate mean for numeric columns only\n",
"speed_groups = df.groupby('Speed').mean(numeric_only=True).round(1)\n",
"print(\"Data grouped by Speed (numeric columns only):\")\n",
"\n",
"speed_groups = speed_groups.iloc[1:-1]\n",
"speed_groups.head()"
]
2025-09-23 15:53:15 +01:00
},
{
"cell_type": "code",
2025-09-23 17:18:10 +01:00
"execution_count": 46,
2025-09-23 17:14:36 +01:00
"id": "25f1a8ef",
2025-09-23 15:53:15 +01:00
"metadata": {},
2025-09-23 17:14:36 +01:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" T(sec) HR(bpm) VO2(ml/min) VCO2(ml/min) RER VE(l/min) FEO2 \\\n",
"Speed \n",
"3.5 142.4 96.1 1046.2 854.9 0.8 28.3 0.2 \n",
"4.0 320.8 109.3 1423.6 1271.0 0.9 38.7 0.2 \n",
"4.5 501.8 139.4 1991.2 1862.2 0.9 56.0 0.2 \n",
"5.0 685.6 153.2 2216.6 2098.0 0.9 64.3 0.2 \n",
"5.5 862.6 163.1 2303.3 2198.3 1.0 69.9 0.2 \n",
"6.0 1042.3 170.8 2282.2 2229.4 1.0 72.0 0.2 \n",
"6.5 1225.8 179.6 2381.8 2345.0 1.0 81.2 0.2 \n",
"7.0 1412.0 187.2 2348.1 2409.4 1.1 88.5 0.2 \n",
"7.5 1596.7 194.0 2519.0 2734.9 1.1 107.0 0.2 \n",
"\n",
" FECO2 FETO2 FETCO2 ... EE(kcal/day) EE(kcal/min) CARBS(kcal) \\\n",
"Speed ... \n",
"3.5 0.0 0.0 0.0 ... 7230.0 5.0 0.2 \n",
"4.0 0.0 0.0 0.0 ... 10008.1 7.0 0.4 \n",
"4.5 0.0 0.0 0.0 ... 14132.4 9.8 0.6 \n",
"5.0 0.0 0.0 0.0 ... 15771.4 11.0 0.7 \n",
"5.5 0.0 0.0 0.0 ... 16579.3 11.5 0.7 \n",
"6.0 0.0 0.0 0.0 ... 16763.2 11.6 0.8 \n",
"6.5 0.0 0.0 0.0 ... 17690.0 12.3 0.8 \n",
"7.0 0.0 0.0 0.0 ... 17600.5 12.2 0.9 \n",
"7.5 0.0 0.0 0.0 ... 18976.5 13.2 0.9 \n",
"\n",
" CARBS(%) FAT(kcal) FAT(%) MET CUMULATIVE EE(kcal) BP(kPa) Watts \n",
"Speed \n",
"3.5 39.4 0.3 60.6 5.5 8.8 99.5 95.7 \n",
"4.0 64.1 0.2 35.9 7.5 27.3 99.5 112.4 \n",
"4.5 78.0 0.2 22.0 10.5 52.3 99.5 123.8 \n",
"5.0 80.7 0.2 19.3 11.7 85.1 99.5 135.2 \n",
"5.5 86.3 0.1 13.7 12.2 118.3 99.5 151.9 \n",
"6.0 93.9 0.1 6.1 12.1 152.8 99.5 163.3 \n",
"6.5 93.8 0.1 6.2 12.6 189.8 99.5 180.0 \n",
"7.0 97.3 0.0 2.7 12.4 227.9 99.5 191.4 \n",
"7.5 99.7 0.0 0.3 13.3 267.2 99.5 208.1 \n",
"\n",
"[9 rows x 26 columns]\n"
]
},
{
"data": {
2025-09-23 17:18:10 +01:00
"image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAMWCAYAAAAgRDUeAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQAA8bpJREFUeJzs3Xd4FFXfxvHvpjdSaUmAEDpBOtKkKgqICAICPoI0C9hAFNv7iKAiKHbE8igCCqKAAqLYEJGigPTeE2rogRBC+rx/DNlkUyB9U+7Pde2V7JyZ2d/sbDabO+ecsRiGYSAiIiIiIiIiIlKEHOxdgIiIiIiIiIiIlD0KpUREREREREREpMgplBIRERERERERkSKnUEpERERERERERIqcQikRERERERERESlyCqVERERERERERKTIKZQSEREREREREZEip1BKRERERERERESKnEIpEREREREREREpcgqlREREyqBZs2ZhsVist6KW/rFnzZpV5NtLwZkwYYL1XFSvXt3e5YgUiaFDh1pf9506dbJp0/uTiEjOKZQSkWJl5cqVN/wwFxERYbPOhAkTirzO3LjeB9ec6NSpk83xpt7c3NyoVq0avXr1YtGiRQVWr73DCnv59ddfueeeewgODsbFxYVy5coREhJC27ZtGTVqFN9++629Sywz7PEHXcb3nuxuQ4cOzdfjpP95zsm+/vvf/2KxWBg1alSmtu3bt/Pkk0/StGlT/P39cXZ2xs/Pj5YtWzJu3Di2b9+er1pLiqI6d2VFdr9zMt4iIiLsXWqJpMBKRMSWk70LEBGRvImPj+fYsWMcO3aMH374gRdffJFJkybZu6wSafz48bz66qs2yxITE4mJieHo0aP8888//PPPPwwYMMBOFZY+U6dOtX5/880327GS4i01cO7du7d1WVxcHKNHj+Z///tfpvUvXrzIv//+y7///suCBQsUHIjYgd7fRERyTqGUiEghSE5OJj4+Hg8PjwLdr5+fHy+++CJJSUns37+fuXPnkpCQAMAbb7zB008/jb+/f4E+Zmm3e/duXnvtNev9unXr0qtXL/z8/Lhw4QLbtm1jzZo1dqywdHrmmWfsXcJ1DRgwgBYtWmRaftNNNxVZDQcPHmT37t14e3vTuXNnwHxv6d+/P0uXLrWu5+PjQ58+fahVqxZxcXFs376d3377rdDri46Oxtvbu9AfJ7eKw7nLjStXruDu7o6DQ/EbwJD6Oycr+l2TveL4/lZcf15FRDBERIqRP//80wCst5kzZ2ZaJzw83Gadl19+OdM6hw4dMp544gmjXr16hoeHh+Hm5mbUr1/feO6554yzZ89m+bjDhw83mjZtalSuXNlwcXEx3N3djZo1axpDhw41tm/fnmmbIUOGWGvo2LGjceTIEWPQoEFGxYoVDYvFYrz77rs2dWZ1+/PPP2/4nHTs2NG6fkhIiE3bc889Z7O/f/75x6b9+++/NwYNGmQ0bNjQqFixouHs7Gx4enoa9evXNx577DEjPDw82+c1q1vG53rVqlXGgAEDjKpVqxouLi5GuXLljNatWxsffvihkZCQcMNjMwzD+Pzzz6379/DwMGJiYmzao6KiDFdXV+s6c+bMMQzDMBITE413333XaN26teHj42M4Ojoa/v7+RlhYmDF48GBj3rx5OXr8999/37pvT0/PTI9vGIYRGxtrrFixwmZZxtfqoUOHjHfffdeoX7++4erqagQFBRlPPfWUER0dneXj5uW5O3XqlPHCCy8YjRs3Nry8vAxXV1ejZs2axqOPPmocOXIky20iIiKMgQMHGn5+foaHh4fRvn174/fffzdmzpxpU39ONGnSxLr+xIkTrcv37dtnXe7v72+kpKRY27p162ZtGzlypHV5Vj/n6V/rWd3Sv/4zbv/XX38Zt956q+Hl5WV4eXkZ3bp1M3bu3Jmj4zKMnL33pJeYmGj897//Nbp3727UqFHD8PHxMZycnAx/f3+jXbt2xgcffGBzHl9++eUb/nyl/3k0DMN48803DcAYOHCgddknn3xis02bNm2yfE+7cOGC8e677+a5XsPI/J7w559/Gp9//rnRtGlTw83NzWjcuHGmYwsJCTGio6ONsWPHGlWqVDFcXV2N+vXrG9OmTbN5XRiGYcTExBgTJ040mjZtanh5eRlOTk5GhQoVjMaNGxsPPvig8fPPP1/3HKTK7bnL7tjmzZtntGzZ0nB3dzd8fX2Nfv36GUePHs1y+61btxrDhg0zatSoYbi5uRmenp5GkyZNjEmTJmX5HhISEmLzPrp69WrjtttuM7y9vQ3AiIqKMgzDPE9vvPGGUatWLcPFxcWoUaOGMWnSJCMhISHLYxw/frx1WZUqVYzk5GSbx925c6fNduvWrbvhc3O93zlZ+fjjj63rOzk5GZs2bbK2HThwwPDw8LC2v/rqq9a2jMfz008/Gbfccovh6elp+Pr6Gn379jUOHDiQ5WPm9nd8+mMaMmSIsX//fmPgwIFGQECA4erqajRt2tRYvHhxlo/1119/GR07djQ8PDwMPz8/o1+/fsbBgwczfQZILz/vb1m9Nq93LKly+vOa6ocffjDuvvtuo3Llyoazs7Ph6+trdO7c2ZgzZ06mn1URkcKkUEpEipWCCKUWL15s8yE44y04ONjYvXu3zTZPP/30dT8suri4GL///rvNNuk/kNauXduoXLmyzTZFEUp98MEHNvvL+AG+b9++1318b29va+CW21DqxRdfvO667du3z/KPs4yio6NtztfXX39t0z5jxgxrm4+PjxEbG5vp+c/q1qpVqxs+tmEYxttvv23dxtnZ2fj3339ztF3G1+qtt96aZR0333yzcfXqVZtt8/Lc/f3330b58uWz3cbHx8dYtWqVzTbh4eGZXpeAYbFYjDvvvNNmWU489dRT1vVvv/126/L0wSJgDYOSk5Otf3QDxvz5863b5OePtozb33777YaDg0Om9QMCAowzZ87k6NhyG2xcvnz5hj8vXbp0MZKSkgzDyFso1bZtWwMwvv32W+uyevXqWdd3c3MzTpw4kaPjy229hpH5PaF9+/Y297MKpSpVqmS0aNEiy/0/8cQTNjV16tTpuvUMGDAgR8dWEKFUu3btsqyhdu3amX5+P/roI8PJySnbusPCwozIyEibbdKHUm3atDEcHR1ttkkNpQYOHJjlPnv27JnlMZ48edJwdna2Lv/pp59sHjd9aBUWFpaj5zO3oZRhGEavXr2s2zRs2NCIj483kpOTjVtuucW6vEOHDjahWfrj6dy5c5bHHRAQYOzbt8/msfLyOz79MTVq1MgoV65cpu0sFouxfPlym+2WLl2a5bn29/c32rRpY71fHEOp7H5ek5OTjcGDB1+3lnvvvdfmvUBEpDBp+J6IFGu//PIL586ds1kWFRWV7frh4eHcd999XL16FYAGDRpwzz33kJKSwty5czly5AgnTpygb9++7NixA0dHRwA8PT3p2LEjDRs2xN/fH3d3d86fP89PP/3Enj17SEhI4Mknn2T37t1ZPu6BAwcA6NOnD40bN+bIkSM4OzszdepUvv32WzZu3AhAjRo1bCYsrlmzZp6el+TkZPbv388XX3xhXdasWTNq1apls56vry933HEH9evXx8/PDxcXF06fPs2iRYs4evQo0dHRPPfccyxbtgx/f3+mTp3Kxo0bbSb1Tj83Rtu2bQH45ptveP31163Lu3btyi233MLp06eZPXs2MTExrF69mqeeeirLeW/SK1euHP369ePLL78E4Ouvv+a+++6ztn/99dfW7wcOHIi7uzsxMTHMmTPHurxv3740a9aMS5cuceTIEf76668cPY+pz1uqxMREbr75ZsLCwmjZsiXNmze3vi5uZMWKFfTq1YvGjRvz888/8++//wLw77//8uabbzJ+/Hggb89ddHQ0vXv3tv4shISEMGDAANzd3Vm4cCG7du3i0qVL9O3blwMHDuDj4wPA448/zqlTp6yP1bNnT5o2bcrPP//MsmXLcvwcpercuTPvvvsuAP/88w/Jyck4OjqyevVqm/VWrVpFgwYN2LZtG9HR0QA5muh/1KhR3HX
2025-09-23 17:14:36 +01:00
"text/plain": [
"<Figure size 1200x800 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"speed_groups = df.groupby('Speed').mean(numeric_only=True).round(1)\n",
"# Plot Speed vs Heart Rate from the grouped data\n",
"plt.figure(figsize=(12, 8))\n",
"\n",
"# Drop the first and last row from speed_groups\n",
"speed_groups = speed_groups.iloc[1:-1]\n",
"print(speed_groups)\n",
2025-09-23 17:18:10 +01:00
"\n",
2025-09-23 17:14:36 +01:00
"# Create speed bins from 3.5 to 7.5 mph\n",
2025-09-23 17:18:10 +01:00
"speed_bins = np.arange(3.5, 8.0, 0.5)\n",
2025-09-23 17:14:36 +01:00
"stage_labels = [f'Stage {i}' for i in range(1, len(speed_bins) + 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",
"# Create the main axis for heart rate line plot\n",
"ax1 = plt.gca()\n",
"line = ax1.plot(filtered_data.index, filtered_data['HR(bpm)'], marker='o', linewidth=2, markersize=6, color='red', label='Heart Rate')\n",
"ax1.set_xlabel('Speed (mph)', fontsize=12)\n",
"ax1.set_ylabel('Heart Rate (bpm)', fontsize=12, color='red')\n",
"ax1.tick_params(axis='y', labelcolor='red')\n",
"\n",
"# Add heart rate values as text labels on the points\n",
"for i, (speed, hr) in enumerate(zip(filtered_data.index, filtered_data['HR(bpm)'])):\n",
" ax1.text(speed, hr + 2, f'{int(hr)}', ha='center', va='bottom', fontsize=9, fontweight='bold', color='red')\n",
"\n",
2025-09-23 17:18:10 +01:00
"# Create secondary y-axis for stacked bar chart (Fat and Carbs)\n",
2025-09-23 17:14:36 +01:00
"ax2 = ax1.twinx()\n",
"\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",
"# Create stacked bar chart\n",
"bars_fat = ax2.bar(filtered_data.index, fat_ee, alpha=0.7, width=0.2, color='orange', label='Fat')\n",
"bars_carbs = ax2.bar(filtered_data.index, carbs_ee, bottom=fat_ee, alpha=0.7, width=0.2, color='blue', label='Carbs')\n",
"\n",
"ax2.set_ylabel('Energy Expenditure (kcal/min)', fontsize=12, color='black')\n",
"ax2.tick_params(axis='y', labelcolor='black')\n",
"\n",
"# Add total EE values as text labels on top of bars\n",
"for i, (speed, total_ee) in enumerate(zip(filtered_data.index, filtered_data['EE(kcal/min)'])):\n",
" ax2.text(speed, total_ee + 0.3, f'{total_ee:.1f}', ha='center', va='bottom', fontsize=9, fontweight='bold', color='black')\n",
2025-09-23 17:14:36 +01:00
"\n",
"# Update x-axis with stage labels\n",
"plt.xticks(filtered_data.index, stage_labels)\n",
2025-09-23 17:18:10 +01:00
"plt.title('Heart Rate vs Speed with Fat/Carbs Energy Expenditure', fontsize=14, fontweight='bold')\n",
2025-09-23 17:14:36 +01:00
"\n",
"# Combine legends\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",
"plt.grid(True, alpha=0.3)\n",
"plt.tight_layout()\n",
"plt.show()"
]
2025-09-23 17:18:10 +01:00
},
{
"cell_type": "code",
"execution_count": null,
"id": "8a1878a0",
"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
}