From d5951196159259fb233abb8fbe147c7727464bf4 Mon Sep 17 00:00:00 2001 From: Gabriella Chan Date: Wed, 6 Nov 2024 15:21:03 +1100 Subject: [PATCH] updated readme and examples --- README.md | 27 +++-- data/behapy-ppd.png | Bin 0 -> 50319 bytes examples/analyse.ipynb | 232 ++++++++++++++++++++++++++++++++++++++ examples/showevents.ipynb | 11 +- poisson_test.py | 0 5 files changed, 257 insertions(+), 13 deletions(-) create mode 100644 data/behapy-ppd.png create mode 100644 examples/analyse.ipynb create mode 100644 poisson_test.py diff --git a/README.md b/README.md index 831ed9e..fb031ae 100644 --- a/README.md +++ b/README.md @@ -11,25 +11,38 @@ conda activate behapy pip install -e . ``` -## Examples +## Preprocessing -There is a MedPC event reading example in the examples subfolder. This example by default assumes MedPC data files are in the same folder as the notebook file. +To use behapy, the TDT proprietary formatted source data needs to first be converted BIDS-like raw data format. This assumes session_map.csv is in the sourcedata_root folder: +`tdt2bids [session_fn] [experiment_fn] [bidsroot]` -## Preprocessing +Alternatively, you can specify the source data directory with --sourcedata_root. (Note that this path is relative to session_fn and not the current directory.): -Convert TDT source data to BIDS-like raw data format: +`tdt2bids [--sourcedata_root sourcedata_root] [session_fn] [experiment_fn] [bidsroot]` -`tdt2bids [session_fn] [experiment_fn] [bidsroot]` +This will output raw data files in +`[bidsroot]/rawdata` -Open the preprocessing dashboard and confirm rejected regions of the recording: +Next open the preprocessing dashboard and identify regions of the recording for exclusion from analysis: `ppd [bidsroot]` -Write the preprocessed data to the `derivatives/preprocess` tree: +The preprocessing dashboard will open in a browser window. Select a recording by index to pull up an interactive bokeh plot of raw fluorescence and normalised fluorescence. Then use the box-select tool to exclude time points from analysis. + +![example interactive dashboard](data/behapy-ppd.png) + +Finally, write the preprocessed data to the `[bidsroot]/derivatives/preprocess` tree: `preprocess [bidsroot]` +## Demo Notebooks + +A sample annotated analysis pipeline is available in `examples/analyse.ipynb` + +There is a MedPC event reading example in `examples/showevents.ipynb` + + ## Contributors behapy is maintained by [Chris Nolan](https://github.com/crnolan). diff --git a/data/behapy-ppd.png b/data/behapy-ppd.png new file mode 100644 index 0000000000000000000000000000000000000000..f63805a9dc4b1940ca522865b96d2f20d90f6866 GIT binary patch literal 50319 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 literal 0 HcmV?d00001 diff --git a/examples/analyse.ipynb b/examples/analyse.ipynb new file mode 100644 index 0000000..25d6801 --- /dev/null +++ b/examples/analyse.ipynb @@ -0,0 +1,232 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## behapy analysis pipeline\n", + "\n", + "This notebook walks through a basic behapy analysis pipeline using demo data that has been preprocessed with tdt2bids. We perform a linear regression to identify fluoresence signal response to various event types. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load modules" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "import logging\n", + "from pathlib import Path\n", + "import pandas as pd\n", + "import numpy as np\n", + "from behapy.utils import load_preprocessed_experiment\n", + "from behapy.events import build_design_matrix, regress, find_events\n", + "import statsmodels.api as sm\n", + "import seaborn as sns\n", + "sns.set_theme()\n", + "\n", + "logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load example data\n", + "\n", + "This pipeline is designed to be dropped into your experiment folder with structure:\n", + "```\n", + "└── bids_root/\n", + " ├── derivatives\n", + " ├── etc\n", + " ├── rawdata\n", + " ├── scripts/\n", + " │ └── analyse.py\n", + " └── sourcedata\n", + "```\n", + "\n", + "It will also run in-place as-is with demo data from Github." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "BIDSROOT = Path('..')\n", + "pre = load_preprocessed_experiment(BIDSROOT)\n", + "dff_id = ['subject', 'session', 'task', 'run', 'label']\n", + "dff_recordings = pre.recordings.loc[:, dff_id].drop_duplicates()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "# z-score the dff\n", + "dff = pre.dff.copy()\n", + "dff['dff'] = dff.dff.groupby(dff_id, group_keys=False).apply(lambda df: (df - df.mean()) / df.std())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "# Map IPSI and CONTRA\n", + "def _map_ipsi_contra(row):\n", + " r = row.iloc[0]\n", + " if r.label == 'RDMS':\n", + " events = pre.events.loc[(r.subject, r.session, r.task, r.run, r.label)].replace({'rlp': 'ipsilp', 'llp': 'contralp'})\n", + " elif r.label == 'LDMS':\n", + " events = pre.events.loc[(r.subject, r.session, r.task, r.run, r.label)].replace({'rlp': 'contralp', 'llp': 'ipsilp'})\n", + " else:\n", + " raise ValueError(f'Unknown label {r.label}')\n", + " return events.sort_index(level='onset')\n", + "\n", + "\n", + "events = dff_recordings.groupby(dff_id).apply(_map_ipsi_contra)\n", + "events" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "# Map events to individual recordings\n", + "def _get_nonevent(events, sub_events):\n", + " nonevent = events.loc[:, ['duration']].merge(sub_events.loc[:, ['latency']], how='left', left_index=True, right_index=True, indicator=True)\n", + " return nonevent.loc[nonevent._merge == 'left_only', ['duration', 'latency']]\n", + "\n", + "\n", + "REWmag = find_events(events, 'mag', ['pel', 'suc'])\n", + "NOREWmag = _get_nonevent(events.loc[events.event_id == 'mag', :], REWmag)\n", + "first_ipsilp = find_events(events, 'ipsilp', ['ipsilp', 'contralp', 'mag'], allow_exact_matches=False)\n", + "first_ipsilp = first_ipsilp.loc[first_ipsilp.latency < pd.to_timedelta('2s')]\n", + "# first_ipsilp = first_ipsilp.loc[first_ipsilp.latency < 2]\n", + "notfirst_ipsilp = _get_nonevent(events.loc[events.event_id == 'ipsilp', :], first_ipsilp)\n", + "first_contralp = find_events(events, 'contralp', ['ipsilp', 'contralp', 'mag'], allow_exact_matches=False)\n", + "first_contralp = first_contralp.loc[first_contralp.latency < pd.to_timedelta('2s')]\n", + "# first_contralp = first_contralp.loc[first_contralp.latency < 2]\n", + "notfirst_contralp = _get_nonevent(events.loc[events.event_id == 'contralp', :], first_contralp)\n", + "new_events = pd.concat([REWmag, NOREWmag, first_ipsilp, notfirst_ipsilp, first_contralp, notfirst_contralp],\n", + " keys=['REWmag', 'NOREWmag', 'first_ipsilp', 'notfirst_ipsilp', 'first_contralp', 'notfirst_contralp'],\n", + " names=['event_id'])\n", + "new_events = new_events.reset_index('event_id').loc[:, ['duration', 'event_id']]\n", + "events = pd.concat([events, new_events]).sort_index()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "plot_meta = {'Magazine': ['REWmag', 'NOREWmag']}\n", + "# plot_meta = {'Magazine': ['REWmag', 'NOREWmag'],\n", + "# 'Reward': ['pel', 'suc'],\n", + "# 'First press': ['first_ipsilp', 'first_contralp'],\n", + "# 'Other press': ['notfirst_ipsilp', 'notfirst_contralp']}\n", + "event_ids_of_interest = sum(plot_meta.values(), [])\n", + "events_of_interest = events.loc[events.event_id.isin(event_ids_of_interest), :]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "def _build_design_matrix(row):\n", + " r = row.iloc[0]\n", + " return build_design_matrix(\n", + " dff.loc[(r.subject, r.session, r.task, r.run, r.label), :],\n", + " events_of_interest.loc[(r.subject, r.session, r.task, r.run, r.label), :],\n", + " (-1, 2))\n", + "design_matrix = dff_recordings.groupby(dff_id).apply(_build_design_matrix).fillna(False).astype(bool)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "dm_filt filters on dff task" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "idx = pd.IndexSlice\n", + "dm_filt = design_matrix.loc[idx[:, :, ['FI15', 'RR5', 'RR10'], :, :, :], :].sort_index()\n", + "\n", + "\n", + "def _regress(df):\n", + " return regress(df, dff.loc[df.index, 'dff'], min_events=25)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "r1 = dm_filt.loc[:, idx[sum(plot_meta.values(), []), :]].groupby(level=('subject', 'task'), group_keys=True).apply(_regress)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %%\n", + "# s1 = r1.stack(0).stack()\n", + "s1 = r1.copy()\n", + "s1.name = 'beta'\n", + "s1 = s1.reset_index()\n", + "s1['event_type'] = s1.event.map({v: k for k, l in plot_meta.items() for v in l})\n", + "sns.relplot(data=s1, x='offset', y='beta', hue='event', row='event_type',\n", + " col='task',\n", + " kind='line', hue_order=sum(plot_meta.values(), []), aspect=2)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "behapy", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/showevents.ipynb b/examples/showevents.ipynb index 7a9c531..bf619e0 100644 --- a/examples/showevents.ipynb +++ b/examples/showevents.ipynb @@ -6,7 +6,9 @@ "source": [ "# MedPC event reading example\n", "\n", - "Demonstration of loading a set of subjects data from a MedPC format and plotting by subject and event." + "Demonstration of loading a set of subjects data from a MedPC format and plotting by subject and event.\n", + "\n", + "This example assumes MedPC data files are in the same folder as the notebook file." ] }, { @@ -127,11 +129,8 @@ } ], "metadata": { - "interpreter": { - "hash": "98bbee547cde878ca2d72f8442bd9530f0cc78c2a794beb5e8b4d2804654d41b" - }, "kernelspec": { - "display_name": "Python 3.9.12 ('behapy')", + "display_name": "behapy", "language": "python", "name": "python3" }, @@ -145,7 +144,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.12" + "version": "3.12.7" }, "orig_nbformat": 4 }, diff --git a/poisson_test.py b/poisson_test.py new file mode 100644 index 0000000..e69de29