From 3bcec7394597f41dabcf05906b49fd24d1d65442 Mon Sep 17 00:00:00 2001 From: olivier Date: Tue, 6 Feb 2024 12:51:58 +0000 Subject: [PATCH] documentation: add the AGEA loading example --- examples/Working with ibllib atlas.ipynb | 4 +- .../atlas_circular_pyramidal_flatmap.ipynb | 496 ++++++++-------- examples/atlas_dorsal_cortex_flatmap.ipynb | 444 +++++++------- examples/atlas_genomics_load_agea.ipynb | 107 ++-- examples/atlas_mapping.ipynb | 109 ++-- examples/atlas_plotting_points_on_slice.ipynb | 502 ++++++++-------- examples/atlas_plotting_scalar_on_slice.ipynb | 554 +++++++++--------- examples/atlas_swanson_flatmap.ipynb | 214 ++++--- .../atlas_working_with_ibllib_atlas.ipynb | 549 ++++++++--------- 9 files changed, 1515 insertions(+), 1464 deletions(-) diff --git a/examples/Working with ibllib atlas.ipynb b/examples/Working with ibllib atlas.ipynb index 3e0319b..a6e7be0 100644 --- a/examples/Working with ibllib atlas.ipynb +++ b/examples/Working with ibllib atlas.ipynb @@ -357,9 +357,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.16" + "version": "3.11.6" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/examples/atlas_circular_pyramidal_flatmap.ipynb b/examples/atlas_circular_pyramidal_flatmap.ipynb index 03ab28c..d3c84b2 100644 --- a/examples/atlas_circular_pyramidal_flatmap.ipynb +++ b/examples/atlas_circular_pyramidal_flatmap.ipynb @@ -1,248 +1,248 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "f199bec2", - "metadata": {}, - "source": [ - "# Plotting brain region values on circular flatmap" - ] - }, - { - "cell_type": "markdown", - "id": "94c08e66", - "metadata": {}, - "source": [ - "This example walks through various ways to overlay brain region values on a circular flatmap" - ] - }, - { - "cell_type": "markdown", - "id": "17fd07ec", - "metadata": {}, - "source": [ - "## The circular flatmap" - ] - }, - { - "cell_type": "markdown", - "id": "3ca88864", - "metadata": {}, - "source": [ - "The circular flatmap is obtained by sampling the volume using concentric circles through the brain." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1178246b", - "metadata": {}, - "outputs": [], - "source": [ - "from iblatlas.flatmaps import FlatMap\n", - "flmap_cr = FlatMap(flatmap='circles')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "490614c3", - "metadata": {}, - "outputs": [], - "source": [ - "# Display the concentric circles used in flatmap\n", - "ax = flmap_cr.plot_top(volume='image')\n", - "ax.plot(flmap_cr.ml_scale * 1e6, flmap_cr.ap_scale * 1e6)" - ] - }, - { - "cell_type": "markdown", - "id": "135dd187", - "metadata": {}, - "source": [ - "This results in a flatmap that can be displayed in the following way" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8b8c4223", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "fig, ax = plt.subplots(figsize=(18,4))\n", - "flmap_cr.plot_flatmap(ax)" - ] - }, - { - "cell_type": "markdown", - "id": "ec15f88c", - "metadata": {}, - "source": [ - "It is also possible to display this flatmap such that each circle is stacked on top of eachother. For this, the **pyramid** flatmap should be used" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7461e3f8", - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate flatmap with circles arranged vetically on top of eachother\n", - "flmap_py = FlatMap(flatmap='pyramid')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1f78b2ab", - "metadata": {}, - "outputs": [], - "source": [ - "fig, ax = plt.subplots(figsize=(8, 8))\n", - "flmap_py.plot_flatmap(ax=ax)" - ] - }, - { - "cell_type": "markdown", - "id": "e7af738a", - "metadata": {}, - "source": [ - "## Data preparation" - ] - }, - { - "cell_type": "markdown", - "id": "40fa09d0", - "metadata": {}, - "source": [ - "In order to plot brain regions values on the flatmap an array of acronyms and an array of values corresponding to each acronym must be provided. A detailed overview of how to prepare your data can be found [here](https://int-brain-lab.github.io/iblenv/notebooks_external/atlas_plotting_scalar_on_slice.html#Data-preparation)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "20a1db83", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "# prepare array of acronyms\n", - "acronyms = np.array(['VPM', 'PO', 'LP', 'CA1', 'DG-mo', 'VISa5', 'SSs5'])\n", - "# assign data to each acronym\n", - "values = np.arange(acronyms.size)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e6ae51d0", - "metadata": {}, - "outputs": [], - "source": [ - "from iblatlas.regions import BrainRegions\n", - "br = BrainRegions()\n", - "# prepare array of acronyms with beryl mapping\n", - "acronyms_beryl = np.unique(br.acronym2acronym(acronyms, mapping='Beryl'))\n", - "values_beryl = np.arange(acronyms_beryl.size)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3724b968", - "metadata": {}, - "outputs": [], - "source": [ - "# prepare different values for left and right hemipshere for Beryl acronyms\n", - "values_beryl_lh = np.random.randint(0, 10, acronyms_beryl.size)\n", - "values_beryl_rh = np.random.randint(0, 10, acronyms_beryl.size)\n", - "values_beryl_lr = np.c_[values_beryl_lh, values_beryl_rh]" - ] - }, - { - "cell_type": "markdown", - "id": "74fe528a", - "metadata": {}, - "source": [ - "## Examples" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dfa2d623", - "metadata": {}, - "outputs": [], - "source": [ - "from iblatlas.plots import plot_scalar_on_flatmap\n", - "# Plot region values on the left hemisphere of circle flatmap overlaid on brain region boundaries using Allen mapping\n", - "fig, ax = plt.subplots(figsize=(18,4))\n", - "fig, ax = plot_scalar_on_flatmap(acronyms, values, hemisphere='left', mapping='Allen', flmap_atlas=flmap_cr, ax=ax)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cc78a1c7", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot region values on the both hemispheres of circle flatmap overlaid on the dwi Allen image using Beryl mapping\n", - "fig, ax = plt.subplots(figsize=(18,4))\n", - "fig, ax = plot_scalar_on_flatmap(acronyms_beryl, values_beryl, hemisphere='both', mapping='Beryl', background='image', \n", - " cmap='Reds', flmap_atlas=flmap_cr, ax=ax)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "37bf7bd8", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot region values on the right hemisphere of pyramidal flatmap overlaid on the dwi Allen image using Allen mapping\n", - "fig, ax = plt.subplots(figsize=(8,8))\n", - "fig, ax = plot_scalar_on_flatmap(acronyms, values, hemisphere='right', mapping='Allen', background='image', \n", - " cmap='Reds', flmap_atlas=flmap_py, ax=ax)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "28f7f30c", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot two column region values on the both hemispheres of pyramidal flatmap overlaid on brain region boundaries \n", - "# using Beryl mapping\n", - "fig, ax = plt.subplots(figsize=(8,8))\n", - "fig, ax = plot_scalar_on_flatmap(acronyms_beryl, values_beryl_lr, hemisphere='both', mapping='Beryl', \n", - " background='boundary', cmap='Blues', flmap_atlas=flmap_py, ax=ax)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [conda env:iblenv] *", - "language": "python", - "name": "conda-env-iblenv-py" - }, - "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.9.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f199bec2", + "metadata": {}, + "source": [ + "# Plotting brain region values on circular flatmap" + ] + }, + { + "cell_type": "markdown", + "id": "94c08e66", + "metadata": {}, + "source": [ + "This example walks through various ways to overlay brain region values on a circular flatmap" + ] + }, + { + "cell_type": "markdown", + "id": "17fd07ec", + "metadata": {}, + "source": [ + "## The circular flatmap" + ] + }, + { + "cell_type": "markdown", + "id": "3ca88864", + "metadata": {}, + "source": [ + "The circular flatmap is obtained by sampling the volume using concentric circles through the brain." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1178246b", + "metadata": {}, + "outputs": [], + "source": [ + "from iblatlas.flatmaps import FlatMap\n", + "flmap_cr = FlatMap(flatmap='circles')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "490614c3", + "metadata": {}, + "outputs": [], + "source": [ + "# Display the concentric circles used in flatmap\n", + "ax = flmap_cr.plot_top(volume='image')\n", + "ax.plot(flmap_cr.ml_scale * 1e6, flmap_cr.ap_scale * 1e6)" + ] + }, + { + "cell_type": "markdown", + "id": "135dd187", + "metadata": {}, + "source": [ + "This results in a flatmap that can be displayed in the following way" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b8c4223", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "fig, ax = plt.subplots(figsize=(18,4))\n", + "flmap_cr.plot_flatmap(ax)" + ] + }, + { + "cell_type": "markdown", + "id": "ec15f88c", + "metadata": {}, + "source": [ + "It is also possible to display this flatmap such that each circle is stacked on top of eachother. For this, the **pyramid** flatmap should be used" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7461e3f8", + "metadata": {}, + "outputs": [], + "source": [ + "# Instantiate flatmap with circles arranged vetically on top of eachother\n", + "flmap_py = FlatMap(flatmap='pyramid')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f78b2ab", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(figsize=(8, 8))\n", + "flmap_py.plot_flatmap(ax=ax)" + ] + }, + { + "cell_type": "markdown", + "id": "e7af738a", + "metadata": {}, + "source": [ + "## Data preparation" + ] + }, + { + "cell_type": "markdown", + "id": "40fa09d0", + "metadata": {}, + "source": [ + "In order to plot brain regions values on the flatmap an array of acronyms and an array of values corresponding to each acronym must be provided. A detailed overview of how to prepare your data can be found [here](https://int-brain-lab.github.io/iblenv/notebooks_external/atlas_plotting_scalar_on_slice.html#Data-preparation)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20a1db83", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "# prepare array of acronyms\n", + "acronyms = np.array(['VPM', 'PO', 'LP', 'CA1', 'DG-mo', 'VISa5', 'SSs5'])\n", + "# assign data to each acronym\n", + "values = np.arange(acronyms.size)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6ae51d0", + "metadata": {}, + "outputs": [], + "source": [ + "from iblatlas.regions import BrainRegions\n", + "br = BrainRegions()\n", + "# prepare array of acronyms with beryl mapping\n", + "acronyms_beryl = np.unique(br.acronym2acronym(acronyms, mapping='Beryl'))\n", + "values_beryl = np.arange(acronyms_beryl.size)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3724b968", + "metadata": {}, + "outputs": [], + "source": [ + "# prepare different values for left and right hemipshere for Beryl acronyms\n", + "values_beryl_lh = np.random.randint(0, 10, acronyms_beryl.size)\n", + "values_beryl_rh = np.random.randint(0, 10, acronyms_beryl.size)\n", + "values_beryl_lr = np.c_[values_beryl_lh, values_beryl_rh]" + ] + }, + { + "cell_type": "markdown", + "id": "74fe528a", + "metadata": {}, + "source": [ + "## Examples" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dfa2d623", + "metadata": {}, + "outputs": [], + "source": [ + "from iblatlas.plots import plot_scalar_on_flatmap\n", + "# Plot region values on the left hemisphere of circle flatmap overlaid on brain region boundaries using Allen mapping\n", + "fig, ax = plt.subplots(figsize=(18,4))\n", + "fig, ax = plot_scalar_on_flatmap(acronyms, values, hemisphere='left', mapping='Allen', flmap_atlas=flmap_cr, ax=ax)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc78a1c7", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot region values on the both hemispheres of circle flatmap overlaid on the dwi Allen image using Beryl mapping\n", + "fig, ax = plt.subplots(figsize=(18,4))\n", + "fig, ax = plot_scalar_on_flatmap(acronyms_beryl, values_beryl, hemisphere='both', mapping='Beryl', background='image', \n", + " cmap='Reds', flmap_atlas=flmap_cr, ax=ax)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37bf7bd8", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot region values on the right hemisphere of pyramidal flatmap overlaid on the dwi Allen image using Allen mapping\n", + "fig, ax = plt.subplots(figsize=(8,8))\n", + "fig, ax = plot_scalar_on_flatmap(acronyms, values, hemisphere='right', mapping='Allen', background='image', \n", + " cmap='Reds', flmap_atlas=flmap_py, ax=ax)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28f7f30c", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot two column region values on the both hemispheres of pyramidal flatmap overlaid on brain region boundaries \n", + "# using Beryl mapping\n", + "fig, ax = plt.subplots(figsize=(8,8))\n", + "fig, ax = plot_scalar_on_flatmap(acronyms_beryl, values_beryl_lr, hemisphere='both', mapping='Beryl', \n", + " background='boundary', cmap='Blues', flmap_atlas=flmap_py, ax=ax)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:iblenv] *", + "language": "python", + "name": "conda-env-iblenv-py" + }, + "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.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/atlas_dorsal_cortex_flatmap.ipynb b/examples/atlas_dorsal_cortex_flatmap.ipynb index 6323c65..6f200fc 100644 --- a/examples/atlas_dorsal_cortex_flatmap.ipynb +++ b/examples/atlas_dorsal_cortex_flatmap.ipynb @@ -1,222 +1,222 @@ -{ - "cells": [ - { - "cell_type": "code", - "outputs": [], - "source": [ - "# Turn off logging and disable tqdm this is a hidden cell on docs page\n", - "import logging\n", - "import os\n", - "\n", - "logger = logging.getLogger('ibllib')\n", - "logger.setLevel(logging.CRITICAL)\n", - "\n", - "os.environ[\"TQDM_DISABLE\"] = \"1\"" - ], - "metadata": { - "nbsphinx": "hidden", - "collapsed": false - }, - "id": "5711974f8dd963cd" - }, - { - "cell_type": "markdown", - "id": "fdc19afd", - "metadata": {}, - "source": [ - "# Plotting brain region values on cortical flatmap" - ] - }, - { - "cell_type": "markdown", - "id": "328a2d74", - "metadata": {}, - "source": [ - "This example walks through various ways to overlay brain region values on a cortical flatmap" - ] - }, - { - "cell_type": "markdown", - "id": "bd3eecf6", - "metadata": {}, - "source": [ - "## The dorsal cortex flatmap" - ] - }, - { - "cell_type": "markdown", - "id": "8354c14e", - "metadata": {}, - "source": [ - "The **dorsal_cortex** flatmap comprises a flattened volume of cortex up to depth 2000 um" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "33fa3ec7", - "metadata": {}, - "outputs": [], - "source": [ - "from iblatlas.flatmaps import FlatMap\n", - "\n", - "res = 25\n", - "flmap = FlatMap(flatmap='dorsal_cortex', res_um=res)\n", - "\n", - "# Plot flatmap at depth = 0 \n", - "flmap.plot_flatmap(int(0 / res))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dfdd67e8", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot flatmap at depth = 800 um\n", - "flmap.plot_flatmap(int(800 / res))" - ] - }, - { - "cell_type": "markdown", - "id": "6e4a49d8", - "metadata": {}, - "source": [ - "## Data preparation" - ] - }, - { - "cell_type": "markdown", - "id": "919372e5", - "metadata": {}, - "source": [ - "In order to plot brain regions values on the flatmap an array of acronyms and an array of values corresponding to each acronym must be provided. A detailed overview of how to prepare your data can be found [here](https://int-brain-lab.github.io/iblenv/notebooks_external/atlas_plotting_scalar_on_slice.html#Data-preparation)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0de1b18b", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "# prepare array of acronyms\n", - "acronyms = np.array(['ACAd1', 'ACAv1', 'AId1', 'AIp1', 'AIv1', 'AUDd1', 'AUDp1','AUDpo1', 'AUDv1', \n", - " 'SSp-m1', 'SSp-n1', 'SSp-tr1', 'SSp-ul1','SSp-un1', 'SSs1', \n", - " 'VISC1', 'VISa1', 'VISal1', 'VISam1', 'VISl1', 'VISli1', 'VISp1', 'VISp2/3', 'VISpl1', 'VISpm1', \n", - " 'SSp-n2/3', 'SSp-tr2/3', 'SSp-ul2/3', 'SSp-un2/3', 'SSs2/3',\n", - " 'VISC2/3', 'VISa2/3', 'VISal2/3', 'VISam2/3', 'VISl2/3','VISli2/3', 'VISp2/3', 'VISpl1', 'VISpl2/3'])\n", - "# assign data to each acronym\n", - "values = np.arange(acronyms.size)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b9eb9b3a", - "metadata": {}, - "outputs": [], - "source": [ - "from iblatlas.regions import BrainRegions\n", - "br = BrainRegions()\n", - "# prepare array of acronyms with beryl mapping\n", - "acronyms_beryl = np.unique(br.acronym2acronym(acronyms, mapping='Beryl'))\n", - "values_beryl = np.arange(acronyms_beryl.size)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "251385a1", - "metadata": {}, - "outputs": [], - "source": [ - "# prepare different values for left and right hemipshere for Beryl acronyms\n", - "values_beryl_lh = np.random.randint(0, 10, acronyms_beryl.size)\n", - "values_beryl_rh = np.random.randint(0, 10, acronyms_beryl.size)\n", - "values_beryl_lr = np.c_[values_beryl_lh, values_beryl_rh]" - ] - }, - { - "cell_type": "markdown", - "id": "6ad92aca", - "metadata": {}, - "source": [ - "## Examples" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e26dcf4c", - "metadata": {}, - "outputs": [], - "source": [ - "from iblatlas.plots import plot_scalar_on_flatmap\n", - "\n", - "# Plot region values on the left hemisphere at depth=0um overlaid on boundary image using Allen mapping\n", - "fig, ax = plot_scalar_on_flatmap(acronyms, values, depth=0, mapping='Allen', hemisphere='left', background='boundary',\n", - " cmap='viridis', flmap_atlas=flmap)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "de4a63a0", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot region values on the right hemisphere at depth=200um overlaid on boundary image using Allen mapping and show cbar\n", - "fig, ax, cbar = plot_scalar_on_flatmap(acronyms, values, depth=200, mapping='Allen', hemisphere='right', background='boundary',\n", - " cmap='Reds', flmap_atlas=flmap, show_cbar=True)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "da848f40", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot single column region values on the both hemisphere at depth=800um overlaid dwi Allen image using Beryl mapping\n", - "fig, ax = plot_scalar_on_flatmap(acronyms_beryl, values_beryl, depth=800, mapping='Beryl', hemisphere='both', \n", - " background='image', cmap='plasma', flmap_atlas=flmap)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "322f3a04", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot two column region values on the both hemispheres at depth=0um on boundary image using Allen mapping\n", - "fig, ax, cbar = plot_scalar_on_flatmap(acronyms_beryl, values_beryl_lr, depth=0, mapping='Beryl', hemisphere='both', \n", - " background='boundary', cmap='Blues', flmap_atlas=flmap, show_cbar=True)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [conda env:iblenv] *", - "language": "python", - "name": "conda-env-iblenv-py" - }, - "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.9.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "5711974f8dd963cd", + "metadata": { + "nbsphinx": "hidden" + }, + "outputs": [], + "source": [ + "# Turn off logging and disable tqdm this is a hidden cell on docs page\n", + "import logging\n", + "import os\n", + "\n", + "logger = logging.getLogger('ibllib')\n", + "logger.setLevel(logging.CRITICAL)\n", + "\n", + "os.environ[\"TQDM_DISABLE\"] = \"1\"" + ] + }, + { + "cell_type": "markdown", + "id": "fdc19afd", + "metadata": {}, + "source": [ + "# Plotting brain region values on cortical flatmap" + ] + }, + { + "cell_type": "markdown", + "id": "328a2d74", + "metadata": {}, + "source": [ + "This example walks through various ways to overlay brain region values on a cortical flatmap" + ] + }, + { + "cell_type": "markdown", + "id": "bd3eecf6", + "metadata": {}, + "source": [ + "## The dorsal cortex flatmap" + ] + }, + { + "cell_type": "markdown", + "id": "8354c14e", + "metadata": {}, + "source": [ + "The **dorsal_cortex** flatmap comprises a flattened volume of cortex up to depth 2000 um" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33fa3ec7", + "metadata": {}, + "outputs": [], + "source": [ + "from iblatlas.flatmaps import FlatMap\n", + "\n", + "res = 25\n", + "flmap = FlatMap(flatmap='dorsal_cortex', res_um=res)\n", + "\n", + "# Plot flatmap at depth = 0 \n", + "flmap.plot_flatmap(int(0 / res))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dfdd67e8", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot flatmap at depth = 800 um\n", + "flmap.plot_flatmap(int(800 / res))" + ] + }, + { + "cell_type": "markdown", + "id": "6e4a49d8", + "metadata": {}, + "source": [ + "## Data preparation" + ] + }, + { + "cell_type": "markdown", + "id": "919372e5", + "metadata": {}, + "source": [ + "In order to plot brain regions values on the flatmap an array of acronyms and an array of values corresponding to each acronym must be provided. A detailed overview of how to prepare your data can be found [here](https://int-brain-lab.github.io/iblenv/notebooks_external/atlas_plotting_scalar_on_slice.html#Data-preparation)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0de1b18b", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "# prepare array of acronyms\n", + "acronyms = np.array(['ACAd1', 'ACAv1', 'AId1', 'AIp1', 'AIv1', 'AUDd1', 'AUDp1','AUDpo1', 'AUDv1', \n", + " 'SSp-m1', 'SSp-n1', 'SSp-tr1', 'SSp-ul1','SSp-un1', 'SSs1', \n", + " 'VISC1', 'VISa1', 'VISal1', 'VISam1', 'VISl1', 'VISli1', 'VISp1', 'VISp2/3', 'VISpl1', 'VISpm1', \n", + " 'SSp-n2/3', 'SSp-tr2/3', 'SSp-ul2/3', 'SSp-un2/3', 'SSs2/3',\n", + " 'VISC2/3', 'VISa2/3', 'VISal2/3', 'VISam2/3', 'VISl2/3','VISli2/3', 'VISp2/3', 'VISpl1', 'VISpl2/3'])\n", + "# assign data to each acronym\n", + "values = np.arange(acronyms.size)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b9eb9b3a", + "metadata": {}, + "outputs": [], + "source": [ + "from iblatlas.regions import BrainRegions\n", + "br = BrainRegions()\n", + "# prepare array of acronyms with beryl mapping\n", + "acronyms_beryl = np.unique(br.acronym2acronym(acronyms, mapping='Beryl'))\n", + "values_beryl = np.arange(acronyms_beryl.size)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "251385a1", + "metadata": {}, + "outputs": [], + "source": [ + "# prepare different values for left and right hemipshere for Beryl acronyms\n", + "values_beryl_lh = np.random.randint(0, 10, acronyms_beryl.size)\n", + "values_beryl_rh = np.random.randint(0, 10, acronyms_beryl.size)\n", + "values_beryl_lr = np.c_[values_beryl_lh, values_beryl_rh]" + ] + }, + { + "cell_type": "markdown", + "id": "6ad92aca", + "metadata": {}, + "source": [ + "## Examples" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e26dcf4c", + "metadata": {}, + "outputs": [], + "source": [ + "from iblatlas.plots import plot_scalar_on_flatmap\n", + "\n", + "# Plot region values on the left hemisphere at depth=0um overlaid on boundary image using Allen mapping\n", + "fig, ax = plot_scalar_on_flatmap(acronyms, values, depth=0, mapping='Allen', hemisphere='left', background='boundary',\n", + " cmap='viridis', flmap_atlas=flmap)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "de4a63a0", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot region values on the right hemisphere at depth=200um overlaid on boundary image using Allen mapping and show cbar\n", + "fig, ax, cbar = plot_scalar_on_flatmap(acronyms, values, depth=200, mapping='Allen', hemisphere='right', background='boundary',\n", + " cmap='Reds', flmap_atlas=flmap, show_cbar=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da848f40", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot single column region values on the both hemisphere at depth=800um overlaid dwi Allen image using Beryl mapping\n", + "fig, ax = plot_scalar_on_flatmap(acronyms_beryl, values_beryl, depth=800, mapping='Beryl', hemisphere='both', \n", + " background='image', cmap='plasma', flmap_atlas=flmap)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "322f3a04", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot two column region values on the both hemispheres at depth=0um on boundary image using Allen mapping\n", + "fig, ax, cbar = plot_scalar_on_flatmap(acronyms_beryl, values_beryl_lr, depth=0, mapping='Beryl', hemisphere='both', \n", + " background='boundary', cmap='Blues', flmap_atlas=flmap, show_cbar=True)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:iblenv] *", + "language": "python", + "name": "conda-env-iblenv-py" + }, + "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.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/atlas_genomics_load_agea.ipynb b/examples/atlas_genomics_load_agea.ipynb index 0e92586..187ce65 100644 --- a/examples/atlas_genomics_load_agea.ipynb +++ b/examples/atlas_genomics_load_agea.ipynb @@ -2,52 +2,87 @@ "cells": [ { "cell_type": "markdown", - "source": [ - "# Loading the gene expression atlas" - ], + "id": "48e25dbdfb3b180c", "metadata": { - "collapsed": false + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } }, - "id": "48e25dbdfb3b180c" + "source": [ + "# Loading the gene expression atlas\n", + "\n", + "This will download a formatted version of the agea gene expression matrix and load the following variables:\n", + "\n", + "- `df_genes`: is a dataframe containing the genes names (size 4345)\n", + "- `gene_expression_volumes`: is a 4D array of gene expression volumes, shape (ngenes, ML, DV, AP) = (4345, 58, 41, 67)\n", + "- `atlas_agea`: is a `iblatlas.atlas.BrainAtlas` object with a geometry and anatomical labels matching the geometry of the AGEA volumes." + ] }, { "cell_type": "code", + "execution_count": 1, + "id": "bb2f59faef37c1b3", + "metadata": { + "editable": true, + "ibl_execute": false, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "from iblatlas.genomics import agea\n", "\n", - "df_genes, gene_expression_volumes, atlas_agea = agea.load()\n" - ], - "metadata": { - "collapsed": false, - "ibl_execute": false - }, - "id": "bb2f59faef37c1b3", - "execution_count": null + "df_genes, gene_expression_volumes, atlas_agea = agea.load()" + ] }, { "cell_type": "markdown", - "source": [ - "Displaying a coronal and a sagittal slice.\n", - "The top row is the diffusion MRI Allen template, the middle row corresponds to the brain regions annotations and the bottom row corresponds to the first gene expression volume." - ], + "id": "62db803f3b14fc9", "metadata": { - "collapsed": false + "collapsed": false, + "editable": true, + "jupyter": { + "outputs_hidden": false + }, + "slideshow": { + "slide_type": "" + }, + "tags": [] }, - "id": "62db803f3b14fc9" + "source": [ + "To demonstrate how to using the atlas object, we will display registered coronal and a sagittal slices from the first gene.\n", + "\n", + "The top row is the diffusion MRI Allen template, the middle row corresponds to the brain regions annotations and the bottom row corresponds to the first gene expression volume." + ] }, { - "cell_type": "markdown", - "source": [], + "cell_type": "code", + "execution_count": 2, + "id": "e5b06d6b647373b4", "metadata": { - "collapsed": false + "editable": true, + "ibl_execute": false, + "slideshow": { + "slide_type": "" + }, + "tags": [] }, - "id": "9a7afbf944dd385c" - }, - { - "cell_type": "code", - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "igenes = (0,)\n", "fig, axs = plt.subplots(3, 2, sharex=True, sharey=True)\n", @@ -58,32 +93,28 @@ "atlas_agea.plot_sslice(0, ax=axs[1, 1], volume='annotation')\n", "atlas_agea.plot_sslice(0, ax=axs[2, 1], volume=gene_expression_volumes[igenes[0]], cmap='viridis')\n", "fig.tight_layout()" - ], - "metadata": { - "collapsed": false, - "ibl_execute": false - }, - "id": "e5b06d6b647373b4", - "execution_count": null + ] } ], "metadata": { + "docs_executed": "executed", + "ibl_execute": false, "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" + "pygments_lexer": "ipython3", + "version": "3.11.6" } }, "nbformat": 4, diff --git a/examples/atlas_mapping.ipynb b/examples/atlas_mapping.ipynb index a75818b..67462c8 100644 --- a/examples/atlas_mapping.ipynb +++ b/examples/atlas_mapping.ipynb @@ -68,53 +68,55 @@ }, { "cell_type": "markdown", + "id": "7aec0a3a", + "metadata": { + "collapsed": false + }, "source": [ "The `br.mappings` contains the `index` of the region for a given mapping.\n", "You can use these indices to find for example the acronyms contained in Cosmos:" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, + "id": "f71464a3", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "import numpy as np\n", "cosmos_indices = np.unique(br.mappings['Cosmos'])\n", "br.acronym[cosmos_indices]" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", - "source": [ - "You can check that all brain regions within these 4 mappings are contained in the Allen parcellation, for example for Beryl:" - ], + "id": "595936a6", "metadata": { "collapsed": false - } + }, + "source": [ + "You can check that all brain regions within these 4 mappings are contained in the Allen parcellation, for example for Beryl:" + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "set(np.unique(br.mappings['Beryl'])).difference(set(np.unique(br.mappings['Allen'])))\n", - "# Expect to return an empty set" - ], + "id": "e7a881a0", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "set(np.unique(br.mappings['Beryl'])).difference(set(np.unique(br.mappings['Allen'])))\n", + "# Expect to return an empty set" + ] }, { "cell_type": "markdown", @@ -196,26 +198,27 @@ }, { "cell_type": "markdown", - "source": [ - "Under the Swanson mapping, it is assigned to the region **MD**" - ], + "id": "4f472ab2", "metadata": { "collapsed": false - } + }, + "source": [ + "Under the Swanson mapping, it is assigned to the region **MD**" + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "print(br.acronym2acronym('MDm', mapping='Swanson'))" - ], + "id": "628e543b", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "print(br.acronym2acronym('MDm', mapping='Swanson'))" + ] }, { "cell_type": "markdown", @@ -246,46 +249,48 @@ { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "print(br.acronym2acronym('TH', mapping='Swanson'))" - ], + "id": "c697d716", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "print(br.acronym2acronym('TH', mapping='Swanson'))" + ] }, { "cell_type": "markdown", - "source": [ - "However, a child region that is not included in the mapping will be returned as its closest parent in the mapping. For example, VISa is not included in Swanson, but its parent PLTp is:" - ], + "id": "7360b9e5", "metadata": { "collapsed": false - } + }, + "source": [ + "However, a child region that is not included in the mapping will be returned as its closest parent in the mapping. For example, VISa is not included in Swanson, but its parent PLTp is:" + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "print(br.acronym2acronym('VISa', mapping='Swanson'))" - ], + "id": "d7f762fc", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "print(br.acronym2acronym('VISa', mapping='Swanson'))" + ] }, { "cell_type": "markdown", - "source": [], + "id": "384ab414", "metadata": { "collapsed": false - } + }, + "source": [] }, { "cell_type": "markdown", @@ -642,9 +647,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.7" + "version": "3.11.6" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/examples/atlas_plotting_points_on_slice.ipynb b/examples/atlas_plotting_points_on_slice.ipynb index c013a97..cfca593 100644 --- a/examples/atlas_plotting_points_on_slice.ipynb +++ b/examples/atlas_plotting_points_on_slice.ipynb @@ -1,251 +1,251 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "87d1873a", - "metadata": {}, - "source": [ - "# Plotting cluster locations on histology slices" - ] - }, - { - "cell_type": "markdown", - "id": "77834a05", - "metadata": {}, - "source": [ - "This example walks through various ways to display the 3D location of clusters on histology slices" - ] - }, - { - "cell_type": "markdown", - "id": "5011bf58", - "metadata": {}, - "source": [ - "## Data Preparation" - ] - }, - { - "cell_type": "markdown", - "id": "60f93667", - "metadata": {}, - "source": [ - "For all examples below the xyz coordinates of each point and an array of values must be provided. Here we load in the spikesorting data for an example probe insertion and set the xyz coordinates to the coordinates of the clusters and the array of values to the firing rate." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a5d22548", - "metadata": {}, - "outputs": [], - "source": [ - "from one.api import ONE\n", - "from brainbox.io.one import SpikeSortingLoader\n", - "from iblatlas.atlas import AllenAtlas\n", - "import numpy as np\n", - "\n", - "one = ONE()\n", - "ba = AllenAtlas()\n", - "pid = 'da8dfec1-d265-44e8-84ce-6ae9c109b8bd'\n", - "sl = SpikeSortingLoader(pid=pid, one=one, atlas=ba)\n", - "spikes, clusters, channels = sl.load_spike_sorting()\n", - "clusters = sl.merge_clusters(spikes, clusters, channels)\n", - "\n", - "# Extract xyz coords from clusters dict\n", - "# Here we will set all ap values to a chosen value for visualisation purposes\n", - "xyz = np.c_[clusters['x'], np.ones_like(clusters['x']) * 400 / 1e6, clusters['z']]\n", - "values = clusters['firing_rate']" - ] - }, - { - "cell_type": "markdown", - "id": "c84d11bd", - "metadata": {}, - "source": [ - "## Example 1: Aggregation methods" - ] - }, - { - "cell_type": "markdown", - "id": "b9340c33", - "metadata": {}, - "source": [ - "The values of points that lie within the same voxel within the volume can be aggregated together in different ways by changing the `aggr` argument. Below shows an example where values in each voxel have been aggregated according to the average firing rate of the clusters (left) and according to the count of clusters in each voxel (right)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f35b8827", - "metadata": {}, - "outputs": [], - "source": [ - "from iblatlas.plots import plot_points_on_slice\n", - "import matplotlib.pyplot as plt\n", - "\n", - "fig, axs = plt.subplots(1, 2, figsize=(16,4))\n", - "\n", - "# Plot points on the coronal slice at ap=400um overlaid overlaid on brain region boundaries using Allen mapping \n", - "# and a 3D gaussian kernel with fwhm=100um is applied\n", - "\n", - "# Values in the same voxel are aggregated by the mean\n", - "fig, ax = plot_points_on_slice(xyz, values=values, coord=400, slice='coronal', mapping='Allen', background='boundary', \n", - " cmap='Reds', aggr='mean', fwhm=100, brain_atlas=ba, ax=axs[0])\n", - "\n", - "# Values in the same voxel are aggregated by the count\n", - "# N.B. can also pass values=None in this case as they are not used in the computation\n", - "fig, ax, cbar = plot_points_on_slice(xyz, values=values, coord=400, slice='coronal', mapping='Allen', background='boundary', \n", - " cmap='Reds', aggr='count', fwhm=100, brain_atlas=ba, ax=axs[1], show_cbar=True)" - ] - }, - { - "cell_type": "markdown", - "id": "54650899", - "metadata": {}, - "source": [ - "The different options for aggregation are listed in the docstring of the function" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0b6ad58e", - "metadata": {}, - "outputs": [], - "source": [ - "help(plot_points_on_slice)" - ] - }, - { - "cell_type": "markdown", - "id": "ea0cf9a4", - "metadata": {}, - "source": [ - "## Example 2: Applying gaussian kernels with varying FWHM" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2ba3ca84", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot points on the coronal slice at ap=400um overlaid overlaid on Allen dwi image using Cosmos mapping with\n", - "# values aggregated by max\n", - "\n", - "figs, axs = plt.subplots(1, 3, figsize=(18,4))\n", - "\n", - "# FWHM of 100 um\n", - "fig, ax = plot_points_on_slice(xyz, values=values, coord=400, slice='coronal', background='image', \n", - " cmap='Purples', aggr='max', fwhm=100, brain_atlas=ba, ax=axs[0])\n", - "\n", - "# FWHM of 300 um\n", - "fig, ax = plot_points_on_slice(xyz, values=values, coord=400, slice='coronal', background='image', \n", - " cmap='Purples', aggr='max', fwhm=300, brain_atlas=ba, ax=axs[1])\n", - "\n", - "# FWHM of 0 um\n", - "# if fwhm=0 no gaussian kernal applied\n", - "fig, ax = plot_points_on_slice(xyz, values=values, coord=400, slice='coronal', background='image', \n", - " cmap='Purples', aggr='max', fwhm=0, brain_atlas=ba, ax=axs[2])" - ] - }, - { - "cell_type": "markdown", - "id": "a0aca146", - "metadata": {}, - "source": [ - "## Example 3: Precomputing Volume" - ] - }, - { - "cell_type": "markdown", - "id": "19edcc5b", - "metadata": {}, - "source": [ - "Convolving the 3D volume with the gaussian kernal can take some time to compute, particularly when using a large fwhm value. When exploring the same volume at different coordinates and using different slices it is recommended to precompute the volume and then plot the slices. Below shows an example of how to do this." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "81f6919c", - "metadata": {}, - "outputs": [], - "source": [ - "from iblatlas.plots import compute_volume_from_points, plot_volume_on_slice\n", - "\n", - "# Extract xyz coords from clusters dict\n", - "xyz = np.c_[clusters['x'], clusters['y'], clusters['z']]\n", - "values = clusters['amp_max']\n", - "\n", - "# Compute volume\n", - "volume = compute_volume_from_points(xyz, values=values, aggr='mean', fwhm=250, ba=ba)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9d938d24", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot points on the coronal slices on brain region boundaries using Beryl maping\n", - "figs, axs = plt.subplots(1, 3, figsize=(18,4))\n", - "fig, ax = plot_volume_on_slice(volume, coord=300, slice='coronal', mapping='Beryl', background='boundary', \n", - " cmap='Oranges', brain_atlas=ba, ax=axs[0])\n", - "ax.set_title('ap = 300um')\n", - "fig, ax = plot_volume_on_slice(volume, coord=400, slice='coronal', mapping='Beryl', background='boundary', \n", - " cmap='Oranges', brain_atlas=ba, ax=axs[1])\n", - "ax.set_title('ap = 400um')\n", - "fig, ax = plot_volume_on_slice(volume, coord=500, slice='coronal', mapping='Beryl', background='boundary', \n", - " cmap='Oranges', brain_atlas=ba,ax=axs[2])\n", - "ax.set_title('ap = 500um')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0311b5ad", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot points on the saggital slice at ap=-800um overlaid on brain region boundaries using Cosmos mapping\n", - "fig, ax, cbar = plot_volume_on_slice(volume, coord=-800, slice='sagittal', mapping='Cosmos', background='boundary', \n", - " cmap='Blues', brain_atlas=ba, clevels=[0, 2e-7], show_cbar=True)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7835fa36", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot points on the horizontal slice at dv=-5000um overlaid on allen dwi image\n", - "fig, ax = plot_volume_on_slice(volume, coord=-5000, slice='horizontal', background='image', cmap='Greens', brain_atlas=ba)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [conda env:iblenv] *", - "language": "python", - "name": "conda-env-iblenv-py" - }, - "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.9.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file +{ + "cells": [ + { + "cell_type": "markdown", + "id": "87d1873a", + "metadata": {}, + "source": [ + "# Plotting cluster locations on histology slices" + ] + }, + { + "cell_type": "markdown", + "id": "77834a05", + "metadata": {}, + "source": [ + "This example walks through various ways to display the 3D location of clusters on histology slices" + ] + }, + { + "cell_type": "markdown", + "id": "5011bf58", + "metadata": {}, + "source": [ + "## Data Preparation" + ] + }, + { + "cell_type": "markdown", + "id": "60f93667", + "metadata": {}, + "source": [ + "For all examples below the xyz coordinates of each point and an array of values must be provided. Here we load in the spikesorting data for an example probe insertion and set the xyz coordinates to the coordinates of the clusters and the array of values to the firing rate." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5d22548", + "metadata": {}, + "outputs": [], + "source": [ + "from one.api import ONE\n", + "from brainbox.io.one import SpikeSortingLoader\n", + "from iblatlas.atlas import AllenAtlas\n", + "import numpy as np\n", + "\n", + "one = ONE()\n", + "ba = AllenAtlas()\n", + "pid = 'da8dfec1-d265-44e8-84ce-6ae9c109b8bd'\n", + "sl = SpikeSortingLoader(pid=pid, one=one, atlas=ba)\n", + "spikes, clusters, channels = sl.load_spike_sorting()\n", + "clusters = sl.merge_clusters(spikes, clusters, channels)\n", + "\n", + "# Extract xyz coords from clusters dict\n", + "# Here we will set all ap values to a chosen value for visualisation purposes\n", + "xyz = np.c_[clusters['x'], np.ones_like(clusters['x']) * 400 / 1e6, clusters['z']]\n", + "values = clusters['firing_rate']" + ] + }, + { + "cell_type": "markdown", + "id": "c84d11bd", + "metadata": {}, + "source": [ + "## Example 1: Aggregation methods" + ] + }, + { + "cell_type": "markdown", + "id": "b9340c33", + "metadata": {}, + "source": [ + "The values of points that lie within the same voxel within the volume can be aggregated together in different ways by changing the `aggr` argument. Below shows an example where values in each voxel have been aggregated according to the average firing rate of the clusters (left) and according to the count of clusters in each voxel (right)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f35b8827", + "metadata": {}, + "outputs": [], + "source": [ + "from iblatlas.plots import plot_points_on_slice\n", + "import matplotlib.pyplot as plt\n", + "\n", + "fig, axs = plt.subplots(1, 2, figsize=(16,4))\n", + "\n", + "# Plot points on the coronal slice at ap=400um overlaid overlaid on brain region boundaries using Allen mapping \n", + "# and a 3D gaussian kernel with fwhm=100um is applied\n", + "\n", + "# Values in the same voxel are aggregated by the mean\n", + "fig, ax = plot_points_on_slice(xyz, values=values, coord=400, slice='coronal', mapping='Allen', background='boundary', \n", + " cmap='Reds', aggr='mean', fwhm=100, brain_atlas=ba, ax=axs[0])\n", + "\n", + "# Values in the same voxel are aggregated by the count\n", + "# N.B. can also pass values=None in this case as they are not used in the computation\n", + "fig, ax, cbar = plot_points_on_slice(xyz, values=values, coord=400, slice='coronal', mapping='Allen', background='boundary', \n", + " cmap='Reds', aggr='count', fwhm=100, brain_atlas=ba, ax=axs[1], show_cbar=True)" + ] + }, + { + "cell_type": "markdown", + "id": "54650899", + "metadata": {}, + "source": [ + "The different options for aggregation are listed in the docstring of the function" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b6ad58e", + "metadata": {}, + "outputs": [], + "source": [ + "help(plot_points_on_slice)" + ] + }, + { + "cell_type": "markdown", + "id": "ea0cf9a4", + "metadata": {}, + "source": [ + "## Example 2: Applying gaussian kernels with varying FWHM" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ba3ca84", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot points on the coronal slice at ap=400um overlaid overlaid on Allen dwi image using Cosmos mapping with\n", + "# values aggregated by max\n", + "\n", + "figs, axs = plt.subplots(1, 3, figsize=(18,4))\n", + "\n", + "# FWHM of 100 um\n", + "fig, ax = plot_points_on_slice(xyz, values=values, coord=400, slice='coronal', background='image', \n", + " cmap='Purples', aggr='max', fwhm=100, brain_atlas=ba, ax=axs[0])\n", + "\n", + "# FWHM of 300 um\n", + "fig, ax = plot_points_on_slice(xyz, values=values, coord=400, slice='coronal', background='image', \n", + " cmap='Purples', aggr='max', fwhm=300, brain_atlas=ba, ax=axs[1])\n", + "\n", + "# FWHM of 0 um\n", + "# if fwhm=0 no gaussian kernal applied\n", + "fig, ax = plot_points_on_slice(xyz, values=values, coord=400, slice='coronal', background='image', \n", + " cmap='Purples', aggr='max', fwhm=0, brain_atlas=ba, ax=axs[2])" + ] + }, + { + "cell_type": "markdown", + "id": "a0aca146", + "metadata": {}, + "source": [ + "## Example 3: Precomputing Volume" + ] + }, + { + "cell_type": "markdown", + "id": "19edcc5b", + "metadata": {}, + "source": [ + "Convolving the 3D volume with the gaussian kernal can take some time to compute, particularly when using a large fwhm value. When exploring the same volume at different coordinates and using different slices it is recommended to precompute the volume and then plot the slices. Below shows an example of how to do this." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81f6919c", + "metadata": {}, + "outputs": [], + "source": [ + "from iblatlas.plots import compute_volume_from_points, plot_volume_on_slice\n", + "\n", + "# Extract xyz coords from clusters dict\n", + "xyz = np.c_[clusters['x'], clusters['y'], clusters['z']]\n", + "values = clusters['amp_max']\n", + "\n", + "# Compute volume\n", + "volume = compute_volume_from_points(xyz, values=values, aggr='mean', fwhm=250, ba=ba)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d938d24", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot points on the coronal slices on brain region boundaries using Beryl maping\n", + "figs, axs = plt.subplots(1, 3, figsize=(18,4))\n", + "fig, ax = plot_volume_on_slice(volume, coord=300, slice='coronal', mapping='Beryl', background='boundary', \n", + " cmap='Oranges', brain_atlas=ba, ax=axs[0])\n", + "ax.set_title('ap = 300um')\n", + "fig, ax = plot_volume_on_slice(volume, coord=400, slice='coronal', mapping='Beryl', background='boundary', \n", + " cmap='Oranges', brain_atlas=ba, ax=axs[1])\n", + "ax.set_title('ap = 400um')\n", + "fig, ax = plot_volume_on_slice(volume, coord=500, slice='coronal', mapping='Beryl', background='boundary', \n", + " cmap='Oranges', brain_atlas=ba,ax=axs[2])\n", + "ax.set_title('ap = 500um')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0311b5ad", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot points on the saggital slice at ap=-800um overlaid on brain region boundaries using Cosmos mapping\n", + "fig, ax, cbar = plot_volume_on_slice(volume, coord=-800, slice='sagittal', mapping='Cosmos', background='boundary', \n", + " cmap='Blues', brain_atlas=ba, clevels=[0, 2e-7], show_cbar=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7835fa36", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot points on the horizontal slice at dv=-5000um overlaid on allen dwi image\n", + "fig, ax = plot_volume_on_slice(volume, coord=-5000, slice='horizontal', background='image', cmap='Greens', brain_atlas=ba)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:iblenv] *", + "language": "python", + "name": "conda-env-iblenv-py" + }, + "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.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/atlas_plotting_scalar_on_slice.ipynb b/examples/atlas_plotting_scalar_on_slice.ipynb index a5a2c81..dc16eff 100644 --- a/examples/atlas_plotting_scalar_on_slice.ipynb +++ b/examples/atlas_plotting_scalar_on_slice.ipynb @@ -1,277 +1,277 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "12df3a26", - "metadata": {}, - "source": [ - "# Plotting brain region values on histology slices" - ] - }, - { - "cell_type": "markdown", - "id": "a056f78f", - "metadata": {}, - "source": [ - "This example walks through various ways to overlay brain region values on histology slices" - ] - }, - { - "cell_type": "markdown", - "id": "8cef5812", - "metadata": {}, - "source": [ - "## Data preparation\n", - "For all the examples below, an array of acronyms and an array of values corresponding to each acronym must be provided. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dd06e7ff", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "# prepare array of acronyms\n", - "acronyms = np.array(['VPM', 'VPL', 'PO', 'LP', 'CA1', 'DG-mo', 'SSs5', 'VISa5', 'AUDv6a', 'MOp5', 'FRP5'])\n", - "# assign data to each acronym\n", - "values = np.arange(len(acronyms))\n", - "\n", - "# acronyms and values must have the same number of rows\n", - "assert (acronyms.size == values.size)" - ] - }, - { - "cell_type": "markdown", - "id": "e0b26454", - "metadata": {}, - "source": [ - "If different values for each acronym want to be shown on each hemisphere, the array of values must contain two columns, the first corresponding to values on the left hemisphere and the second corresponding to values on the right hemisphere" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fa6bdd24", - "metadata": {}, - "outputs": [], - "source": [ - "# values to be used for left and right hemisphere\n", - "values_lh = np.random.randint(0, 10, acronyms.size)\n", - "values_rh = np.random.randint(0, 10, acronyms.size)\n", - "values_lr = np.c_[values_lh, values_rh]" - ] - }, - { - "cell_type": "markdown", - "id": "7115c423", - "metadata": {}, - "source": [ - "When providing values for each hemisphere, if a value for a given acronym has only been computed, for example, in the left hemisphere, the corresponding value in right hemisphere array should be set to NaN. A helper function is available that will prepare the array of values in the correct format" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "06c9e0c7", - "metadata": {}, - "outputs": [], - "source": [ - "from iblatlas.plots import prepare_lr_data\n", - "\n", - "acronyms_lh = np.array(['VPM', 'VPL', 'PO', 'LP', 'CA1', 'DG-mo'])\n", - "values_lh = np.random.randint(0, 10, acronyms_lh.size)\n", - "\n", - "acronyms_rh = np.array(['VPM', 'PO', 'LP', 'CA1', 'DG-mo', 'VISa5', 'SSs5'])\n", - "values_rh = np.random.randint(0, 10, acronyms_rh.size)\n", - "\n", - "acronyms_lr, values_lr = prepare_lr_data(acronyms_lh, values_lh, acronyms_rh, values_rh)" - ] - }, - { - "cell_type": "markdown", - "id": "45aa4b07", - "metadata": {}, - "source": [ - "Different mappings can be used when plotting the images (see [here](https://int-brain-lab.github.io/iblenv/notebooks_external/atlas_mapping.html) for more information on atlas mappings). The acronyms provided must correspond to the specified map" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7afc0de4", - "metadata": {}, - "outputs": [], - "source": [ - "from iblatlas.regions import BrainRegions\n", - "br = BrainRegions()\n", - "\n", - "acronyms_beryl = np.unique(br.acronym2acronym(acronyms, mapping='Beryl'))\n", - "values_beryl = np.arange(acronyms_beryl.size)\n", - "\n", - "acronyms_cosmos = np.unique(br.acronym2acronym(acronyms, mapping='Cosmos'))\n", - "values_cosmos = np.arange(acronyms_cosmos.size)" - ] - }, - { - "cell_type": "markdown", - "id": "9bcda7f3", - "metadata": {}, - "source": [ - "## Example 1: Coronal slices" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "33270b88", - "metadata": {}, - "outputs": [], - "source": [ - "from iblatlas.plots import plot_scalar_on_slice\n", - "from iblatlas.atlas import AllenAtlas\n", - "ba = AllenAtlas()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0731a71d", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot region values on the left hemisphere of a coronal slice at ap=-2000um overlaid on the dwi Allen image\n", - "fig, ax = plot_scalar_on_slice(acronyms, values, coord=-2000, slice='coronal', mapping='Allen', hemisphere='left',\n", - " background='image', cmap='Reds', brain_atlas=ba)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "284efd17", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot single column region values on both hemispheres of a coronal slice at ap=-2000um overlaid on brain region boundaries\n", - "# using Beryl mapping\n", - "# If values only contains one column, the values will be mirrored on each hemisphere\n", - "fig, ax = plot_scalar_on_slice(acronyms_beryl, values_beryl, coord=-2000, slice='coronal', mapping='Beryl', \n", - " hemisphere='both', background='boundary', cmap='Blues', brain_atlas=ba)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2df60008", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot two column region values on both hemispheres of a coronal slice at ap=-1800um overlaid on brain region boundaries\n", - "# and display colorbar\n", - "# Values contains two columns, so each hemisphere has different values \n", - "fig, ax, cbar = plot_scalar_on_slice(acronyms_lr, values_lr, coord=-1800, slice='coronal', mapping='Allen', hemisphere='both', \n", - " background='boundary', cmap='viridis', brain_atlas=ba, show_cbar=True)" - ] - }, - { - "cell_type": "markdown", - "id": "cbdc5f5d", - "metadata": {}, - "source": [ - "## Example 2: Sagittal slices" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "25fec19d", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot region values on the left hemisphere of a sagittal slice at ml=-2000um overlaid on the dwi Allen image \n", - "# using cosmos mapping\n", - "fig, ax = plot_scalar_on_slice(acronyms_cosmos, values_cosmos, coord=-2000, slice='sagittal', mapping='Cosmos', \n", - " hemisphere='left', background='image', cmap='Greens', brain_atlas=ba)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4ee0db12", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot region values on the left hemisphere of a sagittal slice at ml=-1000um overlaid on brain region boundaries\n", - "# Create figure before and pass in axis on which to plot\n", - "import matplotlib.pyplot as plt\n", - "fig, ax = plt.subplots()\n", - "fig, ax = plot_scalar_on_slice(acronyms, values, coord=-1000, slice='sagittal', mapping='Allen', hemisphere='left', \n", - " background='boundary', cmap='plasma', brain_atlas=ba, ax=ax)" - ] - }, - { - "cell_type": "markdown", - "id": "b78a2be9", - "metadata": {}, - "source": [ - "## Example 3: Horizontal slices" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "11f7862e", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot two column region values on the both hemispheres of a horizontal slice at dv=--2500um overlaid on the dwi Allen image\n", - "# Pass in clevels min max values to cap the colormap\n", - "fig, ax = plot_scalar_on_slice(acronyms_lr, values_lr, coord=-2500, slice='horizontal', mapping='Allen', hemisphere='both', \n", - " background='image', cmap='Reds', brain_atlas=ba, clevels=[0, 5])" - ] - }, - { - "cell_type": "markdown", - "id": "dbfc97d2", - "metadata": {}, - "source": [ - "## Example 4: Top view" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "238294a4", - "metadata": {}, - "outputs": [], - "source": [ - "# Plot region values on left hemisphere of a top view overlaid on brain region boundaries using Beryl mapping and show cbar\n", - "\n", - "fig, ax, cbar = plot_scalar_on_slice(acronyms_beryl, values_beryl, slice='top', mapping='Beryl', hemisphere='left', \n", - " background='boundary', cmap='Purples', brain_atlas=ba, show_cbar=True)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [conda env:iblenv] *", - "language": "python", - "name": "conda-env-iblenv-py" - }, - "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.9.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} +{ + "cells": [ + { + "cell_type": "markdown", + "id": "12df3a26", + "metadata": {}, + "source": [ + "# Plotting brain region values on histology slices" + ] + }, + { + "cell_type": "markdown", + "id": "a056f78f", + "metadata": {}, + "source": [ + "This example walks through various ways to overlay brain region values on histology slices" + ] + }, + { + "cell_type": "markdown", + "id": "8cef5812", + "metadata": {}, + "source": [ + "## Data preparation\n", + "For all the examples below, an array of acronyms and an array of values corresponding to each acronym must be provided. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd06e7ff", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "# prepare array of acronyms\n", + "acronyms = np.array(['VPM', 'VPL', 'PO', 'LP', 'CA1', 'DG-mo', 'SSs5', 'VISa5', 'AUDv6a', 'MOp5', 'FRP5'])\n", + "# assign data to each acronym\n", + "values = np.arange(len(acronyms))\n", + "\n", + "# acronyms and values must have the same number of rows\n", + "assert (acronyms.size == values.size)" + ] + }, + { + "cell_type": "markdown", + "id": "e0b26454", + "metadata": {}, + "source": [ + "If different values for each acronym want to be shown on each hemisphere, the array of values must contain two columns, the first corresponding to values on the left hemisphere and the second corresponding to values on the right hemisphere" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa6bdd24", + "metadata": {}, + "outputs": [], + "source": [ + "# values to be used for left and right hemisphere\n", + "values_lh = np.random.randint(0, 10, acronyms.size)\n", + "values_rh = np.random.randint(0, 10, acronyms.size)\n", + "values_lr = np.c_[values_lh, values_rh]" + ] + }, + { + "cell_type": "markdown", + "id": "7115c423", + "metadata": {}, + "source": [ + "When providing values for each hemisphere, if a value for a given acronym has only been computed, for example, in the left hemisphere, the corresponding value in right hemisphere array should be set to NaN. A helper function is available that will prepare the array of values in the correct format" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "06c9e0c7", + "metadata": {}, + "outputs": [], + "source": [ + "from iblatlas.plots import prepare_lr_data\n", + "\n", + "acronyms_lh = np.array(['VPM', 'VPL', 'PO', 'LP', 'CA1', 'DG-mo'])\n", + "values_lh = np.random.randint(0, 10, acronyms_lh.size)\n", + "\n", + "acronyms_rh = np.array(['VPM', 'PO', 'LP', 'CA1', 'DG-mo', 'VISa5', 'SSs5'])\n", + "values_rh = np.random.randint(0, 10, acronyms_rh.size)\n", + "\n", + "acronyms_lr, values_lr = prepare_lr_data(acronyms_lh, values_lh, acronyms_rh, values_rh)" + ] + }, + { + "cell_type": "markdown", + "id": "45aa4b07", + "metadata": {}, + "source": [ + "Different mappings can be used when plotting the images (see [here](https://int-brain-lab.github.io/iblenv/notebooks_external/atlas_mapping.html) for more information on atlas mappings). The acronyms provided must correspond to the specified map" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7afc0de4", + "metadata": {}, + "outputs": [], + "source": [ + "from iblatlas.regions import BrainRegions\n", + "br = BrainRegions()\n", + "\n", + "acronyms_beryl = np.unique(br.acronym2acronym(acronyms, mapping='Beryl'))\n", + "values_beryl = np.arange(acronyms_beryl.size)\n", + "\n", + "acronyms_cosmos = np.unique(br.acronym2acronym(acronyms, mapping='Cosmos'))\n", + "values_cosmos = np.arange(acronyms_cosmos.size)" + ] + }, + { + "cell_type": "markdown", + "id": "9bcda7f3", + "metadata": {}, + "source": [ + "## Example 1: Coronal slices" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33270b88", + "metadata": {}, + "outputs": [], + "source": [ + "from iblatlas.plots import plot_scalar_on_slice\n", + "from iblatlas.atlas import AllenAtlas\n", + "ba = AllenAtlas()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0731a71d", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot region values on the left hemisphere of a coronal slice at ap=-2000um overlaid on the dwi Allen image\n", + "fig, ax = plot_scalar_on_slice(acronyms, values, coord=-2000, slice='coronal', mapping='Allen', hemisphere='left',\n", + " background='image', cmap='Reds', brain_atlas=ba)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "284efd17", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot single column region values on both hemispheres of a coronal slice at ap=-2000um overlaid on brain region boundaries\n", + "# using Beryl mapping\n", + "# If values only contains one column, the values will be mirrored on each hemisphere\n", + "fig, ax = plot_scalar_on_slice(acronyms_beryl, values_beryl, coord=-2000, slice='coronal', mapping='Beryl', \n", + " hemisphere='both', background='boundary', cmap='Blues', brain_atlas=ba)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2df60008", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot two column region values on both hemispheres of a coronal slice at ap=-1800um overlaid on brain region boundaries\n", + "# and display colorbar\n", + "# Values contains two columns, so each hemisphere has different values \n", + "fig, ax, cbar = plot_scalar_on_slice(acronyms_lr, values_lr, coord=-1800, slice='coronal', mapping='Allen', hemisphere='both', \n", + " background='boundary', cmap='viridis', brain_atlas=ba, show_cbar=True)" + ] + }, + { + "cell_type": "markdown", + "id": "cbdc5f5d", + "metadata": {}, + "source": [ + "## Example 2: Sagittal slices" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25fec19d", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot region values on the left hemisphere of a sagittal slice at ml=-2000um overlaid on the dwi Allen image \n", + "# using cosmos mapping\n", + "fig, ax = plot_scalar_on_slice(acronyms_cosmos, values_cosmos, coord=-2000, slice='sagittal', mapping='Cosmos', \n", + " hemisphere='left', background='image', cmap='Greens', brain_atlas=ba)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ee0db12", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot region values on the left hemisphere of a sagittal slice at ml=-1000um overlaid on brain region boundaries\n", + "# Create figure before and pass in axis on which to plot\n", + "import matplotlib.pyplot as plt\n", + "fig, ax = plt.subplots()\n", + "fig, ax = plot_scalar_on_slice(acronyms, values, coord=-1000, slice='sagittal', mapping='Allen', hemisphere='left', \n", + " background='boundary', cmap='plasma', brain_atlas=ba, ax=ax)" + ] + }, + { + "cell_type": "markdown", + "id": "b78a2be9", + "metadata": {}, + "source": [ + "## Example 3: Horizontal slices" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11f7862e", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot two column region values on the both hemispheres of a horizontal slice at dv=--2500um overlaid on the dwi Allen image\n", + "# Pass in clevels min max values to cap the colormap\n", + "fig, ax = plot_scalar_on_slice(acronyms_lr, values_lr, coord=-2500, slice='horizontal', mapping='Allen', hemisphere='both', \n", + " background='image', cmap='Reds', brain_atlas=ba, clevels=[0, 5])" + ] + }, + { + "cell_type": "markdown", + "id": "dbfc97d2", + "metadata": {}, + "source": [ + "## Example 4: Top view" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "238294a4", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot region values on left hemisphere of a top view overlaid on brain region boundaries using Beryl mapping and show cbar\n", + "\n", + "fig, ax, cbar = plot_scalar_on_slice(acronyms_beryl, values_beryl, slice='top', mapping='Beryl', hemisphere='left', \n", + " background='boundary', cmap='Purples', brain_atlas=ba, show_cbar=True)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:iblenv] *", + "language": "python", + "name": "conda-env-iblenv-py" + }, + "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.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/atlas_swanson_flatmap.ipynb b/examples/atlas_swanson_flatmap.ipynb index 0b41e31..a8f624c 100644 --- a/examples/atlas_swanson_flatmap.ipynb +++ b/examples/atlas_swanson_flatmap.ipynb @@ -1,7 +1,12 @@ { "cells": [ - { + { "cell_type": "code", + "execution_count": null, + "id": "5711974f8dd963cd", + "metadata": { + "nbsphinx": "hidden" + }, "outputs": [], "source": [ "# Turn off logging and disable tqdm this is a hidden cell on docs page\n", @@ -12,12 +17,7 @@ "logger.setLevel(logging.CRITICAL)\n", "\n", "os.environ[\"TQDM_DISABLE\"] = \"1\"" - ], - "metadata": { - "nbsphinx": "hidden", - "collapsed": false - }, - "id": "5711974f8dd963cd" + ] }, { "cell_type": "markdown", @@ -53,51 +53,55 @@ }, { "cell_type": "markdown", - "source": [ - "### What regions are represented in the Swanson flatmap" - ], "metadata": { "collapsed": false - } + }, + "source": [ + "### What regions are represented in the Swanson flatmap" + ] }, { "cell_type": "markdown", + "metadata": { + "collapsed": false + }, "source": [ "The Swanson map holds 323 brain region acronyms.\n", "To find these acronyms, use the indices stored in the swanson mapping:" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "swanson_indices = np.unique(br.mappings['Swanson'])\n", "swanson_ac = np.sort(br.acronym[swanson_indices])\n", "swanson_ac.size" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", - "source": [ - "Regions which are \"children\" or \"parents\" of a Swanson region will not be included in the acronyms. For example `VISa` is in Swanson, but its parent `PTLp` or child `VISa2/3` are not:" - ], "metadata": { "collapsed": false - } + }, + "source": [ + "Regions which are \"children\" or \"parents\" of a Swanson region will not be included in the acronyms. For example `VISa` is in Swanson, but its parent `PTLp` or child `VISa2/3` are not:" + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# Example: VISa is in Swanson\n", @@ -108,51 +112,47 @@ "\n", "# Example parent: PTLp is not in Swanson\n", "print(np.isin(['PTLp'], swanson_ac))" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", - "source": [ - "Also, only the indices corresponding to one hemisphere are represented in Swanson. For example, for VISa:" - ], "metadata": { "collapsed": false - } + }, + "source": [ + "Also, only the indices corresponding to one hemisphere are represented in Swanson. For example, for VISa:" + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# indices of VISa\n", "indices = br.acronym2index('VISa')[1][0]\n", "print(f'Index {indices[0]} in swanson? {indices[0] in swanson_indices}')\n", "print(f'Index {indices[1]} in swanson? {indices[1] in swanson_indices}')" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", - "source": [ - "### Selecting the brain regions for plotting" - ], "metadata": { "collapsed": false - } + }, + "source": [ + "### Selecting the brain regions for plotting" + ] }, { "cell_type": "markdown", + "metadata": { + "collapsed": false + }, "source": [ "You can only plot value for a given region that is in Swanson, or a parent region (see below for detailed explanation on this latter point). You cannot plot value on children regions of those in the Swanson mapping. In other words, the brain regions contains in the Swanson mapping are the lowest hierarchical level you can plot onto.\n", "\n", @@ -160,14 +160,16 @@ "For example, if you were to input values for both `VISa1` and `VISa2/3`, it is unclear whether the mean, median or else should have been plotted onto the `VISa` area - instead, we ask you to do the aggregation yourself and pass this into the plotting function.\n", "\n", "For example," - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# 'VISa', 'CA1', 'VPM' are in Swanson and all 3 are plotted\n", @@ -181,26 +183,25 @@ "values = np.array([1, 2, 3, 4])\n", "plot_swanson_vector(acronyms, values, annotate=True,\n", " annotate_list=['VISa1','VISa2/3', 'CA1', 'VPM'],empty_color='silver')" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", - "source": [ - "You can plot onto the parent of a region in the Swanson mapping, for example you can plot over `PTLp` (which is the parent of `VISa` and `VISrl`). This paints the same value across all regions of the Swanson mapping contained in the parent region." - ], "metadata": { "collapsed": false - } + }, + "source": [ + "You can plot onto the parent of a region in the Swanson mapping, for example you can plot over `PTLp` (which is the parent of `VISa` and `VISrl`). This paints the same value across all regions of the Swanson mapping contained in the parent region." + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# Plotting over a parent region (PTLp) paints the same value across all children (VISa and VISrl)\n", @@ -208,26 +209,25 @@ "values = np.array([1.5, 3, 4])\n", "plot_swanson_vector(acronyms, values, annotate=True,\n", " annotate_list=['PTLp', 'CA1', 'VPM'],empty_color='silver')" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", - "source": [ - "Plotting over a parent and child region simultaneously will overwrite the corresponding portion of the parent region:" - ], "metadata": { "collapsed": false - } + }, + "source": [ + "Plotting over a parent and child region simultaneously will overwrite the corresponding portion of the parent region:" + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# Plotting over 'PTLp' and overwriting the 'VISrl' value\n", @@ -235,64 +235,56 @@ "values = np.array([1, 2, 3, 4])\n", "plot_swanson_vector(acronyms, values, annotate=True,\n", " annotate_list=['PTLp','VISrl', 'CA1', 'VPM'],empty_color='silver')" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", - "source": [ - "As such, you can easily fill in a whole top-hierarchy region, supplemented by one particular region of interest." - ], "metadata": { "collapsed": false - } + }, + "source": [ + "As such, you can easily fill in a whole top-hierarchy region, supplemented by one particular region of interest." + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "acronyms = ['Isocortex', 'VISa']\n", "values = np.array([1, 2])\n", "plot_swanson_vector(acronyms, values, annotate=True,\n", " annotate_list=['Isocortex', 'VISa'],empty_color='silver')" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", + "metadata": { + "collapsed": false + }, "source": [ "## Mapping to the swanson brain regions\n", "\n", "Similarly as explained in this [page](https://int-brain-lab.github.io/iblenv/notebooks_external/atlas_mapping.html), you can map brain regions to those found in Swanson using `br.acronym2acronym`:" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "br.acronym2acronym('MDm', mapping='Swanson')" - ], "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "br.acronym2acronym('MDm', mapping='Swanson')" + ] }, { "cell_type": "markdown", @@ -393,24 +385,22 @@ }, { "cell_type": "markdown", + "metadata": { + "collapsed": false + }, "source": [ "## Portrait orientation\n", "One can also mirror the hemispheres and orient the display in portrait mode." - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "plot_swanson_vector(acronyms=acronyms, values=values, orientation='portrait', cmap='Greens', hemisphere='mirror')" - ], - "metadata": { - "collapsed": false - } + ] } ], "metadata": { @@ -429,9 +419,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.7" + "version": "3.11.6" } }, "nbformat": 4, "nbformat_minor": 1 -} \ No newline at end of file +} diff --git a/examples/atlas_working_with_ibllib_atlas.ipynb b/examples/atlas_working_with_ibllib_atlas.ipynb index ebbd874..9ef3889 100644 --- a/examples/atlas_working_with_ibllib_atlas.ipynb +++ b/examples/atlas_working_with_ibllib_atlas.ipynb @@ -248,64 +248,73 @@ }, { "cell_type": "markdown", - "source": [ - "Voxels outside of the brain are labelled with `void`, which has the both the index and Allen ID being 0:" - ], + "id": "b96a19fb", "metadata": { "collapsed": false - } + }, + "source": [ + "Voxels outside of the brain are labelled with `void`, which has the both the index and Allen ID being 0:" + ] }, { "cell_type": "code", "execution_count": null, + "id": "fc30fb17", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "index_void = 0\n", "print(brain_regions.id[index_void])\n", "print(brain_regions.acronym[index_void])" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", - "source": [ - "As such, you can find all the voxels within the brain by filtering for non-zero indices:" - ], + "id": "3fbc71bb", "metadata": { "collapsed": false - } + }, + "source": [ + "As such, you can find all the voxels within the brain by filtering for non-zero indices:" + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "vox_in = np.where(brain_regions.id != index_void)" - ], + "id": "89e5712b", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "vox_in = np.where(brain_regions.id != index_void)" + ] }, { "cell_type": "markdown", - "source": [ - "You can jump betwen acronym / id / index with these functions :" - ], + "id": "69ff80c5", "metadata": { "collapsed": false - } + }, + "source": [ + "You can jump betwen acronym / id / index with these functions :" + ] }, { "cell_type": "code", "execution_count": null, + "id": "7368f6e9", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# From an acronym, get the index and id\n", @@ -329,20 +338,15 @@ "acronym = brain_regions.acronym[index]\n", "\n", "print(f'The index {index} has the acronym {acronym} and the Allen id {id}')" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", - "source": [], + "id": "411ea768", "metadata": { "collapsed": false - } + }, + "source": [] }, { "cell_type": "markdown", @@ -357,30 +361,37 @@ { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "# Print how many indexes there are\n", - "print(brain_regions.id.size)" - ], + "id": "75539930", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "# Print how many indexes there are\n", + "print(brain_regions.id.size)" + ] }, { "cell_type": "markdown", - "source": [ - "This is equivalent to 2x the number of unique Allen IDs (positive + negative), plus `void` (0) that is not lateralised:" - ], + "id": "322a0246", "metadata": { "collapsed": false - } + }, + "source": [ + "This is equivalent to 2x the number of unique Allen IDs (positive + negative), plus `void` (0) that is not lateralised:" + ] }, { "cell_type": "code", "execution_count": null, + "id": "636c60e8", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "positive_id = np.where(brain_regions.id>0)[0]\n", @@ -388,118 +399,117 @@ "void_id = np.where(brain_regions.id==0)[0]\n", "\n", "print(len(positive_id) + len(negative_id) + len(void_id))" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", - "source": [ - "We can understand this better by exploring the `brain_regions.id` and `brain_regions.name` at the indices where it transitions between hemispheres." - ], + "id": "ad006b5f", "metadata": { "collapsed": false - } + }, + "source": [ + "We can understand this better by exploring the `brain_regions.id` and `brain_regions.name` at the indices where it transitions between hemispheres." + ] }, { "cell_type": "markdown", - "source": [ - "The first value of `brain_region.id` is `void` (Allen id `0`):" - ], + "id": "e74d2590", "metadata": { "collapsed": false - } + }, + "source": [ + "The first value of `brain_region.id` is `void` (Allen id `0`):" + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "print(brain_regions.id[index_void])" - ], + "id": "1d69a398", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "print(brain_regions.id[index_void])" + ] }, { "cell_type": "markdown", - "source": [ - "The point of change between right and left hemisphere is at the index:" - ], + "id": "2c0a876c", "metadata": { "collapsed": false - } + }, + "source": [ + "The point of change between right and left hemisphere is at the index:" + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "print(len(positive_id))" - ], + "id": "74862f4c", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "print(len(positive_id))" + ] }, { "cell_type": "markdown", - "source": [ - "Around this index, the `brain_region.id` go from positive Allen atlas ids (right hemisphere) to negative Allen atlas ids (left hemisphere)." - ], + "id": "1e1041c5", "metadata": { "collapsed": false - } + }, + "source": [ + "Around this index, the `brain_region.id` go from positive Allen atlas ids (right hemisphere) to negative Allen atlas ids (left hemisphere)." + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "print(brain_regions.id[1320:1340])" - ], + "id": "f655253e", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "print(brain_regions.id[1320:1340])" + ] }, { "cell_type": "markdown", + "id": "ee3e09d0", + "metadata": { + "collapsed": false + }, "source": [ "Regions are organised following the same index ordering in left/right hemisphere.\n", "For example, you will find the same acronym `PPYd` at the index 1000, and once you've passed the positive integers:" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, + "id": "a27c39ff", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "index = 1000\n", "print(brain_regions.acronym[index])\n", "print(brain_regions.acronym[index + len(positive_id)])\n", "# Note: do not re-use this approach, this is for explanation only - you will see below a dedicated function" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", @@ -559,6 +569,10 @@ }, { "cell_type": "markdown", + "id": "987d5b19", + "metadata": { + "collapsed": false + }, "source": [ "## Navigate the brain region hierarchy\n", "The 1328 regions in the Allen parcelation are organised in a hierarchical tree.\n", @@ -566,41 +580,43 @@ "\n", "You can visually explore the hierarchy through this [webpage](https://openalyx.internationalbrainlab.org/admin/experiments/brainregion/) (username: `intbrainlab`, password: `international`).\n", "(TODO THIS IS NOT A GREAT WAY, CHANGE TO OTHER REFERENCE)\n" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "markdown", + "id": "42036641", + "metadata": { + "collapsed": false + }, "source": [ "### Ancestors\n", "\n", "To find ancestors of a region, i.e. regions that are higher in the hierarchy tree, use `brain_regions.ancestors`.\n", "\n", "Let's use the region PPYd as an example:" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "index = 1000 # Remember the Allen id at this index is 185\n", - "brain_regions.ancestors(ids=brain_regions.id[index])" - ], + "id": "5ec4df76", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "index = 1000 # Remember the Allen id at this index is 185\n", + "brain_regions.ancestors(ids=brain_regions.id[index])" + ] }, { "cell_type": "markdown", + "id": "dbb9f817", + "metadata": { + "collapsed": false + }, "source": [ "All parents along the hierarchy tree are returned.\n", "The parents are organised in increasing order of `level` (0-1-2...), i.e. the highest, all-encompassing level is first (`root` in the example above).\n", @@ -610,56 +626,58 @@ "- The field `order` returns values used for plotting (Note: this is *not* the parent's index)\n", "\n", "For example, the last `parent` region is PPY (which is indeed the closest parent of PPYd):" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, + "id": "0a98230a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "index = 999\n", "print(brain_regions.id[index])\n", "print(brain_regions.acronym[index])" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", + "id": "e6dfeaab", + "metadata": { + "collapsed": false + }, "source": [ "### Descendants\n", "To find the descendants of a region, use `brain_regions.descendants`.\n", "\n", "Let's use the region PPY as an example:" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "index = 999\n", - "brain_regions.descendants(ids=brain_regions.id[index])" - ], + "id": "5269d81c", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "index = 999\n", + "brain_regions.descendants(ids=brain_regions.id[index])" + ] }, { "cell_type": "markdown", + "id": "8e15c7b1", + "metadata": { + "collapsed": false + }, "source": [ "Note:\n", "- The fields contain all the descendant regions, including the one passed in (which is first).\n", @@ -667,14 +685,17 @@ "- The field `order` returns values used for plotting (Note: this is *not* the parent's index)\n", "\n", "Note also that the `descendants` methods will return all descendants from all the different branches down, for example for PTLp :" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, + "id": "616fc7f2", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "atlas_id = brain_regions.acronym2id('PTLp')\n", @@ -682,16 +703,14 @@ "print(brain_regions.descendants(ids=atlas_id)['acronym'])\n", "# Print the levels of the descendants of this region\n", "print(brain_regions.descendants(ids=atlas_id)['level'])" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", + "id": "280c88a6", + "metadata": { + "collapsed": false + }, "source": [ "### Find region at a particular place in the hierarchy\n", "\n", @@ -700,117 +719,117 @@ "If you need to check a region is a leaf node, i.e. that it has no descendant, you could use the `descendants` method and check that the returned length of the `id` is one (i.e. it only returns itself).\n", "\n", "For example, PPYd is a leaf node:" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, + "id": "5cf6d290", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "index = 1000\n", "ppyd_desc = brain_regions.descendants(ids=brain_regions.id[index])\n", "\n", "len(ppyd_desc['id']) == 1" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", + "id": "9ce99254", + "metadata": { + "collapsed": false + }, "source": [ "However, there is a faster method.\n", "To find all the regions that are leaf nodes, use `brain_regions.leaves`:" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "brain_regions.leaves()" - ], + "id": "cb26254a", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "brain_regions.leaves()" + ] }, { "cell_type": "markdown", - "source": [ - "It is recommended you use this function to check whether a region is a leaf node:" - ], + "id": "a9289014", "metadata": { "collapsed": false - } + }, + "source": [ + "It is recommended you use this function to check whether a region is a leaf node:" + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "index = 1000\n", - "brain_regions.id[index] in brain_regions.leaves().id" - ], + "id": "65770625", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "index = 1000\n", + "brain_regions.id[index] in brain_regions.leaves().id" + ] }, { "cell_type": "markdown", + "id": "5ad79184", + "metadata": { + "collapsed": false + }, "source": [ "#### Find region at a given hierarchy level\n", "\n", "To find all the regions that are on a given level of the hierarchy, use `brain_regions.level`:" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "print(f'brain_regions.level contains {brain_regions.level.size} values, which are either {np.unique(brain_regions.level)}')" - ], + "id": "6f8446a1", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "print(f'brain_regions.level contains {brain_regions.level.size} values, which are either {np.unique(brain_regions.level)}')" + ] }, { "cell_type": "code", "execution_count": null, + "id": "6f4153c6", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# Example: find the index and acronyms of brain regions at level 0 (i.e. highest parents):\n", "index = np.where(brain_regions.level == 0)[0]\n", "print(index)\n", "brain_regions.acronym[index] # Note that root appears twice because of the lateralisation" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", @@ -835,90 +854,100 @@ }, { "cell_type": "markdown", - "source": [ - "Below we show the value of Bregma in the Allen CCF space (in micrometer um):" - ], + "id": "d9cdb8af", "metadata": { "collapsed": false - } + }, + "source": [ + "Below we show the value of Bregma in the Allen CCF space (in micrometer um):" + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "from iblatlas.atlas import ALLEN_CCF_LANDMARKS_MLAPDV_UM\n", - "print(ALLEN_CCF_LANDMARKS_MLAPDV_UM)" - ], + "id": "f0564eb4", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "from iblatlas.atlas import ALLEN_CCF_LANDMARKS_MLAPDV_UM\n", + "print(ALLEN_CCF_LANDMARKS_MLAPDV_UM)" + ] }, { "cell_type": "markdown", - "source": [ - "To translate this into an index into the volume `brain_atlas`, you need to divide by the atlas resolution (also in micrometer):" - ], + "id": "16639d05", "metadata": { "collapsed": false - } + }, + "source": [ + "To translate this into an index into the volume `brain_atlas`, you need to divide by the atlas resolution (also in micrometer):" + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "# Find bregma position in indices\n", - "bregma_index = ALLEN_CCF_LANDMARKS_MLAPDV_UM['bregma'] / brain_atlas.res_um" - ], + "id": "a198dbf6", "metadata": { - "collapsed": false, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "# Find bregma position in indices\n", + "bregma_index = ALLEN_CCF_LANDMARKS_MLAPDV_UM['bregma'] / brain_atlas.res_um" + ] }, { "cell_type": "markdown", - "source": [ - "This index can be passed into `brain_atlas.bc.i2xyz` that converts volume indices into IBL xyz coordinates (i.e. relative to Bregma):" - ], + "id": "abdf3b95", "metadata": { "collapsed": false - } + }, + "source": [ + "This index can be passed into `brain_atlas.bc.i2xyz` that converts volume indices into IBL xyz coordinates (i.e. relative to Bregma):" + ] }, { "cell_type": "code", "execution_count": null, + "id": "ff968b6b", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# Find bregma position in xyz in m (expect this to be 0 0 0)\n", "bregma_xyz = brain_atlas.bc.i2xyz(bregma_index)\n", "print(bregma_xyz)" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", + "id": "ca958935", + "metadata": { + "collapsed": false + }, "source": [ "Functions exist in both direction, i.e. from a volume index to IBL xyz, and from xyz to an index.\n", "Note that the functions return/input values are in *meters*, not micrometers." - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": null, + "id": "8ca452f3", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# Convert from arbitrary index to xyz position (m) position relative to Bregma\n", @@ -929,26 +958,27 @@ "# Convert from xyz position (m) to index in atlas\n", "xyz = np.array([-325, 4000, 250]) / 1e6\n", "index = brain_atlas.bc.xyz2i(xyz)" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", - "source": [ - "To know the sign and voxel resolution for each xyz axis, use:" - ], + "id": "2b641e22", "metadata": { "collapsed": false - } + }, + "source": [ + "To know the sign and voxel resolution for each xyz axis, use:" + ] }, { "cell_type": "code", "execution_count": null, + "id": "6e9e9b22", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# Find the resolution (in meter) of each axis\n", @@ -958,38 +988,33 @@ "sign_xyz = np.sign(res_xyz)\n", "\n", "print(f\"Resolution xyz: {res_xyz} in meter \\nSign xyz:\\t\\t{sign_xyz}\")" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", - "source": [ - "To jump directly from an Allen xyz value to an IBL xyz value, use `brain_atlas.ccf2xyz`:" - ], + "id": "8758089a", "metadata": { "collapsed": false - } + }, + "source": [ + "To jump directly from an Allen xyz value to an IBL xyz value, use `brain_atlas.ccf2xyz`:" + ] }, { "cell_type": "code", "execution_count": null, + "id": "f8c5d039", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# Example: Where is the Allen 0 relative to IBL Bregma?\n", "# This will give the Bregma value shown above (in meters), but with opposite axis sign value\n", "brain_atlas.ccf2xyz(np.array([0, 0, 0]))" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] } ], "metadata": { @@ -1008,9 +1033,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.16" + "version": "3.11.6" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +}