{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# pyAFQ: Automated Fiber Quantification in Python \n",
    "\n",
    "The core of the tractometry.org ecosystem is the pyAFQ software library. This\n",
    "library uses inputs from various other programs to perform the delineation of\n",
    "major white matter pathways and to quantify white matter tissue properties\n",
    "along their lengths - tract profiles. The final output of the program includes\n",
    "a tabular summary with these tract profiles for each subject in the dataset,\n",
    "and one merged table that includes the tract profiles for all of the subjects. \n",
    "\n",
    "Along the way, the program produces many different intermediate data, including \n",
    "tractography results, maps of tissue properties, and visualizations, which \n",
    "can be used for quality assurance of the data and processing.\n",
    "\n",
    "There are two ways to use pyAFQ: through a command line interface, and by \n",
    "writing Python code. Here, we will focus on the latter, using pyAFQ's \n",
    "Python Application Programming Interface (API)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup \n",
    "\n",
    "We start with a few setup steps. The pyAFQ software downloads templates that \n",
    "are required for anatomical delineation of tracts into a designated directory \n",
    "on the user's machine. For the purpose of these examples, we will set the \n",
    "path to this directory to `/data/tractometry`. \n",
    "You will see a similar setup step at the top of many of the notebooks here, \n",
    "and it always does the same thing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os.path as op\n",
    "from paths import afq_home"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we import the `GroupAFQ` class from the pyAFQ `api` module. We also \n",
    "import `plotly`, which we will use for visualization."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "from AFQ.api.group import GroupAFQ\n",
    "import plotly"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set up tracking parameters \n",
    "\n",
    "Before we initialize the `GroupAFQ` object, we create a `tracking_params`\n",
    "variable, which we will pass to the `GroupAFQ` object to specify the\n",
    "tractography part of the pipeline. Here, we specify that we want 100,000 seeds\n",
    "randomly distributed in the white matter. We also set ``num_chunks`` to `True`.\n",
    "This will tell pyAFQ to use the `ray` software library to parallelize the\n",
    "tracking across all cores. This can be removed to process in serial, or set to\n",
    "use a particular distribution of work by setting `num_chunks` to an integer\n",
    "number.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tracking_params = dict(n_seeds=100000,\n",
    "                       random_seeds=True,\n",
    "                       rng_seed=2022,\n",
    "                       num_chunks=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Initialize an AFQ object\n",
    "\n",
    "Next, we initialize the `GroupAFQ` object. Upon initialization, the object \n",
    "does some validation steps, but no major computation is triggered. Instead, \n",
    "computation is deferred until the `export` method is called."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "myafq = GroupAFQ(\n",
    "    bids_path=op.join(afq_home, 'stanford_hardi'),\n",
    "    preproc_pipeline='vistasoft',\n",
    "    tracking_params=tracking_params,\n",
    "    viz_backend_spec='plotly_no_gif')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Recognize the tracts and calculating tract profiles:\n",
    "\n",
    "The `myafq` class instance now has all the information that it needs in order to \n",
    "do all kinds of computations on the data. Typically, we will want to calculate \n",
    "the tract profiles. To trigger the\n",
    "pyAFQ pipeline that calculates the profiles, users can call the\n",
    "`export('profiles')` method.\n",
    "\n",
    "For the purpose of this demonstration, the pipeline has been run in advance and\n",
    "cached in the data folder (under `/data`). In usual practice, the\n",
    "following line of code would trigger the full computational pipeline, which\n",
    "takes about 10 minutes to run and requires about 6GB RAM. However, the caching behavior is typical to pyAFQ. Once derivatives are computed, they are cached such that they\n",
    "can be reused."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "myafq.export('profiles')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After this line of code has finished running, a CSV file that contains the \n",
    "tract profiles should be saved into the afq folder within the derivatives \n",
    "folder of the dataset. At this point, we can export a visualization that \n",
    "shows all of the tracts and tract profiles of FA by calling `export` again. \n",
    "The call to plotly then renders the html of the figure into the notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bundle_html = myafq.export(\"all_bundles_figure\")\n",
    "plotly.io.show(bundle_html[\"01\"][0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tract profile data for all subjects in a particular dataset can be accessed as \n",
    "a Pandas dataframe, using the `combine_profiles` method.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "profiles_df = myafq.combine_profiles()"
   ]
  }
 ],
 "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.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
