├── .coveragerc ├── .gitattributes ├── .github └── images │ └── imaging_transcriptomics.png ├── .gitignore ├── LICENSE ├── MANIFEST.in ├── README.md ├── docs ├── .vscode │ └── settings.json ├── Makefile ├── chapters │ ├── 01_getting_started.rst │ ├── 02_theory.rst │ ├── 03_installation.rst │ ├── 04_usage.rst │ ├── 05_what_to_do.rst │ ├── 06_contributing.rst │ ├── 07_contact_us.rst │ ├── 08_faq.rst │ └── images │ │ ├── dk_atlas.jpg │ │ └── imaging_transcriptomics.png ├── conf.py ├── index.rst ├── make.bat └── requirements.txt ├── environment.yml ├── imaging_transcriptomics ├── __init__.py ├── corr.py ├── data │ ├── atlases │ │ ├── DK │ │ │ ├── atlas-DK_1mm.nii.gz │ │ │ ├── atlas-DK_2mm.nii.gz │ │ │ ├── atlas-DK_fsa5_lh_aparc.annot │ │ │ ├── atlas-DK_fsa5_rh_aparc.annot │ │ │ ├── atlas-DK_gene_expression_data.csv │ │ │ ├── atlas-DK_gene_expression_labels.txt │ │ │ └── atlas-DK_labels.csv │ │ └── Schaefer_100 │ │ │ ├── atlas-Schaefer_100_1mm.nii.gz │ │ │ ├── atlas-Schaefer_100_2mm.nii.gz │ │ │ ├── atlas-Schaefer_100_gene_expression_data.csv │ │ │ ├── atlas-Schaefer_100_labels.csv │ │ │ ├── atlas-Schaefer_100_lh_aparc.annot │ │ │ └── atlas-Schaefer_100_rh_aparc.annot │ ├── geneset_LAKE.gmt │ └── geneset_Pooled.gmt ├── errors.py ├── genes.py ├── inputs.py ├── log_config.yaml ├── pls.py ├── reporting.py ├── resources │ ├── Header_final.pdf │ ├── header.png │ ├── header.svg │ └── order_enigma.csv ├── script │ ├── __init__.py │ ├── imagingtranscriptomics.py │ ├── imt_gsea.py │ └── log_config.yaml ├── tests │ ├── __init__.py │ ├── auto_test.py │ ├── conftest.py │ ├── data │ │ ├── MNI152_T1_1mm.nii.gz │ │ ├── anatomical.nii │ │ ├── example_nifti2.nii.gz │ │ ├── test_input.txt │ │ └── wrong_format.txt │ ├── errors_test.py │ ├── inputs_test.py │ └── transcriptomics_test.py └── transcriptomics.py ├── pytest.ini ├── requirements.txt └── setup.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | omit = 4 | */src/* 5 | imaging_transcriptomics/reporting.py 6 | imaging_transcriptomics/pls.py 7 | imaging_transcriptomics/corr.py 8 | imaging_transcriptomics/genes.py 9 | imaging_transcriptomics/script/* 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pkl filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /.github/images/imaging_transcriptomics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/.github/images/imaging_transcriptomics.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Python template 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | share/python-wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | dist/* 31 | build/* 32 | .pytest_cache/* 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .nox/ 48 | .coverage 49 | .coverage.* 50 | .cache 51 | nosetests.xml 52 | coverage.xml 53 | *.cover 54 | *.py,cover 55 | .hypothesis/ 56 | .pytest_cache/ 57 | cover/ 58 | 59 | # Translations 60 | *.mo 61 | *.pot 62 | 63 | # Django stuff: 64 | *.log 65 | *.log.* 66 | local_settings.py 67 | db.sqlite3 68 | db.sqlite3-journal 69 | 70 | # Flask stuff: 71 | instance/ 72 | .webassets-cache 73 | 74 | # Scrapy stuff: 75 | .scrapy 76 | 77 | # Sphinx documentation 78 | docs/_build/ 79 | 80 | # PyBuilder 81 | .pybuilder/ 82 | target/ 83 | 84 | # Jupyter Notebook 85 | .ipynb_checkpoints 86 | 87 | # IPython 88 | profile_default/ 89 | ipython_config.py 90 | 91 | # pyenv 92 | # For a library or package, you might want to ignore these files since the code is 93 | # intended to run in multiple environments; otherwise, check them in: 94 | # .python-version 95 | 96 | # pipenv 97 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 98 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 99 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 100 | # install all needed dependencies. 101 | #Pipfile.lock 102 | 103 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 104 | __pypackages__/ 105 | 106 | # Celery stuff 107 | celerybeat-schedule 108 | celerybeat.pid 109 | 110 | # SageMath parsed files 111 | *.sage.py 112 | 113 | # Environments 114 | .env 115 | .venv 116 | env/ 117 | venv/ 118 | ENV/ 119 | env.bak/ 120 | venv.bak/ 121 | 122 | # Spyder project settings 123 | .spyderproject 124 | .spyproject 125 | 126 | # Rope project settings 127 | .ropeproject 128 | 129 | # mkdocs documentation 130 | /site 131 | 132 | # mypy 133 | .mypy_cache/ 134 | .dmypy.json 135 | dmypy.json 136 | 137 | # Pyre type checker 138 | .pyre/ 139 | 140 | # pytype static type analyzer 141 | .pytype/ 142 | 143 | # Cython debug symbols 144 | cython_debug/ 145 | 146 | ### macOS template 147 | # General 148 | .DS_Store 149 | .AppleDouble 150 | .LSOverride 151 | 152 | # Icon must end with two \r 153 | Icon 154 | 155 | # Thumbnails 156 | ._* 157 | 158 | # Files that might appear in the root of a volume 159 | .DocumentRevisions-V100 160 | .fseventsd 161 | .Spotlight-V100 162 | .TemporaryItems 163 | .Trashes 164 | .VolumeIcon.icns 165 | .com.apple.timemachine.donotpresent 166 | 167 | # Directories potentially created on remote AFP share 168 | .AppleDB 169 | .AppleDesktop 170 | Network Trash Folder 171 | Temporary Items 172 | .apdisk 173 | 174 | # Strange directories or locally installed packages to ignore 175 | .idea/ 176 | src/ 177 | pyls/ 178 | ENIGMA/ 179 | # Ignore all files in the tests directory resulting from testing 180 | /tests/Imt_**/ 181 | /Imt__corr/ 182 | src/ 183 | pyls/ 184 | ENIGMA/ 185 | imaging_transcriptomics/tests/data/*.npy 186 | imaging_transcriptomics/tests/Imt_**/ 187 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include imaging_transcriptomics/data/* 2 | include imaging_transcriptomics/data/atlases/**/* 3 | include imaging_transcriptomics/resources/* 4 | include requirements.txt 5 | include ./**/*.yaml 6 | include imaging_transcriptomics/script/* 7 | include imaging_transcriptomics/* 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Imaging Transcriptomics 2 | 3 | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6364963.svg)](https://doi.org/10.5281/zenodo.6364963) 4 | [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) 5 | [![Maintainer](https://img.shields.io/badge/maintainer-alegiac95-blue)](https://github.com/alegiac95) 6 | [![Generic badge](https://img.shields.io/badge/python->=3.6-blue.svg)](https://www.python.org/doc/versions/) 7 | [![Documentation Status](https://readthedocs.org/projects/imaging-transcriptomics/badge/?version=latest)](https://imaging-transcriptomics.readthedocs.io/en/latest/?badge=latest) 8 | 9 | 10 | ![Imaging-transcriptomics_overwiew](https://raw.githubusercontent.com/alegiac95/imt/main/.github/images/imaging_transcriptomics.png 11 | "Overview of the imaging 12 | transcriptomics methodology") 13 | 14 | Imaging transcriptomics is a methodology that allows to identify patterns of correlation between gene expression and some 15 | property of brain structure or function as measured by neuroimaging (e.g., MRI, fMRI, PET). 16 | 17 | --- 18 | 19 | The `imaging-transcriptomics` package allows performing imaging transcriptomics analysis on a neuroimaging scan 20 | (e.g., PET, MRI, fMRI...). 21 | 22 | The software is implemented in Python3 (v.3.7), its source code is available on GitHub, it can be installed via Pypi and 23 | is released under the GPL v3 license. 24 | 25 | 26 | 27 | > **NOTE** Versions from v1.0.0 are or will be maintained. The original script linked by the BioRxiv preprint (v0.0) is 28 | > [still available on GitHub](https://github.com/alegiac95/Imaging_Transcriptomics_preprint) but no changes will be made to that code. If you have downloaded or used that script please 29 | > update to the newer version by installing this new version. 30 | 31 | ## Installation 32 | 33 | > **NOTE** We recommend to install the package in a dedicated environment of your choice 34 | > (e.g., [venv](https://docs.python.org/3/library/venv.html) or [anaconda](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html)). Once you have created your environment and you 35 | > have activated it, you can follow the below guide to install the package and dependencies. This process will avoid 36 | > clashes between conflicting packages that could happen during/after the installation. 37 | 38 | 39 | > **TIP**: To create easily an environment on your machine download the `environment.yml` file from the [Github repo](https://github.com/alegiac95/Imaging-transcriptomics/) and install the environemnt with the command: `conda env create -f environment.yml`, then you can proceed with the following steps. 40 | 41 | To install the `imaging-transcriptomics` Python package, first you will need to install an additional package that can't be installed directly from PyPi, but require to be downloaded from GitHub. 42 | This package to install is [pypyls](https://github.com/netneurolab/pypyls). To install this package you can follow the installation on the documentation for the package or simply run the command 43 | ```shell 44 | pip install -e git+https://github.com/netneurolab/pypyls.git/#egg=pyls 45 | ``` 46 | 47 | After this, to download the package, and its dependencies directly from GitHub by using `pip`. 48 | 49 | Once this package is installed you can install the `imaging-transcriptomics` package by running 50 | ```shell 51 | pip install imaging-transcriptomics 52 | ``` 53 | 54 | 55 | > **WARNING** At this time the package might some problems running on Mac 56 | > computers that have the M1 chip instead of the Intel ones. The problem is 57 | > not due to the package but on the chip architecture in running Python. 58 | > We're currently working to test some solution for this. 59 | 60 | > **WARNING** There is an issue in running the toolbox in Windows OS experienced by some users. 61 | > One of the packages used tries to write a file for some analyses which the OS doesn't allow, 62 | > resulting in a fatal error. 63 | ## Usage 64 | 65 | 66 | Once installed the software can be used in two ways: 67 | - as standalone script 68 | - as part of some python script 69 | 70 | > **WARNING** Before running the script make sure the Pyhton environment where you have installed the package is activated. 71 | 72 | 73 | ### Standalone script 74 | --- 75 | To run the standalone script from the terminal use the command: 76 | ```shell 77 | imagingtranscriptomics options {corr, pls} 78 | ``` 79 | 80 | The `options` available are: 81 | - `-i (--input)`: Path to the imaging file to analise. The path should be given to the program as an absolute path (e.g., `/Users/myusername/Documents/my_scan.nii`, since a relative path could raise permission errors and crashes. The script only accepts imaging files in the NIfTI format (`.nii`, `.nii.gz`). 82 | - `-o (--output)` *(optional)*: Path where to save the results. If none is provided the results will be saved in the same directory as the input scan. 83 | - `-r` *(optional)*: Regions of the brain to use for the estimation. Can be either "cort+sub" (or equivalently "all") to use all regions or "cort" to use only cortical regions. 84 | - `--no-gsea` *(optional)*: If this option is provided the GSEA analysis will not be performed. 85 | - `--geneset` *(optional)*: Name of the geneset to use to run GSEA. The 86 | full list is available in the documentation or by running the `imt_gsea 87 | avail` command. 88 | Additionally to the above options two specific commands (required) are available: 89 | - `corr`: To run the correlation analysis. 90 | - `pls`: To run the PLS analysis. If you choose to run the pls analysis 91 | there are two additional options available: 92 | - `--ncomp`: number of components to use in the PLS analysis. 93 | - `--var`: variance to estimate from the data. 94 | 95 | ### Part of Python script 96 | 97 | --- 98 | When used as part of a Python script the library can be imported as: 99 | ```python 100 | import imaging_transcriptomics as imt 101 | ``` 102 | 103 | The core class of the package is the `ImagingTranscriptomics` class which gives access to the methods used in the standalone script. 104 | To use the analysis in your scripts you can initialise the class and then simply call the `ImagingTranscriptomics().run()` method. 105 | 106 | ```python 107 | import numpy as np 108 | import imaging_transcriptomics as imt 109 | my_data = np.ones(41) # MUST be of size 41 110 | # (corresponds to the regions in left hemisphere of the DK atlas) 111 | 112 | analysis = imt.ImagingTranscriptomics(my_data, method="pls", n_components=1, 113 | regions="cort+sub") 114 | analysis.run(gsea=False) 115 | # If instead of running PLS you want to analysze the data with correlation you can run the analysis with: 116 | analysis = imt.ImagingTranscriptomics(my_data, method="corr", 117 | regions="cort+sub") 118 | ``` 119 | 120 | Once completed the results will be part of the `analysis` object and can be accessed with `analysis.gene_results`. 121 | 122 | The import of the `imaging_transcriptomics` package will import other helpful functions for input and reporting. For a complete explanation of this please refer to the [official documentation](https://imaging-transcriptomics.readthedocs.io/en/latest/) of the package. 123 | 124 | 125 | ### Documentation 126 | 127 | The documentation of the script is available at [imaging-transcriptomics.rtfd.io/](https://imaging-transcriptomics.rtfd.io/en/latest/). 128 | 129 | ### Troubleshooting 130 | 131 | For any problems with the software you can [open an issue in GitHub](https://github.com/alegiac95/Imaging-transcriptomics/issues) or [contact the maintainer](mailto:alessio.giacomel@kcl.ac.uk)) of the package. 132 | 133 | ### Citing 134 | 135 | If you publish work using `imaging-transcriptomics` as part of your analysis please cite: 136 | 137 | >*Imaging transcriptomics: Convergent cellular, transcriptomic, and 138 | > molecular neuroimaging signatures in the healthy adult human brain.* 139 | > Daniel Martins, Alessio Giacomel, Steven CR Williams, Federico Turkheimer, 140 | > Ottavia Dipasquale, Mattia Veronese, PET templates working group. Cell 141 | > Reports; doi: [https://doi.org/10.1016/j.celrep.2021.110173](https://doi.org/10.1016/j.celrep.2021.110173) 142 | 143 | 144 | >*Imaging-transcriptomics: Second release update (v1.0.2)*.Alessio Giacomel, & Daniel Martins. (2021). Zenodo. https://doi.org/10.5281/zenodo.5726839 145 | 146 | >*Integrating neuroimaging and gene expression data using the imaging transcriptomics toolbox*. 147 | > Alessio Giacomel, Daniel Martins, Matteo Frigo, Federico Turkheimer, Steven CR Williams, Ottavia Dipasquale, and Mattia Veronese. STAR Protocols; doi: [https://doi.org/10.1016/j.xpro.2022.101315](https://doi.org/10.1016/j.xpro.2022.101315) 148 | -------------------------------------------------------------------------------- /docs/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "restructuredtext.confPath": "${workspaceFolder}" 3 | } -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/chapters/01_getting_started.rst: -------------------------------------------------------------------------------- 1 | .. _Gettingstarted: 2 | 3 | =============== 4 | Getting started 5 | =============== 6 | 7 | Once the tool is installed you can run the analysis by calling the script from the terminal as: 8 | 9 | .. code:: bash 10 | 11 | imagingtranscriptomics -i path-to-your-file.nii --no-gsea pls --ncomp 1 12 | 13 | This is the most simple way to run the script and will permorm the analysis with 1 PLS component on your file and save 14 | the results in a folder named *Imt_file_name* in the same path as the original scan file. 15 | It might be that running this will not hold much of the total variance of the scan, however this can be used as a 16 | "first quick estimation". In the resulting path there will be a plot with the variance explained by the first 15 17 | components independently and cumulatively, that can be used to tune consequent analyses, if needed. 18 | 19 | For more information on the use have a look at the :ref:`usage ` page. You can also have a deeper look at the 20 | :ref:`methods ` and on :ref:`what to do with the results from the script `. 21 | 22 | For more advanced use, or to integrate it in your python workflow, you can use the :ref:`python module `. 23 | -------------------------------------------------------------------------------- /docs/chapters/02_theory.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _imgtrans: 3 | 4 | ================================ 5 | What is imaging transcriptomics? 6 | ================================ 7 | 8 | Imaging transcriptomics is a methodology that allows to identify patterns of correlation between gene expression and some property of brain structure or function as measured by neuroimaging (e.g., MRI, fMRI, PET). 9 | 10 | An overview of the methodology can be seen in the figure below. 11 | 12 | .. image:: images/imaging_transcriptomics.png 13 | :alt: imaging transcriptomics workflow overview 14 | :align: center 15 | 16 | 17 | 18 | In brief, average values of the scan are extracted from 41 brain regions as defined by the Desikan-Killiany (DK) atlas. Regional values are then used to perform partial least squares (PLS) regression with gene expression data from the Allen Human Brain Atlas (AHBA) mapped to the DK atlas, in the left hemisphere only. 19 | 20 | As a result of the PLS regression we obtain the ranked genes list according to the spatial alignment with the neuroimaging marker of interest. 21 | 22 | .. seealso:: For a more comprehensive dive into the methodology have a look at our paper: `Imaging transcriptomics: Convergent cellular, transcriptomic, and molecular neuroimaging signatures in the healthy adult human brain. `_ *Daniel Martins, Alessio Giacomel, Steven CR Williams, Federico Turkheimer, Ottavia Dipasquale, Mattia Veronese, PET templates working group*. Cell Reports; doi: `https://doi.org/10.1016/j.celrep.2021.110173 `_ 23 | 24 | 25 | Allen Human Brain Atlas 26 | ----------------------- 27 | The Allen Human Brain Atlas (AHBA) freely available multimodal atlas of gene expression and anatomy comprising a comprehensive ‘all genes–all structures’ array-based dataset of gene expression and complementary *in situ hybridization* (ISH) gene expression studies targeting selected genes in specific brain regions. Available via the Allen Brain Atlas data portal (`www.brain-map.org `_), the Atlas integrates structure, function, and gene expression data to accelerate basic and clinical research of the human brain in normal and disease states. 28 | 29 | The ``imaging-transcriptomics`` script uses a modified version of the AHBA gene data parcellated onto 83 regions from the DK atlas obtained using the `abagen toolbox `_. 30 | In brief, probes that cannot be reliably matched to genes were discarded and filtered based on their intensity compared to the background noise level. The remainig probes were pooled retaining only the one with the highest differential stability to represent each gene, resulting in 15,633 probes each representing an unique gene. The genes were then assigned to brain regions based on their corrected MNI coordinates. 31 | 32 | More details on the processing of the transcriptomic data are available in the methods section of the paper . 33 | 34 | 35 | Desikan-Killiany Atlas 36 | ---------------------- 37 | The DK atlas is a parcellation atlas of the human brain, which includes both cortical and subcortical regions. 38 | 39 | This atlas is derived from a dataset of 40 MRI scans where 34 cortical ROIs were manually delineated for each of the individual hemispheres. More details on the ROIs of the atlas or methods to derive it refer to the original paper. 40 | 41 | .. figure:: images/dk_atlas.jpg 42 | :align: center 43 | :scale: 75 % 44 | :alt: Desikan-Killiany Atlas regions. 45 | 46 | Representation of the pial and inflated view of the cortical regions from the Desikan-Killiany atlas. Image from the `orignal paper `_ 47 | 48 | 49 | 50 | 51 | Partial least squares 52 | --------------------- 53 | The goal of any regression is to model the relationship between a target variable and multiple explanatory variables. The standard approach is to use Ordinary Least Squares (OLS), but in order to use OLS the assumptions of linear regression have to be met. 54 | The assumptions of linear regression are: 55 | 56 | * Independence of observations 57 | * No hidden or missing variables 58 | * Linear relationship 59 | * Normality of the residuals 60 | * No or little multicollinearity 61 | * Homoscedasticity 62 | * All independent variables are uncorrelated with the error term 63 | * Observations of the error term are uncorrelated with each other 64 | 65 | In some cases it can be that we have a lot of independent variables, many of which are correlated with other independent variables, violating thus the assumption of no multicollinearity. 66 | In this case instead of using OLS a more appropriate method is to use Partial Least Squares (PLS) Regression. This method allows to reduce the dimensionality of correlated variables and model the underlying information shared. 67 | 68 | 69 | 70 | 71 | 72 | .. rubric:: References 73 | 74 | 75 | **Imaging transcriptomics: Convergent cellular, transcriptomic, and molecular neuroimaging signatures in the healthy adult human brain.** *Daniel Martins, Alessio Giacomel, Steven CR Williams, Federico Turkheimer, Ottavia Dipasquale, Mattia Veronese, PET templates working group*. bioRxiv 2021.06.18.448872; doi: `https://doi.org/10.1101/2021.06.18.448872 `_ 76 | 77 | 78 | **The Allen Human Brain Atlas: Comprehensive gene expression mapping of the human brain.** *Elaine H. Shein, Caroline C. Overly, Allan R. Jones*, Trends in Neuroscience vol. 35, issue 12, December 2012; doi: `https://doi.org/10.1016/j.tins.2012.09.005 `_ 79 | 80 | **An automated labeling system for subdividing the human cerebral cortex on MRI scans into gyral based regions of interest.** *Rahul S.Desikan, Florent Ségonne, Bruce Fischl, Brian T. Quinn, Bradford C. Dickerson, Deborah Blacker, Randy L. Buckner, Anders M. Dale, R. Paul Maguire, Bradley T. Hyman, Marilyn S. Albert, Ronald J. Killiany*, NeuroImage, Volume 31, Issue 3, July 2006; doi: `https://doi.org/10.1016/j.neuroimage.2006.01.021 `_ 81 | 82 | **An Introduction to Partial Least Squares Regression.** *R. Tobias*, `https://stats.idre.ucla.edu/wp-content/uploads/2016/02/pls.pdf `_ 83 | 84 | **Comparison of prediction methods for multicollinear data**, *T. Naes and H. Martens*, Communications in Statistics, Simulation and Computation, 14(3), 545-576. 85 | 86 | **SIMPLS: An alternative approach to partial least squares regression.** *Sijmen de Jong*, Chemometrics and Intelligent Laboratory Systems, March 1993, doi: `https://doi.org/10.1016/0169-7439(93)85002-X `_ 87 | 88 | **Gene transcription profiles associated with inter-modular hubs and connection distance in human functional magnetic resonance imaging networks.** *Petra E. Vértes, Timothy Rittman, Kirstie J. Whitaker, Rafael Romero-Garcia, František Váša, Manfred G. Kitzbichler, Konrad Wagstyl, Peter Fonagy, Raymond J. Dolan, Peter B. Jones, Ian M. Goodyer, the NSPN Consortium and Edward T. Bullmore*, Philosophical Transactions of the Royal Society B, October 2016, doi: `https://doi.org/10.1098/rstb.2015.0362 `_ 89 | -------------------------------------------------------------------------------- /docs/chapters/03_installation.rst: -------------------------------------------------------------------------------- 1 | .. _Installation: 2 | 3 | ============ 4 | Installation 5 | ============ 6 | 7 | To install the ``imaging-transcriptomics`` Python package you must first of all have Python ``v3.6+`` installed on your system along with the ``pip`` package manager. 8 | 9 | .. warning:: 10 | 11 | At current time Python versions 3.9+ are not fully supported as there 12 | are some issue during the installation of the Numpy version used by the 13 | toolbox in these versions of Python. 14 | 15 | 16 | .. tip:: 17 | 18 | We suggest installing the package in a dedicated python environment using `venv `_ or `conda `_ depending on your personal choice. The installation on a dedicated environment avoids the possible clashes of dependencies after or during installation. 19 | 20 | 21 | .. note:: 22 | 23 | All following steps assume that, if you have created a dedicated environment, this is currently active. If you are unsure you can check with ``which python`` from your terminal or activate your environment via the ``source activate`` (for conda managed environments) or ``source venv/bin/activate`` (for venv managed environments). 24 | 25 | Before installing the ``imaging-transcriptomics`` package we need to install a package that is not available through PyPi but from GitHub only. 26 | This package is `pypls `_ and is used in the script to perform all PLS regressions. 27 | In order to install it you can run the following command from your terminal 28 | 29 | .. code:: shell 30 | 31 | pip install -e git+https://github.com/netneurolab/pypyls.git/#egg=pyls 32 | 33 | This will install install the GitHub repository directly using pip and it will make it available with the name ``pyls``. 34 | 35 | .. warning:: 36 | 37 | Do not install pyls directly from pip with the command ``pip install pyls`` as this is a completely different package! 38 | 39 | A second package to install for the full functionalities of the imaging-transcriptomics toolbox is the `ENIGMA toolbox `_ . 40 | To install this we'll follow the instructions of the developers. In brief, install this by running the commands: 41 | 42 | .. code:: shell 43 | 44 | git clone https://github.com/MICA-MNI/ENIGMA.git 45 | cd ENIGMA 46 | python setup.py install 47 | 48 | Once these packages is installed you can install the ``imaging-transcriptomics`` package by running: 49 | 50 | .. code:: 51 | 52 | pip install imaging-transcriptomics 53 | 54 | 55 | Once you get the message that the installation has completed you are set to go! 56 | 57 | .. note:: The version ``v1.0.0`` and ``v1.0.1``, can cause some issues on the installation due to compatibility issues of some packages. In version ``v1.0.2+`` this issue has been resolved during installation. If you have one of the older versions installed you might want to update the version using the command ``pip install --upgrade imaging-transcriptomics``. 58 | 59 | .. note:: From version ``v1.1.0`` has the possibility of running directly from the toolbox also the gene set enrichment analysis (GSEA). Version ``v1.1.8`` has a major speedup in the correlation analyses, reducing the overall time needed to run the analysis. 60 | -------------------------------------------------------------------------------- /docs/chapters/04_usage.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _Usage: 3 | 4 | ============ 5 | Script usage 6 | ============ 7 | 8 | Once you have installed the package you can run the analysis script as: 9 | 10 | .. code:: bash 11 | 12 | imagingtranscriptomics --input /path-to-your-in-file [options] {corr|pls [options]} 13 | 14 | The script has some options that allow the user to tune the analysis to their specific application. The options are as follows: 15 | 16 | - ``--input`` (``-i``, **mandatory**): path to the input data. This can be either a neuroimaging scan (*i.e.*, .nii[.gz]) or a text file (*i.e.*, .txt). 17 | 18 | .. warning:: 19 | 20 | If the input scan is a neuroimaging scan (*i.e.*, .nii, .nii.gz) this is expected to be in the same resolution as the Desikan-Killiany (DK) atlas used which is 1mm isotropic (matrix size 182x218x182). On the other hand if the input is a text file, this must be a text file with one column and no headers, with the rows containing the values of interest in the same order as the DK atlas used. 21 | 22 | - ``--output`` (``-o``, **optional**): path to the output directory. If none is provided the results will be saved in the same folder as the input scan. 23 | - ``--regions`` (``-r``, **optional**): regions to use for the analysis, can be *cort+sub* (or equivalently *all*) which specifies that all the regions are used, or, alternatively, *cort* for the cortical regions only. The latter is useful with some certain types of data, where the subcortical regions might not be available (*e.g.*, EEG). 24 | - ``--no-gsea`` (**optional**): specifies whether or not Gene Set Enrihment Analysis should be performed. 25 | - ``--geneset`` (**optional**): specifies the name of the gene set or the path to the file to use for Gene Set Enrichment Analysis. 26 | 27 | .. warning:: 28 | 29 | The ``--geneset`` argument will be ignored if you also specify the ``--no-gsea`` flag. If the GSEA analysis is performed, the name of the gene set, or a path to a custom made gene set, should be given. To lookup the name of the available gene sets or on how to create a custom one refer to the GSEA section. 30 | 31 | After the selection of the above options, you can now specify the type of 32 | analysis to perform. The available analyses are: 33 | 34 | - ``corr``: to perform mass univariate correlation analysis using Spearman's rank correlation. 35 | - ``pls``: to perform partial least squares (PLS) analysis. If you select this option you must additionally specify either the number of components to use in the analysis, with the ``--ncomp`` option, or the amount of variance to retain from the data, with the ``--var`` option. 36 | 37 | 38 | .. tip:: 39 | 40 | All paths given as input should be given as absolute paths instead of relative paths to avoid any errors in reading the file. 41 | 42 | 43 | The ``imagingtranscriptomics`` script allows the user to specify the options to perform also the GSEA analysis, directly after the correlation analysis. 44 | However, it is not uncommon that on the same imaging data a researcher might have different research questions, which results in different gene sets to use for the investigation. For this reason, in the toolbox there is an additional script that, once a first correlation analysis is performed, allows to run directly the GSEA analysis. 45 | This script can be invoked as: 46 | 47 | .. code:: bash 48 | 49 | imt_gsea --input /path-to-your-in-file [options] 50 | 51 | The running of this script is pretty straightforward, and the options 52 | available are: 53 | 54 | - ``--input`` (``-i``, **mandatory**): path to the input data. To run this script you must have already have performed a correlation analysis, either with mass univariate correlation or with PLS, as the input file is one of the output files of the previous step. The required file is located in the output folder and has ``.pkl`` extension. 55 | 56 | .. warning:: 57 | 58 | The ``--input`` argument **MUST** be a ``.pkl`` file generated by running the ``imagingtranscriptomics`` script. 59 | 60 | In addition to the ``--input`` argument, the script has the following options: 61 | 62 | - ``--output`` (``-o``, **optional**): path to the output directory. If none is 63 | provided the results will be saved in the same folder as the input file. 64 | - ``--geneset`` (**optional**): specifies the name of the gene set or the path to the file to use for Gene Set Enrichment Analysis. If you want to use one of the provided gene sets you can browse the available ones by running the script with only the ``--geneset avail`` option. 65 | 66 | .. tip:: 67 | 68 | To see the gene sets available in the package, run the script with the ``--geneset avail`` option, i.e. ``imt_gsea --geneset avail``. 69 | 70 | 71 | .. _library: 72 | 73 | ======================= 74 | Usage as python library 75 | ======================= 76 | 77 | Once installed the library can be used like any other Python package in custom written analysis pipelines. 78 | To the library can be imported by running: 79 | 80 | .. code:: python 81 | 82 | import imaging_transcriptomics as imt 83 | 84 | Once imported the package will contain the core ``ImagingTranscriptomics`` 85 | class, along with other useful functions. To see all the available functions 86 | imported in the library run: 87 | 88 | .. code:: python 89 | 90 | dir(imt) 91 | 92 | which will display all the functions and modules imported in the library. 93 | 94 | ImagingTranscriptomics Class 95 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 96 | 97 | The ``ImagingTranscriptomics`` class is the core class of the entire package and allows you to run the entire analysis on your data. 98 | To use the class you simply need to initialise it and then run the ``.run()`` 99 | method. 100 | 101 | To initialise the class, you will need to already have decided the type of correlation analysis to perform, as this will be needed as initialisation keyword for the class. 102 | The initialisation of the class can be done as follows: 103 | 104 | .. code:: python 105 | 106 | # To initialise the class with PLS analysis 107 | analysis = imt.ImagingTranscriptomics(my_data, 108 | method="pls", 109 | n_components=1) 110 | 111 | # To initialise the class with mass univariate correlation analysis 112 | analysis = imt.ImagingTranscriptomics(my_data, 113 | method="corr") 114 | 115 | In the above code snippets the ``my_data`` argument is a ``numpy.ndarray`` 116 | vector with the imaging data of interest (e.g. the mean intensity of the 117 | ROI). The vector **MUST** be a vector with either 35 or 41 elements, 118 | corresponding to the number of ROIs in the left hemisphere of the brain (35 119 | for the cortical regions and the remaining for the subcortical regions). 120 | 121 | There are addiotional parameters that can be used for the initialisation of 122 | the class, which are: 123 | 124 | - ``method`` (``"pls"`` or ``"corr"``, **mandatory**): specifies the type of analysis to perform. 125 | - ``n_components`` (``int``, **optional**): specifies the number of components to use for the PLS analysis. 126 | - ``var`` (``float``, **optional**): specifies the variance explained threshold to use for the PLS analysis. 127 | - ``regions``: specifies if the analysis should be performed on the cortical regions only or on the whole brain. The possible values are: ``"cort+sub"`` (or ``"all"``) or ``"cort"``. 128 | 129 | 130 | Once the class is initialise you can run the analysis by running the ``.run()`` method. 131 | 132 | .. code:: python 133 | 134 | analysis.run() 135 | 136 | The method has some additional parameters that can be used to run the method. 137 | Some of the parameters are: 138 | 139 | - ``gsea``: ``bool`` variable to indicate whether the GSEA analysis should be run. 140 | - ``gene_set``: ``str`` variable to indicate the gene set to use for the GSEA analysis. 141 | - ``outdir``: ``str`` variable to indicate the output directory. 142 | - ``scan_name``: ``str`` variable to indicate the name of the scan to use to save the results. 143 | - ``save_res``: ``bool`` variable to indicate whether the results should be saved. Default is ``True``. 144 | - ``gene_limit``: number of genes to use for the GSEA analysis. Default is ``500``. 145 | 146 | Once the correlation analysis is completed, the results can be accessed in 147 | the ``analysis.gene_results`` attribute. If you want to perform the GSEA 148 | analysis after the correlation, or on a second gene set, you can run the 149 | ``analysis.gsea()`` method. The method has the following parameters: 150 | 151 | - ``gene_set``: ``str`` variable to indicate the gene set to use for the GSEA analysis. 152 | - ``outdir``: ``str`` variable to indicate the output directory. 153 | - ``gene_limit``: number of genes to use for the GSEA analysis. Default is ``500``. 154 | 155 | 156 | It is to note that since in most cases the analysis is performed having as 157 | inputs either a neuroimaging scan (i.e., a .nii or .nii.gz file) or a txt 158 | file with some measure of interest (e.g., measures extracted using 159 | Freesurfer), we also included two additional methods to initialise the class 160 | which are: 161 | 162 | .. code:: python 163 | 164 | analysis = imt.ImagignTranscriptomics.from_scan(my_scan, 165 | method="corr") 166 | 167 | to initialise the class from a scan, extracting the average from the regions, 168 | and: 169 | 170 | .. code:: python 171 | 172 | analysis = imt.ImagignTranscriptomics.from_file(my_txt_file, 173 | method="corr") 174 | 175 | These methods allow you to initialise the class from a scan or a txt file 176 | respectively. In both cases the input is a path to the file of interest, 177 | while the rest of the input parameters are the same as the initialisation of 178 | the normal class explained above. 179 | -------------------------------------------------------------------------------- /docs/chapters/05_what_to_do.rst: -------------------------------------------------------------------------------- 1 | .. _whatdo: 2 | 3 | ============================ 4 | Examples 5 | ============================ 6 | 7 | Coming soon... 8 | -------------------------------------------------------------------------------- /docs/chapters/06_contributing.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Contributing 3 | ============ 4 | 5 | If you want to contribute to the ``imaging_transcriptomics`` python package or script you can clone the GitHub repo and change/add whatever you feel appropriate. 6 | Once you want to merge your changes to the project you can request a pull request to the ``develop`` branch. 7 | Please note that we only accept pull requests to the ``develop`` branch. 8 | 9 | General guidelines for contributing 10 | ----------------------------------- 11 | 12 | If you want to contribute to the project there are some general guidelines we ask you to follow in order to maintain a certain level of consistency: 13 | 14 | 15 | * When you write some functionality you MUST document that functionality with docstrings. The docstrings should include a description of the functionality along with a description of the parameters of the function and returns using the ``:param:`` and ``:return:`` parameters. 16 | * All your code SHOULD be compliant with the `PEP8 `_ python styling guide. 17 | 18 | ==================================== 19 | Contributor Covenant Code of Conduct 20 | ==================================== 21 | 22 | Our Pledge 23 | ---------- 24 | 25 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 26 | 27 | Our Standards 28 | ------------- 29 | 30 | Examples of behavior that contributes to creating a positive environment include: 31 | 32 | * Using welcoming and inclusive language 33 | * Being respectful of differing viewpoints and experiences 34 | * Gracefully accepting constructive criticism 35 | * Focusing on what is best for the community 36 | * Showing empathy towards other community members 37 | 38 | Examples of unacceptable behavior by participants include: 39 | 40 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 41 | * Trolling, insulting/derogatory comments, and personal or political attacks 42 | * Public or private harassment 43 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 44 | * Other conduct which could reasonably be considered inappropriate in a professional setting 45 | 46 | Our Responsibilities 47 | -------------------- 48 | 49 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 50 | 51 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 52 | 53 | Scope 54 | ----- 55 | 56 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. 57 | Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. 58 | Representation of a project may be further defined and clarified by project maintainers. 59 | 60 | Enforcement 61 | ----------- 62 | 63 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hs@ox.cx. 64 | All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. 65 | The project team is obligated to maintain confidentiality with regard to the reporter of an incident. 66 | Further details of specific enforcement policies may be posted separately. 67 | 68 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 69 | 70 | Attribution 71 | ----------- 72 | 73 | This Code of Conduct is adapted from the `Contributor Covenant `_, version 1.4, available at . 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /docs/chapters/07_contact_us.rst: -------------------------------------------------------------------------------- 1 | .. _contactus: 2 | 3 | ============================ 4 | How to cite and get in touch 5 | ============================ 6 | 7 | 8 | Contact us 9 | ---------- 10 | We are happy to answer any questions you might have about the methods and/or problems/suggestions with the software. 11 | 12 | For any questions regarding the methodology you can contact `Dr Daniel Martins `_, or the 13 | senior authors of the paper `Dr Ottavia Dipasquale `_ and `Dr Mattia Veronese 14 | `_. 15 | 16 | For questions about the software you can contact `Alessio Giacomel `_ or any of the 17 | authors above. 18 | 19 | .. seealso:: 20 | 21 | For questions regarding the software you can also check out our :ref:`FAQ ` section or open a new issue on `GitHub `_. 22 | 23 | 24 | Cite our work 25 | ------------- 26 | If you use our software or methods in your research please cite our work: 27 | 28 | * **Imaging transcriptomics: Convergent cellular, transcriptomic, and molecular neuroimaging signatures in the healthy adult human brain.** *Daniel Martins, Alessio Giacomel, Steven CR Williams, Federico Turkheimer, Ottavia Dipasquale, Mattia Veronese, PET templates working group*. bioRxiv 2021.06.18.448872; doi: `https://doi.org/10.1101/2021.06.18.448872 `_ 29 | * **Imaging-transcriptomics: python package (v1.0.0).** Alessio Giacomel, Daniel Martins. Zenodo 2021. `https://doi.org/10.5281/zenodo.5507506 `_ 30 | 31 | 32 | 33 | For more information about ongoing research please visit our website at: 34 | `https://molecular-neuroimaging.com `_ 35 | -------------------------------------------------------------------------------- /docs/chapters/08_faq.rst: -------------------------------------------------------------------------------- 1 | .. _faq: 2 | 3 | === 4 | FAQ 5 | === 6 | 7 | 8 | 9 | #. **How can I install the imaging transcriptomics package?** 10 | The short answer is: you can install it via ``pip``. For more details on how to install refer to the :ref:`installation section. ` 11 | 12 | #. **Why does the analysis use only the left hemisphere?** 13 | The analysis relies on the left hemisphere only due to the genetic data used. The Allen Human Brain Atlas (AHBA) has a discrepancy in data acquisition between left and right hemisphere resulting in a lot of missing data in the right hemisphere. Given that the brain is not symmetrical, we decided to not mirror data from one hemisphere to the other and constrain the analysis to this hemisphere only. 14 | 15 | #. **Why did you use the pypls library instead of some more maintained PLS library, e.g., sklearn?** 16 | We used pypls instead of sklearn because the latter one, and most of the other available, are implemented using the NIPALS algorithm, while pypls uses the SIMPLS. 17 | One of the main advantages of the SIMPLS algorithm in respect to the NIPALS is that is is less time consuming. 18 | 19 | #. **Can I run the ImaginTranscriptomics analysis on just the cortical areas without the subcortical areas?** 20 | Yes, check out the main page on the use to get an idea on how to do this. 21 | -------------------------------------------------------------------------------- /docs/chapters/images/dk_atlas.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/docs/chapters/images/dk_atlas.jpg -------------------------------------------------------------------------------- /docs/chapters/images/imaging_transcriptomics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/docs/chapters/images/imaging_transcriptomics.png -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | sys.path.insert(0, os.path.abspath('../../imaging_transcriptomics/')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'imaging-transcriptomics' 21 | copyright = '2022, Alessio Giacomel, Daniel Martins' 22 | author = 'Alessio Giacomel, Daniel Martins' 23 | 24 | # The full version, including alpha/beta/rc tags 25 | release = '1.1.8' 26 | 27 | 28 | # -- General configuration --------------------------------------------------- 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = ['sphinx.ext.autodoc'] 34 | 35 | # Add any paths that contain templates here, relative to this directory. 36 | templates_path = ['_templates'] 37 | 38 | # List of patterns, relative to source directory, that match files and 39 | # directories to ignore when looking for source files. 40 | # This pattern also affects html_static_path and html_extra_path. 41 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 42 | 43 | 44 | # -- Options for HTML output ------------------------------------------------- 45 | 46 | # The theme to use for HTML and HTML Help pages. See the documentation for 47 | # a list of builtin themes. 48 | # 49 | html_theme = 'alabaster' 50 | 51 | # Add any paths that contain custom static files (such as style sheets) here, 52 | # relative to this directory. They are copied after the builtin static files, 53 | # so a file named "default.css" will overwrite the builtin "default.css". 54 | html_static_path = ['_static'] 55 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. imaging-transcriptomics documentation master file, created by 2 | sphinx-quickstart on Fri Jul 30 22:43:35 2021. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to imaging-transcriptomics's documentation! 7 | =================================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | :glob: 13 | 14 | chapters/* 15 | 16 | 17 | Indices and tables 18 | ================== 19 | 20 | * :ref:`genindex` 21 | * :ref:`modindex` 22 | * :ref:`search` 23 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx_celery 2 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: imaging-transcriptomics 2 | channels: 3 | - defaults 4 | dependencies: 5 | - ca-certificates=2021.7.5 6 | - certifi=2021.5.30 7 | - libcxx=10.0.0 8 | - libffi=3.3 9 | - ncurses=6.2 10 | - openssl=1.1.1k 11 | - pip=21.1.3 12 | - python=3.7.10 13 | - readline=8.1 14 | - sqlite=3.36.0 15 | - tk=8.6.10 16 | - tqdm=4.61.2 17 | - wheel=0.36.2 18 | - xz=5.2.5 19 | - zlib=1.2.11 20 | - pip: 21 | - aiohttp==4.0.0a1 22 | - alabaster==0.7.12 23 | - appdirs==1.4.4 24 | - async-timeout==3.0.1 25 | - attrs==21.2.0 26 | - babel==2.9.1 27 | - bctpy==0.5.2 28 | - beautifulsoup4==4.10.0 29 | - bioservices==1.8.2 30 | - black==21.9b0 31 | - bleach==4.1.0 32 | - build==0.6.0.post1 33 | - cached-property==1.5.2 34 | - cattrs==1.10.0 35 | - chardet==3.0.4 36 | - charset-normalizer==2.0.3 37 | - click==8.0.3 38 | - colorama==0.4.4 39 | - colorlog==6.6.0 40 | - cycler==0.10.0 41 | - docutils==0.17.1 42 | - easydev==0.12.0 43 | - et-xmlfile==1.1.0 44 | - execnet==1.9.0 45 | - fpdf2==2.4.2 46 | - gevent==21.12.0 47 | - greenlet==1.1.2 48 | - grequests==0.6.0 49 | - gseapy==1.1.3 50 | - h5py==3.3.0 51 | - idna==3.2 52 | - imagesize==1.2.0 53 | - importlib-metadata==4.6.3 54 | - iniconfig==1.1.1 55 | - jinja2==3.0.1 56 | - joblib==1.0.1 57 | - keyring==23.1.0 58 | - kiwisolver==1.3.1 59 | - llvmlite==0.38.0 60 | - lxml==4.7.1 61 | - markupsafe==2.0.1 62 | - matplotlib==3.4.2 63 | - multidict==4.7.6 64 | - mypy-extensions==0.4.3 65 | - netneurotools==0.2.3 66 | - nibabel==3.2.1 67 | - nilearn==0.8.1 68 | - numba==0.55.1 69 | - numpy==1.21.1 70 | - openpyxl==3.0.9 71 | - packaging==21.0 72 | - pandas==1.3.1 73 | - pathspec==0.9.0 74 | - patsy==0.5.1 75 | - pep517==0.11.0 76 | - pep8==1.7.1 77 | - pexpect==4.8.0 78 | - pillow==8.3.1 79 | - pkginfo==1.7.1 80 | - platformdirs==2.4.0 81 | - pluggy==0.13.1 82 | - ptyprocess==0.7.0 83 | - py==1.10.0 84 | - pygments==2.9.0 85 | - pyparsing==2.4.7 86 | - pytest==6.2.4 87 | - pytest-cache==1.0 88 | - python-dateutil==2.8.2 89 | - pytz==2021.1 90 | - pyyaml==5.4.1 91 | - readme-renderer==29.0 92 | - regex==2021.10.8 93 | - requests==2.26.0 94 | - requests-cache==0.9.0 95 | - requests-toolbelt==0.9.1 96 | - rfc3986==1.5.0 97 | - scikit-learn==0.24.2 98 | - scipy==1.7.0 99 | - setuptools==52.0.0 100 | - six==1.16.0 101 | - snowballstemmer==2.1.0 102 | - soupsieve==2.3.1 103 | - sphinx==4.1.2 104 | - sphinx-celery==2.0.0 105 | - sphinxcontrib-applehelp==1.0.2 106 | - sphinxcontrib-devhelp==1.0.2 107 | - sphinxcontrib-htmlhelp==2.0.0 108 | - sphinxcontrib-jsmath==1.0.1 109 | - sphinxcontrib-qthelp==1.0.3 110 | - sphinxcontrib-serializinghtml==1.1.5 111 | - statsmodels==0.12.2 112 | - style==1.1.0 113 | - suds-community==1.0.0 114 | - threadpoolctl==2.2.0 115 | - tomli==1.2.1 116 | - twine==3.4.2 117 | - typed-ast==1.4.3 118 | - typing-extensions==3.10.0.0 119 | - update==0.0.1 120 | - url-normalize==1.4.3 121 | - urllib3==1.26.6 122 | - vtk==9.1.0 123 | - webencodings==0.5.1 124 | - wrapt==1.13.3 125 | - wslink==1.3.1 126 | - xmltodict==0.12.0 127 | - yarl==1.7.2 128 | - zipp==3.5.0 129 | - zope-event==4.5.0 130 | - zope-interface==5.4.0 131 | prefix: /Users/alessiogiacomel/anaconda3/envs/imaging-transcriptomics 132 | -------------------------------------------------------------------------------- /imaging_transcriptomics/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | __version__ = "1.1.15" 3 | 4 | from . import inputs 5 | from . import reporting 6 | 7 | from .transcriptomics import ImagingTranscriptomics 8 | from .inputs import ( 9 | read_scan, 10 | extract_average, 11 | ) 12 | from .genes import GeneResults 13 | from .corr import CorrAnalysis 14 | from .pls import PLSAnalysis 15 | -------------------------------------------------------------------------------- /imaging_transcriptomics/corr.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from pathlib import Path 3 | from scipy.stats import spearmanr 4 | import pandas as pd 5 | from statsmodels.stats.multitest import multipletests 6 | from collections import OrderedDict 7 | import gseapy 8 | from gseapy.plot import gseaplot 9 | from .genes import GeneResults, CorrGenes 10 | from .inputs import get_geneset 11 | import yaml 12 | import logging 13 | import logging.config 14 | import numba 15 | 16 | np.random.seed(1234) 17 | 18 | cfg_file_path = Path(__file__).parent / "log_config.yaml" 19 | with open(cfg_file_path, "r") as config_file: 20 | log_cfg = yaml.safe_load(config_file.read()) 21 | 22 | logging.config.dictConfig(log_cfg) 23 | logger = logging.getLogger("genes") 24 | logger.setLevel(logging.DEBUG) 25 | 26 | 27 | # --------- CORR ANALYSIS --------- # 28 | def _spearman_op(idx, permuted, y): # pragma: no cover, used for multiprocess 29 | """Wrapper for the spearman correlation function, to be used for 30 | parallel computation.""" 31 | return spearmanr(permuted[:, idx[0]], y[:, idx[1]])[0] 32 | 33 | 34 | @numba.njit() 35 | def rank_array(array): 36 | _args = array.argsort() 37 | ranked = np.empty_like(array) 38 | ranked[_args] = np.arange(array.size) 39 | return ranked 40 | 41 | 42 | @numba.guvectorize(['f8[:], f8[:,:], f8[:]'], 43 | '(n_reg), (n_reg, n_gen), (n_gen)', 44 | nopython=True, 45 | fastmath=True) 46 | def spearman_opt(imaging, genes, corr): 47 | """Calculate the Spearman rank correlation between two arrays.""" 48 | ranked_img = rank_array(imaging) 49 | for i in range(genes.shape[1]): 50 | ranked_gen = rank_array(genes[:, i]) 51 | corr[i] = np.corrcoef(ranked_img, ranked_gen)[0, 1] 52 | 53 | 54 | class CorrAnalysis: 55 | """Class to store all the results of the correlation analysis. 56 | The only field contained is the a GeneResults object, storing all 57 | information about the correlation analysis. 58 | """ 59 | def __init__(self, n_iterations=1000): 60 | self.gene_results = GeneResults("corr", n_iter=n_iterations) 61 | self.gsea_res = None 62 | 63 | # --------- COMPUTE FUNCTIONS --------- # 64 | def bootstrap_correlation(self, imaging_data, permuted_imaging, 65 | gene_exp, gene_labels): 66 | """Perform bootstrapping on the correlation. 67 | 68 | The function first calculates the correlation between the imaging 69 | vector and each of the genes. Then, it performs 1000 bootstrapping 70 | iterations of the same correaltion only using the permuted imaging 71 | data. The function then calls the methods of the GeneResults class 72 | to order the genes and calculate the p-values. 73 | 74 | :param np.ndarray imaging_data: the imaging data. This vector 75 | represents the original data to be correlated, and can have either 76 | length 41 or 34, depending on whether the subcortical regions want 77 | to be included in the analysis. 78 | :param np.ndarray permuted_imaging: the imaging data permuted. This 79 | is a matrix with shape (n_imaging, 1000), where `n_imaging` 80 | represents the length of the imaging vector. 81 | :param np.ndarray gene_exp: the gene expression data. 82 | :param list gene_labels: the labels of the genes. 83 | """ 84 | assert isinstance(self.gene_results.results, CorrGenes) 85 | logger.info("Calculating correlation on original data.") 86 | # Run correlation 87 | spearman_opt(imaging_data, gene_exp, self.gene_results.results.corr) 88 | logger.info("Calculating correlation on permuted data.") 89 | # Bootstrap the correlation 90 | for i in range(permuted_imaging.shape[1]): 91 | spearman_opt(permuted_imaging[:, i], gene_exp, 92 | self.gene_results.results.boot_corr[:, i]) 93 | self.gene_results.results.genes = gene_labels 94 | self.gene_results.results.sort_genes() 95 | self.gene_results.results.compute_pval() 96 | return 97 | 98 | def gsea(self, gene_set="lake", outdir=None, 99 | gene_limit=1500, n_perm=1_000): # pragma: no cover, long to run 100 | """Perform GSEA on the correlation. 101 | 102 | The function runs a first gsea with the data and then runs the same 103 | analysis using the permuted data. The analysis of the permuted data 104 | is used ot calculate the p-values for the Enrichment scores (ES). 105 | 106 | :param n_perm: number of permutations 107 | :param gene_limit: max number of genes to use 108 | :param str gene_set: the gene set to use for the analysis. 109 | :param str outdir: the directory where to save the results. 110 | """ 111 | assert isinstance(self.gene_results.results, CorrGenes) 112 | logger.info("Performing GSEA.") 113 | gene_set = get_geneset(gene_set) 114 | # prepare the gene_list as a list of strings 115 | gene_list = list(self.gene_results.results.genes[:, 0].tolist()) 116 | # perform the GSEA on original results 117 | rnk = pd.DataFrame( 118 | zip(gene_list, self.gene_results.results.corr[0, :])) 119 | gsea_results = gseapy.prerank(rnk, gene_set, 120 | max_size=gene_limit, 121 | outdir=None, 122 | permutation_num=0, 123 | seed=1234) 124 | _origin_es = gsea_results.res2d.ES.to_numpy() 125 | _boot_es = np.zeros((_origin_es.shape[0], n_perm)) 126 | # perform the GSEA on the permutations 127 | for i in range(n_perm): 128 | rnk = pd.DataFrame( 129 | zip(gene_list, self.gene_results.results.boot_corr[:, i])) 130 | _gsea_res = gseapy.prerank(rnk, gene_set, 131 | max_size=gene_limit, 132 | permutation_num=0, 133 | no_plot=True, 134 | outdir=None, 135 | seed=1234) 136 | _boot_es[:, i] = _gsea_res.res2d.ES.values 137 | # calculate the p-value and NES 138 | boot_nes_mean = np.mean(_boot_es, axis=1) 139 | boot_nes_std = np.std(_boot_es, axis=1) 140 | boot_nes = (boot_nes_mean - _origin_es) / boot_nes_std 141 | _p_val = np.zeros((_origin_es.shape[0],)) 142 | _eps = .00001 143 | for i in range(_origin_es.shape[0]): 144 | _p_val[i] = np.sum(_boot_es[i, :] >= _origin_es[i]) / n_perm if _origin_es[i] >= 0 else np.sum(_boot_es[i, :] <= _origin_es[i]) / n_perm 145 | if _p_val[i] == 0.0: 146 | _p_val[i] += _eps 147 | # calculate the p-value corrected 148 | _, _p_corr, _, _ = multipletests(_p_val, method='fdr_bh', 149 | is_sorted=False) 150 | # Prepare data to save 151 | _out_data = OrderedDict() 152 | _out_data["Term"] = gsea_results.res2d.Term.values.tolist() 153 | _out_data["es"] = gsea_results.res2d.ES.values 154 | _out_data["nes"] = boot_nes 155 | _out_data["p_val"] = _p_val 156 | _out_data["fdr"] = _p_corr 157 | #_out_data["genest_size"] = gsea_results.res2d.Geneset_Size.values 158 | #_out_data["matched_size"] = gsea_results.res2d.values[:, 5] 159 | #_out_data["matched_genes"] = gsea_results.res2d.values[:, 6] 160 | #_out_data["ledge_genes"] = gsea_results.res2d.Lead_genes.values 161 | out_df = pd.DataFrame.from_dict(_out_data) 162 | if outdir is not None: 163 | logger.info("Saving GSEA results.") 164 | outdir = Path(outdir) 165 | assert outdir.exists() 166 | out_df.to_csv(outdir / "gsea_corr_results.tsv", index=False, 167 | sep="\t") 168 | # for i in range(len(gsea_results.res2d.index)): 169 | # term = gsea_results.res2d.index[i] 170 | # gsea_results.results[term]["pval"] = _p_val[i] 171 | # gsea_results.results[term]["fdr"] = _p_corr[i] 172 | # gseaplot(rank_metric=gsea_results.ranking, 173 | # term=term, 174 | # **gsea_results.results[term], 175 | # ofname=f"{outdir}/{term}_corr_prerank.pdf") 176 | 177 | # --------- SAVE FUNCTIONS --------- # 178 | def save_results(self, outdir): # pragma: no cover, simply saves stuff 179 | """Save the results to a file.""" 180 | outdir = Path(outdir) 181 | assert outdir.exists() 182 | # Create the data to save 183 | logger.info("Saving results.") 184 | data_to_save = zip(self.gene_results.results.genes[:, 0][::-1], 185 | self.gene_results.results.corr[0, :][::-1], 186 | self.gene_results.results.pval[0, :][::-1], 187 | self.gene_results.results.pval_corr[0, :][::-1]) 188 | # Save the data 189 | pd.DataFrame( 190 | data_to_save, columns=["Gene", "Corr", "Pval", "Pval_corr"] 191 | ).to_csv(outdir / "corr_genes.tsv", index=False, sep='\t') 192 | return 193 | -------------------------------------------------------------------------------- /imaging_transcriptomics/data/atlases/DK/atlas-DK_1mm.nii.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/data/atlases/DK/atlas-DK_1mm.nii.gz -------------------------------------------------------------------------------- /imaging_transcriptomics/data/atlases/DK/atlas-DK_2mm.nii.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/data/atlases/DK/atlas-DK_2mm.nii.gz -------------------------------------------------------------------------------- /imaging_transcriptomics/data/atlases/DK/atlas-DK_fsa5_lh_aparc.annot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/data/atlases/DK/atlas-DK_fsa5_lh_aparc.annot -------------------------------------------------------------------------------- /imaging_transcriptomics/data/atlases/DK/atlas-DK_fsa5_rh_aparc.annot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/data/atlases/DK/atlas-DK_fsa5_rh_aparc.annot -------------------------------------------------------------------------------- /imaging_transcriptomics/data/atlases/DK/atlas-DK_labels.csv: -------------------------------------------------------------------------------- 1 | ,id,label,hemisphere,structure 2 | 0,1,bankssts,L,cortex 3 | 1,2,caudalanteriorcingulate,L,cortex 4 | 2,3,caudalmiddlefrontal,L,cortex 5 | 3,4,cuneus,L,cortex 6 | 4,5,entorhinal,L,cortex 7 | 5,6,fusiform,L,cortex 8 | 6,7,inferiorparietal,L,cortex 9 | 7,8,inferiortemporal,L,cortex 10 | 8,9,isthmuscingulate,L,cortex 11 | 9,10,lateraloccipital,L,cortex 12 | 10,11,lateralorbitofrontal,L,cortex 13 | 11,12,lingual,L,cortex 14 | 12,13,medialorbitofrontal,L,cortex 15 | 13,14,middletemporal,L,cortex 16 | 14,15,parahippocampal,L,cortex 17 | 15,16,paracentral,L,cortex 18 | 16,17,parsopercularis,L,cortex 19 | 17,18,parsorbitalis,L,cortex 20 | 18,19,parstriangularis,L,cortex 21 | 19,20,pericalcarine,L,cortex 22 | 20,21,postcentral,L,cortex 23 | 21,22,posteriorcingulate,L,cortex 24 | 22,23,precentral,L,cortex 25 | 23,24,precuneus,L,cortex 26 | 24,25,rostralanteriorcingulate,L,cortex 27 | 25,26,rostralmiddlefrontal,L,cortex 28 | 26,27,superiorfrontal,L,cortex 29 | 27,28,superiorparietal,L,cortex 30 | 28,29,superiortemporal,L,cortex 31 | 29,30,supramarginal,L,cortex 32 | 30,31,frontalpole,L,cortex 33 | 31,32,temporalpole,L,cortex 34 | 32,33,transversetemporal,L,cortex 35 | 33,34,insula,L,cortex 36 | 34,35,thalamusproper,L,subcortex/brainstem 37 | 35,36,caudate,L,subcortex/brainstem 38 | 36,37,putamen,L,subcortex/brainstem 39 | 37,38,pallidum,L,subcortex/brainstem 40 | 38,39,accumbensarea,L,subcortex/brainstem 41 | 39,40,hippocampus,L,subcortex/brainstem 42 | 40,41,amygdala,L,subcortex/brainstem 43 | 41,42,bankssts,R,cortex 44 | 42,43,caudalanteriorcingulate,R,cortex 45 | 43,44,caudalmiddlefrontal,R,cortex 46 | 44,45,cuneus,R,cortex 47 | 45,46,entorhinal,R,cortex 48 | 46,47,fusiform,R,cortex 49 | 47,48,inferiorparietal,R,cortex 50 | 48,49,inferiortemporal,R,cortex 51 | 49,50,isthmuscingulate,R,cortex 52 | 50,51,lateraloccipital,R,cortex 53 | 51,52,lateralorbitofrontal,R,cortex 54 | 52,53,lingual,R,cortex 55 | 53,54,medialorbitofrontal,R,cortex 56 | 54,55,middletemporal,R,cortex 57 | 55,56,parahippocampal,R,cortex 58 | 56,57,paracentral,R,cortex 59 | 57,58,parsopercularis,R,cortex 60 | 58,59,parsorbitalis,R,cortex 61 | 59,60,parstriangularis,R,cortex 62 | 60,61,pericalcarine,R,cortex 63 | 61,62,postcentral,R,cortex 64 | 62,63,posteriorcingulate,R,cortex 65 | 63,64,precentral,R,cortex 66 | 64,65,precuneus,R,cortex 67 | 65,66,rostralanteriorcingulate,R,cortex 68 | 66,67,rostralmiddlefrontal,R,cortex 69 | 67,68,superiorfrontal,R,cortex 70 | 68,69,superiorparietal,R,cortex 71 | 69,70,superiortemporal,R,cortex 72 | 70,71,supramarginal,R,cortex 73 | 71,72,frontalpole,R,cortex 74 | 72,73,temporalpole,R,cortex 75 | 73,74,transversetemporal,R,cortex 76 | 74,75,insula,R,cortex 77 | 75,76,thalamusproper,R,subcortex/brainstem 78 | 76,77,caudate,R,subcortex/brainstem 79 | 77,78,putamen,R,subcortex/brainstem 80 | 78,79,pallidum,R,subcortex/brainstem 81 | 79,80,accumbensarea,R,subcortex/brainstem 82 | 80,81,hippocampus,R,subcortex/brainstem 83 | 81,82,amygdala,R,subcortex/brainstem 84 | 82,83,brainstem,B,subcortex/brainstem 85 | -------------------------------------------------------------------------------- /imaging_transcriptomics/data/atlases/Schaefer_100/atlas-Schaefer_100_1mm.nii.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/data/atlases/Schaefer_100/atlas-Schaefer_100_1mm.nii.gz -------------------------------------------------------------------------------- /imaging_transcriptomics/data/atlases/Schaefer_100/atlas-Schaefer_100_2mm.nii.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/data/atlases/Schaefer_100/atlas-Schaefer_100_2mm.nii.gz -------------------------------------------------------------------------------- /imaging_transcriptomics/data/atlases/Schaefer_100/atlas-Schaefer_100_labels.csv: -------------------------------------------------------------------------------- 1 | id,label,hemisphere,structure 2 | 1,7Networks_LH_Vis_1,L,cortex 3 | 2,7Networks_LH_Vis_2,L,cortex 4 | 3,7Networks_LH_Vis_3,L,cortex 5 | 4,7Networks_LH_Vis_4,L,cortex 6 | 5,7Networks_LH_Vis_5,L,cortex 7 | 6,7Networks_LH_Vis_6,L,cortex 8 | 7,7Networks_LH_Vis_7,L,cortex 9 | 8,7Networks_LH_Vis_8,L,cortex 10 | 9,7Networks_LH_Vis_9,L,cortex 11 | 10,7Networks_LH_SomMot_1,L,cortex 12 | 11,7Networks_LH_SomMot_2,L,cortex 13 | 12,7Networks_LH_SomMot_3,L,cortex 14 | 13,7Networks_LH_SomMot_4,L,cortex 15 | 14,7Networks_LH_SomMot_5,L,cortex 16 | 15,7Networks_LH_SomMot_6,L,cortex 17 | 16,7Networks_LH_DorsAttn_Post_1,L,cortex 18 | 17,7Networks_LH_DorsAttn_Post_2,L,cortex 19 | 18,7Networks_LH_DorsAttn_Post_3,L,cortex 20 | 19,7Networks_LH_DorsAttn_Post_4,L,cortex 21 | 20,7Networks_LH_DorsAttn_Post_5,L,cortex 22 | 21,7Networks_LH_DorsAttn_Post_6,L,cortex 23 | 22,7Networks_LH_DorsAttn_PrCv_1,L,cortex 24 | 23,7Networks_LH_DorsAttn_FEF_1,L,cortex 25 | 24,7Networks_LH_SalVentAttn_ParOper_1,L,cortex 26 | 25,7Networks_LH_SalVentAttn_FrOperIns_1,L,cortex 27 | 26,7Networks_LH_SalVentAttn_FrOperIns_2,L,cortex 28 | 27,7Networks_LH_SalVentAttn_PFCl_1,L,cortex 29 | 28,7Networks_LH_SalVentAttn_Med_1,L,cortex 30 | 29,7Networks_LH_SalVentAttn_Med_2,L,cortex 31 | 30,7Networks_LH_SalVentAttn_Med_3,L,cortex 32 | 31,7Networks_LH_Limbic_OFC_1,L,cortex 33 | 32,7Networks_LH_Limbic_TempPole_1,L,cortex 34 | 33,7Networks_LH_Limbic_TempPole_2,L,cortex 35 | 34,7Networks_LH_Cont_Par_1,L,cortex 36 | 35,7Networks_LH_Cont_PFCl_1,L,cortex 37 | 36,7Networks_LH_Cont_pCun_1,L,cortex 38 | 37,7Networks_LH_Cont_Cing_1,L,cortex 39 | 38,7Networks_LH_Default_Temp_1,L,cortex 40 | 39,7Networks_LH_Default_Temp_2,L,cortex 41 | 40,7Networks_LH_Default_Par_1,L,cortex 42 | 41,7Networks_LH_Default_Par_2,L,cortex 43 | 42,7Networks_LH_Default_PFC_1,L,cortex 44 | 43,7Networks_LH_Default_PFC_2,L,cortex 45 | 44,7Networks_LH_Default_PFC_3,L,cortex 46 | 45,7Networks_LH_Default_PFC_4,L,cortex 47 | 46,7Networks_LH_Default_PFC_5,L,cortex 48 | 47,7Networks_LH_Default_PFC_6,L,cortex 49 | 48,7Networks_LH_Default_PFC_7,L,cortex 50 | 49,7Networks_LH_Default_pCunPCC_1,L,cortex 51 | 50,7Networks_LH_Default_pCunPCC_2,L,cortex 52 | 51,7Networks_RH_Vis_1,R,cortex 53 | 52,7Networks_RH_Vis_2,R,cortex 54 | 53,7Networks_RH_Vis_3,R,cortex 55 | 54,7Networks_RH_Vis_4,R,cortex 56 | 55,7Networks_RH_Vis_5,R,cortex 57 | 56,7Networks_RH_Vis_6,R,cortex 58 | 57,7Networks_RH_Vis_7,R,cortex 59 | 58,7Networks_RH_Vis_8,R,cortex 60 | 59,7Networks_RH_SomMot_1,R,cortex 61 | 60,7Networks_RH_SomMot_2,R,cortex 62 | 61,7Networks_RH_SomMot_3,R,cortex 63 | 62,7Networks_RH_SomMot_4,R,cortex 64 | 63,7Networks_RH_SomMot_5,R,cortex 65 | 64,7Networks_RH_SomMot_6,R,cortex 66 | 65,7Networks_RH_SomMot_7,R,cortex 67 | 66,7Networks_RH_SomMot_8,R,cortex 68 | 67,7Networks_RH_DorsAttn_Post_1,R,cortex 69 | 68,7Networks_RH_DorsAttn_Post_2,R,cortex 70 | 69,7Networks_RH_DorsAttn_Post_3,R,cortex 71 | 70,7Networks_RH_DorsAttn_Post_4,R,cortex 72 | 71,7Networks_RH_DorsAttn_Post_5,R,cortex 73 | 72,7Networks_RH_DorsAttn_PrCv_1,R,cortex 74 | 73,7Networks_RH_DorsAttn_FEF_1,R,cortex 75 | 74,7Networks_RH_SalVentAttn_TempOccPar_1,R,cortex 76 | 75,7Networks_RH_SalVentAttn_TempOccPar_2,R,cortex 77 | 76,7Networks_RH_SalVentAttn_FrOperIns_1,R,cortex 78 | 77,7Networks_RH_SalVentAttn_Med_1,R,cortex 79 | 78,7Networks_RH_SalVentAttn_Med_2,R,cortex 80 | 79,7Networks_RH_Limbic_OFC_1,R,cortex 81 | 80,7Networks_RH_Limbic_TempPole_1,R,cortex 82 | 81,7Networks_RH_Cont_Par_1,R,cortex 83 | 82,7Networks_RH_Cont_Par_2,R,cortex 84 | 83,7Networks_RH_Cont_PFCl_1,R,cortex 85 | 84,7Networks_RH_Cont_PFCl_2,R,cortex 86 | 85,7Networks_RH_Cont_PFCl_3,R,cortex 87 | 86,7Networks_RH_Cont_PFCl_4,R,cortex 88 | 87,7Networks_RH_Cont_Cing_1,R,cortex 89 | 88,7Networks_RH_Cont_PFCmp_1,R,cortex 90 | 89,7Networks_RH_Cont_pCun_1,R,cortex 91 | 90,7Networks_RH_Default_Par_1,R,cortex 92 | 91,7Networks_RH_Default_Temp_1,R,cortex 93 | 92,7Networks_RH_Default_Temp_2,R,cortex 94 | 93,7Networks_RH_Default_Temp_3,R,cortex 95 | 94,7Networks_RH_Default_PFCv_1,R,cortex 96 | 95,7Networks_RH_Default_PFCv_2,R,cortex 97 | 96,7Networks_RH_Default_PFCdPFCm_1,R,cortex 98 | 97,7Networks_RH_Default_PFCdPFCm_2,R,cortex 99 | 98,7Networks_RH_Default_PFCdPFCm_3,R,cortex 100 | 99,7Networks_RH_Default_pCunPCC_1,R,cortex 101 | 100,7Networks_RH_Default_pCunPCC_2,R,cortex 102 | -------------------------------------------------------------------------------- /imaging_transcriptomics/data/atlases/Schaefer_100/atlas-Schaefer_100_lh_aparc.annot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/data/atlases/Schaefer_100/atlas-Schaefer_100_lh_aparc.annot -------------------------------------------------------------------------------- /imaging_transcriptomics/data/atlases/Schaefer_100/atlas-Schaefer_100_rh_aparc.annot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/data/atlases/Schaefer_100/atlas-Schaefer_100_rh_aparc.annot -------------------------------------------------------------------------------- /imaging_transcriptomics/data/geneset_Pooled.gmt: -------------------------------------------------------------------------------- 1 | Astro NA A2ML1 AADAT AASS ABCA7 ABCD2 ABLIM1 ACAA2 ACACB ACADVL ACBD7 ACKR3 ACO2 ACOT11 ACOX2 ACP6 ACSBG1 ACSF2 ACSL6 ACSS1 ACSS3 ADA ADAM20P1 ADAMTSL5 ADCY2 ADCY8 ADCYAP1R1 ADD3 ADGRV1 ADHFE1 ADI1 ADORA2B ADRB1 AEBP1 AGBL2 AGFG2 AGL AGT AHCYL1 AHCYL2 AHNAK AIFM3 AK4 AKR7A2 ALDH1L1 ALDH2 ALDH4A1 ALDH7A1 ALDOC AMOT AMT AMZ2 ANGPTL4 ANKDD1A ANKRD35 ANKRD45 ANO8 APC APEH APLNR APOE AQP1 AQP4 ARHGAP24 ARHGAP32 ARHGAP5 ARHGAP5-AS1 ARHGEF26 ARHGEF26-AS1 ARHGEF4 ARL6IP6 ARRB1 ARSJ ASAP2 ASAP3 ASPH ASRGL1 ASTN1 ATP13A4 ATP1A2 ATP1B2 ATP6AP1L BAZ2B BBOX1 BBS2 BBS4 BCAN BCKDHB BDH2 BHMT2 BMP7 BMPR1A BMPR1B BRINP2 C1orf61 C5 CA12 CABLES1 CACHD1 CACNB1 CACNB2 CADM1 CAMK2G CAPN2 CARMIL1 CASC10 CASC2 CAT CD38 CDH2 CDH20 CDH26 CDH4 CDHR3 CEP350 CEP85L CERS1 CGRRF1 CHDH CHI3L1 CHPT1 CHRDL1 CHRNB1 CKB CLDN10 CLDN12 CLEC16A CLPTM1 CLU CMBL CNTFR CNTNAP3 COL5A3 COLCA1 COLCA2 COPS7B COQ10A CPE CRB1 CRYAB CRYZ CSGALNACT1 CST3 CTH CTNNA2 CTNND2 CXCL3 CXCL5 CYB5B CYBRD1 CYP2J2 CYP4V2 CYP7B1 DAAM2 DAG1 DBI DBP DCLK2 DCT DCUN1D1 DCXR DDAH1 DECR1 DGKG DHODH DHRS4-AS1 DHTKD1 DIAPH3 DIO2 DKK3 DMGDH DNAAF5 DNAH7 DOCK4 DOCK7 DOK5 DOLK DPP10 DPP8 DPY19L3 DPYSL3 DST DTNA DTX1 ECHDC2 EDNRB EEF2K EFEMP1 EFHC1 EFHC2 EFNA5 EFR3B EGFR ELMO2 ELOVL2 EMID1 EMX2 EMX2OS ENHO ENKUR ENO1 ENTPD2 EPHB1 EPHX1 EPHX2 ERBB2 ERBB4 ERLIN2 ETAA1 ETNPPL EYA1 EYA2 EZR F3 F8 FADS2 FAM107A FAM118B FAM167A FAM168A FAM171A1 FAM171B FAM181B FAM184A FAM189A2 FAM198A FAM213A FAM71F2 FARP1 FAT1 FAT3 FBXL7 FBXO2 FERMT2 FEZF2 FGD6 FGF2 FGFR3 FGFRL1 FGGY FHIT FJX1 FKBP10 FKBP9 FMN2 FNBP1 FOS FOXRED2 FUT10 FUT9 FYN FZD8 GABBR1 GABRA2 GABRB1 GABRG1 GAPDH GAS2L1 GAS8 GBA GCDH GDPD2 GFAP GGACT GJA1 GJB6 GLI1 GLI3 GLIS3 GLUD1 GLUD2 GLUL GNA14 GOLGA2P5 GOLIM4 GPAM GPC4 GPC5 GPD2 GPM6A GPM6B GPR143 GPR171 GPR19 GPR37L1 GPR75 GPRC5B GPT2 GRAMD1C GREB1 GRIN2C GRM3 GSTM5 H3F3B HADHB HAP1 HEPACAM HEPH HERPUD2 HES1 HGF HHATL HHIPL1 HIF3A HOPX HPR HPS4 HPSE2 HRH1 HS2ST1 HSBP1L1 HSD17B6 HSDL2 HSPA1A HSPB1 HTRA1 ID2 ID3 ID4 IDH2 IFT27 IFT43 IGFN1 IGSF1 IL17D IL17RB IL33 INHBB INTS3 INTU IQCA1 IQCH IQCH-AS1 ITGA7 ITGB4 ITM2C ITPKB ITPR2 ITSN1 JUN JUNB KATNAL2 KCNA2 KCNJ10 KCNN3 KCTD15 KCTD21 KIAA0319 KIAA1671 KLF15 KLKB1 KNDC1 LAMA1 LANCL2 LCNL1 LCTL LDHB LDHD LETM1 LFNG LGI1 LGI4 LGR4 LGR6 LHX2 LIFR LINC00461 LINC00595 LINC00654 LINC00839 LINC00886 LINC00900 LINC00982 LINC01158 LINC01351 LIX1 LMO3 LPIN1 LRIG1 LRP1 LRP1B LRP4 LRRC3B LRRC75A LRRC8A LRTOMT LSAMP MACF1 MAML2 MAOB MAP3K5 MAPK10 MAPK4 MASP1 MAST4 MCCC2 ME1 MEIS2 METRN METTL7A MGAT4C MGC16275 MGST1 MICALL2 MINK1 MIR99AHG MKLN1 MLC1 MLYCD MOCS1 MOK MOXD1 MRAS MRO MROH7 MRVI1 MRVI1-AS1 MSI2 MST1 MT1G MT2A MT3 MTHFD1 MTM1 MTMR1 MTSS1L MUL1 MUT MUTYH MYBPC1 MYH15 MYO10 MYO6 MYOM1 NACC2 NADK2 NAT8L NAV2 NBPF1 NBPF10 NBPF11 NCAN NCKAP5 NDP NDRG2 NDUFAF6 NDUFS3 NEAT1 NEBL NEK1 NEK11 NEK6 NFATC4 NFIA NFIB NHS NHSL1 NINL NKAIN3 NKAIN4 NME9 NOTCH2 NPAS3 NQO1 NR2E1 NRG3 NRXN1 NT5E NTM NTNG2 NTRK2 NTSR2 NWD1 OAF OGFRL1 OLFM2 OPHN1 ORAI3 OSBPL2 OTX1 OXTR P2RY1 PALLD PAMR1 PAPLN PARD3 PARD3B PARP3 PAX6 PAXIP1-AS2 PBXIP1 PCDH9 PCDHB4 PCDHB5 PCDHGA12 PCDHGA3 PCDHGA7 PCDHGB7 PCDHGC3 PCSK5 PDE4DIP PDE7B PDLIM3 PEX11A PEX12 PFKFB2 PFKM PGM1 PHACTR3 PHF21B PHGDH PHKA1 PHLPP1 PHYHD1 PIK3C2A PIPOX PIR PITPNC1 PLA2G5 PLCD1 PLCD4 PLCG1 PLEKHA7 PLIN4 PLIN5 PLOD2 PLSCR4 PLTP PLXNB1 PMM1 PMP2 PNPLA7 POLL PON2 PON3 POU2F1 POU3F2 PPARA PPARGC1A PPFIA1 PPP1R1B PPP1R26 PPP1R3C PPP1R3D PPP1R3G PPP2R2B PPP2R5A PRDM16 PRDM5 PRDX6 PREX2 PRKCA PRKD1 PRKG1 PRODH PRSS35 PSD2 PSD3 PSMG3-AS1 PTAR1 PTCH1 PTCHD1 PTGDS PTN PTPN9 PTPRA PTPRF PTPRZ1 PYGB PYGM QKI RAB30 RAB34 RALGAPA2 RAMP1 RANBP3L RAPGEF3 RASSF4 RBM26-AS1 RFX2 RFX4 RGMA RGN RGR RGS20 RGS9 RHOB RHOBTB3 RHPN2 RLBP1 RND1 RNF170 RNF182 RNF43 ROBO3 RORA RORB RPS6KA2 RYR3 S100B SALL2 SARDH SASH1 SAT1 SCARA3 SCG3 SCRG1 SDC2 SDC3 SDC4 SDS SEC14L2 SELENBP1 SEMA3D SEMA4A SEMA4B SERPINE2 SESN3 SFXN5 SGCD SHROOM3 SIRPA SLC13A5 SLC14A1 SLC15A2 SLC16A9 SLC18B1 SLC1A2 SLC1A3 SLC1A4 SLC25A18 SLC25A20 SLC25A29 SLC25A33 SLC25A43 SLC25A48 SLC25A53 SLC27A1 SLC2A10 SLC2A12 SLC30A10 SLC35C2 SLC35F1 SLC38A1 SLC39A11 SLC39A12 SLC44A2 SLC44A3 SLC46A1 SLC4A4 SLC7A10 SLC7A11 SLC7A2 SLC9A3R1 SLC9A8 SLCO1C1 SLITRK2 SMO SMOX SNTA1 SON SORBS1 SORCS2 SOX2 SOX21 SOX5 SOX6 SOX9 SOX9-AS1 SPARC SPARCL1 SPON1 SRGAP3 SRI SRPX SSPN STK33 STON2 STOX1 STRIP2 SUGCT SUOX SYCP2 SYNE1 SYPL2 SYTL4 TCF7L2 TCTN1 TET1 TFAP2C TGFBR3 THBS3 THSD1 TKT TLCD1 TM9SF4 TMED8 TMEM132A TMEM136 TMEM150C TMEM164 TMEM220 TMEM229A TMEM241 TMEM47 TMEM56 TMEM72 TMEM9 TNC TNIK TNNT1 TNS3 TOB1 TOM1L2 TOX TP53BP2 TPCN1 TPD52L1 TPP1 TRAF3IP2 TRIL TRIM66 TRIM8 TRPM3 TRPS1 TSC22D4 TSHZ1 TST TTC30A TTLL4 TTPA TTYH1 TUBB2B TULP3 UBAC1 UBC UG0898H09 USP40 VANGL2 VAV3 VCAN VEGFB VWA3A WDFY3-AS2 WDR17 WDR49 WDR60 WFS1 WIF1 WNT7B WWC1 WWOX XYLT2 YAP1 ZBTB20 ZBTB7C ZFAND5 ZFHX2 ZFHX4 ZFP2 ZFP36L1 ZFYVE21 ZHX3 ZIC5 ZMAT1 ZMYND12 ZNF221 ZNF404 ZNF516 ZNF521 ZNF671 ZNF680 ZNF717 ZNF81 ZNF816 ZNF827 ZNRF3 ZSWIM6 2 | Endo NA A2M A4GALT ABCA9 ABCB1 ABCG2 ABHD14B ABLIM3 ACE ACER2 ACKR1 ACTA2 ACTG2 ACTN1 ACTN4 ACVR1 ACVRL1 ADAMTS8 ADAMTS9 ADAR ADCY4 ADD1 ADGRF5 ADIPOR2 ADIRF ADM ADPRM AFAP1L1 AGRN AGTRAP AHNAK AIF1L AKAP12 AKR1E2 ALPL ALS2CL ANGPT2 ANKS1A ANO2 ANP32B ANTXR2 ANXA1 ANXA2 ANXA3 ANXA5 APH1A APOL1 APOL3 APOL4 APOLD1 ARAP3 ARFGEF2 ARHGAP10 ARHGAP29 ARHGAP42 ARHGEF15 ARHGEF17 ARL13B ARL15 ARPC1B ARRDC2 ASAP1-IT2 ASS1 ATAD2 ATP10A ATP7B ATP8B1 ATP8B5P AXIN2 B2M B3GNT2 BACE2 BAMBI BATF2 BCL2L10 BCL6B BCL7B BGN BHLHE40 BIRC3 BLOC1S3 BMP2 BMP6 BMPR2 BRD2 BSG BST2 BTBD6 BTG2 BTN3A3 BTNL9 C12orf57 C1R C2CD2 C2CD4B C7 CA4 CA5B CALD1 CAP1 CAPN12 CAPNS1 CARD6 CAV1 CAV2 CAVIN1 CAVIN2 CBFA2T3 CCDC141 CCDC3 CCDC68 CCDC88C CCL19 CCM2L CCNL1 CCNY CD151 CD248 CD320 CD34 CD44 CD46 CD59 CD63 CDA CDC37 CDH6 CDYL2 CEBPD CEMIP CENPP CEP89 CES1 CFH CFL1 CFLAR CGNL1 CHST12 CKMT2 CLDN5 CLEC14A CLIC5 CMAHP CMPK2 CMTM8 CNKSR3 CNN2 CNOT6L CNTLN COBLL1 COL1A2 COL24A1 COL27A1 COL4A1 COL4A2 COL6A2 COLEC12 COX4I2 COX7A1 CPAMD8 CPD CRIM1 CRIP2 CSDE1 CSNK1G3 CSRNP1 CSRP2 CTBS CTGF CTNNB1 CTR9 CTSV CX3CL1 CXCL12 CXCL2 CYB5R3 CYP1B1 CYR61 CYYR1 DAB2IP DACH1 DACT2 DANCR DCBLD1 DCN DDIT3 DDN DDX11 DDX47 DDX51 DEAF1 DEGS2 DEK DENND2C DIO3 DIO3OS DLC1 DMBT1 DOCK9 DSP DSTN DUSP1 DUSP11 DYRK3 EBF1 ECE1 ECM1 ECM2 ECSCR EDN1 EDN3 EDNRA EEF1A1 EEF1D EEF2 EEFSEC EFNA1 EGFL7 EHD1 EHD2 EIF1 EIF2AK2 EIF3A EIF3I EIF4G2 ELOVL7 EMCN EML1 EMP1 EMP2 ENG EOGT EPAS1 EPB41L4A EPSTI1 ERG ERRFI1 ESAM ESM1 ESYT2 ETS1 ETS2 EVA1C FAM122C FAM129B FAM162B FAM213A FAM89A FBLN5 FBXO25 FES FGD5 FHL2 FHL3 FHL5 FKBP1A FLI1 FLNA FLNB FLT1 FLT4 FMO2 FMOD FN1 FOSB FOSL2 FOXC1 FOXC2 FOXF1 FOXF2 FOXL1 FOXL2 FOXP1 FOXQ1 FRMD3 FRMD6 FRZB FSTL1 FURIN FZD10 FZD6 GABRE GADD45B GALNT15 GALNT18 GATAD2A GBP4 GCNT1 GGT1 GGT5 GIMAP6 GIMAP7 GJA4 GJC1 GNAI2 GNG11 GPCPD1 GPER1 GPIHBP1 GPR108 GPR4 GPR85 GPX1 GPX3 GRB10 GRP GSK3A GSTO2 GSTP1 GUK1 H2AFZ HBB HEBP2 HEG1 HELZ2 HERC2 HERC2P2 HERC2P9 HERPUD1 HES4 HEXIM1 HIGD1B HIST1H1D HIST1H2BC HLA-A HLA-B HLA-C HLA-E HLA-F HMGB1 HPCAL1 HPGD HRC HSF1 HSP90AA1 HSP90B1 HSPA12B HTR1F HYAL2 ICAM2 ID1 ID3 IER2 IFI27 IFI35 IFI44 IFI44L IFI6 IFIH1 IFITM1 IFITM2 IFITM3 IFNGR1 IGF1R IGFBP3 IGFBP7 IGSF9 IL15RA IL32 IMPDH1 ING1 INSR INTS12 IQGAP1 ISG15 ISLR ISM1 ISYNA1 ITGA1 ITGA11 ITGA6 ITGB1 ITIH5 ITM2A ITM2B ITPR3 JAG2 JUN JUNB JUND KANK2 KANK3 KCNE4 KCTD12 KDR KIAA0355 KIF25 KIF5B KLF11 KLF2 KLF4 KLF6 KLF9 KRTCAP3 LAMA2 LAMA3 LAMA4 LAMA5 LAMB2 LAMC1 LAPTM4A LDLR LEF1 LEPR LGALS1 LGALS3 LIMS2 LIN9 LMCD1 LMNA LMO2 LNX2 LRRC17 LRRC32 LRRC70 LSMEM1 LSR LXN LY6E LZTS1 LZTS2 MANBAL MAST2 MATN3 MECOM MEGF6 MFAP4 MFSD2A MGLL MGP MIR22HG MLIP MLKL MMRN2 MRGPRF MRPL1 MRPS24 MSX1 MT1A MT1E MT1F MT1L MT1M MT1X MVP MX1 MX2 MXRA7 MYADM MYCT1 MYH11 MYH9 MYL12A MYL12B MYL6 MYL9 MYLK2 MYO1B MYO1C MYO5C MYRIP NAGS NAMPT NBEAL1 NCL NDUFA4L2 NDUFAF3 NEAT1 NEDD9 NES NET1 NEURL1B NFE2L1 NFIA NFKBIA NID2 NKD1 NKX6-1 NLRC5 NOC3L NOS3 NOSTRIN NOTCH4 NR3C2 NR4A1 NSUN6 NT5DC2 NTAN1 NUDT2 NXN NYNRIN OAZ1 OCLN OLFML2A OPA3 OPTN ORC5 OST4 P2RY14 P4HA2 PALMD PAPSS2 PARP14 PARP9 PARVB PAWR PCAT19 PCBP3 PCCA PCDH1 PCGF2 PCOLCE PDCD4 PDE4C PDK4 PEAR1 PECAM1 PERP PES1 PFN1 PHACTR2 PHF10 PHLDB2 PIBF1 PIK3C2A PKIG PLA1A PLAT PLCB4 PLEKHG1 PLEKHG2 PLOD1 PLOD3 PLXDC1 PMEPA1 PML PODXL POLR2L POLRMT POMP PPARD PPFIBP1 PPP1R10 PPP1R15A PRELP PROCR PROSER2 PRRX1 PRSS23 PRX PSMB8 PSMB9 PSMC3 PSME1 PSME2 PTEN PTGES PTH1R PTMS PTPN14 PTPRB PTPRG PTPRK PTPRM PTTG1IP PXDC1 PXN PYGO2 QRFPR RAB13 RAB37 RAC1 RAI2 RALB RAMP2 RAMP3 RARRES2 RASIP1 RASL12 RBCK1 RBM17 RBM43 RBMS2 RBMS3 RBPMS RBPMS2 RCSD1 RELA RERGL RGCC RGS5 RHOA RHOB RHOBTB1 RHOC RND3 RNF152 ROBO4 RPL11 RPL13A RPL18 RPL19 RPL23 RPL27A RPL28 RPL3 RPL34 RPL35 RPL35A RPL36 RPL37A RPL38 RPL4 RPL41 RPL8 RPLP1 RPS11 RPS12 RPS16 RPS20 RPS21 RPS23 RPS27A RPS28 RPS29 RPS3 RPS4X RPS5 RPS6 RPS8 RPS9 RRAS RSAD2 RSU1 RUNDC3B RUVBL2 S100A10 S100A16 S100A6 S1PR1 SAV1 SCARB1 SCN4A SDCBP SEC14L1 SEMA3G SERF2 SERPINB6 SERPING1 SERPINH1 SERTAD1 SFTA1P SGPP2 SH2D3C SHANK3 SHC2 SHISA5 SIK2 SKAP1 SLC10A3 SLC12A7 SLC16A1 SLC16A13 SLC16A2 SLC16A6 SLC19A1 SLC19A3 SLC20A2 SLC25A39 SLC2A1 SLC2A3 SLC30A1 SLC35A4 SLC38A11 SLC38A3 SLC38A5 SLC39A10 SLC39A13 SLC39A8 SLC3A2 SLC4A2 SLC52A3 SLC5A6 SLC6A12 SLC6A13 SLC6A6 SLC7A1 SLC7A5 SLC9A1 SLC9A3R2 SLCO2A1 SLCO2B1 SLCO4A1 SLFN11 SLFN12 SLFN5 SMIM10 SMIM3 SMOC2 SNAI1 SNAI2 SNED1 SNHG5 SNHG8 SNRK SNTB1 SNX33 SOCS2 SORBS2 SOS1 SOX13 SOX17 SOX18 SOX7 SPARC SPARCL1 SPINK8 SPSB2 SPTBN1 SRGN ST6GAL1 ST6GALNAC1 ST6GALNAC3 STARD8 STAT3 STC2 STOM STRA6 STX10 SUSD2 SUV39H1 SWAP70 SYDE1 SYNE2 SYNPO SYNPO2 SYT15 TACC1 TAF13 TAGLN TAGLN2 TAP1 TBC1D4 TBPL1 TBX2 TBX3 TCF7L1 TCN2 TES TESC TESK1 TFPI TFRC TGFBR2 TGM2 THAP3 THBS1 THSD4 TIE1 TIMP1 TIMP3 TIPARP TJP1 TLN1 TM4SF1 TM4SF18 TMEM179B TMEM204 TMEM45B TMOD3 TMSB10 TNFAIP1 TNFSF10 TNIP1 TNS1 TNS2 TNXB TOPORS TPI1 TPM1 TPM2 TPM3 TPM4 TPT1 TRAM2 TRAPPC2B TRIM28 TRIM56 TRIP10 TSC22D1 TSC22D3 TSKU TSPAN14 TSPAN9 TTLL1 TTN TUBB TUBB4B TUBD1 TUBG1 TWIST1 TXLNA TXNIP UACA UBE2L6 UBE2S ULBP2 USHBP1 UTRN VAMP5 VANGL1 VAT1 VCL VGLL3 VIM VIT VWF WARS WIPI1 WNT11 WWTR1 XAF1 YBX3 YES1 ZBTB10 ZBTB38 ZCCHC14 ZEB1 ZFP36 ZIC1 ZIC3 ZIC4 ZMYM1 ZNF257 ZNF274 ZNF366 ZNF394 ZNF407 ZNF442 ZNF823 3 | Microglia NA AAED1 ABL2 ABR ACSL1 ACTB ACTR2 ACY3 ADAM17 ADAM28 ADAM9 ADAP2 ADPGK AIF1 AKAP13 AKR1A1 ALOX15B ALOX5 ALOX5AP AMZ2P1 ANKRD44 ANXA5 AOAH APAF1 APBB1IP AREL1 ARHGAP22 ARHGAP24 ARHGAP25 ARHGAP9 ARHGDIB ARID3B ARID5A ARL5A ARPC1B ARPC2 ARPC3 ARRB2 ARRDC3 ASH1L ATF6 ATF7IP2 ATM ATP13A3 ATP6V0E1 ATP6V1B2 B2M B3GNT5 B3GNTL1 B4GALT1 BACH1 BATF3 BCAR3 BCAS2 BCL2A1 BHLHE41 BLNK BMS1P4 BRAP C1QA C1QB C1QC C3 C3AR1 C5AR2 CAP1 CAPG CAPNS2 CAPZA1 CAPZB CARS2 CASP1 CCL2 CCL22 CCR1 CCR5 CD14 CD163 CD164 CD226 CD274 CD276 CD300C CD300LB CD33 CD37 CD4 CD53 CD74 CD83 CD84 CD86 CDC42EP3 CDC42SE1 CDV3 CEP170 CH25H CHCHD7 CHD1 CHD2 CHD9 CHST11 CHST14 CHSY1 CITED2 CLEC4A CLEC9A CLINT1 CLPB CMTM6 CMTM7 CNOT1 CNOT6 CNPY3 COL8A2 CORO1A COTL1 CPVL CREB3 CREG1 CSF1R CSF2RA CSF3R CSNK2A2 CTSB CTSC CTSL CTSS CTTNBP2NL CX3CR1 CXCL16 CXCR4 CYB561A3 CYBB CYFIP1 CYP2R1 CYTH4 CYTL1 DAGLB DCTD DDX21 DDX39A DEF6 DENND1C DENND3 DGKA DHRS9 DIAPH2 DIP2B DKC1 DNAH1 DNAJC10 DNAJC2 DNMBP DOCK10 DOCK11 DOCK4 DOCK8 DR1 DUSP2 DUSP6 E2F3 EBI3 EDEM1 EEPD1 EGR2 EGR3 EIF2AK3 EIF3L EIF3M EIF4A3 EIF4E ELF1 ELF4 ELL2 ELMO1 EMB EML4 ENPP1 EPB41L2 ESCO1 ETF1 ETS2 EVI2B EVL F13A1 FAM105A FAM135A FAM149A FAM46A FAM49B FAM91A1 FCER1G FCGBP FCGR1B FCGR2A FCGR3A FCGRT FCHSD2 FGD2 FGD4 FGL2 FHOD1 FMN1 FMNL1 FOLR2 FPR1 FRMD4A FUT4 FYB1 G0S2 GABPB1 GAL3ST4 GBP2 GGA3 GGTA1P GHRLOS GLIPR1 GM2A GMEB1 GMFG GNA13 GNAI3 GNB4 GNL2 GNLY GPR132 GPR183 GPR34 GPX1 GRB2 GRID2 GRN GTF2E2 GTPBP4 GYPC H2AFY HAMP HAUS8 HAVCR2 HCCS HCK HCLS1 HCST HENMT1 HEXB HIF1A HIVEP3 HK2 HLA-DMA HLA-DMB HLA-DPA1 HLA-DPB1 HLA-DRA HLA-DRB1 HLA-E HPGDS HPS3 HS3ST1 HS3ST4 HS6ST1 IFI16 IFNGR2 IGSF6 IL10RA IL13RA1 IL1B IL1RAP IL4R IL6R IL6ST INHBA INPP5D IPCEF1 IRAK2 IRF5 ISG20L2 ITGAM ITGAX ITGB2 ITM2B ITPR2 JDP2 KBTBD8 KCNMB1 KCNQ3 KCTD12 KDM7A KYNU LAPTM5 LAT2 LCP1 LCP2 LDLRAD4 LGMN LHFPL2 LILRB4 LIMS1 LINC-PINT LINC00484 LINC01480 LPAR5 LPAR6 LPCAT2 LPL LPXN LRRFIP1 LRRK1 LST1 LUZP1 LY86 LY96 LYN LYPLA1 LYST M6PR MAF1 MAFB MALT1 MAML2 MAML3 MAN1A1 MAP2K3 MAP4K4 MAPKAPK2 MASTL MBD4 MBNL1 MCM9 MDM2 MED12L MEF2A MEF2C METAP1 MFSD1 MGAT1 MICAL1 MILR1 MIS18BP1 MKNK1 MLXIPL MNDA MOB1A MOB3A MPEG1 MPP1 MR1 MRC1 MS4A4A MS4A7 MTHFD1L MTHFD2 MYBPC3 MYC MYO1F MYO7A MYO9B NAA15 NAA20 NAB2 NABP1 NAV3 NCF4 NCOA3 NCOA4 NEAT1 NEDD9 NFAM1 NKX3-1 NLRP3 NPC2 NPL NR4A2 NRBF2 NRROS NUFIP2 NUP54 OGFRL1 OLR1 OR2B11 OS9 OTUD1 P2RX4 P2RY12 P2RY13 P4HA1 PABPC1 PAG1 PARN PARP4 PBDC1 PCM1 PDE3B PDGFB PDK4 PDPN PELI1 PGM2 PICALM PIK3AP1 PIK3R5 PILRA PKN2 PLAU PLAUR PLBD1 PLCB2 PLD4 PLEKHO1 PLIN2 PLVAP PLXDC2 POPDC2 POU2F2 PPARG PPIG PRKAB1 PRPF38B PRR13 PRRC2C PSMA1 PTAFR PTGER4 PTPRC PTPRE PYCARD QKI RAB32 RAB39A RAB7B RANBP2 RAP2B RAPGEF2 RASAL2 RASGEF1B RASGEF1C RASSF5 RBM25 RC3H1 RCBTB2 RCOR1 REL RGS1 RGS10 RGS18 RHBDF2 RHOG RILPL2 RIN2 RIN3 RNASE6 RNASET2 RNF122 RNF144B RNF149 RNF20 RNF213 RNPEP RPA2 RPS2 RPS6KA1 RRM2B RTTN RUNX2 S100A11 SAT1 SCAMP2 SCIN SDCBP SEC24C SELPLG SERPINA1 SERPINB9 SERPINB9P1 SERPINF1 SFMBT2 SGK1 SGPP1 SH2B3 SIGLEC14 SIPA1L2 SIRPB1 SKAP2 SLA SLC12A6 SLC15A4 SLC16A3 SLC1A5 SLC25A37 SLC26A2 SLC2A5 SLC35A3 SLC43A2 SLC50A1 SLC7A7 SLC9A9 SLCO2B1 SMAD3 SMAP2 SNX29 SNX9 SOAT1 SOCS6 SORL1 SP100 SP140 SP140L SP3 SPATA13 SPHK1 SPI1 SPIDR SPN SPP1 SPRED1 SPTLC2 SRGAP1 SRGAP2 SRGAP2B SRGN SRRM2 ST6GAL1 ST6GALNAC3 ST8SIA4 STAB1 STAMBPL1 STK10 STK17B STK38L STK4 SUSD3 SUSD6 SWAP70 SYAP1 SYK SYNDIG1 SYNE4 SYNPO2L SYTL3 TAB3 TAL1 TBC1D14 TBC1D22A TBXAS1 TCF12 TCOF1 TET2 TFEC TGFBI TGFBR1 THEMIS2 TLN2 TLR1 TLR2 TLR3 TLR4 TLR6 TM6SF1 TMC8 TMED5 TMEM106A TNF TNFAIP8L3 TNFRSF11A TNFRSF12A TNFRSF13C TPD52L2 TPM3P9 TRA2B TRAF6 TREM2 TREML1 TRIB1 TSPYL5 TSR1 TXLNB TYROBP UBAC2 UBE2E2 UBXN11 UCP2 UGCG USP15 USP53 USP6 UTP14A VAMP8 VASH1 VAV1 VHL VMO1 VMP1 VSIG4 WASF2 WDFY4 WDR1 WDR91 XAF1 XIRP1 YIPF1 ZBTB1 ZBTB21 ZCCHC6 ZCCHC8 ZFP36L2 ZMYND15 ZNF143 ZNF217 ZNF267 ZNF3 ZNF490 ZNF655 ZNF700 ZNF805 ZNRF2 ZSWIM6 4 | Neuro_Exc NA ABCC8 ABI2 ABLIM2 ABR ACSL3 ACTB ACTG1 ACTN1 ACTR2 ADAM23 ADAMTS19 ADCY1 ADCY2 ADD2 ADGRB3 ADGRL2 AEBP2 AES AFF3 AGBL4 AHI1 AIG1 AK5 AKAP11 ALCAM ALDOA ALOX12P2 AMPH ANKRD17 ANKRD20A5P ANKRD36B ANKS1B ANO3 ANO5 APBA2 APBB1 APLP1 APLP2 APP ARAP2 ARF1 ARHGAP10 ARHGAP21 ARHGAP26 ARHGAP32 ARHGAP44 ARHGEF7 ARID1B ARL15 ARL4C ARL6IP5 ARNT2 ARNTL2 ARPP19 ARPP21 ASAP1 ASIC2 ASTN2 ATCAY ATL1 ATP1A1 ATP1B1 ATP1B3 ATP2A2 ATP2B1 ATP2B2 ATP2C1 ATP6AP1 ATP6AP2 ATP6V0A1 ATP6V0B ATP6V1A ATP6V1B2 ATP6V1E1 ATP8A2 ATP8B1 ATP9A ATRNL1 ATXN1 ATXN7L3B AUTS2 B4GAT1 BAALC BACH2 BAIAP2 BASP1 BCL11A BCL11B BDP1 BEX1 BEX2 BEX4 BICC1 BICD1 BLCAP BMPER BNIP3 BRAF BRINP1 BRINP2 BRINP3 BSN BTBD9 C11orf80 C11orf87 C16orf45 C1orf115 C8orf34 CA10 CA11 CABP1 CACNA1A CACNA1B CACNA1C CACNA1E CACNA2D1 CACNA2D3 CACNB4 CACNG3 CACNG8 CADM3 CADPS CADPS2 CALM1 CALM3 CAMK1D CAMK2A CAMK2B CAMK2D CAMK2G CAMK2N1 CAMKK1 CAMKK2 CAMKV CAMTA1 CAP2 CBLN2 CCDC136 CCDC3 CCDC30 CCK CCNI CCSER1 CDC14B CDH10 CDH12 CDH13 CDH2 CDH20 CDH22 CDH8 CDH9 CDK14 CDK5R1 CDKL5 CELF2 CELF4 CELF5 CEMIP CEND1 CEP112 CEP126 CERS6 CFL1 CHD5 CHGA CHGB CHL1 CHN1 CHRM2 CHRM3 CHSY3 CIT CKB CKMT1B CLCN4 CLEC16A CLMN CLSTN1 CLSTN2 CLSTN3 CLTA CLTC CLU CNKSR2 CNRIP1 CNTN3 CNTN4 CNTN5 CNTNAP1 CNTNAP2 CNTNAP5 COL11A1 COL24A1 COL5A2 CORO6 COX4I1 COX5B COX6C COX7C CPE CPLX1 CPLX2 CPNE4 CPNE5 CREG2 CRYM CSGALNACT1 CSMD1 CSMD3 CSRNP3 CTDSPL CTNNA2 CTNNAL1 CTNNB1 CTSB CTTNBP2 CUX1 CUX2 CYP46A1 CYTH1 DAB1 DACH1 DAPK1 DCAF6 DCC DCLK1 DCLK2 DDX24 DGCR5 DGKB DGKG DGKH DGKI DGKZ DIAPH2 DIP2A DIRAS2 DKK3 DLC1 DLG2 DLGAP1 DLGAP1-AS4 DLGAP2 DLGAP4 DMD DMTN DNAJA1 DNAJC6 DNM1 DOCK4 DOK6 DPP10 DPY19L1 DPY19L2P1 DPYSL2 DSCAM DSCAML1 DSTN DYNC1H1 DYNC1I1 DYNC2H1 DYNLL1 DYNLL2 DZIP3 EEF1A2 EFNA5 EFR3A EGFEM1P EGR1 EID1 EIF1 EIF4A2 EIF4G2 ELAVL2 ELAVL4 ELL2 ELMOD1 EML6 ENC1 ENO1 ENO2 ENOX1 ENSA EPB41L1 EPB41L2 EPB41L3 EPHA3 EPHA4 EPHA5 EPHA6 EPHB6 ERC2 ETS2 ETV5 EVL EXOC4 EXOC6 EXT1 EXTL2 EYA4 FAIM2 FAM13A FAM13B FAM155A FAM168B FAM189A1 FAM19A1 FAM19A2 FAM217B FAM49A FAM81A FARP1 FARS2 FAT3 FBXL16 FBXL2 FBXW7 FEZ1 FGF12 FGFR1 FHL1 FHOD3 FLRT2 FMN1 FMN2 FOCAD FOXP1 FOXP2 FRAS1 FRMD4A FRMPD4 FRRS1L FRY FSTL4 FTH1 FUT9 FZD3 G3BP2 GABARAPL1 GABARAPL2 GABBR2 GABRA1 GABRA2 GABRB1 GABRB2 GABRB3 GABRD GABRG2 GABRG3 GALNT14 GALNT18 GAP43 GAPDH GARNL3 GAS7 GCC2 GDA GDAP1 GDI1 GFOD1 GHITM GHR GLCCI1 GLIS3 GLRB GLS GNAL GNAO1 GNAS GNB1 GNB5 GNG2 GNG7 GNPTAB GOLGA8A GOT1 GPC1 GPC6 GPR158 GRAMD1B GRIA1 GRIA2 GRIA3 GRIA4 GRIK3 GRIK4 GRIN1 GRIN2A GRIN2B GRIN3A GRINA GRIP1 GRM3 GRM5 GRM7 GRM8 GSG1L GUCY1A2 GUK1 GULP1 HCN1 HDAC9 HECW1 HERC1 HINT1 HIVEP2 HIVEP3 HLF HNRNPA2B1 HNRNPDL HNRNPK HOMER1 HPCAL1 HPSE2 HS3ST2 HS3ST4 HS3ST5 HS6ST2 HS6ST3 HSP90AA1 HSP90AB1 HSP90B1 HSPA12A HSPA8 HSPH1 HTR1E HTR2A HTR2C ICA1L IDS IL1RAPL2 ILDR2 INA INPP4B INPP5F IPCEF1 IQSEC1 ITGA8 ITGB8 ITM2B ITM2C ITPK1 ITPR1 ITPR2 KALRN KCNA2 KCNAB2 KCNB1 KCNB2 KCNC2 KCND3 KCNH1 KCNH3 KCNH5 KCNH7 KCNH8 KCNIP1 KCNIP4 KCNJ6 KCNMA1 KCNMB4 KCNQ2 KCNQ3 KCNQ5 KCNT1 KCNT2 KCTD1 KCTD16 KCTD8 KHDRBS2 KHDRBS3 KIAA0319 KIAA0513 KIAA0930 KIAA1107 KIAA1109 KIAA1211L KIAA1217 KIAA1549L KIF1A KIF21A KIF3A KIF3C KIF5A KIF5C KIFAP3 KIFC2 KIRREL3 KLC1 KLHL32 KLHL5 KSR2 LAMA2 LAMA4 LARP1B LDB2 LDHB LHFPL3 LIN7A LINC-PINT LINC00507 LINC00599 LINC00632 LINGO1 LINGO2 LMO3 LMO4 LMO7 LMTK2 LONRF2 LPCAT4 LRFN2 LRFN5 LRP1B LRRC28 LRRC4C LRRC7 LRRC8B LRRFIP1 LRRK1 LRRK2 LRRN2 LRRTM3 LRRTM4 LSAMP LUZP2 LY86-AS1 MACROD2 MAGI1 MAGI2 MAGI3 MAN1A1 MAN1A2 MAP1A MAP1B MAP1LC3A MAP2 MAP2K1 MAP3K13 MAP3K5 MAP7D2 MAP9 MAPK1 MAPK10 MAPK4 MAPK9 MAPRE2 MARK1 MAST3 MAST4 MBOAT2 MCF2L2 MCHR2 MCTP1 MDGA2 MDH1 MED12L MED13L MEF2A MEF2C MEG3 MEG8 MEIS2 MFSD6 MGAT4C MGAT5 MGLL MGST3 MIAT MICAL2 MICU1 MIPOL1 MIR124-2HG MKL2 MLIP MLLT3 MMP16 MNAT1 MOAP1 MORF4L1 MORF4L2 MPHOSPH8 MPP6 MPRIP MT3 MTCH1 MTURN MTUS2 MYH10 MYO16 MYO5A MYRIP MYT1L NAP1L1 NAP1L2 NAP1L3 NAPB NAPEPLD NAT8L NAV3 NBEA NCALD NCAM2 NCDN NCEH1 NCKAP1 NDFIP1 NDFIP2 NDRG4 NDST3 NDUFA1 NDUFA10 NDUFA4 NDUFB2 NDUFS1 NDUFS2 NDUFV1 NECAB1 NEDD4L NEFL NEFM NEGR1 NEK10 NELL1 NELL2 NETO1 NFAT5 NFIB NFIX NGEF NIN NIPAL2 NISCH NKAIN2 NLGN1 NLGN4Y NLK NOL4 NPAS2 NPTN NPTX1 NPTXR NR2F1 NR2F1-AS1 NR3C1 NR3C2 NR4A2 NRCAM NREP NRG1 NRG3 NRGN NRN1 NRSN1 NRXN1 NSF NTNG1 NTNG2 NTRK2 NTRK3 NUAK1 NUCKS1 NUDCD3 NWD2 NYAP2 OCIAD1 OIP5-AS1 OLFM1 OLFM3 OPCML OPTN OSBP2 OSBPL3 OSBPL6 OXR1 PACRG PACSIN1 PAFAH1B1 PAK1 PAK3 PAM PARM1 PART1 PBX1 PCDH10 PCDH11X PCDH11Y PCDH17 PCDH7 PCDH9 PCLO PCMT1 PCP4 PCSK1 PCSK2 PDE10A PDE1A PDE1C PDE2A PDE3A PDE4D PDE7B PDE8B PDP1 PDS5B PDZD2 PDZRN3 PDZRN4 PEA15 PEBP1 PEX5L PFDN5 PGK1 PGM2L1 PHACTR1 PHACTR2 PHYHIP PI4KA PID1 PIK3R1 PJA2 PKD1 PKM PKNOX2 PLAGL1 PLCB1 PLCH1 PLCL2 PLCXD3 PLD3 PLD5 PLEKHA1 PLEKHA5 PLEKHA6 PLEKHB2 PLEKHH2 PLXNA2 PLXNA4 PNMA2 POU6F2 PPA2 PPFIA2 PPFIBP1 PPIA PPM1E PPM1L PPP2R1A PPP2R2C PPP2R5C PPP3CA PPP3CB PRDM2 PREPL PRICKLE1 PRICKLE2 PRKAG2 PRKAR1A PRKAR1B PRKAR2B PRKCB PRKCE PRKD1 PRKG1 PRMT8 PRNP PRR16 PRRC2B PSAP PTCHD4 PTEN PTK2B PTPN13 PTPN5 PTPRD PTPRG PTPRK PTPRN PTPRN2 PTPRO PTPRR PTPRT PWAR6 R3HDM1 RAB11FIP4 RAB2A RAB3A RAB3B RAB6B RABGAP1 RAC1 RAD9A RALGPS2 RALYL RANBP17 RANGAP1 RAP1GAP RAP1GAP2 RAP1GDS1 RAPGEF2 RAPGEF4 RAPGEF5 RARB RASA2 RASAL2 RASGEF1C RASGRF1 RASGRF2 RASGRP1 RBFOX1 RBFOX2 RBM5 RBMS1 RCAN2 REEP2 REEP5 RFTN1 RFX3 RGS12 RGS4 RGS6 RGS7 RHBDD2 RHOBTB2 RIMS2 RIMS3 RIT2 RNF11 RNF144A RNF145 RNF157 RNF187 ROBO2 ROBO3 ROCK2 RORA RORB RPH3A RPL13 RPL13A RPL15 RPL21 RPL23 RPL27 RPL3 RPL31 RPL32 RPL34 RPL35 RPL37 RPL37A RPL38 RPLP1 RPS12 RPS14 RPS15 RPS18 RPS19 RPS24 RPS27 RPS27A RPS28 RPS4X RPS6 RPS6KC1 RPS8 RSRP1 RTF1 RTN1 RTN3 RTN4 RUFY3 RUNDC3A RUNDC3B RXFP1 RYR2 RYR3 SAMD12 SARAF SATB1 SATB2 SCAI SCAMP5 SCG2 SCG5 SCN1A SCN1B SCN2A SCN3A SCN3B SCN8A SCRN1 SDK1 SEC62 SEMA3E SEMA5B SEMA6D SERINC1 SERINC3 SERPINE2 SERPINI1 SETBP1 SEZ6L SEZ6L2 SGCD SH3GL2 SH3RF3 SHANK2 SHC3 SHISA9 SIK2 SIPA1L1 SIRPA SKP1 SLC12A5 SLC17A7 SLC22A10 SLC22A17 SLC23A2 SLC24A2 SLC24A3 SLC25A3 SLC2A13 SLC30A3 SLC35F1 SLC35F3 SLC38A1 SLC38A11 SLC39A10 SLC39A11 SLC44A5 SLC4A10 SLC6A17 SLC6A7 SLC8A1 SLF1 SLIT1 SLIT2 SLIT3 SMARCA2 SMPD3 SNAP25 SNCA SNCB SNED1 SNHG14 SNTG1 SNU13 SOBP SOD1 SORBS1 SORBS2 SORCS1 SORCS2 SORCS3 SORL1 SOX5 SPAG16 SPARCL1 SPATS2 SPATS2L SPOCK1 SPOCK2 SPON1 SPTBN1 SPTBN4 SRGAP3 SRP14 SRRM3 SRRM4 SRSF11 SRSF5 SSBP2 SSBP3 SSX2IP ST6GALNAC5 ST8SIA1 ST8SIA3 ST8SIA5 STAU2 STMN1 STMN2 STMN3 STMN4 STOX2 STRBP STX1A STXBP1 STXBP5 STXBP5L STXBP6 SUGP2 SULT4A1 SUSD4 SV2A SV2B SYBU SYN1 SYN2 SYN3 SYNGR1 SYNJ1 SYNJ2 SYNPO2 SYNPR SYP SYT1 SYT11 SYT13 SYT16 SYT4 SYT7 SYTL2 TACC1 TAGLN3 TANC2 TARBP1 TASP1 TCEAL2 TENM2 TENM3 TENM4 TERF2IP TESC TESPA1 THEMIS THRB THSD7A THY1 TLE4 TLK1 TLL1 TLN2 TMEFF2 TMEM108 TMEM130 TMEM131 TMEM132B TMEM132D TMEM155 TMEM160 TMEM178A TMEM178B TMEM232 TMEM30A TMEM59L TMOD2 TMSB10 TMSB4X TOLLIP TOMM20 TOX TPI1 TPM1 TPPP TPST1 TRERF1 TRHDE TRIM37 TRIM44 TRIM9 TRPC3 TRPC5 TRPM2 TRPM3 TSC22D1 TSHZ2 TSHZ3 TSPAN13 TSPAN7 TSPYL1 TSPYL2 TSPYL4 TTC3 TTC31 TTC39C TTLL11 TUBA1A TUBA1B TUBA4A TUBB2A UBB UBC UBL3 UCHL1 UGGT2 UNC13A UNC13C UNC5C UNC5D UNC79 UNC80 UQCRB UQCRH USP11 USP22 USP25 UST VAV3 VGLL4 VPS13A VPS13D VPS41 VSNL1 VWC2L WASF1 WBP2 WDFY3 WDR17 WSB1 XKR4 XKR6 XYLT1 YPEL3 YWHAB YWHAE YWHAG YWHAH YWHAZ ZBTB16 ZBTB18 ZFAND5 ZFPM2 ZFYVE28 ZMAT4 ZMYND8 ZNF365 ZNF385B ZNF385D ZNF483 ZNF704 ZNF91 5 | Neuro_Inb NA AAK1 ABAT ABI1 ABLIM2 ABR ACSL6 ACTG1 ADAM22 ADAMTS19 ADAMTSL3 ADARB2 ADCY1 ADCY2 ADCY8 ADGRB3 ADGRL2 ADK ADRA1A AEBP2 AES AFAP1 AFF2 AFF3 AHI1 AIG1 AK5 AKAP6 ALCAM ALDOA ALK AMMECR1 AMPH ANK1 ANKH ANKRD12 ANKRD26 ANKRD36C ANKS1A ANO4 AP1S2 APBA1 APLP2 APP ARHGAP20 ARHGAP44 ARHGAP5 ARHGEF3 ARID5B ARL15 ARL4C ARL6IP1 ARNT2 ASIC2 ASTN1 ASTN2 ATCAY ATG7 ATP1A1 ATP1A3 ATP1B1 ATP6V0A1 ATP6V1A ATP6V1B2 ATP8A2 ATRNL1 ATRX AUH AUTS2 B4GALT6 BACH1 BACH2 BCL11A BCL11B BCL2 BEND6 BEX1 BEX2 BICD1 BLCAP BRINP2 BTBD11 C16orf45 C8orf34 CA8 CACNA1A CACNA1B CACNA1C CACNA1D CACNA1E CACNA2D1 CACNA2D3 CACNB2 CACNB4 CACNG2 CACNG3 CACNG8 CADM2 CADPS CADPS2 CALB1 CALB2 CALM3 CALN1 CAMK2D CAMK2N1 CAMKV CAMTA1 CANX CAP2 CBLN4 CCDC136 CCDC91 CCK CCNI CCSER1 CDC5L CDH10 CDH12 CDH13 CDH4 CDH8 CDH9 CDHR3 CDK14 CDK8 CDR2 CELF4 CELF5 CEMIP CEP112 CERS6 CHD5 CHL1 CHRM3 CHRNA7 CHST11 CHSY3 CIT CLEC16A CLIP4 CLSTN2 CLSTN3 CLTC CLVS1 CLVS2 CNR1 CNTN3 CNTN4 CNTN5 CNTN6 CNTNAP2 CNTNAP4 CNTNAP5 COG5 COL11A1 COL16A1 COL19A1 COL21A1 COL25A1 COL5A2 CORO6 COX4I1 CPLX1 CPLX2 CRH CSMD1 CSMD3 CSRNP3 CTNNA2 CTTNBP2 CUX2 CXCL14 CYFIP2 CYP46A1 DAAM1 DAB1 DAPK1 DCC DCLK1 DDX24 DENND5B DGKB DGKD DGKG DKK3 DLGAP1 DLGAP2 DLX1 DMD DNER DNM1 DOCK10 DOCK3 DOCK9 DOK5 DOK6 DOPEY1 DPP10 DPP6 DSCAM DSCAML1 DYNLL2 EDIL3 EEA1 EEPD1 EFR3B EGFEM1P EGFR ELAVL2 ELAVL3 ELAVL4 ELMOD1 EML6 ENOX1 ENTPD3 EPB41L1 EPB41L3 EPHA3 EPHA5 EPHA6 EPHB6 ERBB4 ERC2 ESRRG ETV6 EVL EXT1 EYA4 FAIM2 FAM110B FAM135B FAM168A FAM189A1 FAM19A2 FAM19A5 FAM49A FAR2 FARP1 FAT1 FBXL7 FGF12 FGF13 FGF14 FHOD3 FLRT2 FMN1 FNDC3A FOXG1 FRAS1 FREM1 FRMD4A FRMPD4 FRRS1L FRY FSTL5 FUT9 FXYD6 G3BP2 GABBR1 GABBR2 GABRA1 GABRB1 GABRB2 GABRD GABRG2 GABRG3 GAD1 GAD2 GALNT13 GALNT18 GAPDH GARNL3 GAS7 GFOD1 GIT2 GLG1 GNAL GNAS GNB1 GNG4 GOLIM4 GOT1 GPC6 GPHN GPR137C GPR155 GPR158 GRIA1 GRIA2 GRIA3 GRIA4 GRID1 GRID2 GRIK1 GRIK2 GRIK3 GRIN1 GRIN2A GRIN2B GRIN3A GRIP1 GRIP2 GRM5 GRM7 GRM8 GULP1 HCN1 HDAC9 HECTD2 HECW2 HIVEP3 HMBOX1 HOOK3 HPCAL1 HPSE2 HS3ST5 HS6ST3 HSD17B12 HSP90AA1 HSP90AB1 HSP90B1 HTR1E IDS IGF1 IGSF11 IL1RAPL1 IL1RAPL2 INPP4A INPP4B INPP5F ITFG1 ITM2B ITM2C ITPR1 ITSN1 KAZN KCNAB1 KCNAB3 KCNB2 KCNC1 KCNC2 KCND3 KCNH1 KCNH5 KCNH7 KCNIP1 KCNIP4 KCNJ3 KCNJ6 KCNMA1 KCNMB4 KCNQ1OT1 KCNQ3 KCNQ5 KCNT1 KCNT2 KCTD16 KHDRBS2 KHDRBS3 KIAA1107 KIAA1109 KIAA1211 KIAA1217 KIAA1324 KIDINS220 KIF1A KIF21A KIF26B KIF3A KIFAP3 KIRREL3 KIT KLC1 KLF12 KLF3-AS1 KLHL5 KMT2A L3MBTL4 LAMP5 LANCL1 LARP1 LHFPL3 LIMCH1 LIN7A LINC00461 LINC00599 LINC01197 LINGO2 LONRF2 LPCAT4 LRFN5 LRP1B LRP8 LRRC39 LRRC4C LRRC7 LRRC8B LRRFIP1 LRRFIP2 LRRN3 LRRTM3 LRRTM4 LSAMP LUZP1 LUZP2 MACROD2 MAF MAFB MAGED1 MAGI1 MAGI3 MAML3 MAN1A1 MAN1A2 MAP1A MAP1B MAP2 MAP3K5 MAP7D2 MAP9 MAPK4 MARK1 MAST4 MBOAT2 MCC MCTP1 MDGA2 MDH1 MEF2C MEG3 MEG8 METTL15 MGAT4C MGAT5 MGEA5 MIAT MICU1 MIR99AHG MLLT3 MMP16 MORF4L2 MPDZ MPHOSPH8 MPP6 MPPED1 MTSS1 MTUS1 MTUS2 MYCBP2 MYO16 MYRIP MYT1L NALCN NAP1L1 NAP1L3 NAPB NAV2 NBEA NCALD NCAM1 NCAM2 NCOA2 NDFIP1 NDRG4 NDST3 NDUFA4 NEAT1 NEBL NECAB2 NEDD4L NEGR1 NELL1 NETO1 NETO2 NF1 NFIB NHS NIPAL3 NKAIN3 NLGN1 NLGN4Y NMNAT2 NPAS1 NPAS2 NPAS3 NPTN NPTXR NPY NR2F1-AS1 NR2F2 NR2F2-AS1 NR3C2 NRG1 NRG3 NRIP3 NRXN1 NRXN2 NRXN3 NSF NSG2 NTN4 NTNG1 NTRK2 NTRK3 NXPH1 NXPH2 NYAP2 ODF2L OIP5-AS1 OLFM3 OPCML OSBPL1A OSBPL3 OSBPL6 OSBPL8 OXCT1 OXR1 PACRG PAIP2 PAK3 PALLD PAM PARM1 PCDH10 PCDH11X PCDH11Y PCDH15 PCDH17 PCDH7 PCLO PCP4 PCSK2 PDE1C PDE4B PDE7B PDE8B PDGFD PDS5B PDXK PDZRN3 PDZRN4 PEBP1 PEG3 PENK PEX5L PGM2L1 PHF14 PHF20L1 PHTF1 PHYHIPL PID1 PIP5K1B PITPNC1 PJA2 PKN2 PKNOX2 PKP2 PLCB1 PLCB4 PLCE1 PLCH1 PLCXD3 PLD3 PLD5 PLEKHA1 PLEKHA5 PLPPR1 PLPPR4 PLS3 PLXNA4 PNMA2 PPARGC1A PPIP5K2 PPM1E PPM1K PRELID2 PREPL PRICKLE2 PRKAR2A PRKAR2B PRKCA PRKCB PRKCE PRKD1 PRKG1 PRNP PROX1 PRR16 PTCHD4 PTPN13 PTPN4 PTPRB PTPRE PTPRG PTPRJ PTPRM PTPRN2 PTPRO PTPRS PTPRT PVALB RAB2A RAB3B RAB3C RAB3IP RAB6B RALGAPA2 RANBP17 RAPGEF4 RARB RASA1 RASAL2 RASGRF2 RASSF8 RBFOX1 RBFOX2 RBMS3 RCAN2 REEP1 REEP5 RELN REPS1 RERG REV3L RGS12 RGS6 RGS7 RGS7BP RIMBP2 RIMS2 RNF150 RNF157 RNF175 RNF180 RNF24 RNPC3 ROBO1 ROBO2 RORA RPH3A RPL34 RPL37A RPS6KA2 RPS6KA3 RTF1 RTN3 RUNDC3B RUNX1T1 RYR1 RYR2 RYR3 SAMD12 SAMD4A SARAF SAT1 SCAI SCAMP5 SCG2 SCG5 SCLT1 SCN1A SCN3A SCN8A SDK1 SEMA6D SERINC1 SERPINI1 SETBP1 SEZ6 SEZ6L SEZ6L2 SGCD SGK1 SH3GL3 SH3KBP1 SH3PXD2A SH3RF3 SHANK2 SHC3 SHISA6 SHISA8 SHISA9 SIPA1L1 SLC12A5 SLC22A17 SLC24A3 SLC25A12 SLC2A13 SLC35F1 SLC38A1 SLC44A5 SLC4A10 SLC4A8 SLC6A1 SLC6A17 SLC8A1 SLC9A9 SLCO3A1 SLIT2 SMARCA2 SMYD3 SNED1 SNHG14 SNTG1 SOBP SORBS2 SORCS1 SORCS3 SOX2-OT SOX6 SPAG16 SPARCL1 SPATS2L SPECC1 SPHKAP SPIN1 SPOCK1 SPOCK2 SPOCK3 SPTAN1 SPTBN4 SRGAP1 SRRM3 SRRM4 SSBP2 SST ST6GALNAC5 ST8SIA1 STARD13 STXBP6 SULT4A1 SUPT3H SUSD4 SV2A SV2C SYN2 SYN3 SYNPR SYP SYT1 SYT11 SYT14 SYT15 TAC1 TAC3 TAOK3 TCEAL2 TCF4 TENM1 TENM2 TENM3 TENM4 TERF2IP TFDP2 THRB THSD7A THY1 TIAM1 TIMP2 TLK1 TLN2 TMEFF2 TMEM108 TMEM130 TMEM132B TMEM132C TMEM132D TMEM178B TMEM232 TMEM59L TMSB4X TMTC1 TMTC2 TNIK TNRC6A TOX TOX2 TOX3 TPST1 TRAF3IP2-AS1 TRANK1 TRHDE TRIO TRPC3 TRPC5 TRPS1 TSC22D1 TSHZ2 TSPAN7 TSPYL2 TTBK2 TTC28 TTN TTTY14 TUBA1A TUBB2A UCHL1 UNC13C UNC5C UNC5D UPP1 USP11 USP22 VIP VSNL1 VSTM2A VWA8 VWC2 VWC2L WASF3 WIF1 WLS WNK2 WSB1 WWP1 XKR4 YWHAB ZBTB16 ZCCHC11 ZEB1 ZEB2 ZMAT4 ZNF292 ZNF385B ZNF385D ZNF483 ZNF536 ZNF608 ZYG11B 6 | Oligo NA AATK ABCA2 ABCA8 ABCG1 ABHD17B ABHD6 ACER3 ACTL6A ACVR1C ADCY5 ADIPOR2 ADSS AFG3L1P AFMID AGA AGAP1 AGPAT4 AGPAT4-IT1 AGTPBP1 AHR AIF1L AK5 AKAP9 AKTIP ALAD ALCAM AMD1 AMER2 AMPD3 ANAPC5 ANGPTL2 ANK3 ANKIB1 ANKRD12 ANKRD18A ANKRD28 ANKRD36C ANKRD40 ANKRD65 ANKS1B ANKS6 ANLN ANO4 ANP32C APBA3 APBB1 APBB2 APIP APLP1 APOD APP ARAP2 ARHGAP21 ARHGEF37 ARMC1 ASB13 ASPA ATE1 ATG3 ATG4C ATP10B ATP8A1 AUTS2 AZGP1 B3GNT7 BACE1 BAZ2B BBX BCAS1 BCHE BEST1 BEST3 BMP8B BNIP3L BOD1L1 BOK BRCA1 BTBD16 BTBD3 BVES C10orf90 C1GALT1 CA10 CA14 CA2 CACNA2D1 CACNG4 CALD1 CAPN13 CAPN3 CARNS1 CASP8AP2 CBR1 CCDC121 CCDC160 CCDC25 CCDC88A CCNE2 CCP110 CD22 CD2BP2 CD9 CDC42BPA CDC42EP1 CDC42EP2 CDC42SE2 CDH1 CDH19 CDH20 CDK17 CDK18 CDK19 CDR2L CENPB CEP97 CERCAM CFAP20 CFL2 CHADL CHCHD4 CHD1L CHN2 CHST6 CLASP2 CLCA4 CLCN3 CLCN4 CLDN11 CLDND1 CLIP2 CLK1 CLMN CMTM5 CNDP1 CNP CNTN2 CNTNAP4 COBL COL16A1 COL4A5 COL8A1 COL9A1 COL9A2 COL9A3 COLGALT2 COMMD3 CPNE2 CPOX CPPED1 CRADD CREB5 CRYAB CSE1L CSRP1 CTNNA3 CUEDC1 CUTC CYB5R2 DAAM2 DDX17 DHCR24 DICER1 DIMT1 DIP2B DIXDC1 DLC1 DLG1 DLG2 DLL1 DMRT2 DNAJB2 DNAJC21 DNAJC22 DNAJC6 DNM3 DOCK10 DOCK5 DPF2 DPYD DPYSL2 DSCAML1 DST DTD2 DTNB DUSP10 DUSP16 DUSP7 DYNC1I2 DYNC1LI2 DYSF EBAG9 ECHDC1 EDIL3 EFS ELMO1 ELOVL1 ELP5 EMC3-AS1 ENDOD1 ENOPH1 ENOSF1 ENOX2 ENPP2 ENPP4 ENPP6 EPN2 ERBB3 ERMN ERMP1 EVI2A EXOC5 EXOC6B FA2H FAF1 FAM107B FAM122B FAM124A FAM126A FAM131B FAM13C FAM177A1 FAM192A FAM218A FAM219A FAM221A FAM222A FAM229B FAM69A FAM84B FANCB FANCL FAR1 FBXL5 FBXL7 FBXO32 FBXO7 FCHO1 FEZ1 FGF1 FHIT FIS1 FKBP7 FLNC FMNL2 FNBP1 FOLH1 FOLH1B FOXN2 FOXO4 FRK FRMD4B FRMD5 FRYL FUT8 FXR1 GAB1 GAB2 GALNT5 GALNT6 GALR1 GAS7 GCA GDE1 GDNF GJB1 GJC2 GLTP GNAI1 GNAZ GOLGA4 GOLGA7 GPD1 GPM6B GPR17 GPR37 GPR62 GPRC5B GPSM2 GREB1L GRHPR GRM3 GSKIP GSN GZF1 HAGLR HAPLN2 HAUS2 HBS1L HDAC11 HEBP1 HECW2 HHIP HHIP-AS1 HIP1 HIPK2 HIST1H2AC HNRNPA2B1 HPN HS3ST5 HSD11B1 HSD17B3 HSD17B4 HSP90AA1 HSPA2 HTATIP2 ICK IGSF8 IKZF2 IKZF5 IL1RAPL1 INPP1 INSL3 IP6K3 IPO13 ITGA2 ITGAE ITGB8 JAM3 KAT2B KATNAL1 KBTBD2 KCNH8 KCNJ2 KCNK10 KCNMB4 KCTD4 KIAA1324L KIF13A KIF13B KIF1B KIF1C KIF2A KIF6 KIRREL3 KIZ KLHL2 KLHL32 KLHL4 KLK6 KLRC2 KLRC3 KMT2E KNOP1 LACC1 LACTB2 LAMP2 LANCL1 LARP6 LAYN LDB3 LDLRAD4 LDLRAP1 LGI3 LGR5 LHFPL3 LHPP LIMCH1 LIN54 LINC00320 LINC00844 LINC00909 LINC01105 LPAR1 LPGAT1 LRP2 LRP6 LRRC63 LRRC8D LTN1 MAG MAL MAN2A1 MAP4K4 MAP4K5 MAP6D1 MAP7 MAP7D1 MAPK8IP1 MARCKSL1 MATN2 MBNL2 MBP MCM7 MEGF11 MEX3A MEX3C MGA MIB1 MIF4GD MIPEP MMACHC MND1 MOB3B MOBP MOG MOSPD2 MRPL52 MTF1 MTFR1 MTMR2 MTRR MTURN MTUS1 MUSK MVB12B MXI1 MYO1D MYO6 MYOT MYRF NAALADL2 NACAD NAP1L6 NAPEPLD NBR1 NCAM2 NCAPD2 NCKAP5 NDE1 NDRG1 NDUFS7 NEAT1 NEK3 NEK7 NENF NFASC NFYA NFYB NIFK-AS1 NINJ2 NIPA1 NIPAL3 NKAIN1 NKAIN2 NKTR NKX2-2 NKX6-2 NLK NPAS3 NPC1 NR0B1 NSDHL NT5DC1 NUCKS1 NUDT16 NXPE3 OLIG1 OLIG2 OMG OPALIN OR2L13 OSBPL1A OTUD6B OTUD7B PAIP2B PALB2 PALM2 PAPSS1 PAQR6 PAXBP1 PAXBP1-AS1 PCBP4 PCDH15 PCDH9 PCGF6 PCNA PCSK6 PDE1A PDE1C PDE4B PDE6B PDE8A PDGFRA PDHB PDIK1L PEPD PEX16 PEX5L PGM3 PHACTR3 PHIP PHLDA3 PHLDB1 PHLPP1 PHYHIPL PIEZO2 PIGN PIK3C2B PIP4K2A PKP4 PLA2G16 PLCL1 PLD1 PLEKHB1 PLEKHG3 PLEKHH1 PLEKHH2 PLLP PLP1 PLXDC2 PMP22 PNPT1 POGK POLR1B POPDC3 POU2AF1 PPA1 PPM1B PPM1D PPP1R14A PPP1R16B PPP1R21 PPP1R8 PPP1R9A PPP2R2A PPP2R2B PPP2R3A PPP6C PRDM8 PRKCQ PRKCQ-AS1 PRR18 PRR5L PRRC2C PRRG1 PRUNE2 PSEN1 PTBP2 PTGDS PTK2 PTMA PTP4A2 PTPDC1 PTPN11 PTPRD PTPRD-AS1 PTPRK PWWP2A PXK PYROXD1 QDPR QKI RAB28 RAB33A RAB3IP RAB40B RALA RAP1GDS1 RAPGEF5 RASAL1 RASGRP3 RASSF2 RBM25 RBP7 RBPJ RDX REEP3 RERE RHBDL2 RHOU RICTOR RMND5A RNASE1 RNASEH2A RNF13 RNF130 RNF141 RNF144A RNF220 RPS6KC1 RTKN RTN4 S100B S1PR5 SAMD4B SAP18 SAPCD2 SBDS SCARB2 SCD SCD5 SEC14L5 SECISBP2L SEMA4D SEMA6A SENP2 SERAC1 SERINC5 SET SFRP1 SFT2D1 SFTPC SGK1 SGK2 SGPL1 SH3D19 SH3GL3 SH3PXD2A SH3TC2 SHB SHC4 SHROOM4 SHTN1 SIK3 SIRT2 SLAIN1 SLC12A2 SLC22A15 SLC24A2 SLC35A5 SLC35D2 SLC3A1 SLC44A1 SLC45A3 SLC5A11 SLCO1A2 SLCO3A1 SMIM6 SMOC1 SNHG18 SNRPF SNX1 SNX22 SNX27 SNX30 SNX6 SORT1 SOSTDC1 SOX2-OT SOX3 SOX8 SPATA7 SPDL1 SPECC1 SPG21 SPOCK3 SPP1 SPPL3 SPSB1 SRCIN1 SRD5A3 SRPK2 SRRM1 ST13 ST18 ST3GAL5 ST3GAL6-AS1 STEAP1B STK31 STK39 STMN4 STRN SUGT1 SUN2 SWT1 SYNJ2 TALDO1 TAOK1 TARSL2 TAS2R39 TBC1D15 TBC1D32 TBC1D5 TCF12 TCFL5 TCP11L2 TF TGFB3 THAP5 THBS2 THBS4 TJAP1 TJP1 TJP2 TMC7 TMCC2 TMCC3 TMED4 TMEFF2 TMEM125 TMEM144 TMEM151A TMEM165 TMEM189 TMEM206 TMEM230 TMEM235 TMEM258 TMEM63A TMEM64 TMEM87A TMEM98 TMTC2 TMTC4 TNR TP53INP2 TP53TG5 TPPP TPPP3 TPRN TPTEP1 TRAM1L1 TRIM2 TRIM21 TRIM59 TRIM62 TRMT13 TSEN15 TSPAN15 TSPAN5 TTC23L TTL TTLL7 TTYH2 TUBA1A TUBB4A TULP4 TXNL1 TYMS TYMSOS UBE2E2 UBE4B UGT8 UNC5C URI1 USH1C USP32 UTP15 VAMP3 VEZF1 VRK2 VSTM2B WDPCP WDR20 WDR44 WDR89 WIPF1 WNK1 WRB WSCD1 XYLT1 YBEY YPEL2 YWHAQ ZBTB20 ZBTB6 ZC3H13 ZCCHC24 ZDHHC11 ZDHHC20 ZDHHC9 ZEB2 ZFP3 ZFYVE16 ZGRF1 ZKSCAN1 ZNF146 ZNF175 ZNF24 ZNF268 ZNF271P ZNF281 ZNF415 ZNF488 ZNF536 ZNF559 ZNF565 ZNF572 ZNF576 ZNF577 ZNF585B ZNF607 ZNF652 ZNF664 ZNF682 ZNF708 ZNF728 ZNF738 ZNF826P ZNF841 ZNHIT6 ZSCAN29 ZZZ3 7 | OPC NA ABHD2 ADARB2 ADGRL3 AGAP1 ALCAM APBB2 ASAP1 ASIC4 ASTN2 ATRNL1 BCAN BCAS1 BRINP3 C1orf61 CA10 CASK CCDC50 CD81 CDH20 CHD7 CHL1 CHST11 CMYA5 COBL COL11A1 COL9A1 CSMD1 CSMD3 CSPG5 CTTNBP2 DCC DGKG DOCK10 DPP6 DSCAM DSCAML1 EPN2 FCHSD2 FERMT1 FGF12 FHIT GALNT13 GPC6 GPR17 GRID2 GRIK1 GRM7 HIP1 HTRA1 ITPR2 KAT2B KAZN KCND2 KCNQ1OT1 KIF13A KIF26B KLF12 LHFPL3 LRP1 LRP1B LRRC4C LRRTM4 LSAMP LUZP2 MAML2 MARCKS MDGA2 MEGF11 MMP16 MTSS1 NAALADL2 NAV1 NAV2 NCAM1 NCAM2 NCKAP5 NFIA NKAIN3 NLGN1 NLGN4X NOVA1 NPAS3 NRCAM NRXN1 NTM NXPH1 OLIG1 OLIG2 OPCML OPHN1 PCDH15 PDE4B PDGFRA PDZD2 PDZRN4 PEAK1 PHLPP1 PID1 PLPPR1 PPP1R9A PRKCA PSAP PTPRZ1 QKI REV3L RPL13 SCD5 SCN1A SDC3 SEMA5A SERPINE2 SETD5 SEZ6L SGCD SGK1 SH3D19 SHISA9 SLC24A3 SLC35F1 SMOC1 SNTG1 SNX22 SORCS3 SOX2-OT SOX5 SOX6 SPATA6 TAOK3 TCF12 TMBIM6 TMEM132C TNK2 TNR VCAN WWOX XKR4 XYLT1 ZBTB20 ZEB1 ZNF462 ZSWIM6 -------------------------------------------------------------------------------- /imaging_transcriptomics/errors.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | 4 | # Custom Errors to throw at the user 5 | class InvalidFormatError(Exception): 6 | """Exception raised when the format of one of the input files in not correct. 7 | 8 | Attributes: 9 | errorFile -- file that is not in the correct format. 10 | message -- optional user overridden error message to display. 11 | """ 12 | def __init__( 13 | self, 14 | error_file, 15 | message="The provided file has an invalid format. Please use files " 16 | "in the .nii, .nii.gz format.", 17 | ): 18 | self.error_file = error_file 19 | self.message = message 20 | super().__init__(self.message) 21 | 22 | def __str__(self): 23 | return f"{self.message}" \ 24 | f" The error was caused by the file {self.error_file}." 25 | 26 | 27 | class InvalidSizeError(Exception): 28 | """Exception raised when the size of the images is not correct. 29 | 30 | Attributes: 31 | * errorFile -- file with the wrong size 32 | * size -- size of the input image 33 | * message -- optional user defined error message 34 | """ 35 | def __init__( 36 | self, shape=(182, 218, 182), 37 | message="The provided file has a wrong shape." 38 | ): 39 | self.message = message 40 | self.shape = shape 41 | super().__init__(self.message) 42 | 43 | def __str__(self): 44 | return f"{self.message} The file has shape: {self.shape}" 45 | 46 | 47 | # Checks Decorators 48 | class CheckPath: 49 | """Decorator to check if a path exists. 50 | 51 | In order to run the function decorated the path provided to the function 52 | has to exists, otherwise an error is raised. 53 | 54 | :raises FileNotFoundError: 55 | """ 56 | def __init__(self, function): 57 | self.function = function 58 | 59 | def __call__(self, path, *args, **kwargs): 60 | if not Path(path).absolute().exists(): 61 | raise FileNotFoundError 62 | return self.function(path, *args, **kwargs) 63 | 64 | 65 | class CheckExtension: 66 | """Decorator to check the file extension of the input scan. 67 | 68 | Extension of the imaging scan has to be in NIfTI format (compressed or not) 69 | in order to run the function. 70 | 71 | :raises InvalidFormatError: 72 | """ 73 | def __init__(self, function): 74 | self.function = function 75 | 76 | def __call__(self, path, *args, **kwargs): 77 | imaging_path = Path(path) 78 | if str().join(imaging_path.suffixes) in {".nii", ".nii.gz"}: 79 | return self.function(path, *args, **kwargs) 80 | else: 81 | raise InvalidFormatError(path) 82 | 83 | 84 | class CheckShape: 85 | """Decorator to check the correct matrix shape of the imaging scan. 86 | 87 | Shape of the matrix has to be 182x218x182 in order to run the function, 88 | otherwise raises and error. 89 | 90 | :raises InvalidSizeError: 91 | """ 92 | def __init__(self, function): 93 | self.function = function 94 | 95 | def __call__(self, image, *args, **kwargs): 96 | valid_shapes = [(182, 218, 182), (91, 109, 91)] 97 | if image.shape not in valid_shapes: 98 | raise InvalidSizeError(image.shape) 99 | return self.function(image, *args, **kwargs) 100 | 101 | 102 | class CheckVariance: 103 | """Decorator to check that the variance is in the correct range of values. 104 | 105 | Target variance has to be in the range 0.0-1.0 (equivalent to 0-100%) in 106 | order to run the function. 107 | 108 | :raises ValueError: 109 | """ 110 | def __init__(self, function): 111 | self.function = function 112 | 113 | def __call__(self, target_var, *args, **kwargs): 114 | if target_var < 0.0 or target_var > 1.0: 115 | raise ValueError 116 | return self.function(target_var, *args, **kwargs) 117 | -------------------------------------------------------------------------------- /imaging_transcriptomics/genes.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import logging.config 3 | import yaml 4 | from pathlib import Path 5 | from pyls import pls_regression 6 | from scipy.stats import zscore, norm 7 | from statsmodels.stats.multitest import multipletests 8 | import numpy as np 9 | from collections import OrderedDict 10 | import gseapy 11 | from gseapy.plot import gseaplot 12 | import pandas as pd 13 | from .inputs import get_geneset 14 | 15 | 16 | cfg_file_path = Path(__file__).parent / "log_config.yaml" 17 | with open(cfg_file_path, "r") as config_file: 18 | log_cfg = yaml.safe_load(config_file.read()) 19 | 20 | logging.config.dictConfig(log_cfg) 21 | logger = logging.getLogger("genes") 22 | logger.setLevel(logging.DEBUG) 23 | 24 | 25 | # --------- GENE ANALYSIS --------- # 26 | class GeneResults: 27 | def __init__(self, method, **kwargs): 28 | """Initialize the results of the analysis. Depending on the method 29 | used, the results will have underlying result classes, which account 30 | for the different analysis methods. 31 | 32 | :param str method: the method used for the analysis. 33 | :param kwargs: Additional parameters, for the initialisation. If the 34 | method is "pls" among the kwargs you *MUST* specify the number of 35 | components used, for the initialisation of the pls class. 36 | """ 37 | self.method = method 38 | if self.method == "pls": 39 | self.results = PLSGenes(kwargs.get("n_components")) 40 | elif self.method == "corr": 41 | self.results = CorrGenes(n_iter=kwargs.get("n_iter")) 42 | else: 43 | raise ValueError(f"The method {method} is not supported.") 44 | 45 | @property 46 | def n_genes(self): 47 | return self.results.n_genes 48 | 49 | @property 50 | def genes(self): 51 | if isinstance(self.results, PLSGenes): 52 | return self.results.orig.genes 53 | elif isinstance(self.results, CorrGenes): 54 | return self.results.genes 55 | 56 | @property 57 | def scores(self): 58 | if isinstance(self.results, PLSGenes): 59 | return self.results.orig.weights 60 | elif isinstance(self.results, CorrGenes): 61 | return self.results.corr 62 | 63 | @property 64 | def boot(self): 65 | if isinstance(self.results, PLSGenes): 66 | return self.results.boot.weights 67 | elif isinstance(self.results, CorrGenes): 68 | return self.results.boot_corr 69 | 70 | @property 71 | def pvals(self): 72 | if isinstance(self.results, PLSGenes): 73 | return self.results.boot.pval 74 | elif isinstance(self.results, CorrGenes): 75 | return self.results.pval 76 | 77 | @property 78 | def pvals_corr(self): 79 | if isinstance(self.results, PLSGenes): 80 | return self.results.boot.pval_corr 81 | elif isinstance(self.results, CorrGenes): 82 | return self.results.pval_corr 83 | 84 | 85 | # --------- PLS GENES --------- # 86 | class PLSGenes: 87 | def __init__(self, n_components): 88 | """ Initialize the results of the PLS analysis. The result will 89 | include both the permuted and the original results. The class 90 | contains two subclasses, one for the original results and one for 91 | the bootrapped results. 92 | 93 | :param int n_components: number of components used for the analysis. 94 | """ 95 | self.n_genes = 15633 96 | self.n_components = n_components 97 | self.orig = OrigPLS(n_components, self.n_genes) 98 | self.boot = BootPLS(n_components, self.n_genes) 99 | 100 | def boot_genes(self, imaging_data, permuted_imaging, 101 | scan_data, gene_exp, gene_labels): 102 | """Bootstrapping on the PLS components. 103 | 104 | :param imaging_data: imaging data. Allows the user to specify the 105 | data to use (e.g., with only cortical regions this can be only the 106 | cortical vector, other wise the whole data). 107 | :param permuted_imaging: imaging data permuted. Allows the user to 108 | specify the data to use (e.g., with only cortical regions this can be 109 | only the cortical vector, other wise the whole data). 110 | :param scan_data: Original scam data, not zscored. 111 | :param gene_exp: gene expression data. 112 | :param gene_labels: gene labels. 113 | """ 114 | logger.info("Performing bootstrapping of the genes.") 115 | 116 | def correlate(c1, c2): 117 | """Return the MATLAB style correlation between two vectors.""" 118 | return np.corrcoef(np.hstack((c1, c2)), rowvar=False)[0, 1:] 119 | 120 | _res = pls_regression(gene_exp, imaging_data.reshape( 121 | imaging_data.shape[0], 1), 122 | n_components=self.n_components, 123 | n_boot=0, n_perm=0) 124 | r1 = correlate(_res.get("x_scores"), scan_data.reshape( 125 | scan_data.shape[0], 1)) 126 | _weights = _res.get("x_weights") 127 | _scores = _res.get("x_scores") 128 | for i in range(r1.size): 129 | if r1[i] < 0: 130 | _weights[:, i] *= -1 131 | _scores[:, i] *= -1 132 | for _idx in range(self.n_components): 133 | _sort_weights_indexes = np.argsort(_weights[:, _idx], 134 | kind="mergesort")[::-1] 135 | self.orig.index[_idx, :] = _sort_weights_indexes 136 | self.orig.genes[_idx, :] = gene_labels[:, 0][_sort_weights_indexes] 137 | self.orig.weights[_idx, :] = _weights[:, _idx][ 138 | _sort_weights_indexes] 139 | self.orig.zscored[_idx, :] = zscore(self.orig.weights[_idx, :], 140 | axis=0, 141 | ddof=1) 142 | for _iter in range(1000): 143 | _perm_imaging = permuted_imaging[:, _iter] 144 | _i_results = pls_regression(gene_exp, _perm_imaging.reshape( 145 | _perm_imaging.shape[0], 1), 146 | n_components=self.n_components, 147 | n_boot=0, n_perm=0) 148 | _weights_i = _i_results.get("x_weights") 149 | for _comp in range(self.n_components): 150 | _temp_weights = _weights_i[:, _comp] 151 | _new_weights = _temp_weights[self.orig.index[_comp, :]] 152 | _temp_genes = self.orig.weights[_comp, :] 153 | _corr = correlate( 154 | _temp_genes.reshape(_temp_genes.size, 1), 155 | _new_weights.reshape(_new_weights.shape[0], 1) 156 | ) 157 | if _corr < 0: 158 | _new_weights *= -1 159 | self.boot.weights[_comp, :, _iter] = _new_weights 160 | return 161 | 162 | def compute(self): 163 | """ Compute the p-values of the z-scored weights. 164 | The compute function calculates the zscores based on the original 165 | weights, orders the weights in descending order and then calculates 166 | the p-values and corrects for multiple comparisons using the 167 | Benjamini-Hochberg method. 168 | """ 169 | logger.info("Calculating statistics.") 170 | for component in range(self.n_components): 171 | # Calculate the standard deviation of all the wights 172 | self.boot.std[component, :] = self.boot.weights[component, :, 173 | :].std(axis=1, ddof=1) 174 | # Calculate the zscore and store it sorted in descending order 175 | _z = self.orig.weights[component, :] / self.boot.std[component, :] 176 | self.boot.z_score[component, :] = np.sort( 177 | _z, axis=0, kind='mergesort')[::-1] 178 | _index = np.argsort(_z, axis=0, kind='mergesort')[::-1] 179 | # Reorder the genes according to the zscore 180 | self.boot.genes[component, :] = self.orig.genes[component, _index] 181 | # Calculate pvalue and pvalue corrected 182 | _p_val = norm.sf(abs(self.boot.z_score[component, :])) 183 | self.boot.pval[component, :] = _p_val 184 | _, _p_corr, _, _ = multipletests(_p_val[::-1].reshape(1, 185 | self.n_genes), 186 | method='fdr_bh', 187 | is_sorted=True) 188 | self.boot.pval_corr[component, :] = _p_corr 189 | return 190 | 191 | def gsea(self, gene_set="lake", outdir=None, gene_limit=1500, n_iter=1000): 192 | """Perform a GSEA analysis on the z-scored weights.""" 193 | assert isinstance(self.orig, OrigPLS) 194 | assert isinstance(self.boot, BootPLS) 195 | logger.info("Performing GSEA.") 196 | if Path(gene_set).exists() and Path(gene_set).is_file() and Path( 197 | gene_set).suffix == ".gmt": 198 | gene_set = Path(gene_set) 199 | else: 200 | gene_set = get_geneset(gene_set) 201 | for _component in range(self.n_components): 202 | gene_list = list(self.orig.genes[_component, :]) 203 | rnk = pd.DataFrame(zip(gene_list, 204 | self.orig.zscored[_component, :])) 205 | gsea_results = gseapy.prerank(rnk, gene_set, 206 | max_size=gene_limit, 207 | outdir=None, 208 | seed=1234, 209 | permutation_num=n_iter) 210 | _origin_es = gsea_results.res2d.es.to_numpy() 211 | _boot_es = np.zeros((_origin_es.shape[0], n_iter)) 212 | for i in range(n_iter): 213 | rnk = pd.DataFrame(zip(gene_list, 214 | zscore( 215 | self.boot.weights[_component, :, i], 216 | ddof=1) 217 | ) 218 | ) 219 | gsea_res = gseapy.prerank(rnk, gene_set, 220 | max_size=gene_limit, 221 | outdir=None, 222 | seed=1234, 223 | permutation_num=1) 224 | _boot_es[:, i] = gsea_res.res2d.es.to_numpy() 225 | _p_val = np.zeros((_origin_es.shape[0],)) 226 | for i in range(_origin_es.shape[0]): 227 | _p_val[i] = np.sum(_boot_es[i, :] >= _origin_es[i]) / n_iter if _origin_es[i] >= 0 else np.sum(_boot_es[i, :] <= _origin_es[i]) / n_iter 228 | # calculate the p-value corrected 229 | _, _p_corr, _, _ = multipletests(_p_val, method='fdr_bh', 230 | is_sorted=False) 231 | # Prepare data to save 232 | _out_data = OrderedDict() 233 | _out_data["Term"] = gsea_results.res2d.axes[0].to_list() 234 | _out_data["es"] = gsea_results.res2d.values[:, 0] 235 | _out_data["nes"] = gsea_results.res2d.values[:, 1] 236 | _out_data["p_val"] = _p_val 237 | _out_data["fdr"] = _p_corr 238 | _out_data["genest_size"] = gsea_results.res2d.values[:, 4] 239 | _out_data["matched_size"] = gsea_results.res2d.values[:, 5] 240 | _out_data["matched_genes"] = gsea_results.res2d.values[:, 6] 241 | _out_data["ledge_genes"] = gsea_results.res2d.values[:, 7] 242 | out_df = pd.DataFrame.from_dict(_out_data) 243 | if outdir is not None: 244 | logger.info("Saving GSEA results.") 245 | outdir = Path(outdir) 246 | assert outdir.exists() 247 | out_df.to_csv( 248 | outdir / f"gsea_pls{_component + 1}_results.tsv", 249 | index=False, 250 | sep="\t") 251 | for _i in range(len(gsea_results.res2d.index)): 252 | term = gsea_results.res2d.index[_i] 253 | gsea_results.results[term]["pval"] = _p_val[_i] 254 | gsea_results.results[term]["fdr"] = _p_corr[_i] 255 | gseaplot(rank_metric=gsea_results.ranking, 256 | term=term, 257 | **gsea_results.results[term], 258 | ofname=f"{outdir}/{term}_pls" 259 | f"{_component + 1}_prerank.pdf") 260 | 261 | 262 | # --------- ORIG PLS --------- # 263 | class OrigPLS: 264 | def __init__(self, n_components, n_genes): 265 | """ Initialize the original results of the PLS analysis. The class 266 | contains the fields corresponding to the number of components used, 267 | the weights of the pls for each gene ordered in descending order, 268 | the index where the original genes and the zscore of the weights. 269 | 270 | :param int n_components: number of components used. 271 | :param int n_genes: number of genes. 272 | """ 273 | self.n_components = n_components 274 | self.weights = np.zeros((n_components, n_genes)) 275 | self.genes = np.zeros((n_components, n_genes), dtype=object) 276 | self.index = np.zeros((n_components, n_genes), dtype=np.int32) 277 | self.zscored = np.zeros((n_components, n_genes)) 278 | 279 | 280 | # --------- BOOT PLS --------- # 281 | class BootPLS: 282 | def __init__(self, n_components, n_genes, n_iter=1000): 283 | """Initialise a class to store the results of the bootstrapping of 284 | the genes. 285 | 286 | All the initialised fields are stored as numpy arrays with the 287 | number of rows corresponding to the number of components and the 288 | columns corresponding to the number of genes. The weights field has 289 | an additional 3rd dimension corresponding to the number of 290 | iterations (the default number is 1000). 291 | The fields are: 292 | 293 | * weights (n_components, n_genes, n_iter): the weights of the genes 294 | for each component, for each iteration. 295 | 296 | * genes (n_components, n_genes, n_iter): the genes that correspond 297 | to the most contributing genes for each component. 298 | 299 | * index (n_components, n_genes, n_iter): the index of the genes 300 | compared to the original list of gene labels. 301 | 302 | * std: the standard deviation of the weights for each component, 303 | calculated from the bootstrapped weights. 304 | 305 | * zscored (n_components, n_genes, n_iter): the z-scored weights. 306 | 307 | * pval (n_components, n_genes): the p-value of the z-scored gene 308 | wights. 309 | 310 | * pval_corr (n_components, n_genes): the p-value of the correlation 311 | corrected for multiple comparisons using the Benjamini-Hochberg method. 312 | 313 | :param int n_components: number of components used for the analysis. 314 | :param int n_genes: number of genes used for the analysis. 315 | :param int n_iter: number of iterations used for the bootstrapping, 316 | the default is 1000. 317 | """ 318 | self.n_components = n_components 319 | self.weights = np.zeros((n_components, n_genes, n_iter)) 320 | self.genes = np.zeros((n_components, n_genes), dtype=object) 321 | self.std = np.zeros((n_components, n_genes)) 322 | self._z_score = np.zeros((n_components, n_genes)) 323 | self.pval = np.zeros((n_components, n_genes)) 324 | self.pval_corr = np.zeros((n_components, n_genes)) 325 | 326 | @property 327 | def z_score(self): 328 | """The z-scored weights. 329 | """ 330 | return self._z_score 331 | 332 | 333 | # --------- CORRELATION GENES --------- # 334 | class CorrGenes: 335 | """Class that stores the gene results of the correlation analysis. It 336 | has the following fields: 337 | 338 | * boot_corr: the bootstrapped results of the correlation analysis. 339 | * corr: the original results of the correlation analysis. 340 | * boot_corr: the bootstrapped results of the correlation analysis. 341 | * genes: the gene list used for the analysis. 342 | * pval: the p-value of the correlation. 343 | * pval_corr: the p-value of the correlation corrected for multiple 344 | comparisons using the Benjamini-Hochberg method. 345 | """ 346 | def __init__(self, n_iter=1000): 347 | """Initialise the class. 348 | 349 | :param int n_iter: number of iterations used for the bootstrapping, 350 | """ 351 | self.n_genes = 15633 352 | self._n_iter = n_iter 353 | self.boot_corr = np.zeros((self.n_genes, self._n_iter)) 354 | self.corr = np.zeros((1, self.n_genes)) 355 | self.genes = np.zeros((1, self.n_genes)) 356 | self.pval = np.zeros((1, self.n_genes)) 357 | self.pval_corr = np.zeros((1, self.n_genes)) 358 | self._index = None 359 | 360 | def compute_pval(self): 361 | """Compute the p-values, and its fdr correction, of the correlation, 362 | from the list of bootstrapped correlations. 363 | """ 364 | # This calculation assumes that the order of the genes is the same 365 | # in both the original and the bootstrapped list. IF one is ordered, 366 | # make sure the order of the other is the same. 367 | logger.info("Computing p values.") 368 | for i in range(self.n_genes): 369 | self.pval[0, i] = np.sum(self.boot_corr[i, :] >= self.corr[0, i]) / self._n_iter if self.corr[0, i] >= 0 else np.sum(self.boot_corr[i, :] <= self.corr[0, i]) / self._n_iter 370 | _, p_corr, _, _ = multipletests(self.pval[0, :], method='fdr_bh', 371 | is_sorted=False) 372 | 373 | self.pval_corr[0, :] = p_corr 374 | return 375 | 376 | @property 377 | def is_sorted(self): 378 | """Check if the list of genes is sorted. 379 | 380 | :return: True if the list of genes is sorted, False otherwise. 381 | """ 382 | return self._index is not None 383 | 384 | def sort_genes(self): 385 | """Order the genes in the list of genes. Both the order of the 386 | order of the bootstrapped genes are ordered. 387 | """ 388 | logger.info("Sorting genes in ascending order.") 389 | self._index = self.corr.argsort(axis=1, kind='mergesort')[::-1] 390 | self.corr[0, :] = self.corr[0, self._index] 391 | self.genes[:] = self.genes[self._index] 392 | self.pval[0, :] = self.pval[0, self._index] 393 | self.pval_corr[0, :] = self.pval_corr[0, self._index] 394 | for i in range(self._n_iter): 395 | self.boot_corr[:, i] = self.boot_corr[:, i][self._index] 396 | return 397 | -------------------------------------------------------------------------------- /imaging_transcriptomics/inputs.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import logging 3 | import logging.config 4 | import yaml 5 | 6 | import nibabel as nib 7 | import numpy as np 8 | import pandas as pd 9 | from scipy.stats import zscore 10 | 11 | from .errors import CheckShape, CheckPath, CheckExtension, CheckVariance 12 | 13 | cfg_file_path = Path(__file__).parent / "log_config.yaml" 14 | with open(cfg_file_path, "r") as config_file: 15 | log_cfg = yaml.safe_load(config_file.read()) 16 | 17 | logging.config.dictConfig(log_cfg) 18 | logger = logging.getLogger("inputs") 19 | logger.setLevel(logging.DEBUG) 20 | 21 | 22 | # Imaging data 23 | @CheckPath 24 | @CheckExtension 25 | def read_scan(path): 26 | """Return the imaging file associated to the input scan. 27 | 28 | Uses the `Nibabel `_ 29 | to read the input imaging file and get the voxel data. 30 | 31 | :param str path: path of the imaging file to analyze. 32 | :return: Numpy matrix with the voxel of the input scan. 33 | """ 34 | logger.debug("Reading scan: %s", path) 35 | return nib.load(Path(path)).get_fdata() 36 | 37 | 38 | @CheckShape 39 | def get_vox_size(imaging_matrix): 40 | """ 41 | Get the voxel dimensions in mm from the matrix dimensions (i.e., (91, 42 | 109, 91) = 2mm 43 | :param imaging_matrix: 44 | :return str mm: 45 | """ 46 | if imaging_matrix.shape == (91, 109, 91): 47 | mm = "2mm" 48 | elif imaging_matrix.shape == (182, 218, 182): 49 | mm = "1mm" 50 | else: 51 | raise ValueError("This voxel dimension is not supported!") 52 | return mm 53 | 54 | 55 | # Atlas data 56 | def load_atlas_imaging(atlas_name="DK", vox_dim="1mm"): 57 | """ 58 | Load the name and path of the atlas used for the analysis. 59 | 60 | :param vox_dim: voxel dimension of an image to analyse. 61 | :param atlas_name: Name of the atlas to use for analysis. Available 62 | atlases, so far, are: Desikan-Killiany ("DK_1mm"), Shaefer 100 ( 63 | "Shaefer_100"), 64 | Shaefer 200 ("Shaefer_200"), Shaefer 400 ("Shaefer_400"). 65 | :return: 66 | """ 67 | # Check if the atlas specified is one of the available atlases 68 | atlas_list = ["DK", "Schaefer_100", "Schaefer_200", "Schaefer_400"] 69 | atlas_base_path = Path(__file__).resolve().parent / "data" / "atlases" 70 | if atlas_name not in atlas_list: 71 | raise FileExistsError(f"The atlas {atlas_name} is not a valid " 72 | f"atlas!") 73 | elif atlas_name == "DK": 74 | # Desikan-Killiany atlas 75 | n_regions = 41 76 | atlas_path = atlas_base_path / "DK" 77 | atlas_path = atlas_path / "atlas-DK_1mm.nii.gz" if vox_dim == "1mm" \ 78 | else atlas_path / "atlas-DK_2mm.nii.gz" 79 | elif atlas_name == "Schaefer_100": 80 | n_regions = 50 81 | atlas_path = atlas_base_path / "Schaefer_100" 82 | atlas_path = atlas_path / \ 83 | "atlas-Schaefer_100_1mm.nii.gz" if vox_dim == "1mm" \ 84 | else atlas_path / "atlas-Schaefer_100_2mm.nii.gz" 85 | elif atlas_name == "Schaefer_200": 86 | n_regions = 100 87 | atlas_path = atlas_base_path / "Schaefer_200" 88 | elif atlas_name == "Schaefer_400": 89 | n_regions = 200 90 | atlas_path = atlas_base_path / "Schaefer_400" 91 | 92 | return n_regions, atlas_path 93 | 94 | 95 | @CheckShape 96 | def extract_average(imaging_matrix, atlas="DK"): 97 | """Extract the average value of the ROIs from the imaging scan. 98 | 99 | The values are extracted from the left hemisphere only, since the data of 100 | the Allen Human Brain Atlas are available for that hemisphere only for 101 | all donors. 102 | 103 | :param atlas: atlas to use for the parcellation of the scan 104 | :param imaging_matrix: matrix with the voxels of the image. 105 | 106 | :return: numpy array with the average value from 41 brain regions. 107 | """ 108 | vox_dim = get_vox_size(imaging_matrix) 109 | # Load atlas 110 | n_regions, atlas_path = load_atlas_imaging(atlas, vox_dim=vox_dim) 111 | logger.debug(f"Extracting average from {atlas} of scan") 112 | atlas_data = nib.load(atlas_path).get_fdata() 113 | # create empty array to store the regional average values 114 | data = np.zeros(n_regions) 115 | for i in range(1, n_regions + 1): 116 | data[i - 1] = np.nanmean(imaging_matrix[np.where(atlas_data == i)]) 117 | logger.debug(f"Extracted values are: {data}") 118 | return np.array(data) 119 | 120 | 121 | def get_annot_files(atlas="DK"): 122 | atlas_base_path = Path(__file__).resolve().parent / "data" / "atlases" / \ 123 | atlas 124 | lh_annot = list(atlas_base_path.glob(f"atlas-{atlas}*_lh_aparc.annot"))[0] 125 | rh_annot = list(atlas_base_path.glob(f"atlas-{atlas}*_rh_aparc.annot"))[0] 126 | return str(lh_annot), str(rh_annot) 127 | 128 | 129 | # Gene expression data 130 | def load_gene_expression(regions="cort+sub", atlas="DK"): 131 | """Return matrix with gene expression data. 132 | 133 | The data have been previously normalised and are available in the 134 | ``data/atlases`` sub-folder. 135 | 136 | :param regions: String indicating whether the regions of only cortical 137 | or cortical and subcortical are used. 138 | :param atlas: 139 | :return: numpy array with the gene expression data. 140 | """ 141 | if regions not in ["cort+sub", "cort", "all"]: 142 | raise ValueError("The regions must be either 'cort+sub', 'cort' or " 143 | "'all'.") 144 | logger.debug("Loading gene_expression data.") 145 | # TODO: change file loadings based on atlas, and retrieve automatically 146 | # the gene labels from header. 147 | expression_file_path = ( 148 | Path(__file__).resolve().parent / f"data/atlases/{atlas}/" 149 | f"atlas-{atlas}_gene_expression_data.csv") 150 | expression_data = pd.read_csv(expression_file_path, sep=",") 151 | if atlas == "DK": 152 | my_data_x = expression_data.iloc[0:41, 2:].to_numpy() 153 | my_data = zscore(my_data_x, ddof=1) 154 | if regions in ["cort+sub", "all"]: 155 | my_data = my_data 156 | elif regions == "cort": 157 | my_data = my_data[:34, :] 158 | elif atlas == "Schaefer_100": 159 | my_data_x = expression_data.iloc[0:50, 2:].to_numpy() 160 | my_data = zscore(my_data_x, ddof=1) 161 | if regions in ["cort+sub", "all"]: 162 | my_data = my_data 163 | elif regions == "cort": 164 | my_data = my_data[:34, :] 165 | return my_data 166 | 167 | 168 | def load_gene_labels(atlas="DK"): 169 | """Return an array with the gene labels. 170 | The gene labels are available in the ``data`` sub-folder. 171 | 172 | :return: numpy array with the labels of the genes. 173 | """ 174 | logger.debug("Loading gene labels.") 175 | expression_file_path = ( 176 | Path(__file__).resolve().parent / 177 | f"data/atlases/{atlas}/atlas-{atlas}_gene_expression_data.csv") 178 | expression_labels = pd.read_csv(expression_file_path, sep=",") 179 | return np.array(expression_labels.columns[2:]).reshape( 180 | (expression_labels.columns[2:].shape[0], 1)) 181 | 182 | 183 | def get_geneset(gene_set: str): 184 | """Returns the path to the geneset file, if it is not one of those 185 | defined in gseapy. 186 | 187 | :param str gene_set: the name of the geneset. If the geneset is "lake" 188 | or "pooled", the genesets are provided with the package data, otherwise 189 | the gene sets are from the gseapy package. 190 | """ 191 | if gene_set.lower() == "lake": 192 | return str(Path(__file__).parent / "data" / "geneset_LAKE.gmt") 193 | elif gene_set.lower() == "pooled": 194 | return str(Path(__file__).parent / "data" / 195 | "geneset_Pooled.gmt") 196 | else: 197 | return gene_set 198 | -------------------------------------------------------------------------------- /imaging_transcriptomics/log_config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 1 3 | 4 | formatters: 5 | extended: 6 | format: "[%(levelname)s] %(asctime)s: %(name)s - %(funcName)s - %(lineno)d - %(message)s" 7 | timefmt: "%Y-%m-%dT%H:%M:%S" 8 | 9 | simple: 10 | format: "%(asctime)s: %(message)s" 11 | timefmt: "%Y-%m-%dT%H:%M:%S" 12 | 13 | handlers: 14 | module_log: 15 | class: logging.handlers.RotatingFileHandler 16 | level: DEBUG 17 | filename: module_logs.log 18 | maxBytes: 6164480 19 | backupCount: 2 20 | formatter: extended 21 | 22 | console: 23 | class: logging.StreamHandler 24 | level: INFO 25 | formatter: simple 26 | 27 | loggers: 28 | transcriptomics: 29 | handlers: [module_log, console] 30 | 31 | genes: 32 | handlers: [module_log, console] 33 | 34 | inputs: 35 | handlers: [module_log, console] 36 | 37 | bootstrapping: 38 | handlers: [module_log, console] 39 | -------------------------------------------------------------------------------- /imaging_transcriptomics/pls.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from pyls import pls_regression 3 | import pandas as pd 4 | 5 | from .genes import GeneResults, PLSGenes 6 | from pathlib import Path 7 | import yaml 8 | import logging.config 9 | import logging 10 | 11 | cfg_file_path = Path(__file__).parent / "log_config.yaml" 12 | with open(cfg_file_path, "r") as config_file: 13 | log_cfg = yaml.safe_load(config_file.read()) 14 | 15 | logging.config.dictConfig(log_cfg) 16 | logger = logging.getLogger("genes") 17 | logger.setLevel(logging.DEBUG) 18 | 19 | np.random.seed(1234) 20 | 21 | 22 | # --------- PLS ANALYSIS --------- # 23 | class PLSAnalysis: 24 | """Class for performing PLS regression on the imaging data. 25 | This class contains fields for 26 | """ 27 | def __init__(self, imaging_data, gene_exp, n_components: int, var: float): 28 | self.var, self.n_components, self.components_var = self.set_coef( 29 | imaging_data, gene_exp, n_components=n_components, var=var) 30 | self._p_val = np.zeros(self.n_components) 31 | self._r2 = np.zeros(self.n_components) 32 | self.gene_results = GeneResults("pls", n_components=self.n_components) 33 | 34 | @staticmethod 35 | def check_var(var: float): 36 | """ Check if the variance is between 0 and 1. 37 | 38 | :param float var: variance. 39 | """ 40 | if var < 0: 41 | raise ValueError("The variance must be a positive number.") 42 | elif var > 1: 43 | raise ValueError("The variance must be a number between 0 and 1.") 44 | return var 45 | 46 | @staticmethod 47 | def set_coef(data, gene_exp, var=None, n_components=None): 48 | """Set the coefficients for the PLS regression. The function will 49 | estimate the variance or the number of components depending on the 50 | non missing parameter through a PLS regression with 15 components. 51 | 52 | :param data: imaging data. 53 | :param gene_exp: gene expression data. 54 | :param var: variance. 55 | :param n_components: number of components. 56 | """ 57 | res = pls_regression(gene_exp, data.reshape(data.shape[0], 1), 58 | n_components=15, 59 | n_perm=0, 60 | n_boot=0) 61 | explained_var = res.get("varexp") 62 | if var is None: 63 | var = np.cumsum(explained_var)[n_components-1] 64 | if n_components is None: 65 | dim = 1 66 | cumulative_var = np.cumsum(explained_var) 67 | while cumulative_var[dim - 1] < var: 68 | dim += 1 69 | n_components = dim 70 | return var, n_components, explained_var 71 | 72 | @property 73 | def p_val(self): 74 | """P-value of the pls regression given by the bootstrapping on the 75 | PLS components.""" 76 | return self._p_val 77 | 78 | @property 79 | def r2(self): 80 | """R2 of the pls regression given by the bootstrapping on the PLS 81 | components""" 82 | return self._r2 83 | 84 | @p_val.setter 85 | def p_val(self, p_val): 86 | self._p_val = p_val 87 | 88 | @r2.setter 89 | def r2(self, r2): 90 | self._r2 = r2 91 | 92 | def boot_pls(self, 93 | imaging_data, 94 | permuted_imaging, 95 | gene_exp): # pragma: no cover 96 | """Bootstrapping on the PLS components. 97 | 98 | :param imaging_data: imaging data. Allows the user to specify the 99 | data to use (e.g., with only cortical regions this can be only the 100 | cortical vector, other wise the whole data). 101 | :param permuted_imaging: imaging data permuted. Allows the user to 102 | specify the data to use (e.g., with only cortical regions this can be 103 | only the cortical vector, other wise the whole data). 104 | :param gene_exp: gene expression data. 105 | """ 106 | # Iterate over the components 107 | logger.info("Calculating PLS with permuted data") 108 | for component in range(1, self.n_components + 1): 109 | _res = pls_regression(gene_exp, imaging_data.reshape( 110 | imaging_data.shape[0], 1), 111 | n_components=component, 112 | n_perm=0, n_boot=0) 113 | _exp_var = _res.get("varexp") 114 | _temp = _exp_var.cumsum(axis=0) 115 | _R = _temp[component - 1] 116 | _R_sq = np.zeros(1000) 117 | # Iterate over the permutations 118 | for i in range(1000): 119 | y_data = permuted_imaging[:, i].reshape( 120 | imaging_data.shape[0], 1) 121 | _res = pls_regression(gene_exp, y_data, n_components=component, 122 | n_perm=0, n_boot=0) 123 | _exp_var = _res.get("varexp") 124 | _R_sq[i] = _exp_var.cumsum(axis=0)[component - 1] 125 | # Set the results 126 | self.r2[component - 1] = _R 127 | self.p_val[component - 1] = np.sum(_R_sq >= _R) / 1000 128 | self.print_table() 129 | return 130 | 131 | def print_table(self): 132 | print("+-----------+----------------+-------+") 133 | print("| Component | Cumulative var | p val |") 134 | print("|-----------|----------------|-------|") 135 | for i in range(self.p_val.shape[0]): 136 | print("| {} | {:.3f} | {} |".format( 137 | i + 1, self.r2[i], self.p_val[i])) 138 | print("+-----------+----------------+-------+") 139 | print("") 140 | 141 | def save_results(self, outdir=None): 142 | """Save the results of the PLS regression. 143 | 144 | :param outdir: output directory. 145 | """ 146 | assert isinstance(self.gene_results.results, PLSGenes) 147 | for i in range(self.n_components): 148 | data = zip(self.gene_results.results.orig.genes[i, :], 149 | self.gene_results.results.orig.zscored[i, :], 150 | self.gene_results.results.boot.pval[i, :], 151 | self.gene_results.results.boot.pval_corr[i, :]) 152 | df = pd.DataFrame(data, columns=["Gene", "Z-score", "p-value", 153 | "fdr"]) 154 | df.to_csv(f"{outdir}/pls_component_{i+1}.tsv", sep='\t', 155 | index=False) 156 | 157 | -------------------------------------------------------------------------------- /imaging_transcriptomics/reporting.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from datetime import datetime 3 | 4 | import numpy as np 5 | import pandas as pd 6 | import matplotlib.pyplot as plt 7 | import nibabel as nib 8 | from fpdf import FPDF 9 | 10 | from .errors import CheckPath 11 | from .genes import GeneResults 12 | from .transcriptomics import ImagingTranscriptomics 13 | 14 | 15 | @CheckPath 16 | def make_folder(path, folder_name: str): 17 | """Create a folder based on path and name to use. 18 | 19 | The function checks if in the directory there are already folders with the same name. If this is the case the new 20 | folder will have a trialing underscore with a progressive number (e.g., _2) 21 | 22 | :param path: path where to save the folder. 23 | :param folder_name: name of the folder to save 24 | 25 | :return folder_made: path of the folder created. 26 | """ 27 | n_folds = len(list(Path(path).absolute().glob(f"{folder_name}*"))) 28 | if n_folds != 0: 29 | folder_name = f"{folder_name}_{n_folds}" 30 | folder_made = Path(path).absolute() / folder_name 31 | folder_made.mkdir() 32 | return folder_made 33 | 34 | 35 | @CheckPath 36 | def make_plots(path, limit_x, data_y): 37 | """Generate the plots for the explained variance by each component, 38 | one with the cumulative sum and one with the variance explained by each 39 | individual component. 40 | 41 | :param path: path where the plots will be saved. 42 | :param limit_x: number of PLS components. 43 | :param data_y: data to plot on the y axis. 44 | :return: 45 | """ 46 | if not isinstance(path, Path): 47 | path = Path(path) 48 | varexp = 100 * np.cumsum(data_y) 49 | 50 | # Plot cumulative percentage variance 51 | plt.plot(range(1, 16), varexp, marker="o", color="sandybrown") 52 | plt.plot(limit_x, varexp[limit_x - 1], "o", color="red") 53 | plt.vlines( 54 | limit_x, 55 | varexp[0] - 10, 56 | varexp[limit_x - 1], 57 | colors="lightgrey", 58 | linestyles="dashed", 59 | ) 60 | plt.hlines(varexp[limit_x - 1], 0, limit_x, colors="lightgrey", 61 | linestyles="dashed") 62 | plt.title("Cumulative variance explained by PLS components") 63 | plt.ylabel("Total explained variance (%)") 64 | plt.xlabel("Number of PLS components") 65 | plt.xlim(0, 15) 66 | plt.ylim(varexp[0] - 10, 105) 67 | plt.grid(True) 68 | plt.savefig(path / "cumulative_variance.png", dpi=1200) 69 | plt.close() 70 | 71 | # Plot individual explained variance by each component 72 | plt.bar(range(1, 16), 100 * data_y, color="sandybrown") 73 | for index, value in enumerate(data_y): 74 | plt.text(index + 0.5, 100 * value, "{:.1f}".format(100 * value)) 75 | plt.title("Individual variance explained by PLS components") 76 | plt.xlabel("PLS component") 77 | plt.ylabel("Variance (%)") 78 | plt.savefig(path / "individual_variance.png", dpi=1200) 79 | plt.close() 80 | return 81 | 82 | 83 | def extract_from_atlas(image): 84 | """Extract the average signal from the image using the DK 85 | atlas. 86 | """ 87 | # Atlas to use for parcellation 88 | atlas_image = Path(__file__).parent / "data" / \ 89 | "atlas-desikankilliany_1mm_MNI152.nii.gz" 90 | atlas_image = nib.load(atlas_image).get_fdata() 91 | max_region = int(atlas_image.max()) 92 | 93 | new_order = pd.read_csv("alessio_order_enigma.csv")["Enigma_order"] 94 | new_order = new_order.to_numpy() - 1 95 | image = nib.load(Path(image)).get_fdata() 96 | e_values = np.zeros(max_region) 97 | for i in range(1, max_region): 98 | e_values[i] = np.mean(image[np.where(atlas_image==i)]) 99 | return e_values[new_order] 100 | 101 | 102 | def plot_brain(image): 103 | average_val = extract_from_atlas(image) 104 | avg_fs5 = parcel_to_surface(average_val, 'aparc_fsa5') 105 | plot_cortical( 106 | array_name=avg_fs5, 107 | surface_name='fsa5', 108 | size=(800, 400), 109 | color_bar=True, 110 | color_range=(-0.5, 0.5), 111 | screenshot=True, 112 | filename="cortical.png", 113 | transparent_bg=True, 114 | ) 115 | plot_subcortical( 116 | array_name=average_val[67:], 117 | size=(800, 400), 118 | color_bar=True, 119 | color_range=(-0.5, 0.5), 120 | screenshot=True, 121 | filename="subcortical.png", 122 | transparent_bg=True, 123 | ) 124 | 125 | 126 | def pls_components(data): 127 | """Return a string with the number of components, its cumulative 128 | variance and its p value from the analysis.""" 129 | if not isinstance(data, ImagingTranscriptomics): 130 | raise TypeError("The data must be an ImagingTranscriptomics object.") 131 | n_components = data.analysis.n_components 132 | res_str = "PLS Component: R2 pval " 133 | for i in range(n_components): 134 | res_str += f"PLS {i+1}: " \ 135 | f"{data.analysis.r2[i]:.3f}" \ 136 | f" {data.analysis.p_val[i]:.4f}" 137 | return res_str 138 | 139 | 140 | def make_pdf(transcriptomics_data, save_dir, name="report", scanname="", ): 141 | if not isinstance(transcriptomics_data, ImagingTranscriptomics): 142 | raise TypeError("The data must be an ImagingTranscriptomics object.") 143 | save_dir = Path(save_dir) 144 | WIDTH = 210 # mm 145 | HEIGHT = 297 # mm 146 | report = FPDF(orientation="P", unit="mm", format="A4") 147 | report.set_font("Arial", size=11) 148 | report.add_page() 149 | # Header 150 | report.image(str(Path(__file__).parent / "resources" / "header.png"), 151 | x=0, y=0, w=WIDTH) 152 | # Info on the analysis 153 | analysis_date = datetime.now().strftime("%d-%m-%Y") 154 | report.ln(25) 155 | report.cell(WIDTH/2, txt=f"Scan name: {scanname}") 156 | report.cell(WIDTH/2, txt=f"Analysis date:{analysis_date}") 157 | # PLS plots 158 | if transcriptomics_data.method == "pls": 159 | report.ln(10) 160 | make_plots(save_dir, 161 | transcriptomics_data.analysis.n_components, 162 | transcriptomics_data.analysis.components_var) 163 | report.cell(WIDTH, txt="PLS Analysis") 164 | MARGIN = 5 # mm 165 | report.image(str(save_dir / "individual_variance.png"), 166 | x=MARGIN, y=53, w=WIDTH/2) 167 | report.image(str(save_dir / "cumulative_variance.png"), 168 | x=WIDTH/2 + MARGIN, y=53, w=WIDTH/2) 169 | report.ln(90) 170 | report.cell(WIDTH, txt=pls_components(transcriptomics_data)) 171 | # MAKE GENE RESULTS TABLE 172 | report.ln(80) 173 | report.cell(WIDTH, txt="For the gene results refer to the spreadsheet in " 174 | "the report folder.") 175 | report.output(str(save_dir / f"{name}.pdf"), "F") 176 | -------------------------------------------------------------------------------- /imaging_transcriptomics/resources/Header_final.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/resources/Header_final.pdf -------------------------------------------------------------------------------- /imaging_transcriptomics/resources/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/resources/header.png -------------------------------------------------------------------------------- /imaging_transcriptomics/resources/header.svg: -------------------------------------------------------------------------------- 1 | IMAGING TRANSCRIPTOMICS ANALYSIS REPORT -------------------------------------------------------------------------------- /imaging_transcriptomics/resources/order_enigma.csv: -------------------------------------------------------------------------------- 1 | Region,Freesurfer_order,Abagen_order,Enigma_order 2 | L_bankssts,72,1,1 3 | L_caudalanteriorcingulate,54,2,2 4 | L_caudalmiddlefrontal,50,3,3 5 | L_cuneus,62,4,4 6 | L_entorhinal,68,5,5 7 | L_fusiform,66,6,6 8 | L_inferiorparietal,60,7,7 9 | L_inferiortemporal,70,8,8 10 | L_isthmuscingulate,56,9,9 11 | L_lateraloccipital,64,10,10 12 | L_lateralorbitofrontal,42,11,11 13 | L_lingual,65,12,12 14 | L_medialorbitofrontal,45,13,13 15 | L_middletemporal,71,14,14 16 | L_parahippocampal,67,15,15 17 | L_paracentral,52,16,16 18 | L_parsopercularis,47,17,17 19 | L_parsorbitalis,43,18,18 20 | L_parstriangularis,46,19,19 21 | L_pericalcarine,63,20,20 22 | L_postcentral,57,21,21 23 | L_posteriorcingulate,55,22,22 24 | L_precentral,51,23,23 25 | L_precuneus,61,24,24 26 | L_rostralanteriorcingulate,53,25,25 27 | L_rostralmiddlefrontal,48,26,26 28 | L_superiorfrontal,49,27,27 29 | L_superiorparietal,59,28,28 30 | L_superiortemporal,73,29,29 31 | L_supramarginal,58,30,30 32 | L_frontalpole,44,31,31 33 | L_temporalpole,69,32,32 34 | L_transversetemporal,74,33,33 35 | L_insula,75,34,34 36 | L_thalamusproper,76,35,75 37 | L_caudate,77,36,71 38 | L_putamen,78,37,74 39 | L_pallidum,79,38,73 40 | L_accumbensarea,80,39,69 41 | L_hippocampus,81,40,72 42 | L_amygdala,82,41,70 43 | R_bankssts,31,42,35 44 | R_caudalanteriorcingulate,13,43,36 45 | R_caudalmiddlefrontal,9,44,37 46 | R_cuneus,21,45,38 47 | R_entorhinal,27,46,39 48 | R_fusiform,25,47,40 49 | R_inferiorparietal,19,48,41 50 | R_inferiortemporal,29,49,42 51 | R_isthmuscingulate,15,50,43 52 | R_lateraloccipital,23,51,44 53 | R_lateralorbitofrontal,1,52,45 54 | R_lingual,24,53,46 55 | R_medialorbitofrontal,4,54,47 56 | R_middletemporal,30,55,48 57 | R_parahippocampal,26,56,49 58 | R_paracentral,11,57,50 59 | R_parsopercularis,6,58,51 60 | R_parsorbitalis,2,59,52 61 | R_parstriangularis,5,60,53 62 | R_pericalcarine,22,61,54 63 | R_postcentral,16,62,55 64 | R_posteriorcingulate,14,63,56 65 | R_precentral,10,64,57 66 | R_precuneus,20,65,58 67 | R_rostralanteriorcingulate,12,66,59 68 | R_rostralmiddlefrontal,7,67,60 69 | R_superiorfrontal,8,68,61 70 | R_superiorparietal,18,69,62 71 | R_superiortemporal,32,70,63 72 | R_supramarginal,17,71,64 73 | R_frontalpole,3,72,65 74 | R_temporalpole,28,73,66 75 | R_transversetemporal,33,74,67 76 | R_insula,34,75,68 77 | R_thalamusproper,35,76,82 78 | R_caudate,36,77,79 79 | R_putamen,37,78,81 80 | R_pallidum,38,79,80 81 | R_accumbensarea,39,80,76 82 | R_hippocampus,40,81,79 83 | R_amygdala,41,82,77 84 | brainstem,83,83,83 -------------------------------------------------------------------------------- /imaging_transcriptomics/script/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/script/__init__.py -------------------------------------------------------------------------------- /imaging_transcriptomics/script/imagingtranscriptomics.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import imaging_transcriptomics as imt 5 | from pathlib import Path 6 | 7 | 8 | def parse_cmdline(): 9 | DESCRIPTION = """Perform imaging transcriptomics analysis of a 10 | neuroimaging data.""" 11 | EPILOG = """ 12 | If you use this software in your work, please cite: 13 | 14 | * Imaging transcriptomics: Convergent cellular, transcriptomic, 15 | and molecular neuroimaging signatures in the healthy adult human brain.* 16 | Daniel Martins, Alessio Giacomel, Steven CR Williams, Federico Turkheimer, 17 | Ottavia Dipasquale, Mattia Veronese, PET templates working group. Cell 18 | Reports; doi: [https://doi.org/10.1016/j.celrep.2021.110173] 19 | (https://doi.org/10.1016/j.celrep.2021.110173) 20 | """ 21 | parser = argparse.ArgumentParser(description=DESCRIPTION, 22 | epilog=EPILOG) 23 | # IO arguments 24 | parser.add_argument("-i", "--input", type=str, required=True, 25 | help="Input file, can be a neuroimaging file (e.g., " 26 | ".nii[.gz] or a text file (e.g, .txt, .tsv, " 27 | ".csv) containing the values in a column") 28 | parser.add_argument("-o", "--output", type=str, required=False, 29 | help="Output directory, if not provided, the same of " 30 | "the input file is used") 31 | # Control arguments 32 | parser.add_argument("-r", "--regions", type=str, required=False, 33 | choices=["all", "cort+sub", "cort"], default="all", 34 | help="Regions to be used for the analysis, can be " 35 | "either 'all' (default), 'cort+sub' or 'cort'." 36 | "The behaviour with 'all' is the same as " 37 | "'cort+sub' and will use all regions to perform " 38 | "the analysis, while with 'cort' will use only " 39 | "the cortical regions.") 40 | parser.add_argument("--no-gsea", action="store_false", required=False, 41 | help="If True perform GSEA analysis, otherwise skip.") 42 | parser.add_argument("--geneset", type=str, required=False, default="lake", 43 | help="geneset to use for the GSEA analysis. Can be " 44 | "either 'lake' (default), 'pooled' or any of " 45 | "the genesets included in the gseapy package.") 46 | parser.add_argument("--max_genes", type=int, required=False, 47 | default=500, 48 | help="Maximum number of genes to use in the " 49 | "analysis. Default is 500.") 50 | subparser = parser.add_subparsers(title="method", dest="method") 51 | parse_corr = subparser.add_parser("corr") 52 | parse_corr.add_argument("--cpu", type=int, required=False, default=4, 53 | help="Number of CPUs to use for the analysis.") 54 | parse_pls = subparser.add_parser("pls") 55 | pls_group = parse_pls.add_mutually_exclusive_group(required=True) 56 | pls_group.add_argument("--ncomp", type=int, help="Number of " 57 | "PLS components.") 58 | pls_group.add_argument("--var", type=float, 59 | help="Percentage of variance to extract form " 60 | "the data.") 61 | return parser.parse_args() 62 | 63 | 64 | def main(): 65 | parsed = parse_cmdline() 66 | regions = parsed.regions 67 | gsea = parsed.no_gsea 68 | geneset = parsed.geneset 69 | infile = Path(parsed.input) 70 | input_name = infile.stem 71 | outdir = Path(parsed.output) if parsed.output else infile.parent 72 | if parsed.method == "corr": 73 | if infile.suffix in {".txt", ".tsv", ".csv"}: 74 | transcriptomics = imt.ImagingTranscriptomics.from_file( 75 | infile, 76 | method="corr", 77 | regions=regions) 78 | elif str().join(infile.suffixes) in {".nii", ".nii.gz"}: 79 | transcriptomics = imt.ImagingTranscriptomics.from_scan( 80 | infile, 81 | method="corr", 82 | regions=regions) 83 | n_cpu = parsed.cpu 84 | elif parsed.method == "pls": 85 | pls_arg = { 86 | "n_components": parsed.ncomp, 87 | "var": parsed.var 88 | } 89 | if infile.suffix in {".txt", ".tsv", ".csv"}: 90 | transcriptomics = imt.ImagingTranscriptomics.from_file( 91 | infile, 92 | method="pls", 93 | regions=regions, **pls_arg) 94 | elif str().join(infile.suffixes) in {".nii", ".nii.gz"}: 95 | transcriptomics = imt.ImagingTranscriptomics.from_scan( 96 | infile, 97 | method="pls", 98 | regions=regions, **pls_arg) 99 | n_cpu = 4 100 | else: 101 | raise ValueError("Method not recognized") 102 | transcriptomics.run(outdir, 103 | scan_name=input_name, 104 | gsea=gsea, 105 | gene_set=geneset, 106 | n_cpu=n_cpu, 107 | gene_limit=parsed.max_genes) 108 | # PLOTTING and PDF creation 109 | imt.reporting.make_pdf( 110 | transcriptomics_data=transcriptomics, 111 | save_dir=Path(outdir) / f"Imt_{input_name}_" 112 | f"{transcriptomics.method}", 113 | name=str(input_name), 114 | scanname=infile.name, 115 | ) 116 | 117 | 118 | if __name__ == "__main__": 119 | main() 120 | -------------------------------------------------------------------------------- /imaging_transcriptomics/script/imt_gsea.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pickle 4 | import argparse 5 | from pathlib import Path 6 | import gseapy 7 | 8 | 9 | def parse_args(): 10 | DESCRIPTION = "" 11 | EPILOG = "" 12 | parser = argparse.ArgumentParser(description=DESCRIPTION, 13 | epilog=EPILOG) 14 | parser.add_argument("-i", "--input", type=str, required=False, 15 | help="Path to the input. This MUST be a pickle file, " 16 | "(i.e. a file ending in .pkl), created by " 17 | "running an imaging transcriptomics " 18 | "analysis with the imagingtranscriptomics " 19 | "script.") 20 | parser.add_argument("-o", "--output", type=str, required=False, 21 | help="Path where the results will be saved. If this " 22 | "is not provided the same path as the input " 23 | "will be used.") 24 | parser.add_argument("-g", "--geneset", type=str, required=False, 25 | default="lake", 26 | help="Name of the gene set to use. Some of the " 27 | "avilable gene sets are:\n" 28 | "- 'lake': \n" 29 | "- 'pooled' \n" 30 | "- 'kegg' \n" 31 | "The 'lake' and 'pooled' gene sets are inluded " 32 | "in the imaging transcriptomics package while " 33 | "all the other gene sets are available in the " 34 | "gseapy package. If you want to see all the " 35 | "available gene sets, please run the " 36 | "'imt_gsea -g avail' command.") 37 | parser.add_argument("-m", "--max_genes", type=int, required=False, 38 | default=500, 39 | help="Maximum number of genes to use in the " 40 | "analysis. Default is 500.") 41 | 42 | return parser.parse_args() 43 | 44 | 45 | def main(): 46 | parsed = parse_args() 47 | if parsed.geneset == "avail": 48 | avail_gene_sets = ["lake", "pooled"] + gseapy.get_library_name() 49 | print("The following gene sets are available:") 50 | for gene_set in avail_gene_sets: 51 | print(f"- {gene_set}") 52 | else: 53 | geneset = parsed.geneset 54 | if parsed.input is None: 55 | raise ValueError("Please provide an input file.") 56 | infile = Path(parsed.input) 57 | if infile.suffix != ".pkl": 58 | raise ValueError("The input file must be a pickle file.") 59 | outdir = Path(parsed.output) if parsed.output else infile.parent 60 | with open(infile, "rb") as f: 61 | transcriptomics = pickle.load(f) 62 | transcriptomics.gsea(outdir=outdir, gene_set=geneset, 63 | gene_limit=parsed.max_genes) 64 | 65 | 66 | if __name__ == '__main__': 67 | main() 68 | 69 | -------------------------------------------------------------------------------- /imaging_transcriptomics/script/log_config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 1 3 | 4 | formatters: 5 | simple: 6 | format: "[%(levelname)s] %(asctime)s: %(message)s" 7 | timefmt: "%Y-%m-%dT%H:%M:%S" 8 | 9 | extended: 10 | format: "[%(levelname)s] %(asctime)s: %(name)s - %(funcName)s - %(lineno)d - %(message)s" 11 | timefmt: "%Y-%m-%dT%H:%M:%S" 12 | 13 | 14 | handlers: 15 | console_info: 16 | class: logging.StreamHandler 17 | formatter: simple 18 | level: INFO 19 | 20 | console_warning: 21 | class: logging.StreamHandler 22 | level: WARNING 23 | formatter: simple 24 | 25 | console_verbose: 26 | class: logging.StreamHandler 27 | level: DEBUG 28 | formatter: simple 29 | 30 | loggers: 31 | info: 32 | handlers: [console_info] 33 | verbose: 34 | handlers: [console_verbose] 35 | warning: 36 | handlers: [console_warning] 37 | -------------------------------------------------------------------------------- /imaging_transcriptomics/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/tests/__init__.py -------------------------------------------------------------------------------- /imaging_transcriptomics/tests/auto_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | import imaging_transcriptomics as imt 4 | 5 | 6 | def test_version(): 7 | """Test that the version is imported correctly.""" 8 | imported = dir(imt) 9 | assert "__version__" in imported 10 | 11 | 12 | def test_modules_import(): 13 | """Test that the submodules are all imported correctly.""" 14 | imported = dir(imt) 15 | assert "inputs" in imported 16 | assert "reporting" in imported 17 | assert "oermutatiuons" not in imported 18 | 19 | 20 | def test_functions_import(): 21 | """Test that the functions are imported correctly.""" 22 | imported = dir(imt) 23 | assert "read_scan" in imported 24 | assert "extract_average" in imported 25 | 26 | 27 | def test_classes_import(): 28 | """Test that the classes are imported correctly.""" 29 | imported = dir(imt) 30 | assert "ImagingTranscriptomics" in imported 31 | assert "GeneResults" in imported 32 | 33 | 34 | def test_not_in_module(): 35 | """Test that an error is raised when 36 | trying to import a non existing module""" 37 | with pytest.raises(ImportError): 38 | from imaging_transcriptomics import outputs 39 | -------------------------------------------------------------------------------- /imaging_transcriptomics/tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import numpy as np 3 | from pathlib import Path 4 | 5 | 6 | @pytest.fixture(scope="session") 7 | def tdata_dir(): 8 | yield Path(__file__).parent / 'data' 9 | 10 | -------------------------------------------------------------------------------- /imaging_transcriptomics/tests/data/MNI152_T1_1mm.nii.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/tests/data/MNI152_T1_1mm.nii.gz -------------------------------------------------------------------------------- /imaging_transcriptomics/tests/data/anatomical.nii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/tests/data/anatomical.nii -------------------------------------------------------------------------------- /imaging_transcriptomics/tests/data/example_nifti2.nii.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/tests/data/example_nifti2.nii.gz -------------------------------------------------------------------------------- /imaging_transcriptomics/tests/data/test_input.txt: -------------------------------------------------------------------------------- 1 | -1.635237754 2 | 0.255716141 3 | -1.018681225 4 | -0.648232157 5 | 1.972433013 6 | -0.913493909 7 | -3.391377792 8 | -1.354893436 9 | -0.209065125 10 | -2.026201134 11 | -1.619781072 12 | -1.042303914 13 | -1.180346914 14 | -1.983037632 15 | 0.352800321 16 | -2.005634044 17 | -0.354617884 18 | -1.109127894 19 | -1.81329833 20 | -0.535985644 21 | 0.390585161 22 | -0.472059549 23 | -1.060126275 24 | -0.513570565 25 | 0.624203987 26 | -1.204124982 27 | -2.635143056 28 | -1.21217398 29 | -1.925115643 30 | -0.839038675 31 | -1.028532407 32 | 0.080350238 33 | -1.149865812 34 | 0.410996598 35 | -1.228776992 36 | 0.451691495 37 | -1.51049856 38 | 0.44416055 39 | -0.244479445 40 | -1.903263154 41 | -1.21203209 42 | -------------------------------------------------------------------------------- /imaging_transcriptomics/tests/data/wrong_format.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/molecular-neuroimaging/Imaging_Transcriptomics/ffe5cb93e39506928ad8a82ac792882a58eb7b4e/imaging_transcriptomics/tests/data/wrong_format.txt -------------------------------------------------------------------------------- /imaging_transcriptomics/tests/errors_test.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import pytest 3 | import numpy as np 4 | 5 | from imaging_transcriptomics.errors import ( 6 | CheckExtension, 7 | InvalidFormatError, 8 | CheckShape, 9 | InvalidSizeError, 10 | CheckVariance, 11 | CheckPath, 12 | ) 13 | 14 | 15 | def test_check_extension(): 16 | """Test that the CheckExtension decorator works""" 17 | 18 | @CheckExtension 19 | def function(path): 20 | """Dummy function to test the decorator.""" 21 | return path 22 | 23 | test_path = Path(__file__).parent / "data" 24 | p = function(test_path / "anatomical.nii") 25 | assert str(p) == str(Path(__file__).parent / "data" / "anatomical.nii") 26 | 27 | 28 | def test_check_extension_error(): 29 | """Test that the CheckExtension decorator throws the correct error.""" 30 | 31 | @CheckExtension 32 | def function(path): # pragma: no cover 33 | """Dummy function to test the decorator.""" 34 | return path 35 | 36 | test_path = Path(__file__).parent / "data" 37 | with pytest.raises(InvalidFormatError) as ex: 38 | function(test_path / "wrong_format.txt") 39 | 40 | assert ( 41 | str(ex.value) 42 | == f"The provided file has an invalid format. Please use files in " 43 | f"the .nii, .nii.gz format. The error was caused by the file" 44 | f" {test_path.absolute()}/wrong_format.txt." 45 | ) 46 | 47 | 48 | def test_check_shape(): 49 | """Test the CheckShape decorator.""" 50 | matrix = np.zeros((182, 218, 182)) 51 | 52 | @CheckShape 53 | def function(in_matrix): 54 | """Dummy function to test the decorator.""" 55 | return in_matrix.shape 56 | 57 | assert function(matrix) == (182, 218, 182) 58 | 59 | 60 | def test_check_shape_error(): 61 | """Test the CheckShape decorator throws the correct error.""" 62 | matrix = np.zeros((171, 230, 167)) 63 | 64 | @CheckShape 65 | def function(in_matrix): # pragma: no cover 66 | """Dummy function to test the decorator.""" 67 | return in_matrix.shape 68 | 69 | with pytest.raises(InvalidSizeError) as ex: 70 | function(matrix) 71 | 72 | assert ( 73 | str(ex.value) 74 | == "The provided file has a wrong shape. The file has shape: (171, 230, 167)" 75 | ) 76 | 77 | 78 | def test_check_variance(): 79 | """Test the CheckVariance decorator.""" 80 | 81 | @CheckVariance 82 | def function(var): 83 | """Dummy function to test the decorator.""" 84 | return var + 1 85 | 86 | assert function(0.1) == 1.1 87 | 88 | 89 | def test_check_variance_error(): 90 | """Test that the CheckVariance decorator throws the correct error.""" 91 | 92 | @CheckVariance 93 | def function(var): # pragma: no cover 94 | """Dummy function to test the decorator.""" 95 | return var + 1 96 | 97 | with pytest.raises(ValueError): 98 | function(1.2) 99 | with pytest.raises(ValueError): 100 | function(-0.1) 101 | 102 | 103 | def test_check_path(tmp_path): 104 | @CheckPath 105 | def function(path): 106 | return str(path) 107 | 108 | assert function(tmp_path) == str(tmp_path) 109 | with pytest.raises(FileNotFoundError): 110 | function(tmp_path / "foo_bar") 111 | -------------------------------------------------------------------------------- /imaging_transcriptomics/tests/inputs_test.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pytest 3 | from pathlib import Path 4 | import gseapy 5 | 6 | from imaging_transcriptomics.inputs import ( 7 | extract_average, 8 | load_gene_expression, 9 | load_gene_labels, 10 | read_scan, 11 | get_geneset, 12 | get_annot_files 13 | ) 14 | from imaging_transcriptomics.errors import InvalidSizeError, InvalidFormatError 15 | 16 | 17 | # READ SCAN FUNCTION TESTS 18 | def test_read_scan(tdata_dir): 19 | """Test the read scan function.""" 20 | scan = read_scan(tdata_dir / "MNI152_T1_1mm.nii.gz") 21 | assert scan.shape == (182, 218, 182) 22 | assert scan.dtype == np.float64 23 | 24 | 25 | def test_read_scan_errors(tdata_dir): 26 | """Test the errors given by the read scan function""" 27 | with pytest.raises(FileNotFoundError): 28 | read_scan(tdata_dir / "MNI152_T1_1mm.nii") 29 | with pytest.raises(InvalidFormatError): 30 | read_scan(tdata_dir / "wrong_format.txt") 31 | 32 | 33 | # EXTRACT AVERAGE FUNCTION TESTS 34 | def test_extract_average(): 35 | """Test the extract average function.""" 36 | scan = np.ones((182, 218, 182)) 37 | average = extract_average(scan) 38 | assert average.dtype == np.float64 39 | assert average.shape == (41,) 40 | np.testing.assert_array_equal(average, np.ones(41)) 41 | 42 | 43 | def test_extract_average_errors(): 44 | """Test the errors given by the extract average function.""" 45 | with pytest.raises(InvalidSizeError): 46 | extract_average(np.ones((182, 218, 182, 1))) 47 | with pytest.raises(InvalidSizeError): 48 | extract_average(np.ones((91, 102, 92))) 49 | 50 | 51 | def test_extract_average_Schaefer_100(): 52 | """Test no errors are raised when the atlas is the Schaefer 100.""" 53 | scan = np.ones((91, 109, 91)) 54 | average = extract_average(scan, atlas="Schaefer_100") 55 | assert average.dtype == np.float64 56 | assert average.shape == (50,) 57 | np.testing.assert_array_equal(average, np.ones(50)) 58 | 59 | def test_Schaefer_100_annot_files(): 60 | atlas = "Schaefer_100" 61 | lh_annot, rh_annot = get_annot_files(atlas) 62 | assert lh_annot == "/Users/alessiogiacomel/Documents/Projects/ImagingTranscriptomics/imaging_transcriptomics/data/atlases/Schaefer_100/atlas-Schaefer_100_lh_aparc.annot" 63 | assert rh_annot == "/Users/alessiogiacomel/Documents/Projects/ImagingTranscriptomics/imaging_transcriptomics/data/atlases/Schaefer_100/atlas-Schaefer_100_rh_aparc.annot" 64 | 65 | 66 | # LOAD GENE EXPRESSION FUNCTION TESTS 67 | def test_load_gene_expression(): 68 | """Test the load gene expression function.""" 69 | expression = load_gene_expression(regions="all") 70 | assert expression.shape == (41, 15633) 71 | assert expression.dtype == np.float64 72 | np.testing.assert_almost_equal(expression[0, 0], -.281, decimal=3) 73 | np.testing.assert_almost_equal(expression[34, 18], 1.199, decimal=3) 74 | np.testing.assert_almost_equal(expression[39, 13], -3.201, decimal=3) 75 | 76 | 77 | def test_load_gene_expression_cort(): 78 | expression = load_gene_expression(regions="cort") 79 | assert expression.shape == (34, 15633) 80 | assert expression.dtype == np.float64 81 | np.testing.assert_almost_equal(expression[0, 0], -.281, decimal=3) 82 | np.testing.assert_almost_equal(expression[32, 18], .473, decimal=3) 83 | 84 | 85 | def test_load_gene_expression_errors(): 86 | """Test the errors given by the load gene expression function.""" 87 | with pytest.raises(ValueError): 88 | load_gene_expression(regions="wrong_region") 89 | 90 | 91 | # LOAD GENE LABELS FUNCTION TESTS 92 | def test_gene_labels_load(): 93 | """Test that the genes labels are loaded correctly.""" 94 | labels = load_gene_labels() 95 | assert labels.shape == (15633, 1) 96 | assert labels[78] == "ABHD6" 97 | assert labels[1635] == "C6orf106" 98 | assert "SLC7A10" in labels 99 | assert "audhd49b" not in labels 100 | assert "LOC102723968" in labels 101 | 102 | 103 | # GENESET FUNCTION TESTS 104 | def test_get_geneset(): 105 | """Test the geneset function.""" 106 | geneset = get_geneset("lake") 107 | assert isinstance(geneset, str) 108 | assert Path(geneset).exists() 109 | geneset = get_geneset("pooled") 110 | assert isinstance(geneset, str) 111 | assert Path(geneset).exists() 112 | geneset = get_geneset("POOLed") 113 | assert isinstance(geneset, str) 114 | assert Path(geneset).exists() 115 | geneset = get_geneset("GO_Biological_Process_2017") 116 | assert isinstance(geneset, str) 117 | assert geneset in gseapy.get_library_name() 118 | -------------------------------------------------------------------------------- /imaging_transcriptomics/tests/transcriptomics_test.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import numpy as np 3 | import pytest 4 | import imaging_transcriptomics as imt 5 | from scipy.stats import zscore 6 | 7 | 8 | # INITIALIZATION TESTS 9 | def test_init_transcriptomics_corr(): 10 | """ 11 | Test the initialization of a transcriptomics object. 12 | """ 13 | # Test with all regions (cort + sub) 14 | data = np.random.rand(41) 15 | imt_instance = imt.ImagingTranscriptomics(data, regions="all", 16 | method="corr") 17 | assert isinstance(imt_instance, imt.ImagingTranscriptomics) 18 | assert imt_instance._regions == "all" 19 | assert imt_instance._method == "corr" 20 | assert imt_instance.scan_data.shape == (41,) 21 | assert imt_instance.scan_data.dtype == np.float64 22 | np.testing.assert_array_almost_equal(imt_instance._cortical, zscore(data, 23 | ddof=1)[:34]) 24 | assert imt_instance.zscore_data.shape == (41,) 25 | assert imt_instance._permutations is None 26 | # Test with only cortical regions 27 | data = np.random.rand(34) 28 | imt_instance = imt.ImagingTranscriptomics(data, regions="cort", 29 | method="corr") 30 | assert isinstance(imt_instance, imt.ImagingTranscriptomics) 31 | assert imt_instance._regions == "cort" 32 | assert imt_instance._method == "corr" 33 | assert imt_instance.scan_data.shape == (34,) 34 | assert imt_instance.scan_data.dtype == np.float64 35 | assert imt_instance._subcortical is None 36 | np.testing.assert_array_almost_equal(imt_instance._cortical, zscore( 37 | data, ddof=1)) 38 | assert imt_instance.zscore_data.shape == (34,) 39 | assert imt_instance._permutations is None 40 | 41 | 42 | def test_init_transcriptomics_pls(): 43 | """ 44 | Test the initialization of a transcriptomics object. 45 | """ 46 | # Test with a all regions (cort + sub) 47 | data = np.random.rand(41) 48 | imt_instance = imt.ImagingTranscriptomics(data, regions="all", 49 | method="pls", n_components=1) 50 | assert isinstance(imt_instance, imt.ImagingTranscriptomics) 51 | assert imt_instance._regions == "all" 52 | assert imt_instance._method == "pls" 53 | assert imt_instance.scan_data.shape == (41,) 54 | assert imt_instance.scan_data.dtype == np.float64 55 | np.testing.assert_array_almost_equal(imt_instance._cortical, zscore( 56 | data, ddof=1)[:34]) 57 | assert imt_instance.zscore_data.shape == (41,) 58 | assert imt_instance._permutations is None 59 | # Test with only cortical regions 60 | data = np.random.rand(41) 61 | imt_instance = imt.ImagingTranscriptomics(data, regions="cort", 62 | method="pls", n_components=1) 63 | assert isinstance(imt_instance, imt.ImagingTranscriptomics) 64 | assert imt_instance._regions == "cort" 65 | assert imt_instance._method == "pls" 66 | assert imt_instance.scan_data.shape == (41,) 67 | assert imt_instance.scan_data.dtype == np.float64 68 | assert imt_instance._subcortical is None 69 | assert imt_instance.zscore_data.shape == (41,) 70 | assert imt_instance._permutations is None 71 | 72 | 73 | def test_wrong_method(): 74 | """ 75 | Test the initialization of a transcriptomics object with a wrong method. 76 | """ 77 | data = np.random.rand(41) 78 | with pytest.raises(ValueError): 79 | imt.ImagingTranscriptomics(data, regions="all", method="wrong") 80 | 81 | 82 | def test_missing_pls_argument(): 83 | """ 84 | Test the initialization of a transcriptomics object with a wrong method. 85 | """ 86 | data = np.random.rand(41) 87 | with pytest.raises(ValueError): 88 | imt.ImagingTranscriptomics(data, regions="all", method="pls") 89 | 90 | 91 | def test_from_scan_init(tdata_dir): 92 | scan = tdata_dir / "MNI152_T1_1mm.nii.gz" 93 | imt_instance = imt.ImagingTranscriptomics.from_scan(scan, regions="all", 94 | method="corr") 95 | assert isinstance(imt_instance, imt.ImagingTranscriptomics) 96 | with pytest.raises(ValueError): 97 | imt.ImagingTranscriptomics.from_scan(scan, regions="all", 98 | method="pca") 99 | with pytest.raises(ValueError): 100 | imt.ImagingTranscriptomics.from_scan(scan, regions="none", 101 | method="corr") 102 | 103 | 104 | def test_from_scan_errors(tdata_dir): 105 | scan = tdata_dir / "MNI152_T1_1mm_brain.nii.gz" 106 | with pytest.raises(FileNotFoundError): 107 | imt.ImagingTranscriptomics.from_scan(scan, regions="all", 108 | method="corr") 109 | 110 | 111 | def test_from_file_init(tdata_dir): 112 | file = tdata_dir / "test_input.txt" 113 | imt_instance = imt.ImagingTranscriptomics.from_file(file, regions="all", 114 | method="corr") 115 | assert isinstance(imt_instance, imt.ImagingTranscriptomics) 116 | with pytest.raises(ValueError): 117 | imt.ImagingTranscriptomics.from_file(tdata_dir, regions="all", 118 | method="corr") 119 | with pytest.raises(FileNotFoundError): 120 | imt.ImagingTranscriptomics.from_file(tdata_dir / "new_file.txt", 121 | regions="none", method="corr") 122 | 123 | 124 | def test_permute_data(): 125 | """Test the permutations method.""" 126 | data = np.random.rand(41) 127 | imt_instance = imt.ImagingTranscriptomics(data, regions="all", 128 | method="pls", n_components=1) 129 | assert imt_instance._permutations is None 130 | imt_instance.permute_data() 131 | assert imt_instance._permutations is not None 132 | assert imt_instance._permutations.shape == (41, 1000) 133 | assert imt_instance._permutations.dtype == np.float64 134 | 135 | 136 | def test_permute_data_with_cort(): 137 | """Test the permutations method.""" 138 | data = np.random.rand(34) 139 | imt_instance = imt.ImagingTranscriptomics(data, regions="cort", 140 | method="pls", n_components=1) 141 | imt_instance.permute_data() 142 | assert imt_instance._permutations.shape == (34, 1000) 143 | assert imt_instance._permutations.dtype == np.float64 144 | 145 | 146 | def test_make_out_dir(tmpdir): 147 | """Test the make_out_dir method.""" 148 | out_dir = tmpdir / "Imt_test_pls" 149 | imt_instance = imt.ImagingTranscriptomics(np.random.rand(41), 150 | regions="all", method="pls", 151 | n_components=1) 152 | imt_instance._make_output_dir(tmpdir, "test") 153 | assert out_dir.exists() 154 | 155 | 156 | def test_atlas_transcriptomics(): 157 | imt_instance = imt.ImagingTranscriptomics(np.random.rand(41), 158 | atlas="DK") 159 | assert imt_instance.atlas == "DK" 160 | assert imt_instance.atlas != "Schaefer_100" 161 | imt_instance = imt.ImagingTranscriptomics(np.random.rand(50), 162 | atlas="Schaefer_100") 163 | assert imt_instance.atlas != "DK" 164 | assert imt_instance.atlas == "Schaefer_100" 165 | 166 | 167 | def test_permute_data_schaefer_100(): 168 | """Test the permutations method.""" 169 | data = np.random.rand(50) 170 | imt_instance = imt.ImagingTranscriptomics(data, 171 | atlas="Schaefer_100", 172 | regions="all", 173 | method="corr") 174 | assert imt_instance._permutations is None 175 | imt_instance.permute_data() 176 | assert imt_instance._permutations is not None 177 | assert imt_instance._permutations.shape == (50, 1000) 178 | assert imt_instance._permutations.dtype == np.float64 179 | 180 | 181 | def test_shaefer_error(): 182 | """Test the correct number of inputs.""" 183 | data = np.random.rand(41) 184 | with pytest.raises(ValueError): 185 | imt.ImagingTranscriptomics(data, atlas="Schaefer_100", 186 | regions="all", method="corr") 187 | 188 | def test_run_schaefer(): 189 | """Test the run method.""" 190 | data = np.random.rand(50) 191 | imt_instance = imt.ImagingTranscriptomics(data, 192 | atlas="Schaefer_100", 193 | regions="all", 194 | method="corr") 195 | imt_instance.run(save_res = False) 196 | assert imt_instance._permutations is not None 197 | assert imt_instance._permutations.shape == (50, 1000) 198 | assert imt_instance._permutations.dtype == np.float64 199 | assert imt_instance._method == "corr" 200 | assert imt_instance.atlas == "Schaefer_100" 201 | assert imt_instance._regions == "all" 202 | assert imt_instance.scan_data is not None 203 | assert imt_instance._subcortical is None 204 | assert imt_instance.zscore_data is not None 205 | 206 | 207 | def test_imt_gsea(): 208 | """Test runing an analysis with GSEA. (used for profiling""" 209 | 210 | -------------------------------------------------------------------------------- /imaging_transcriptomics/transcriptomics.py: -------------------------------------------------------------------------------- 1 | import logging.config 2 | import logging 3 | import warnings 4 | from pathlib import Path 5 | import pickle 6 | 7 | import numpy as np 8 | import yaml 9 | from scipy.stats import zscore 10 | 11 | with warnings.catch_warnings(): 12 | warnings.filterwarnings("ignore") 13 | from netneurotools import freesurfer, stats 14 | 15 | from .inputs import load_gene_expression, load_gene_labels, \ 16 | extract_average, read_scan, load_atlas_imaging, get_annot_files 17 | from .pls import PLSAnalysis 18 | from .corr import CorrAnalysis 19 | 20 | cfg_file_path = Path(__file__).parent / "log_config.yaml" 21 | with open(cfg_file_path, "r") as config_file: 22 | log_cfg = yaml.safe_load(config_file.read()) 23 | 24 | logging.config.dictConfig(log_cfg) 25 | logger = logging.getLogger("transcriptomics") 26 | logger.setLevel(logging.DEBUG) 27 | 28 | 29 | class ImagingTranscriptomics: 30 | # --------- INITIALIZATION --------- # 31 | def __init__(self, 32 | scan_data, 33 | regions="cort+sub", 34 | method="corr", 35 | atlas="DK", 36 | n_permutations=1000, 37 | **kwargs): 38 | """ImagingTranscriptomics class for imaging transcriptomics analysis. 39 | 40 | :param np.array scan_data: imaging scan data. 41 | :param str regions: regions to be used for analysis. These can be 42 | "cort+sub" (or "all") which will perform the analysis on the 43 | cortical and subcortical regions, or "cort" which will only perform 44 | the analysis on the cortical regions. 45 | :param str method: method to run the analysis, can be either "pls" 46 | for pls regression or "corr" cor simple correlation analysis. 47 | :param kwargs: additional arguments for the method. This include: 48 | * "n_components": number of components for pls regression. 49 | * "var": variance explained for pls regression. 50 | * "n_permutations": number of permutations for permutation test. 51 | 52 | """ 53 | self.atlas = atlas 54 | self.n_regions, _ = load_atlas_imaging(self.atlas) 55 | self.n_permutations = n_permutations 56 | if self.atlas == "DK": 57 | if regions in ["cort+sub", "all"]: 58 | assert scan_data.shape == (41,) 59 | self.zscore_data = zscore(scan_data, axis=0, ddof=1) 60 | self._cortical = self.zscore_data[:34] 61 | self._subcortical = self.zscore_data[34:] 62 | elif regions == "cort": 63 | assert scan_data.shape in [(34,), (41,)] 64 | self.zscore_data = zscore(scan_data, axis=0, ddof=1) 65 | self._cortical = self.zscore_data if scan_data.shape == ( 66 | 34,) else \ 67 | self.zscore_data[:34] 68 | self._subcortical = None 69 | elif self.atlas == "Schaefer_100": 70 | if regions in ["cort+sub", "all"]: 71 | logging.info( 72 | "The Schaefer_100 atlas only has cortical regions!") 73 | if scan_data.shape != (50,): 74 | raise ValueError("The scan data must have 50 regions!") 75 | self.zscore_data = zscore(scan_data, axis=0, ddof=1) 76 | self._cortical = self.zscore_data 77 | self._subcortical = None 78 | self._regions = regions 79 | self.scan_data = scan_data 80 | self.gene_expression = load_gene_expression(self._regions, atlas) 81 | self.gene_labels = load_gene_labels() 82 | if method not in ["pls", "corr"]: 83 | raise ValueError( 84 | "The method must be either pls or corr." 85 | "Please choose either pls or corr to run the analysis." 86 | ) 87 | else: 88 | self._method = method 89 | if self._method == "pls": 90 | if "n_components" not in kwargs and "var" not in kwargs: 91 | raise ValueError("You must specify either the variance or " 92 | "the number of components for pls regression") 93 | if self._regions in ["all", "cort+sub"]: 94 | self.analysis = PLSAnalysis(self.zscore_data, 95 | self.gene_expression, 96 | kwargs.get("n_components"), 97 | kwargs.get("var")) 98 | else: 99 | self.analysis = PLSAnalysis(self._cortical, 100 | self.gene_expression, 101 | kwargs.get("n_components"), 102 | kwargs.get("var")) 103 | elif self._method == "corr": 104 | self.analysis = CorrAnalysis(n_iterations=self.n_permutations) 105 | self._permutations = None 106 | self._permutation_ind = None 107 | 108 | @classmethod 109 | def from_scan(cls, scan_path, method="pls", regions="cort+sub", 110 | atlas="DK", **kwargs): 111 | """Initialise an ImagingTranscriptomics object from a NIfTI scan. 112 | The extracted data corresponds to the average of the ROIs in the DK 113 | atlas. 114 | 115 | :param str scan_path: path to the NIfTI scan. 116 | :param str method: method to run the analysis, can be either "pls" 117 | for pls regression or "corr" cor simple correlation analysis. 118 | :param str regions: regions to be used for analysis. These can be 119 | "cort+sub" (or "all") which will perform the analysis on the 120 | cortical and subcortical regions, or "cort" which will only perform 121 | the analysis on the cortical regions. 122 | :param kwargs: additional arguments for the method. This include: 123 | * "n_components": number of components for pls regression. 124 | * "var": variance explained for pls regression. 125 | * "n_permutations": number of permutations for permutation test. 126 | :return: ImagingTranscriptomics object. 127 | """ 128 | if not Path(scan_path).exists(): 129 | raise FileNotFoundError("The specified scan file does not exist.") 130 | if method not in ["pls", "corr"]: 131 | raise ValueError( 132 | "The method must be either pls or corr." 133 | "Please choose either pls or corr to run the analysis." 134 | ) 135 | if regions not in ["cort+sub", "cort", "all"]: 136 | raise ValueError( 137 | "The regions must be either cort+sub, cort or all." 138 | "Please choose one of these to run the analysis." 139 | ) 140 | scan_data = extract_average(read_scan(scan_path), atlas=atlas) 141 | return cls(scan_data, method=method, regions=regions, 142 | atlas=atlas, **kwargs) 143 | 144 | @classmethod 145 | def from_file(cls, file_path, method="pls", regions="cort+sub", 146 | atlas="DK", 147 | **kwargs): 148 | """Initialise an ImagingTranscriptomics object from a text file. 149 | The file should contain a column with the data you want to use for 150 | the analysis. 151 | 152 | :param str file_path: path to the text file. The text file should 153 | contain a column with the data you want to use for the analysis. 154 | :param str method: method to run the analysis, can be either "pls" 155 | for pls regression or "corr" cor simple correlation analysis. 156 | :param str regions: regions to be used for analysis. These can be 157 | "cort+sub" (or "all") which will perform the analysis on the 158 | cortical and subcortical regions, or "cort" which will only perform 159 | the analysis on the cortical regions. 160 | :param str atlas: atlas to use for the analysis. 161 | :param kwargs: additional arguments for the method. This include: 162 | * "n_components": number of components for pls regression. 163 | * "var": variance explained for pls regression. 164 | * "n_permutations": number of permutations for permutation test. 165 | :return: ImagingTranscriptomics object. 166 | """ 167 | if not Path(file_path).exists(): 168 | raise FileNotFoundError("The specified file does not exist.") 169 | if not Path(file_path).is_file(): 170 | raise ValueError(f"{file_path} is not a file.") 171 | scan_data = np.loadtxt(file_path) 172 | return cls(scan_data, method=method, regions=regions, atlas=atlas, 173 | **kwargs) 174 | 175 | # --------- PROPERTIES --------- # 176 | @property 177 | def method(self): # pragma: no cover, simply returns stuff 178 | return self._method 179 | 180 | @property 181 | def gene_results(self): # pragma: no cover, simply returns stuff 182 | return self.analysis.gene_results 183 | 184 | # --------- METHODS --------- # 185 | def permute_data(self, atlas="DK"): 186 | """Permute the imaging data maintaining spatial autocorrelation for 187 | the cortical regions. The permutation is done using the 188 | netneurotools Python package. 189 | 190 | :param int n_permutations: number of permutations. 191 | 192 | """ 193 | logger.info("Permuting data.") 194 | _permuted = np.zeros((self.zscore_data.shape[0], self.n_permutations)) 195 | _perm_indexes = np.zeros((self.zscore_data.shape[0], 196 | self.n_permutations), dtype=np.int32) 197 | # Calculate the permutations on the subcortical regions. 198 | if atlas == "DK": 199 | if self._subcortical is not None: 200 | sub_permuted = np.zeros((self._subcortical.shape[0], 201 | self.n_permutations)) 202 | for i in range(self.n_permutations): 203 | sub_resample = np.random.choice(7, size=7) 204 | _perm_indexes[34:, i] = sub_resample + 34 # keep into 205 | # account the shift of the subcortical given by the cortical 206 | # regions. 207 | sub_permuted[:, i] = self._subcortical[sub_resample] 208 | _permuted[34:, :] = sub_permuted 209 | # Cortical 210 | # Annotation file for the Desikan-Killiany atlas in fs5 211 | annot_lh, annot_rh = get_annot_files(atlas=atlas) 212 | # Get the parcel centroids of the Desikan-Killiany atlas 213 | parcel_centroids, parcel_hemi = freesurfer.find_parcel_centroids( 214 | lhannot=annot_lh, 215 | rhannot=annot_rh, 216 | version="fsaverage5", 217 | surf="sphere", 218 | method="surface", 219 | ) 220 | # Mask the results to have only the left hemisphere 221 | left_hemi_mask = parcel_hemi == 0 222 | parcel_centroids, parcel_hemi = ( 223 | parcel_centroids[left_hemi_mask], 224 | parcel_hemi[left_hemi_mask], 225 | ) 226 | # Get the spin samples 227 | spins = stats.gen_spinsamples( 228 | parcel_centroids, parcel_hemi, 229 | n_rotate=self.n_permutations, 230 | method="vasa", 231 | seed=1234 232 | ) 233 | cort_permuted = np.array(self._cortical[spins]).reshape(34, 234 | self.n_permutations) 235 | _perm_indexes[:34, :] = spins 236 | _permuted[0:34, :] = cort_permuted 237 | self._permutations = _permuted 238 | self._permutation_ind = _perm_indexes 239 | elif atlas == "Schaefer_100": 240 | # Cortical 241 | # Annotation file for the Desikan-Killiany atlas in fs5 242 | annot_lh, annot_rh = get_annot_files(atlas=atlas) 243 | # Get the parcel centroids of the Desikan-Killiany atlas 244 | parcel_centroids, parcel_hemi = freesurfer.find_parcel_centroids( 245 | lhannot=annot_lh, 246 | rhannot=annot_rh, 247 | version="fsaverage5", 248 | surf="sphere", 249 | method="surface", 250 | ) 251 | # Mask the results to have only the left hemisphere 252 | left_hemi_mask = parcel_hemi == 0 253 | parcel_centroids, parcel_hemi = ( 254 | parcel_centroids[left_hemi_mask], 255 | parcel_hemi[left_hemi_mask], 256 | ) 257 | # Get the spin samples 258 | spins = stats.gen_spinsamples( 259 | parcel_centroids, parcel_hemi, 260 | n_rotate=self.n_permutations, 261 | method="vasa", 262 | seed=1234 263 | ) 264 | self._permutations = self.zscore_data[spins] 265 | self._permutation_ind = spins 266 | return 267 | 268 | def _make_output_dir(self, output_dir, name=""): 269 | """Create the output directory if it does not exist. 270 | 271 | :param str output_dir: path to the output directory. 272 | :param str name: name of the output directory, if not provided 273 | disregard. 274 | """ 275 | outdir = Path(output_dir) / f"Imt_{name}_{self.method}" 276 | outdir.mkdir(exist_ok=True) 277 | return outdir 278 | 279 | def _save_object(self, outdir, name): 280 | """Save the object as a pickle file. 281 | 282 | :param str outdir: path to the output directory. 283 | :param str name: name of the output file. 284 | """ 285 | outfile = Path(outdir) / f"{name}.pkl" 286 | with open(outfile, "wb") as f: 287 | pickle.dump(self, f) 288 | return 289 | 290 | # --------- RUN ANALYSIS --------- # 291 | def gsea(self, outdir=None, gene_set="lake", gene_limit=1500): 292 | 293 | if self.method == "corr": 294 | self.analysis.gsea(gene_set=gene_set, outdir=outdir, 295 | gene_limit=gene_limit) 296 | elif self.method == "pls": 297 | self.gene_results.results.gsea(gene_set=gene_set, 298 | perm_index=self._permutation_ind, 299 | outdir=outdir, 300 | gene_limit=gene_limit) 301 | 302 | def run(self, outdir=None, scan_name="", gsea=False, 303 | gene_set="lake", save_res=True, n_cpu=4, 304 | gene_limit=1500): # pragma: no cover 305 | """Method to run the imaging transcriptomics analysis. 306 | 307 | :param str outdir: path to the output directory, if not provided the 308 | results will be saved in the current directory. 309 | :param str scan_name: name of the scan, if not provided the name will 310 | be ignored. Is used only to create the output directory. 311 | :param bool gsea: if True, run the GSEA analysis, if False the GSEA 312 | analysis is skipped. 313 | :param str gene_set: gene set to use for the GSEA analysis. 314 | :param bool save_res: if True, save the results in a directory, 315 | if False the results are not saved. 316 | :param int n_cpu: number of CPUs to use for the analysis (only for 317 | correlation analysis). 318 | :param int gene_limit: number of genes to use for the GSEA analysis. 319 | """ 320 | logger.info(f"Running the {self.method} analysis.") 321 | # Create the permuted data matrix 322 | self.permute_data(atlas=self.atlas) 323 | # Check if the ouput directory is provided and create the output folder 324 | if save_res: 325 | if outdir is not None: 326 | outdir = self._make_output_dir(outdir, name=scan_name) 327 | else: 328 | outdir = self._make_output_dir(Path.cwd(), name=scan_name) 329 | # Run the analysis 330 | # CORRELATION 331 | if self.atlas == "DK": 332 | if self._method == "corr": 333 | # Select the data or slice of data 334 | if self._regions == "cort": 335 | _d = self._cortical 336 | if self._permutations.shape[0] == self.n_regions: 337 | _d_perm = self._permutations[0:34, :] 338 | else: 339 | _d_perm = self._permutations 340 | elif self._regions in ["cort+sub", "all"]: 341 | _d = self.zscore_data 342 | _d_perm = self._permutations 343 | self.analysis.bootstrap_correlation(_d, _d_perm, 344 | self.gene_expression, 345 | self.gene_labels) 346 | 347 | if save_res: 348 | self._save_object(outdir, f"{self.method}_analysis") 349 | self.analysis.save_results(outdir=outdir) 350 | if gsea: 351 | self.gsea(gene_set=gene_set, outdir=outdir) 352 | elif self._method == "pls": 353 | # Select the data or slice of data 354 | if self._regions == "cort": 355 | _d = self._cortical 356 | if self._permutations.shape[0] == 41: 357 | _d_perm = self._permutations[0:34, :] 358 | else: 359 | _d_perm = self._permutations 360 | elif self._regions in ["cort+sub", "all"]: 361 | _d = self.zscore_data 362 | _d_perm = self._permutations 363 | assert isinstance(self.analysis, PLSAnalysis) 364 | self.analysis.boot_pls(_d, _d_perm, self.gene_expression) 365 | if self._regions == "cort": 366 | _orig = self.scan_data if self.scan_data.shape[ 367 | 0] == 34 else \ 368 | self.scan_data[0:34, :] 369 | elif self._regions in ["cort+sub", "all"]: 370 | _orig = self.scan_data 371 | self.gene_results.results.boot_genes(_d, 372 | _d_perm, 373 | _orig, 374 | self.gene_expression, 375 | self.gene_labels) 376 | self.gene_results.results.compute() 377 | if save_res: 378 | self._save_object(outdir, 379 | f"{self.atlas}_{self.method}_analysis") 380 | self.analysis.save_results(outdir=outdir) 381 | if gsea: 382 | self.gsea(gene_set=gene_set, outdir=outdir, 383 | gene_limit=gene_limit) 384 | 385 | elif self.atlas == "Schaefer_100": 386 | _d = self.zscore_data 387 | _d_perm = self._permutations 388 | if self._method == "corr": 389 | self.analysis.bootstrap_correlation(_d, _d_perm, 390 | self.gene_expression, 391 | self.gene_labels) 392 | elif self._method == "pls": 393 | assert isinstance(self.analysis, PLSAnalysis) 394 | self.analysis.boot_pls(_d, _d_perm, self.gene_expression) 395 | self.gene_results.results.boot_genes(_d, 396 | _d_perm, 397 | self.scan_data, 398 | self.gene_expression, 399 | self.gene_labels) 400 | self.gene_results.results.compute() 401 | if save_res: 402 | #self._save_object(outdir,f"{self.atlas}_{self.method}_analysis") 403 | self.analysis.save_results(outdir=outdir) 404 | if gsea: 405 | self.gsea(gene_set=gene_set, 406 | outdir=outdir, 407 | gene_limit=gene_limit) 408 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | minversion = 3.0 3 | testpaths = 4 | imaging_transcriptomics/tests 5 | 6 | [tool: pytest] 7 | norecursedirs = 8 | src/*pyls* 9 | imaging_transcriptomics/reporting.py 10 | imaging_transcriptomics/pls.py 11 | imaging_transcriptomics/corr.py 12 | imaging_transcriptomics/genes.py 13 | imaging_transcriptomics/scripts/* 14 | 15 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | h5py 2 | numpy==1.21.1 3 | pytest==6.2.4 4 | tqdm==4.61.2 5 | scikit-learn==0.24.2 6 | scipy==1.7.0 7 | pandas==1.3.1 8 | joblib==1.0.1 9 | setuptools==52.0.0 10 | pyyaml==5.4.1 11 | statsmodels==0.12.2 12 | nibabel==3.2.1 13 | matplotlib==3.4.2 14 | netneurotools==0.2.3 15 | gseapy>=1.0.0 16 | nilearn==0.8.1 17 | vtk 18 | numba==0.55.1 19 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | from pathlib import Path 3 | from glob import glob 4 | 5 | 6 | def read_long_description(): 7 | """Read the README file and use it as long description in Pypi. 8 | 9 | :return: contents of the readme file. 10 | """ 11 | with open("README.md", "r") as f: 12 | return f.read() 13 | 14 | 15 | def get_version_number(): 16 | """Get the version of the package from the __init__ file. 17 | 18 | :return version: version of the package. 19 | """ 20 | with open("imaging_transcriptomics/__init__.py", "r") as f: 21 | for line in f: 22 | if '__version__' in line: 23 | _, version, _ = line.split('"') 24 | break 25 | return version 26 | 27 | 28 | def get_requirements(): 29 | """Get the requirements for the installation.""" 30 | requirements = [] 31 | with open('requirements.txt', 'r') as f: 32 | requirements.extend(line.rstrip('\n') for line in f if line[0] != '#') 33 | return requirements 34 | 35 | 36 | setup(name="imaging-transcriptomics", 37 | author="Alessio Giacomel, Daniel Martins", 38 | author_email="alessio.giacomel@kcl.ac.uk , daniel.martins@kcl.ac.uk", 39 | version=get_version_number(), 40 | url="https://github.com/alegiac95/Imaging-transcriptomics", 41 | description="A package to perform imaging transcriptomics analysis on a " 42 | "neuroimaging brain scan.", 43 | license="GPLv3", 44 | long_description=read_long_description(), 45 | long_description_content_type="text/markdown", 46 | classifiers=["Intended Audience :: Healthcare Industry", 47 | "Intended Audience :: Science/Research", 48 | "Topic :: Scientific/Engineering :: Image Processing", 49 | "Topic :: Scientific/Engineering :: Medical Science Apps.", 50 | "Development Status :: 4 - Beta", 51 | "Programming Language :: Python :: 3", 52 | "Programming Language :: Python :: 3.6", 53 | ], 54 | keywords="Image analysis, Neuroimaging, Imaging Transcriptomics, " 55 | "Medical Imaging, Research, Multimodal Imaging", 56 | install_requires=get_requirements(), 57 | packages=["imaging_transcriptomics"], 58 | include_package_data=True, 59 | package_data={"imaging_transcriptomics": ["*.yaml", "*.nii.gz", 60 | "*.csv", "*.txt", "*.annot", 61 | "data/*"]}, 62 | entry_points={ 63 | "console_scripts": [ 64 | "imagingtranscriptomics=imaging_transcriptomics.script" 65 | ".imagingtranscriptomics:main", 66 | "imt_gsea=imaging_transcriptomics.script.imt_gsea:main", 67 | ] 68 | }, 69 | project_urls={ 70 | "Source": "https://github.com/alegiac95/Imaging-transcriptomics", 71 | "Bug Reports": "https://github.com/alegiac95/Imaging-transcriptomics/issues", 72 | "Documentation": "https://imaging-transcriptomics.rtfd.io/" 73 | }, 74 | python_requires=">=3.6, <3.9" 75 | ) 76 | --------------------------------------------------------------------------------