320 lines
69 KiB
Text
320 lines
69 KiB
Text
|
|
{
|
||
|
|
"cells": [
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": null,
|
||
|
|
"id": "6292486f-f8e8-47ab-812f-ebe9f5214f56",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"# COMPARE RED VS GREEN STIMULUS IN CANTONS"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 5,
|
||
|
|
"id": "30307c96-a288-4ab0-9554-68ec28ad686d",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"import ethoscopy as etho\n",
|
||
|
|
"import pandas as pd\n",
|
||
|
|
"import numpy as np\n",
|
||
|
|
"import matplotlib.pyplot as plt\n",
|
||
|
|
"import seaborn as sns\n",
|
||
|
|
"from scipy.stats import ttest_ind"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 6,
|
||
|
|
"id": "ffa045e8-3154-435e-89d5-819f1dec42fd",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"# 1. LOAD THE SAVED PICKLE FILES\n",
|
||
|
|
"\n",
|
||
|
|
"df_red_raw = pd.read_pickle('/home/rdingjin/Optic_2026-04-01/phase2.pkl')\n",
|
||
|
|
"df_green_raw = pd.read_pickle('/home/rdingjin/CantonS_2026-05-01/phase3.pkl')"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 13,
|
||
|
|
"id": "9c34a8ba-a969-4824-87da-53599529e8b9",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"# 2. HELPER FUNCTION TO CALCULATE DELTA SLEEP\n",
|
||
|
|
"\n",
|
||
|
|
"def calculate_delta_sleep(df, base_start, base_end, stim_start, stim_end):\n",
|
||
|
|
" \"\"\"Automates baseline vs stimulus pipeline and returns Delta Sleep\"\"\"\n",
|
||
|
|
" \n",
|
||
|
|
" # --- BASELINE ---\n",
|
||
|
|
" base_df = df.t_filter(start_time=base_start, end_time=base_end).copy()\n",
|
||
|
|
" \n",
|
||
|
|
" sleep_hours_base = (base_df.groupby('id')['asleep'].sum() * 10) / 3600\n",
|
||
|
|
" base_overall = (sleep_hours_base / ((base_end - base_start) / 24)).reset_index(name='Base_Sleep_24h')\n",
|
||
|
|
" \n",
|
||
|
|
" base_df['zt_hour'] = (base_df['t'] / 3600) % 24\n",
|
||
|
|
" base_df['Phase'] = np.where(base_df['zt_hour'] < 12, 'Day', 'Night')\n",
|
||
|
|
" base_phase = base_df.groupby(['id', 'Phase']).agg(\n",
|
||
|
|
" total_sleep_epochs=('asleep', 'sum'), total_tracking_epochs=('t', 'count')\n",
|
||
|
|
" ).reset_index()\n",
|
||
|
|
" \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",
|
||
|
|
" base_pivot = base_phase.pivot(index='id', columns='Phase', values='Base_Sleep_12h').reset_index()\n",
|
||
|
|
" base_pivot.columns = ['id', 'Base_Day_12h', 'Base_Night_12h']\n",
|
||
|
|
" baseline_stats = pd.merge(base_overall, base_pivot, on='id')\n",
|
||
|
|
" \n",
|
||
|
|
" # --- STIMULUS ---\n",
|
||
|
|
" stim_df = df.t_filter(start_time=stim_start, end_time=stim_end).copy()\n",
|
||
|
|
" \n",
|
||
|
|
" sleep_hours_stim = (stim_df.groupby('id')['asleep'].sum() * 10) / 3600\n",
|
||
|
|
" stim_overall = (sleep_hours_stim / ((stim_end - stim_start) / 24)).reset_index(name='Stim_Sleep_24h')\n",
|
||
|
|
" \n",
|
||
|
|
" stim_df['zt_hour'] = (stim_df['t'] / 3600) % 24\n",
|
||
|
|
" stim_df['Phase'] = np.where(stim_df['zt_hour'] < 12, 'Day', 'Night')\n",
|
||
|
|
" stim_phase = stim_df.groupby(['id', 'Phase']).agg(\n",
|
||
|
|
" total_sleep_epochs=('asleep', 'sum'), total_tracking_epochs=('t', 'count')\n",
|
||
|
|
" ).reset_index()\n",
|
||
|
|
" \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",
|
||
|
|
" stim_pivot = stim_phase.pivot(index='id', columns='Phase', values='Stim_Sleep_12h').reset_index()\n",
|
||
|
|
" stim_pivot.columns = ['id', 'Stim_Day_12h', 'Stim_Night_12h']\n",
|
||
|
|
" stim_stats = pd.merge(stim_overall, stim_pivot, on='id')\n",
|
||
|
|
" \n",
|
||
|
|
" # --- MERGE & CALCULATE DELTA ---\n",
|
||
|
|
" combined = pd.merge(baseline_stats, stim_stats, on='id')\n",
|
||
|
|
" \n",
|
||
|
|
" unique_meta = df.meta['machine_name'][~df.meta.index.duplicated(keep='first')]\n",
|
||
|
|
" combined['Machine'] = combined['id'].map(unique_meta)\n",
|
||
|
|
" combined['Tube'] = combined['id'].apply(lambda x: str(x).split('|')[-1])\n",
|
||
|
|
" combined['Fly_Label'] = combined['Machine'] + \" - Fly \" + combined['Tube']\n",
|
||
|
|
" \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",
|
||
|
|
" return combined[['Fly_Label', 'Delta_24h', 'Delta_Day', 'Delta_Night']].dropna()"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 14,
|
||
|
|
"id": "3b7caa58-7f73-42ef-9df1-83cc6dd21ef3",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"Processing Red Light Data...\n",
|
||
|
|
"Processing Green Light Data...\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"# 3. PROCESS GROUPS AND COMBINE\n",
|
||
|
|
"\n",
|
||
|
|
"print(\"Processing Red Light Data...\")\n",
|
||
|
|
"delta_red = calculate_delta_sleep(df_red_raw, base_start=0, base_end=48, stim_start=48, stim_end=72)\n",
|
||
|
|
"delta_red['Condition'] = 'Red'\n",
|
||
|
|
"\n",
|
||
|
|
"print(\"Processing Green Light Data...\")\n",
|
||
|
|
"delta_green = calculate_delta_sleep(df_green_raw, base_start=0, base_end=72, stim_start=72, stim_end=96)\n",
|
||
|
|
"delta_green['Condition'] = 'Green'\n",
|
||
|
|
"\n",
|
||
|
|
"# Merge them into a single Master table\n",
|
||
|
|
"master_delta = pd.concat([delta_red, delta_green], ignore_index=True)\n",
|
||
|
|
"\n",
|
||
|
|
"# Melt the data for plotting and stats (24h, Day, Night stacked)\n",
|
||
|
|
"melted_delta = master_delta.melt(\n",
|
||
|
|
" id_vars=['Fly_Label', 'Condition'],\n",
|
||
|
|
" value_vars=['Delta_24h', 'Delta_Day', 'Delta_Night'],\n",
|
||
|
|
" var_name='Phase', \n",
|
||
|
|
" value_name='Sleep_Change'\n",
|
||
|
|
")\n",
|
||
|
|
"# Clean up phase names\n",
|
||
|
|
"melted_delta['Phase'] = melted_delta['Phase'].map({'Delta_24h': '24h Total', 'Delta_Day': 'Day', 'Delta_Night': 'Night'})"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 15,
|
||
|
|
"id": "1af708c4-5cc8-4b02-a28d-e5a219007f6e",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"\n",
|
||
|
|
"==================================================\n",
|
||
|
|
"--- SCIPY T-TESTS (Red vs Green Delta) ---\n",
|
||
|
|
"==================================================\n",
|
||
|
|
"24h Total Phase Comparison:\n",
|
||
|
|
" Red Δ Mean: 1.61 hours\n",
|
||
|
|
" Green Δ Mean: -3.73 hours\n",
|
||
|
|
" P-value: 2.5958e-07\n",
|
||
|
|
"\n",
|
||
|
|
"Day Phase Comparison:\n",
|
||
|
|
" Red Δ Mean: 1.13 hours\n",
|
||
|
|
" Green Δ Mean: -1.69 hours\n",
|
||
|
|
" P-value: 8.3423e-07\n",
|
||
|
|
"\n",
|
||
|
|
"Night Phase Comparison:\n",
|
||
|
|
" Red Δ Mean: 0.09 hours\n",
|
||
|
|
" Green Δ Mean: -2.76 hours\n",
|
||
|
|
" P-value: 4.9990e-05\n",
|
||
|
|
"\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"# 4. STATISTICAL COMPARISON \n",
|
||
|
|
"\n",
|
||
|
|
"print(\"\\n\" + \"=\"*50)\n",
|
||
|
|
"print(\"--- SCIPY T-TESTS (Red vs Green Delta) ---\")\n",
|
||
|
|
"print(\"=\"*50)\n",
|
||
|
|
"\n",
|
||
|
|
"p_values = {}\n",
|
||
|
|
"phases = ['24h Total', 'Day', 'Night']\n",
|
||
|
|
"\n",
|
||
|
|
"for phase in phases:\n",
|
||
|
|
" group_red = melted_delta[(melted_delta['Phase'] == phase) & (melted_delta['Condition'] == 'Red')]['Sleep_Change']\n",
|
||
|
|
" group_green = melted_delta[(melted_delta['Phase'] == phase) & (melted_delta['Condition'] == 'Green')]['Sleep_Change']\n",
|
||
|
|
" \n",
|
||
|
|
" # Run Independent T-Test\n",
|
||
|
|
" t_stat, p_val = ttest_ind(group_red, group_green)\n",
|
||
|
|
" p_values[phase] = p_val\n",
|
||
|
|
" \n",
|
||
|
|
" print(f\"{phase} Phase Comparison:\")\n",
|
||
|
|
" print(f\" Red Δ Mean: {group_red.mean():.2f} hours\")\n",
|
||
|
|
" print(f\" Green Δ Mean: {group_green.mean():.2f} hours\")\n",
|
||
|
|
" print(f\" P-value: {p_val:.4e}\\n\")"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 25,
|
||
|
|
"id": "f31cbe1e-e965-4eef-a01e-a74cfdf2551d",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stderr",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"/tmp/ipykernel_49373/2116923427.py:14: 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": "iVBORw0KGgoAAAANSUhEUgAAAxAAAAJICAYAAADxUwLTAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAArElJREFUeJzs3XdYU/f+B/B3BiEECHuDqKgIKC7cs2q1jjo7tWprtVpbrV2/Wnurbe+t2j2silVbrfbWOlpH66qjWvdCUVQUUARkyUqYmb8/kFwiQwyBQHi/nqdPOed8c/IGQ8jnnO8Q6PV6PYiIiIiIiGpAaOkARERERETUeLCAICIiIiKiGmMBQURERERENcYCgoiIiIiIaowFBBERERER1RgLCCIiIiIiqjEWEEREREREVGMsIIiIiIiIqMZYQNSz5557Ds8995ylYxARERERmURs6QBNTWpqqqUjEBERERGZjHcgiIiIiIioxlhAEBERERFRjbGAICIiIiKiGmMBQURERERENcYCgoiIiIiIaowFBBERERER1RgLCCIiIiIiqjEWEEREREREVGMsIIiIiIiIqMZYQBARERERUY2xgCAiIiIiohpjAUFERERERDXGAoKIiIiIiGqMBQQREREREdUYCwgiIiIiIqoxFhBERERERFRjLCCIiIiIiKjGWEAQEREREVGNsYAgIiIiIqIaYwFBREREREQ1xgKCiIiIiIhqjAUEERERERHVGAsIIiIiIiKqMRYQRERERERUYywgiIiIiIioxlhAEBERERFRjYktHaA+TJo0CadPn6702JdffokRI0ZUemzgwIFISUmpsD86Ohq2trZmzUhERERE1Bg0iQJi4cKFyM/PN9q3bt067Nu3Dz179qz2sUOHDsXUqVON9kkkErNnJCIiIiJqDJpEAdGqVasK+95880307t0brq6u1T7W3d0dHTt2rKNkRERERESNS5McA3H+/HkkJyfj8ccft3QUIiIiIqJGpUkWEH/88QdkMhkGDRr0wLY7d+5Eu3bt0KlTJ0yfPh2xsbH1kJCIiIiIqGFqEl2YytNoNNi9ezcGDhwImUxWbduBAwciPDwcvr6+SEpKQmRkJCZMmIBt27YhICCgysdVV5ikpqbCx8fH5PxERERERJbU5O5AHDt2DNnZ2Rg5cuQD2/7rX//CqFGjEBERgbFjx2L9+vUA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
|
||
|
|
"text/plain": [
|
||
|
|
"<Figure size 800x600 with 1 Axes>"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "display_data"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"# 5. FINAL COMPARISON PLOT\n",
|
||
|
|
"plt.figure(figsize=(8, 6))\n",
|
||
|
|
"sns.set_theme(style=\"ticks\")\n",
|
||
|
|
"\n",
|
||
|
|
"# Plot Boxplot\n",
|
||
|
|
"ax = sns.boxplot(\n",
|
||
|
|
" data=melted_delta, x='Phase', y='Sleep_Change', hue='Condition', \n",
|
||
|
|
" palette={'Red': '#ff4c4c', 'Green': '#51ff4c'}, order=phases,\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",
|
||
|
|
"# Plot internal points\n",
|
||
|
|
"sns.stripplot(\n",
|
||
|
|
" data=melted_delta, x='Phase', y='Sleep_Change', hue='Condition', \n",
|
||
|
|
" order=phases, dodge=True,\n",
|
||
|
|
" color='black', alpha=0.5, size=4, jitter=0.05, legend=False\n",
|
||
|
|
")\n",
|
||
|
|
"\n",
|
||
|
|
"# Median labels\n",
|
||
|
|
"medians = melted_delta.groupby(['Phase', 'Condition'], sort=False)['Sleep_Change'].median()\n",
|
||
|
|
"offsets = {'Red': -0.4, 'Green': 0.4}\n",
|
||
|
|
"\n",
|
||
|
|
"for i, phase in enumerate(phases):\n",
|
||
|
|
" for condition in ['Red', 'Green']:\n",
|
||
|
|
" val = medians[(phase, condition)]\n",
|
||
|
|
" ax.text(i + offsets[condition], val, f\"{val:.1f}h\", \n",
|
||
|
|
" ha='center', va='bottom', fontsize=9)\n",
|
||
|
|
"\n",
|
||
|
|
"# Add Significance Brackets/Stars\n",
|
||
|
|
"y_max = melted_delta['Sleep_Change'].max()\n",
|
||
|
|
"y_min = melted_delta['Sleep_Change'].min()\n",
|
||
|
|
"y_range = y_max - y_min\n",
|
||
|
|
"y_line = y_max + (y_range * 0.05)\n",
|
||
|
|
"h = y_range * 0.02\n",
|
||
|
|
"\n",
|
||
|
|
"for i, phase in enumerate(phases):\n",
|
||
|
|
" p = p_values[phase]\n",
|
||
|
|
" if p < 0.05:\n",
|
||
|
|
" star = '****' if p < 0.0001 else ('***' if p < 0.001 else ('**' if p < 0.01 else '*'))\n",
|
||
|
|
" \n",
|
||
|
|
" # Draw bracket from Red center to Green center\n",
|
||
|
|
" x1, x2 = i - 0.2, i + 0.2\n",
|
||
|
|
" plt.plot([x1, x1, x2, x2], [y_line, y_line+h, y_line+h, y_line], lw=1.5, c='k')\n",
|
||
|
|
" plt.text((x1+x2)*.5, y_line+h, star, ha='center', va='bottom', fontsize=12)\n",
|
||
|
|
"\n",
|
||
|
|
"# Add a reference line at 0 \n",
|
||
|
|
"plt.axhline(0, color='black', linestyle='--', linewidth=1.5, alpha=0.7)\n",
|
||
|
|
"plt.text(2.5, 0.2, 'Baseline', ha='left', va='bottom', fontsize=10, alpha=0.7)\n",
|
||
|
|
"\n",
|
||
|
|
"# Formatting\n",
|
||
|
|
"sns.despine()\n",
|
||
|
|
"plt.ylabel('Change in average time spent asleep (Δ hours)', fontsize=12)\n",
|
||
|
|
"plt.xlabel('')\n",
|
||
|
|
"plt.xlim(-0.5, 2.5) \n",
|
||
|
|
"\n",
|
||
|
|
"# Move legend outside the plot\n",
|
||
|
|
"plt.legend(title='', frameon=False, loc='center left', bbox_to_anchor=(1, 0.5))\n",
|
||
|
|
"\n",
|
||
|
|
"plt.ylim(y_min - (y_range * 0.1), y_max + (y_range * 0.2)) # Give room for stars\n",
|
||
|
|
"plt.tight_layout()\n",
|
||
|
|
"\n",
|
||
|
|
"plt.savefig(\"Red_vs_Green.png\", dpi=600, bbox_inches='tight')\n",
|
||
|
|
"plt.show()"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"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
|
||
|
|
}
|