Library / SDK
gallantlab/pycortex avatar
gallantlab/pycortex

pycortex: fMRI data on cortical surfaces, from an IPython prompt

Pycortex is a python-based toolkit for surface visualization of fMRI data

665 stars159 forksJavaScriptBSD-2-Clause

At a glance

What is it?
pycortex is a Python toolkit for putting volumetric neuroimaging data onto cortical surfaces and viewing the result in a browser. It ships Cython extensions, a large dependency set, optional headless rendering, and a visual regression test suite, and it expects to be driven interactively rather than from a script.
Who is it for?
Adopt pycortex if you work with surface-based neuroimaging and want an interactive view of functional data on the cortical mesh without writing a WebGL viewer yourself, and if you can accept a dependency set that includes numpy, scipy, nibabel, h5py and tornado. Skip it if your analysis is volumetric only, since pycortex is built around the surface representation, or if you cannot install a C compiler, because the package contains Cython code.
Can I use it commercially?
Yes. BSD-2-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Volumetric data, projected onto a cortical mesh

Pycortex is described as a software library that allows you to visualize fMRI or other volumetric neuroimaging data on cortical surfaces. That single sentence places it precisely in the neuroimaging workflow: the data arrives as a volume, the tool maps it onto a cortical surface representation, and the result is something you can look at and interact with in a browser.

The homepage carries a quickflat demo image, which is the fastest way to understand the output. A flatmap view is the reason this kind of tool exists, because a cortical surface has folds that hide most of the cortex in a 3D view, and flattening it makes activity legible.

The project belongs to gallantlab, the lab of John Gallant, and the documentation is published at gallantlab.github.io/pycortex. The repository topics are fmri, neuroimaging, python and surface-visualization, and the primary language field says JavaScript, which is a hint about where the rendering happens rather than about the API you program against, since the Python package is the interface and the viewer is the browser side.

The installation instructions mention autoflatten, an optional dependency for automatic surface flattening support, pulled in via the autoflatten extra. The distinction is worth keeping straight when you read the install options.

The licence is BSD-2-Clause, and the README asks that the pycortex paper be cited if the tool is used in published work.

Four install flavours, and a compiler you may need

The stable install is a single pip command, with variants for optional features:

bash
# First, install some required dependencies (if not already installed)
pip install -U setuptools wheel numpy cython
# Install the latest release of pycortex from pip
pip install -U pycortex
# or, with headless rendering support:
pip install -U 'pycortex[headless]'
# or, with automatic surface flattening support (see autoflatten):
pip install -U 'pycortex[autoflatten]'
# or, with all optional features:
pip install -U 'pycortex[all]'

The dependency line comes first and is not optional, because setuptools, wheel, numpy and cython are needed to build the package.

The development version comes from GitHub instead, and it needs a flag that is easy to miss:

bash
# Install development version of pycortex from github
pip install -U git+https://github.com/gallantlab/pycortex.git  --no-build-isolation

The README explains why, in one sentence: you will need a C compiler installed to build from scratch because there are Cython code. The no-build-isolation flag tells pip to use the packages already present in your environment rather than a fresh isolated build environment, which is what makes a locally installed numpy and cython visible to the build.

That is the operational trap in this project. pip install from a wheel hides the compiler requirement because the wheel is already built, while a GitHub install needs a working toolchain, and the difference between the two paths is exactly the difference between a smooth install and a failed one.

The filestore is copied into the install prefix

The packaging is more than a Python module, and the setup.py shows it. Data files from the filestore/ directory are installed as data_files, with the directory name stripped so that share/pycortex holds the colormaps and other assets rather than a nested filestore directory.

The install command is overridden with a custom class that runs the normal install, then finds the generated defaults.cfg among the installed outputs, computes a prefix under share/pycortex, and rewrites the configuration so the filestore path points at db and the webgl colormaps path points at colormaps inside that prefix. It then copies the filestore tree and adjusts permissions on every directory and file it writes.

The C side is handled by a Cython extension:

