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",
"execution_count": null,
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": {
"image/png": "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
"text/plain": [
"<Figure size 1200x800 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"\n",
"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",
"# Create speed bins from 3.5 to 7.5 mph\n",
"speed_bins = np.arange(3.5, 8.0, 0.5) # Creates bins: 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5\n",
"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",
"# Create secondary y-axis for EE bar chart\n",
"ax2 = ax1.twinx()\n",
"bars = ax2.bar(filtered_data.index, filtered_data['EE(kcal/min)'], alpha=0.6, width=0.2, color='blue', label='Energy Expenditure')\n",
"ax2.set_ylabel('Energy Expenditure (kcal/min)', fontsize=12, color='blue')\n",
"ax2.tick_params(axis='y', labelcolor='blue')\n",
"\n",
"# Add EE values as text labels on the bars\n",
"for i, (speed, ee) in enumerate(zip(filtered_data.index, filtered_data['EE(kcal/min)'])):\n",
" ax2.text(speed, ee + 0.3, f'{ee:.1f}', ha='center', va='bottom', fontsize=9, fontweight='bold', color='blue')\n",
"\n",
"# Update x-axis with stage labels\n",
"plt.xticks(filtered_data.index, stage_labels)\n",
"plt.title('Heart Rate vs Speed with Energy Expenditure', fontsize=14, fontweight='bold')\n",
"\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 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
}