{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "ec10aab9-454d-4dc2-9059-665e60050d73",
   "metadata": {},
   "outputs": [],
   "source": [
    "import ethoscopy as etho\n",
    "import pandas as pd\n",
    "from scipy.stats import mannwhitneyu\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import seaborn as sns\n",
    "from scipy.stats import wilcoxon, shapiro, ttest_rel"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "5289d86c-0107-4089-83e3-327b70168e08",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2.1.0'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "etho.__version__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "3d32b423-cc70-43f2-a2cc-ed9bd08c2981",
   "metadata": {},
   "outputs": [],
   "source": [
    "meta = '/home/rdingjin/Optic_2026-04-01/metadata_CantonS_2026-04-01.csv'\n",
    "local = '/mnt/ethoscope_results'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "df11ef6f-5475-45b0-95c3-2a8672a21219",
   "metadata": {},
   "outputs": [],
   "source": [
    "metadata = etho.link_meta_index(meta, local)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "ebfbf3dc-d405-4f7b-a4a1-1eacff24f3a5",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Loading ROI_1 from ETHOSCOPE_278\n",
      "Loading ROI_2 from ETHOSCOPE_278\n",
      "Loading ROI_3 from ETHOSCOPE_278\n",
      "Loading ROI_4 from ETHOSCOPE_278\n",
      "Loading ROI_5 from ETHOSCOPE_278\n",
      "Loading ROI_6 from ETHOSCOPE_278\n",
      "Loading ROI_7 from ETHOSCOPE_278\n",
      "Loading ROI_8 from ETHOSCOPE_278\n",
      "Loading ROI_9 from ETHOSCOPE_278\n",
      "Loading ROI_10 from ETHOSCOPE_278\n",
      "Loading ROI_11 from ETHOSCOPE_278\n",
      "Loading ROI_12 from ETHOSCOPE_278\n",
      "Loading ROI_13 from ETHOSCOPE_278\n",
      "Loading ROI_14 from ETHOSCOPE_278\n",
      "Loading ROI_15 from ETHOSCOPE_278\n",
      "Loading ROI_16 from ETHOSCOPE_278\n",
      "Loading ROI_17 from ETHOSCOPE_278\n",
      "Loading ROI_18 from ETHOSCOPE_278\n",
      "Loading ROI_19 from ETHOSCOPE_278\n",
      "Loading ROI_20 from ETHOSCOPE_278\n"
     ]
    }
   ],
   "source": [
    "#fetch data from ethoscope\n",
    "data = etho.load_ethoscope(metadata, reference_hour = 9.0, FUN = etho.sleep_annotation)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "a32d69f8-e66c-47fc-9b9a-2273f2c5082b",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = etho.behavpy(data, metadata, check = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "e633d7d9-99db-4815-900d-e79d11dd65b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "df.to_pickle('/home/rdingjin/Optic_2026-04-01/phase2.pkl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "ae2ff7e0-2f6c-4cc0-9afd-a1c021140760",
   "metadata": {},
   "outputs": [],
   "source": [
    "import ethoscopy as etho\n",
    "import pandas as pd\n",
    "from scipy.stats import wilcoxon, shapiro, ttest_rel\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import seaborn as sns\n",
    "df = pd.read_pickle('/home/rdingjin/Optic_2026-04-01/phase2.pkl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "94a0854d-4b5a-475f-a856-c61ec01d080e",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = df.baseline(column = 'baseline')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "cae6a067-5fd7-493a-9f23-c75d63e6ae06",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      " ==== METADATA ====\n",
      "\n",
      "                                     date   machine_name  region_id  \\\n",
      "id                                                                    \n",
      "2026-04-01_11-20-57_278441|01  2026-04-01  ETHOSCOPE_278          1   \n",
      "2026-04-01_11-20-57_278441|02  2026-04-01  ETHOSCOPE_278          2   \n",
      "2026-04-01_11-20-57_278441|03  2026-04-01  ETHOSCOPE_278          3   \n",
      "2026-04-01_11-20-57_278441|04  2026-04-01  ETHOSCOPE_278          4   \n",
      "2026-04-01_11-20-57_278441|05  2026-04-01  ETHOSCOPE_278          5   \n",
      "2026-04-01_11-20-57_278441|06  2026-04-01  ETHOSCOPE_278          6   \n",
      "2026-04-01_11-20-57_278441|07  2026-04-01  ETHOSCOPE_278          7   \n",
      "2026-04-01_11-20-57_278441|08  2026-04-01  ETHOSCOPE_278          8   \n",
      "2026-04-01_11-20-57_278441|09  2026-04-01  ETHOSCOPE_278          9   \n",
      "2026-04-01_11-20-57_278441|10  2026-04-01  ETHOSCOPE_278         10   \n",
      "2026-04-01_11-20-57_278441|11  2026-04-01  ETHOSCOPE_278         11   \n",
      "2026-04-01_11-20-57_278441|12  2026-04-01  ETHOSCOPE_278         12   \n",
      "2026-04-01_11-20-57_278441|13  2026-04-01  ETHOSCOPE_278         13   \n",
      "2026-04-01_11-20-57_278441|14  2026-04-01  ETHOSCOPE_278         14   \n",
      "2026-04-01_11-20-57_278441|15  2026-04-01  ETHOSCOPE_278         15   \n",
      "2026-04-01_11-20-57_278441|16  2026-04-01  ETHOSCOPE_278         16   \n",
      "2026-04-01_11-20-57_278441|17  2026-04-01  ETHOSCOPE_278         17   \n",
      "2026-04-01_11-20-57_278441|18  2026-04-01  ETHOSCOPE_278         18   \n",
      "2026-04-01_11-20-57_278441|19  2026-04-01  ETHOSCOPE_278         19   \n",
      "2026-04-01_11-20-57_278441|20  2026-04-01  ETHOSCOPE_278         20   \n",
      "\n",
      "                               sleep_deprived  species         food  baseline  \\\n",
      "id                                                                              \n",
      "2026-04-01_11-20-57_278441|01            True  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|02           False  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|03            True  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|04           False  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|05            True  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|06           False  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|07            True  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|08           False  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|09            True  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|10           False  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|11           False  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|12            True  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|13           False  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|14            True  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|15           False  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|16            True  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|17           False  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|18            True  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|19           False  CantonS  normal_food         0   \n",
      "2026-04-01_11-20-57_278441|20            True  CantonS  normal_food         0   \n",
      "\n",
      "                                sex      time  \n",
      "id                                             \n",
      "2026-04-01_11-20-57_278441|01  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|02  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|03  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|04  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|05  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|06  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|07  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|08  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|09  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|10  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|11  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|12  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|13  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|14  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|15  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|16  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|17  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|18  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|19  male  11-20-57  \n",
      "2026-04-01_11-20-57_278441|20  male  11-20-57  \n",
      " ====== DATA ======\n",
      "\n",
      "                                    t           x          y          w  \\\n",
      "id                                                                        \n",
      "2026-04-01_11-20-57_278441|01    8460  248.739130  41.782609  20.130435   \n",
      "2026-04-01_11-20-57_278441|01    8470  116.657143  44.885714  19.542857   \n",
      "2026-04-01_11-20-57_278441|01    8480   27.581395  45.488372  11.744186   \n",
      "2026-04-01_11-20-57_278441|01    8490   21.000000  45.000000  11.000000   \n",
      "2026-04-01_11-20-57_278441|01    8500   21.000000  45.000000  11.000000   \n",
      "...                               ...         ...        ...        ...   \n",
      "2026-04-01_11-20-57_278441|20  701770  161.700000  22.000000  20.800000   \n",
      "2026-04-01_11-20-57_278441|20  701780  160.571429  21.714286  21.428571   \n",
      "2026-04-01_11-20-57_278441|20  701790  162.904762  22.761905  21.476190   \n",
      "2026-04-01_11-20-57_278441|20  701800  161.227273  21.863636  21.818182   \n",
      "2026-04-01_11-20-57_278441|20  701810  160.952381  22.095238  21.714286   \n",
      "\n",
      "                                      h         phi  max_velocity  \\\n",
      "id                                                                  \n",
      "2026-04-01_11-20-57_278441|01  9.217391   90.782609     56.218434   \n",
      "2026-04-01_11-20-57_278441|01  7.171429   35.171429     17.818812   \n",
      "2026-04-01_11-20-57_278441|01  6.604651   15.534884     16.439127   \n",
      "2026-04-01_11-20-57_278441|01  7.000000   18.000000      3.033044   \n",
      "2026-04-01_11-20-57_278441|01  7.000000   18.000000      3.033044   \n",
      "...                                 ...         ...           ...   \n",
      "2026-04-01_11-20-57_278441|20  9.050000  163.750000      1.386369   \n",
      "2026-04-01_11-20-57_278441|20  8.714286  169.142857      2.300799   \n",
      "2026-04-01_11-20-57_278441|20  8.380952  156.000000      1.255679   \n",
      "2026-04-01_11-20-57_278441|20  8.681818  164.954545      1.249910   \n",
      "2026-04-01_11-20-57_278441|20  8.476190  165.047619      1.224274   \n",
      "\n",
      "                               mean_velocity      dist  has_interacted  \\\n",
      "id                                                                       \n",
      "2026-04-01_11-20-57_278441|01      10.761196  0.742523             0.0   \n",
      "2026-04-01_11-20-57_278441|01       4.753718  0.499140             0.0   \n",
      "2026-04-01_11-20-57_278441|01       3.349548  0.432092             0.0   \n",
      "2026-04-01_11-20-57_278441|01       3.033044  0.345767             0.0   \n",
      "2026-04-01_11-20-57_278441|01       3.033044  0.354866             0.0   \n",
      "...                                      ...       ...             ...   \n",
      "2026-04-01_11-20-57_278441|20       0.836259  0.050176             0.0   \n",
      "2026-04-01_11-20-57_278441|20       0.926716  0.058383             0.0   \n",
      "2026-04-01_11-20-57_278441|20       0.869378  0.054771             0.0   \n",
      "2026-04-01_11-20-57_278441|20       0.845312  0.055791             0.0   \n",
      "2026-04-01_11-20-57_278441|20       0.885445  0.055783             0.0   \n",
      "\n",
      "                               beam_cross moving  micro   walk  \\\n",
      "id                                                               \n",
      "2026-04-01_11-20-57_278441|01         0.0   True  False   True   \n",
      "2026-04-01_11-20-57_278441|01         0.0   True  False   True   \n",
      "2026-04-01_11-20-57_278441|01         0.0   True  False   True   \n",
      "2026-04-01_11-20-57_278441|01         0.0   True  False   True   \n",
      "2026-04-01_11-20-57_278441|01         0.0   True  False   True   \n",
      "...                                   ...    ...    ...    ...   \n",
      "2026-04-01_11-20-57_278441|20         0.0   True   True  False   \n",
      "2026-04-01_11-20-57_278441|20         0.0   True   True  False   \n",
      "2026-04-01_11-20-57_278441|20         0.0   True   True  False   \n",
      "2026-04-01_11-20-57_278441|20         0.0   True   True  False   \n",
      "2026-04-01_11-20-57_278441|20         0.0   True   True  False   \n",
      "\n",
      "                               is_interpolated  asleep  \n",
      "id                                                      \n",
      "2026-04-01_11-20-57_278441|01            False   False  \n",
      "2026-04-01_11-20-57_278441|01            False   False  \n",
      "2026-04-01_11-20-57_278441|01            False   False  \n",
      "2026-04-01_11-20-57_278441|01            False   False  \n",
      "2026-04-01_11-20-57_278441|01            False   False  \n",
      "...                                        ...     ...  \n",
      "2026-04-01_11-20-57_278441|20            False   False  \n",
      "2026-04-01_11-20-57_278441|20            False   False  \n",
      "2026-04-01_11-20-57_278441|20            False   False  \n",
      "2026-04-01_11-20-57_278441|20            False   False  \n",
      "2026-04-01_11-20-57_278441|20            False   False  \n",
      "\n",
      "[1386538 rows x 16 columns]\n"
     ]
    }
   ],
   "source": [
    "#display metadata\n",
    "df.display()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "76cd7456-6246-4665-a08a-d6f270a8567d",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/srv/venv/lib/python3.12/site-packages/ethoscopy/behavpy_core.py:1611: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n",
      "  tdf.groupby(\"id\", group_keys=False).apply(\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 73620 characters]",
      "text/plain": [
       "<Figure size 800x200 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#heatmap of CantonS sleep\n",
    "start_hour = 0\n",
    "end_hour = 96\n",
    "fig = df.t_filter(start_time=start_hour, end_time=end_hour).heatmap(variable = 'asleep')\n",
    "fig.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "id": "e97cc949-01e2-4ad2-8a06-fd5b6c36b089",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 184116 characters]",
      "text/plain": [
       "<Figure size 1133.33x466.667 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "start_hour = 0\n",
    "end_hour = 96\n",
    "\n",
    "# Generate plot from Ethoscopy\n",
    "fig = df.t_filter(start_time=start_hour, end_time=end_hour).plot_overtime(variable='asleep', avg_window=30, grids=True)\n",
    "\n",
    "# Extract the main axis from the figure\n",
    "ax = fig.axes[0]\n",
    "\n",
    "# Add shading stimulus shading\n",
    "# Draw a vertical span from ZT 48 to ZT 72\n",
    "ax.axvspan(48, 72, color='#ff4c4c', alpha=0.3, zorder=1)\n",
    "\n",
    "# Set custom labels\n",
    "ax.set_xlabel(\"Zeitgeber Time (Hours)\", fontsize=12)\n",
    "ax.set_ylabel(\"Fraction of Time Asleep\", fontsize=12)\n",
    "\n",
    "# Show plot\n",
    "fig.show()\n",
    "\n",
    "# Save as a high-resolution PNG\n",
    "plt.savefig(\"Figure_2A.png\", dpi=600, bbox_inches='tight')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "81bb4b3e-0d14-4e1b-86af-b304eb557f24",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--- Individual Fly Sleep (Baseline: 0h to 48h, Averaged per day) ---\n",
      "             Fly_Label  Base_Sleep_24h  Base_Day_12h  Base_Night_12h\n",
      "ETHOSCOPE_278 - Fly 01       11.508333      6.030793        6.068056\n",
      "ETHOSCOPE_278 - Fly 02       10.863889      4.857583        6.481944\n",
      "ETHOSCOPE_278 - Fly 03       10.951389      5.397998        6.081944\n",
      "ETHOSCOPE_278 - Fly 04       12.305556      5.017706        7.779167\n",
      "ETHOSCOPE_278 - Fly 05       12.623611      4.623557        8.452778\n",
      "ETHOSCOPE_278 - Fly 06        9.318056      3.846035        5.848611\n",
      "ETHOSCOPE_278 - Fly 07       10.198611      3.513472        7.029167\n",
      "ETHOSCOPE_278 - Fly 08       10.611111      3.398871        7.545833\n",
      "ETHOSCOPE_278 - Fly 09        9.495833      3.040801        6.752778\n",
      "ETHOSCOPE_278 - Fly 10        7.136111      1.992302        5.338889\n",
      "ETHOSCOPE_278 - Fly 11        7.872222      2.909931        5.247222\n",
      "ETHOSCOPE_278 - Fly 12       11.048611      4.259011        7.219444\n",
      "ETHOSCOPE_278 - Fly 13        9.591667      3.630485        6.316667\n",
      "ETHOSCOPE_278 - Fly 14        8.198611      4.460354        4.175000\n",
      "ETHOSCOPE_278 - Fly 15       10.927778      3.765974        7.530556\n",
      "ETHOSCOPE_278 - Fly 16       10.326389      4.676505        6.108333\n",
      "ETHOSCOPE_278 - Fly 17        8.308333      3.885214        4.813889\n",
      "ETHOSCOPE_278 - Fly 18        7.506944      2.677444        5.091667\n",
      "ETHOSCOPE_278 - Fly 19       12.595833      3.788501        9.179167\n",
      "ETHOSCOPE_278 - Fly 20        8.979167      3.086990        6.194444\n",
      "... (Showing first 20 rows)\n",
      "\n",
      "--- Grand Summary Statistics (Baseline: 0h to 48h) ---\n",
      "Total Flies Analyzed: n = 20\n",
      "\n",
      "[ OVERALL SLEEP (Scaled to 24h Baseline Average) ]\n",
      "Mean ± SEM:   10.02 ± 0.37 hours\n",
      "Median:       10.26 hours\n",
      "\n",
      "[ DAY TIME (ZT 0-12, Averaged to 12h blocks) ]\n",
      "Mean ± SEM:   3.94 ± 0.22 hours\n",
      "Median:       3.82 hours\n",
      "\n",
      "[ NIGHT TIME (ZT 12-24, Averaged to 12h blocks) ]\n",
      "Mean ± SEM:   6.46 ± 0.28 hours\n",
      "Median:       6.26 hours\n"
     ]
    }
   ],
   "source": [
    "# BASELINE\n",
    "\n",
    "# Define baseline time period\n",
    "start_hour = 0\n",
    "end_hour = 48\n",
    "\n",
    "# Filter the dataset to ONLY include data within specific baseline window\n",
    "base_df = df.t_filter(start_time=start_hour, end_time=end_hour).copy()\n",
    "\n",
    "# Calculate Overall 24h Baseline Average\n",
    "sleep_hours = (base_df.groupby('id')['asleep'].sum() * 10) / 3600\n",
    "\n",
    "# (48 - 0) / 24 evaluates to exactly 2 days. \n",
    "# Dividing total sleep by 2 to average the 48 hours into a single 24-hour metric\n",
    "days_tracked = (end_hour - start_hour) / 24 \n",
    "base_overall = (sleep_hours / days_tracked).reset_index(name='Base_Sleep_24h')\n",
    "\n",
    "# Calculate Day/Night 12h Baseline Averages\n",
    "base_df['zt_hour'] = (base_df['t'] / 3600) % 24\n",
    "base_df['Phase'] = np.where(base_df['zt_hour'] < 12, 'Day', 'Night')\n",
    "\n",
    "base_phase = base_df.groupby(['id', 'Phase']).agg(\n",
    "    total_sleep_epochs=('asleep', 'sum'),\n",
    "    total_tracking_epochs=('t', 'count')\n",
    ").reset_index()\n",
    "\n",
    "# Tracking_Hours will be ~24 for Day and ~24 for Night \n",
    "# Dividing sleep by 24 and multiplying by 12 averages it to a single 12h block.\n",
    "base_phase['Sleep_Hours'] = (base_phase['total_sleep_epochs'] * 10) / 3600\n",
    "base_phase['Tracking_Hours'] = (base_phase['total_tracking_epochs'] * 10) / 3600\n",
    "base_phase['Base_Sleep_12h'] = (base_phase['Sleep_Hours'] / base_phase['Tracking_Hours']) * 12\n",
    "\n",
    "base_pivot = base_phase.pivot(index='id', columns='Phase', values='Base_Sleep_12h').reset_index()\n",
    "# Rename columns\n",
    "base_pivot.columns = ['id', 'Base_Day_12h', 'Base_Night_12h']\n",
    "\n",
    "# Merge and clean up data\n",
    "merged_df = pd.merge(base_overall, base_pivot, on='id')\n",
    "\n",
    "merged_df['Machine'] = merged_df['id'].map(df.meta['machine_name'])\n",
    "merged_df['Tube'] = merged_df['id'].apply(lambda x: str(x).split('|')[-1])\n",
    "merged_df['Fly_Label'] = merged_df['Machine'] + \" - Fly \" + merged_df['Tube']\n",
    "\n",
    "clean_table = merged_df.dropna(subset=['Machine']).sort_values(by=['Machine', 'Tube'])\n",
    "baseline_stats = clean_table[['Fly_Label', 'Base_Sleep_24h', 'Base_Day_12h', 'Base_Night_12h']]\n",
    "\n",
    "# PRINT RESULTS\n",
    "print(f\"--- Individual Fly Sleep (Baseline: {start_hour}h to {end_hour}h, Averaged per day) ---\")\n",
    "print(baseline_stats.head(20).to_string(index=False)) \n",
    "print(\"... (Showing first 20 rows)\\n\")\n",
    "\n",
    "print(f\"--- Grand Summary Statistics (Baseline: {start_hour}h to {end_hour}h) ---\")\n",
    "print(f\"Total Flies Analyzed: n = {len(baseline_stats)}\")\n",
    "\n",
    "# 1. OVERALL 24H STATS\n",
    "print(\"\\n[ OVERALL SLEEP (Scaled to 24h Baseline Average) ]\")\n",
    "print(f\"Mean ± SEM:   {baseline_stats['Base_Sleep_24h'].mean():.2f} ± {baseline_stats['Base_Sleep_24h'].sem():.2f} hours\")\n",
    "print(f\"Median:       {baseline_stats['Base_Sleep_24h'].median():.2f} hours\")\n",
    "\n",
    "# 2. DAY TIME STATS\n",
    "print(f\"\\n[ DAY TIME (ZT 0-12, Averaged to 12h blocks) ]\")\n",
    "print(f\"Mean ± SEM:   {baseline_stats['Base_Day_12h'].mean():.2f} ± {baseline_stats['Base_Day_12h'].sem():.2f} hours\")\n",
    "print(f\"Median:       {baseline_stats['Base_Day_12h'].median():.2f} hours\")\n",
    "\n",
    "# 3. NIGHT TIME STATS\n",
    "print(f\"\\n[ NIGHT TIME (ZT 12-24, Averaged to 12h blocks) ]\")\n",
    "print(f\"Mean ± SEM:   {baseline_stats['Base_Night_12h'].mean():.2f} ± {baseline_stats['Base_Night_12h'].sem():.2f} hours\")\n",
    "print(f\"Median:       {baseline_stats['Base_Night_12h'].median():.2f} hours\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "6aa39f19-25f6-48cc-aceb-dc7accbc6a58",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--- Individual Fly Sleep (Stimulus: 48h to 72h) ---\n",
      "             Fly_Label  Stim_Sleep_24h  Stim_Day_12h  Stim_Night_12h\n",
      "ETHOSCOPE_278 - Fly 01       11.947222      4.252778        7.694444\n",
      "ETHOSCOPE_278 - Fly 02       11.638889      6.025000        5.613889\n",
      "ETHOSCOPE_278 - Fly 03       12.650000      5.280556        7.369444\n",
      "ETHOSCOPE_278 - Fly 04       10.319444      5.800000        4.519444\n",
      "ETHOSCOPE_278 - Fly 05       15.816667      7.772222        8.044444\n",
      "ETHOSCOPE_278 - Fly 06       11.011111      2.513889        8.497222\n",
      "ETHOSCOPE_278 - Fly 07       12.352778      4.850000        7.502778\n",
      "ETHOSCOPE_278 - Fly 08       10.591667      4.247222        6.344444\n",
      "ETHOSCOPE_278 - Fly 09        9.761111      6.705556        3.055556\n",
      "ETHOSCOPE_278 - Fly 10        5.716667      2.472222        3.244444\n",
      "ETHOSCOPE_278 - Fly 11       10.008333      4.850000        5.158333\n",
      "ETHOSCOPE_278 - Fly 12       10.355556      4.730556        5.625000\n",
      "ETHOSCOPE_278 - Fly 13       11.650000      5.130556        6.519444\n",
      "ETHOSCOPE_278 - Fly 14       13.888889      6.200000        7.688889\n",
      "ETHOSCOPE_278 - Fly 15       13.050000      5.519444        7.530556\n",
      "ETHOSCOPE_278 - Fly 16       12.097222      4.641667        7.455556\n",
      "ETHOSCOPE_278 - Fly 17       11.394444      5.036111        6.358333\n",
      "ETHOSCOPE_278 - Fly 18       10.991667      4.991667        6.000000\n",
      "ETHOSCOPE_278 - Fly 19       15.338889      6.291667        9.047222\n",
      "ETHOSCOPE_278 - Fly 20       11.936111      4.061111        7.875000\n",
      "... (Showing first 20 rows)\n",
      "\n",
      "--- Grand Summary Statistics (Stimulus: 48h to 72h) ---\n",
      "Total Flies Analyzed: n = 20\n",
      "\n",
      "[ OVERALL SLEEP (24h Stimulus Block) ]\n",
      "Mean ± SEM:   11.63 ± 0.48 hours\n",
      "Median:       11.64 hours\n",
      "\n",
      "[ DAY TIME (ZT 0-12 during Stimulus) ]\n",
      "Mean ± SEM:   5.07 ± 0.28 hours\n",
      "Median:       5.01 hours\n",
      "\n",
      "[ NIGHT TIME (ZT 12-24 during Stimulus) ]\n",
      "Mean ± SEM:   6.56 ± 0.37 hours\n",
      "Median:       6.94 hours\n"
     ]
    }
   ],
   "source": [
    "# Define stimulus time period\n",
    "start_hour = 48\n",
    "end_hour = 72\n",
    "\n",
    "# Filter the dataset to ONLY include data within specific stimulus window\n",
    "stim_df = df.t_filter(start_time=start_hour, end_time=end_hour).copy()\n",
    "\n",
    "# Calculate Overall 24h Stimulus Average\n",
    "sleep_hours = (stim_df.groupby('id')['asleep'].sum() * 10) / 3600\n",
    "days_tracked = (end_hour - start_hour) / 24 \n",
    "stim_overall = (sleep_hours / days_tracked).reset_index(name='Stim_Sleep_24h')\n",
    "\n",
    "# Calculate Day/Night 12h Stimulus Averages\n",
    "stim_df['zt_hour'] = (stim_df['t'] / 3600) % 24\n",
    "stim_df['Phase'] = np.where(stim_df['zt_hour'] < 12, 'Day', 'Night')\n",
    "\n",
    "stim_phase = stim_df.groupby(['id', 'Phase']).agg(\n",
    "    total_sleep_epochs=('asleep', 'sum'),\n",
    "    total_tracking_epochs=('t', 'count')\n",
    ").reset_index()\n",
    "\n",
    "# Tracking_Hours will now be ~12 for Day and ~12 for Night\n",
    "# Dividing sleep by tracking hours and multiplying by 12 averages it to a single 12h block.\n",
    "stim_phase['Sleep_Hours'] = (stim_phase['total_sleep_epochs'] * 10) / 3600\n",
    "stim_phase['Tracking_Hours'] = (stim_phase['total_tracking_epochs'] * 10) / 3600\n",
    "stim_phase['Stim_Sleep_12h'] = (stim_phase['Sleep_Hours'] / stim_phase['Tracking_Hours']) * 12\n",
    "\n",
    "stim_pivot = stim_phase.pivot(index='id', columns='Phase', values='Stim_Sleep_12h').reset_index()\n",
    "# Rename columns \n",
    "stim_pivot.columns = ['id', 'Stim_Day_12h', 'Stim_Night_12h']\n",
    "\n",
    "# Merge and clean up data\n",
    "merged_df = pd.merge(stim_overall, stim_pivot, on='id')\n",
    "\n",
    "merged_df['Machine'] = merged_df['id'].map(df.meta['machine_name'])\n",
    "merged_df['Tube'] = merged_df['id'].apply(lambda x: str(x).split('|')[-1])\n",
    "merged_df['Fly_Label'] = merged_df['Machine'] + \" - Fly \" + merged_df['Tube']\n",
    "\n",
    "clean_table = merged_df.dropna(subset=['Machine']).sort_values(by=['Machine', 'Tube'])\n",
    "stim_stats = clean_table[['Fly_Label', 'Stim_Sleep_24h', 'Stim_Day_12h', 'Stim_Night_12h']]\n",
    "\n",
    "# PRINT RESULTS\n",
    "print(f\"--- Individual Fly Sleep (Stimulus: {start_hour}h to {end_hour}h) ---\")\n",
    "print(stim_stats.head(20).to_string(index=False)) \n",
    "print(\"... (Showing first 20 rows)\\n\")\n",
    "\n",
    "print(f\"--- Grand Summary Statistics (Stimulus: {start_hour}h to {end_hour}h) ---\")\n",
    "print(f\"Total Flies Analyzed: n = {len(stim_stats)}\")\n",
    "\n",
    "# 1. OVERALL 24H STATS\n",
    "print(\"\\n[ OVERALL SLEEP (24h Stimulus Block) ]\")\n",
    "print(f\"Mean ± SEM:   {stim_stats['Stim_Sleep_24h'].mean():.2f} ± {stim_stats['Stim_Sleep_24h'].sem():.2f} hours\")\n",
    "print(f\"Median:       {stim_stats['Stim_Sleep_24h'].median():.2f} hours\")\n",
    "\n",
    "# 2. DAY TIME STATS\n",
    "print(f\"\\n[ DAY TIME (ZT 0-12 during Stimulus) ]\")\n",
    "print(f\"Mean ± SEM:   {stim_stats['Stim_Day_12h'].mean():.2f} ± {stim_stats['Stim_Day_12h'].sem():.2f} hours\")\n",
    "print(f\"Median:       {stim_stats['Stim_Day_12h'].median():.2f} hours\")\n",
    "\n",
    "# 3. NIGHT TIME STATS\n",
    "print(f\"\\n[ NIGHT TIME (ZT 12-24 during Stimulus) ]\")\n",
    "print(f\"Mean ± SEM:   {stim_stats['Stim_Night_12h'].mean():.2f} ± {stim_stats['Stim_Night_12h'].sem():.2f} hours\")\n",
    "print(f\"Median:       {stim_stats['Stim_Night_12h'].median():.2f} hours\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "id": "6449454d-1195-451f-b5d2-77887dae0cdc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "--- 24h Total Statistical Analysis ---\n",
      "Shapiro-Wilk P-value (Normality of differences): 0.7122\n",
      "Result: Data is normal. Used Paired T-test.\n",
      "P-value: 8.6132e-04\n",
      "Significance: ***\n",
      "\n",
      "--- Daytime Statistical Analysis ---\n",
      "Shapiro-Wilk P-value (Normality of differences): 0.8870\n",
      "Result: Data is normal. Used Paired T-test.\n",
      "P-value: 1.2991e-03\n",
      "Significance: **\n",
      "\n",
      "--- Nighttime Statistical Analysis ---\n",
      "Shapiro-Wilk P-value (Normality of differences): 0.8906\n",
      "Result: Data is normal. Used Paired T-test.\n",
      "P-value: 8.2210e-01\n",
      "Significance: ns\n"
     ]
    }
   ],
   "source": [
    "from scipy.stats import shapiro, wilcoxon, ttest_rel\n",
    "\n",
    "# 1. Merge Baseline and Stimulus data on Fly_Label\n",
    "paired_df = pd.merge(baseline_stats, stim_stats, on='Fly_Label')\n",
    "\n",
    "def run_paired_stats(df, base_col, stim_col, label):\n",
    "    # Calculate the differences for the paired test\n",
    "    diffs = df[stim_col] - df[base_col]\n",
    "    \n",
    "    # 2. Shapiro-Wilk Test for Normality\n",
    "    _, p_shapiro = shapiro(diffs)\n",
    "    \n",
    "    print(f\"\\n--- {label} Statistical Analysis ---\")\n",
    "    print(f\"Shapiro-Wilk P-value (Normality of differences): {p_shapiro:.4f}\")\n",
    "    \n",
    "    # 3. Determine Test: If P > 0.05, data is normal (use t-test). If P < 0.05, use Wilcoxon.\n",
    "    if p_shapiro > 0.05:\n",
    "        stat, p_val = ttest_rel(df[base_col], df[stim_col])\n",
    "        print(f\"Result: Data is normal. Used Paired T-test.\")\n",
    "    else:\n",
    "        stat, p_val = wilcoxon(df[base_col], df[stim_col])\n",
    "        print(f\"Result: Data is not normal. Used Wilcoxon Signed-Rank test.\")\n",
    "        \n",
    "    print(f\"P-value: {p_val:.4e}\")\n",
    "    if p_val < 0.0001: print(\"Significance: ****\")\n",
    "    elif p_val < 0.001: print(\"Significance: ***\")\n",
    "    elif p_val < 0.01: print(\"Significance: **\")\n",
    "    elif p_val < 0.05: print(\"Significance: *\")\n",
    "    else: print(\"Significance: ns\")\n",
    "\n",
    "# Run for all three metrics\n",
    "run_paired_stats(paired_df, 'Base_Sleep_24h', 'Stim_Sleep_24h', '24h Total')\n",
    "run_paired_stats(paired_df, 'Base_Day_12h', 'Stim_Day_12h', 'Daytime')\n",
    "run_paired_stats(paired_df, 'Base_Night_12h', 'Stim_Night_12h', 'Nighttime')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "id": "f4bf7cde-117c-4ce5-a591-e595f0ac297b",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_38794/1708898274.py:27: FutureWarning: \n",
      "\n",
      "Setting a gradient palette using color= is deprecated and will be removed in v0.14.0. Set `palette='dark:black'` for the same effect.\n",
      "\n",
      "  sns.stripplot(\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 51920 characters]",
      "text/plain": [
       "<Figure size 700x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 1. PREPARE DATA\n",
    "combined = pd.merge(baseline_stats, stim_stats, on='Fly_Label')\n",
    "plot_df = combined.melt(id_vars=['Fly_Label'], var_name='Variable', value_name='Hours')\n",
    "plot_df['Condition'] = plot_df['Variable'].apply(lambda x: '24h' if '24h' in x else ('Day' if 'Day' in x else 'Night'))\n",
    "plot_df['State'] = plot_df['Variable'].apply(lambda x: 'Baseline' if 'Base' in x else 'Stimulus')\n",
    "\n",
    "# 2. GENERATE PLOT\n",
    "plt.figure(figsize=(7, 6))\n",
    "sns.set_theme(style=\"ticks\")\n",
    "\n",
    "order = ['24h', 'Day', 'Night']\n",
    "hue_order = ['Baseline', 'Stimulus']\n",
    "palette = {'Baseline': '#cccccc', 'Stimulus': '#ff4c4c'}\n",
    "\n",
    "# Boxplot (This will generate the legend)\n",
    "sns.boxplot(\n",
    "    data=plot_df, x='Condition', y='Hours', hue='State', \n",
    "    order=order, hue_order=hue_order, palette=palette,\n",
    "    width=0.6, \n",
    "    gap=0.2, \n",
    "    boxprops={'edgecolor': 'black', 'alpha': 0.7},\n",
    "    medianprops={'color': 'black', 'linewidth': 1.5}, showfliers=False\n",
    ")\n",
    "\n",
    "# Stripplot\n",
    "sns.stripplot(\n",
    "    data=plot_df, x='Condition', y='Hours', hue='State', \n",
    "    order=order, hue_order=hue_order, dodge=True,\n",
    "    color='black', alpha=0.5, size=4, jitter=0.05,\n",
    "    legend=False\n",
    ")\n",
    "\n",
    "# 3. ADD MEDIAN LABELS\n",
    "ax = plt.gca()\n",
    "medians = plot_df.groupby(['Condition', 'State'], sort=False)['Hours'].median()\n",
    "\n",
    "# Offsets remain at 0.4 to match the new box centers with gap=0.2\n",
    "offsets = {'Baseline': -0.4, 'Stimulus': 0.4}\n",
    "\n",
    "for i, cond in enumerate(order):\n",
    "    for state in hue_order:\n",
    "        val = medians[(cond, state)]\n",
    "        ax.text(i + offsets[state], val, f\"{val:.1f}h\", \n",
    "                ha='center', va='bottom', fontsize=10)\n",
    "\n",
    "# 4. FORMATTING\n",
    "sns.despine()\n",
    "plt.ylabel('Average time spent asleep (hours)', fontsize=12)\n",
    "plt.xlabel('')\n",
    "plt.ylim(0, 18) \n",
    "plt.legend(title='', frameon=False)\n",
    "plt.tight_layout()\n",
    "\n",
    "plt.savefig(\"CantonS_Red.png\", dpi=600, bbox_inches='tight')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 133,
   "id": "606952df-3087-480a-8a76-71cbd659c0a7",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_38794/2013331516.py:45: FutureWarning: \n",
      "\n",
      "Setting a gradient palette using color= is deprecated and will be removed in v0.14.0. Set `palette='dark:black'` for the same effect.\n",
      "\n",
      "  sns.stripplot(\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 53640 characters]",
      "text/plain": [
       "<Figure size 700x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 1. PREPARE DATA & CALCULATE STATS\n",
    "combined = pd.merge(baseline_stats, stim_stats, on='Fly_Label')\n",
    "\n",
    "# Calculate the paired statistics for the brackets\n",
    "p_values = {}\n",
    "metrics = {\n",
    "    '24h': ('Base_Sleep_24h', 'Stim_Sleep_24h'),\n",
    "    'Day': ('Base_Day_12h', 'Stim_Day_12h'),\n",
    "    'Night': ('Base_Night_12h', 'Stim_Night_12h')\n",
    "}\n",
    "\n",
    "for phase, (base_col, stim_col) in metrics.items():\n",
    "    diffs = combined[stim_col] - combined[base_col]\n",
    "    _, p_shapiro = shapiro(diffs)\n",
    "    \n",
    "    # Use Paired T-Test if normal, Wilcoxon if not\n",
    "    if p_shapiro > 0.05:\n",
    "        _, p_val = ttest_rel(combined[base_col], combined[stim_col])\n",
    "    else:\n",
    "        _, p_val = wilcoxon(combined[base_col], combined[stim_col])\n",
    "    p_values[phase] = p_val\n",
    "\n",
    "# Melt the data for plotting\n",
    "plot_df = combined.melt(id_vars=['Fly_Label'], var_name='Variable', value_name='Hours')\n",
    "plot_df['Condition'] = plot_df['Variable'].apply(lambda x: '24h' if '24h' in x else ('Day' if 'Day' in x else 'Night'))\n",
    "plot_df['State'] = plot_df['Variable'].apply(lambda x: 'Baseline' if 'Base' in x else 'Stimulus')\n",
    "\n",
    "# 2. GENERATE PLOT\n",
    "plt.figure(figsize=(7, 6))\n",
    "sns.set_theme(style=\"ticks\")\n",
    "\n",
    "order = ['24h', 'Day', 'Night']\n",
    "hue_order = ['Baseline', 'Stimulus']\n",
    "palette = {'Baseline': '#cccccc', 'Stimulus': '#ff4c4c'}\n",
    "\n",
    "# Boxplot\n",
    "sns.boxplot(\n",
    "    data=plot_df, x='Condition', y='Hours', hue='State', \n",
    "    order=order, hue_order=hue_order, palette=palette,\n",
    "    width=0.6, gap=0.2, boxprops={'edgecolor': 'black', 'alpha': 0.7},\n",
    "    medianprops={'color': 'black', 'linewidth': 1.5}, showfliers=False\n",
    ")\n",
    "\n",
    "# Stripplot\n",
    "sns.stripplot(\n",
    "    data=plot_df, x='Condition', y='Hours', hue='State', \n",
    "    order=order, hue_order=hue_order, dodge=True,\n",
    "    color='black', alpha=0.5, size=4, jitter=0.05,\n",
    "    legend=False\n",
    ")\n",
    "\n",
    "# 3. ADD MEDIAN LABELS\n",
    "ax = plt.gca()\n",
    "medians = plot_df.groupby(['Condition', 'State'], sort=False)['Hours'].median()\n",
    "\n",
    "offsets = {'Baseline': -0.4, 'Stimulus': 0.4}\n",
    "\n",
    "for i, cond in enumerate(order):\n",
    "    for state in hue_order:\n",
    "        val = medians[(cond, state)]\n",
    "        ax.text(i + offsets[state], val, f\"{val:.1f}h\", \n",
    "                ha='center', va='bottom', fontsize=10)\n",
    "\n",
    "# 4. ADD SIGNIFICANCE BRACKETS\n",
    "y_max = plot_df['Hours'].max()\n",
    "y_line = y_max + 1.0  # Float the bracket 1 hour above the highest data point\n",
    "h = 0.4               # Height of the bracket's downward ticks\n",
    "\n",
    "for i, cond in enumerate(order):\n",
    "    p = p_values[cond]\n",
    "    \n",
    "    # Determine the correct asterisk\n",
    "    if p < 0.0001: star = '****'\n",
    "    elif p < 0.001: star = '***'\n",
    "    elif p < 0.01: star = '**'\n",
    "    elif p < 0.05: star = '*'\n",
    "    else: star = 'ns'\n",
    "    \n",
    "    # Bracket coordinates (Centers of the Baseline and Stimulus boxes)\n",
    "    x1, x2 = i - 0.2, i + 0.2\n",
    "    \n",
    "    # Draw the bracket line\n",
    "    plt.plot([x1, x1, x2, x2], [y_line, y_line+h, y_line+h, y_line], lw=1.5, c='k')\n",
    "    \n",
    "    # Place the text above the bracket\n",
    "    plt.text((x1+x2)*.5, y_line+h, star, ha='center', va='bottom', fontsize=12)\n",
    "\n",
    "# 5. FORMATTING\n",
    "sns.despine()\n",
    "plt.ylabel('Average time spent asleep (hours)', fontsize=12)\n",
    "plt.xlabel('')\n",
    "\n",
    "plt.xlim(-0.6, 2.5) \n",
    "\n",
    "plt.legend(title='', frameon=False)\n",
    "plt.tight_layout()\n",
    "plt.ylim(0, max(18, y_line + h + 1.5))\n",
    "\n",
    "plt.legend(title='', frameon=False, loc='center left', bbox_to_anchor=(1, 0.5))\n",
    "plt.tight_layout()\n",
    "plt.savefig(\"CantonS_Red.png\", dpi=600, bbox_inches='tight')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 116,
   "id": "5f77fc74-7bea-4c2c-a498-791a4656f46f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--- Delta Sleep (Stimulus - Baseline) per Fly ---\n",
      "             Fly_Label  Delta_24h  Delta_Day  Delta_Night\n",
      "ETHOSCOPE_278 - Fly 01   0.438889  -1.778015     1.626389\n",
      "ETHOSCOPE_278 - Fly 02   0.775000   1.167417    -0.868056\n",
      "ETHOSCOPE_278 - Fly 03   1.698611  -0.117443     1.287500\n",
      "ETHOSCOPE_278 - Fly 04  -1.986111   0.782294    -3.259722\n",
      "ETHOSCOPE_278 - Fly 05   3.193056   3.148666    -0.408333\n",
      "ETHOSCOPE_278 - Fly 06   1.693056  -1.332147     2.648611\n",
      "ETHOSCOPE_278 - Fly 07   2.154167   1.336528     0.473611\n",
      "ETHOSCOPE_278 - Fly 08  -0.019444   0.848352    -1.201389\n",
      "ETHOSCOPE_278 - Fly 09   0.265278   3.664755    -3.697222\n",
      "ETHOSCOPE_278 - Fly 10  -1.419444   0.479920    -2.094444\n",
      "ETHOSCOPE_278 - Fly 11   2.136111   1.940069    -0.088889\n",
      "ETHOSCOPE_278 - Fly 12  -0.693056   0.471544    -1.594444\n",
      "ETHOSCOPE_278 - Fly 13   2.058333   1.500071     0.202778\n",
      "ETHOSCOPE_278 - Fly 14   5.690278   1.739646     3.513889\n",
      "ETHOSCOPE_278 - Fly 15   2.122222   1.753471     0.000000\n",
      "ETHOSCOPE_278 - Fly 16   1.770833  -0.034838     1.347222\n",
      "ETHOSCOPE_278 - Fly 17   3.086111   1.150897     1.544444\n",
      "ETHOSCOPE_278 - Fly 18   3.484722   2.314222     0.908333\n",
      "ETHOSCOPE_278 - Fly 19   2.743056   2.503166    -0.131944\n",
      "ETHOSCOPE_278 - Fly 20   2.956944   0.974121     1.680556\n",
      "\n",
      "==================================================\n",
      "\n",
      "--- Average Change (Delta) across all flies ---\n",
      "Delta_24h: 1.61 ± 0.41 hours\n",
      "Delta_Day: 1.13 ± 0.30 hours\n",
      "Delta_Night: 0.09 ± 0.41 hours\n"
     ]
    }
   ],
   "source": [
    "#DELTA\n",
    "\n",
    "# 1. Ensure have the merged paired data\n",
    "combined = pd.merge(baseline_stats, stim_stats, on='Fly_Label')\n",
    "\n",
    "# 2. Calculate the Delta (Stimulus - Baseline) for each fly\n",
    "combined['Delta_24h'] = combined['Stim_Sleep_24h'] - combined['Base_Sleep_24h']\n",
    "combined['Delta_Day'] = combined['Stim_Day_12h'] - combined['Base_Day_12h']\n",
    "combined['Delta_Night'] = combined['Stim_Night_12h'] - combined['Base_Night_12h']\n",
    "\n",
    "# 3. Print the Delta for each individual fly\n",
    "print(\"--- Delta Sleep (Stimulus - Baseline) per Fly ---\")\n",
    "delta_table = combined[['Fly_Label', 'Delta_24h', 'Delta_Day', 'Delta_Night']]\n",
    "print(delta_table.to_string(index=False))\n",
    "print(\"\\n\" + \"=\"*50 + \"\\n\")\n",
    "\n",
    "# 4. Calculate and print the group averages\n",
    "print(\"--- Average Change (Delta) across all flies ---\")\n",
    "avg_delta = delta_table[['Delta_24h', 'Delta_Day', 'Delta_Night']].mean()\n",
    "sem_delta = delta_table[['Delta_24h', 'Delta_Day', 'Delta_Night']].sem()\n",
    "\n",
    "for metric in ['Delta_24h', 'Delta_Day', 'Delta_Night']:\n",
    "    print(f\"{metric}: {avg_delta[metric]:.2f} ± {sem_delta[metric]:.2f} hours\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 117,
   "id": "673c571d-ec35-4f87-b58f-127bd6b9c379",
   "metadata": {},
   "outputs": [],
   "source": [
    "#export to csv\n",
    "delta_table['Condition'] = 'Red'\n",
    "delta_table.to_csv('delta_red.csv', index=False)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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
}