python
ctm = Extension('cortex.openctm', [
            'cortex/openctm.pyx',
            'OpenCTM-1.0.3/lib/openctm.c',
            'OpenCTM-1.0.3/lib/stream.c',
            'OpenCTM-1.0.3/lib/compressRAW.c',
            'OpenCTM-1.0.3/lib/compressMG1.c',
            'OpenCTM-1.0.3/lib/compressMG2.c',

The repository carries an OpenCTM-1.0.3/ directory with the C sources that get compiled into the extension, which is why the C compiler requirement exists and why a source install is noticeably heavier than a wheel install. It also explains why the codespell configuration skips that directory, since vendored C sources are full of identifiers that trip a spell checker.

The runtime dependency list is long and specific

The requirements file is a fair description of what pycortex touches. It starts with setuptools and future, then numpy at 1.13.0 or later, scipy, tornado at 4.3 or later, shapely, lxml, html5lib, h5py, numexpr, cython, matplotlib, pillow, nibabel at 2.1 or later, networkx at 2.1 or later, imageio, looseversion, and mda_xdrlib. The last entry is a conditional: typing_extensions for Python versions below 3.11.

Two things in that list deserve comment. tornado is the web server the viewer runs behind, and its presence is the clearest evidence that pycortex serves the browser view locally rather than rendering to a file. h5py points at HDF5 as a data format, which is how large neuroimaging volumes are typically stored.

The dependency on future and the conditional typing_extensions is a sign of the supported Python range. The project badge states Python 3.10 or newer, and the conditional dependency exists so that code written against newer typing features still installs on 3.10.

For an adoption decision, the practical question is whether your environment can absorb this set. In a locked-down analysis environment, the presence of a C compiler, tornado, and a from-source OpenCTM extension may be more friction than the visualization itself is worth.

Extras are declared as PEP 621 optional dependencies

The pyproject file is the modern core of the project, and it declares the extras in the standard way:

toml
[project.optional-dependencies]
headless = [
    "playwright>=1.58.0"
]
autoflatten = [
    "autoflatten>=1.0.0"
]
all = [
    "pycortex[headless,autoflatten]"
]

The headless extra pulls in Playwright, which is how the browser view can be rendered without a human at the screen, and that is what makes the visual regression tests possible. The all extra simply composes the two.

The build system section requires setuptools 64 or newer, setuptools-scm 8 or newer, build, numpy 1.13.0 or newer, cython and wheel, with the setuptools build backend. The version is stamped by setuptools_scm, which writes it into cortex/_version.py and uses the local_scheme of no-local-version, so a build from a git checkout does not carry a local version suffix.

The project metadata itself is mostly dynamic, with authors, license, readme, version and classifiers filled in at build time rather than written by hand. There is a mypy section that allows redefinition and disables the import-untyped error code, with a TODO to narrow that to specific packages, and per-module overrides that ignore missing imports for bpy, bpy.ops, mayavi, progressbar, scikits.sparse.cholmod and tvtk.api, the last three being the Mayavi stack and a sparse Cholesky binding that the visualisation path can reach for.

Visual regression tests against reference renders

The test dependency group is the most interesting part of the configuration, because it explains how a browser-based visualiser can be tested at all.

The group includes pycortex[headless], so the tests run with the headless extra, and then matplotlib pinned to 3.10.9, playwright pinned to 1.62.0, ipykernel, nbclient, nbformat, pytest, pytest-cov and pytest-timeout. A comment in the file explains the pins: the visual-regression tests compare against renders from these builds, and both are unpinned for users, with a pointer to cortex/tests/reference_images/README.md.

So the project stores expected images of the rendered output and compares new renders against them. Pinning the rendering stack is what makes that comparison meaningful, since a different matplotlib or a different browser build would change pixels for reasons unrelated to the code under test.

The nbclient and ipykernel entries point at a second style of test, running notebooks, which fits a project whose documentation is an example gallery built with sphinx-gallery, where the examples are executable.

The repository also has pytest.ini for the test configuration, a.codecov.yml for coverage reporting, and a coverage badge in the README, and a codespell configuration that skips generated and vendored paths and carries a small ignore-words list for identifiers that appear in the domain vocabulary.

IPython is the intended interface

The README states that pycortex is best used with IPython, and the demo is two lines:

ipython
$ ipython
In [1]: import cortex
In [2]: cortex.webshow(cortex.Volume.random("S1", "fullhead"))

The shape of that call is the whole API in miniature. A Volume is created, here a random one named S1 with the fullhead surface, and webshow displays it. The randomness is a convenience for the demo, since it avoids needing real data to see the tool work.

If you do not already have IPython, the README gives the install command for it, and this is a reasonable place to note the design choice: pycortex is built for an interactive session where you iterate on a visualisation, not for a batch script that emits a figure and exits. The data volume, the surface, the colormap and the display call are separate pieces you adjust one at a time.

The documentation is built locally with sphinx-gallery and numpydoc:

bash
# Install required dependencies for the documentation
pip install sphinx_gallery numpydoc
# Move into the docs folder (assuming already in pycortex directory)
cd docs
# Build a local version of the documentation site
make html

After that, the built site is at docs/_build/html/index.html, and the online example gallery at gallantlab.github.io/pycortex/auto_examples/index.html collects many worked examples of the features.

Versioning, citation and the state of the branch

The default branch is dev, and the release tags sit on top of it. Recent releases include v1.3.1 on 2026-05-10, v1.3.2 on 2026-05-11 and v1.4.0 on 2026-10-02, with the last push on 2026-10-18. There is a RELEASE.md at the top of the repository for the release process, and the version is derived from git tags by setuptools-scm rather than edited in a file, which means a local checkout reports a different version than the published package.

The citation requirement is explicit. If you use pycortex in published work, the README asks you to cite the pycortex paper, Gao JS, Huth AG, Lescroart MD and Gallant JL (2015), Pycortex: an interactive surface visualizer for fMRI, Frontiers in Neuroinformatics 9:23, with a DOI given. There is also a CITATION.cff file in the repository, which is the machine-readable form of the same information for tooling that collects it.

Two files in the repository are new enough to be worth mentioning for anyone contributing. AGENTS.md and CLAUDE.md sit at the top level alongside the code, which is the current convention for repositories that want to describe their conventions to automated tooling.

The licence is BSD-2-Clause, which is permissive and requires only that the copyright notice and licence text travel with copies of the source.

Editorial conclusion

Adopt pycortex if you work with surface-based neuroimaging and want an interactive view of functional data on the cortical mesh without writing a WebGL viewer yourself, and if you can accept a dependency set that includes numpy, scipy, nibabel, h5py and tornado. Skip it if your analysis is volumetric only, since pycortex is built around the surface representation, or if you cannot install a C compiler, because the package contains Cython code. Before your first run, install the headless extra if you want browser rendering in a non-interactive environment, read cortex/tests/reference_images/README.md if you plan to touch the visual regression baselines, and cite the pycortex paper if the result appears in published work. The last push was on 2026-10-18 and v1.4.0 was released on 2026-10-02.

Frequently asked questions

How do I install pycortex with headless rendering?

Install the extra with pip install -U 'pycortex[headless]', which pulls in Playwright. The headless extra is also what the project's own visual regression tests use, and pip install -U 'pycortex[all]' combines it with the autoflatten extra.

Why does installing pycortex from GitHub need a C compiler?

The README states you will need a C compiler installed to build from scratch because there are Cython code, and the repository builds an OpenCTM extension from vendored C sources. The development install command is pip install -U git+https://github.com/gallantlab/pycortex.git --no-build-isolation.

What does pycortex.webshow do?

It displays a Volume in the browser-based viewer. The demo in the README is cortex.webshow(cortex.Volume.random("S1", "fullhead")), and the project is intended to be used from an IPython session.

How are pycortex visual regression tests pinned?

The test dependency group pins matplotlib to 3.10.9 and playwright to 1.62.0, and the pyproject comment explains that the visual-regression tests compare against renders from these builds while both are left unpinned for users. The reference images live under cortex/tests/reference_images, with details in its README.

Official sources

  1. gallantlab/pycortex on GitHub
  2. License: BSD-2-Clause
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/gallantlab-pycortex.svg)](https://hysenlabs.com/projects/gallantlab-pycortex)

Was this useful?