Skip to content

freesurfer_subject_dir not passed to get_surf() in segment.cut_surface() #591

@keanutoomer

Description

@keanutoomer

Hi,

I have encountered this issue with pycortex 1.2.12 where I access FreeSurfer via shims that invoke a containerised installation, so SUBJECTS_DIR is not set in my shell environment. Calling cortex.segment.cut_surface() with freesurfer_subject_dir specified causes a KeyError when SUBJECTS_DIR is inaccessible via os.environ. The issue stems from freesurfer_subject_dir not being passed to freesurfer.get_surf() during the vertex check for 'inflated' and 'fiducial' surfaces (line 188-189). This causes subsequent function calls to default the freesurfer_subject_dir path to None, which triggers an error in freesurfer.get_paths() if SUBJECTS_DIR is not exported to the environment (as in my case).

In [3]: cortex.segment.cut_surface(cx_subject="sub-102311", hemi="lh", name="flatten", freesurfer_subject_dir="/home/keanu/projects/hcp-retinotopy/derivatives/freesurfer", flatten_with="blender", recache=True, do_import_subject=False)
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[3], line 1
----> 1 cortex.segment.cut_surface(cx_subject="sub-102311", hemi="lh", name="flatten", freesurfer_subject_dir="/home/keanu/projects/hcp-retinotopy/derivatives/freesurfer", flatten_with="blender", recache=True, do_import_subject=False)

File ~/projects/hcp-retinotopy/.venv/lib/python3.13/site-packages/cortex/segment.py:189, in cut_surface(cx_subject, hemi, name, fs_subject, data, freesurfer_subject_dir, flatten_with, method, do_import_subject, blender_path, recache, auto_overwrite, **kwargs)
    184     fs_subject = cx_subject
    186 # Double-check that fiducial and inflated vertex counts match
    187 # (these may not match if a subject is initially imported from freesurfer to pycortex,
    188 # and then edited further for a better segmentation and not re-imported)
--> 189 ipt, ipoly, inrm = freesurfer.get_surf(fs_subject, hemi, "inflated")
    190 fpt, fpoly, fnrm = freesurfer.get_surf(fs_subject, hemi, "fiducial")
    191 if ipt.shape[0] != fpt.shape[0]:

File ~/projects/hcp-retinotopy/.venv/lib/python3.13/site-packages/cortex/freesurfer.py:495, in get_surf(subject, hemi, type, patch, flatten_step, freesurfer_subject_dir)
    493     surf_file = get_paths(subject, hemi, 'surf', freesurfer_subject_dir=freesurfer_subject_dir).format(name='smoothwm')
    494 else:
--> 495     surf_file = get_paths(subject, hemi, 'surf', freesurfer_subject_dir=freesurfer_subject_dir).format(name=type)
    497 pts, polys = parse_surf(surf_file)
    499 if patch is not None:

File ~/projects/hcp-retinotopy/.venv/lib/python3.13/site-packages/cortex/freesurfer.py:43, in get_paths(fs_subject, hemi, type, freesurfer_subject_dir)
     27 """Retrieve paths for all surfaces for a subject processed by freesurfer
     28 
     29 Parameters
   (...)     40     by freesurfer)
     41 """
     42 if freesurfer_subject_dir is None:
---> 43     freesurfer_subject_dir = os.environ['SUBJECTS_DIR']
     44 base = os.path.join(freesurfer_subject_dir, fs_subject)
     45 if type == "patch":

File <frozen os>:717, in __getitem__(self, key)

KeyError: 'SUBJECTS_DIR'

It looks like freesurfer.get_surf() should be passed freesurfer_subject_dir, as in other functions, to prevent the path regressing to None and triggering freesurfer.get_paths() to pull from SUBJECTS_DIR. Under normal installations this would not trigger this error, as SUBJECTS_DIR would be available, however this would still cause issues when specifying a custom path unless it is exported to the environment beforehand.

Suggested fix:
Pass freesurfer_subject_dir to freesurfer.get_surf() calls in segment.cut_surface(). This would not affect cases where the argument is not specified, since it will default to None anyway and be set by the environment SUBJECTS_DIR.

ipt, ipoly, inrm = freesurfer.get_surf(fs_subject, hemi, "inflated", freesurfer_subject_dir=freesurfer_subject_dir)
fpt, fpoly, fnrm = freesurfer.get_surf(fs_subject, hemi, "fiducial", freesurfer_subject_dir=freesurfer_subject_dir)

Testing the changes appears to fix the issue:

In [5]: cortex.segment.cut_surface(cx_subject="sub-102311", hemi="lh", name="flatten", freesurfer_subject_dir="/home/keanu/projects/hcp-retinotopy/derivatives/freesurfer", flatten_with="blender", recache=True, do_import_subject=False)
b'created by kltoomer on Sat Jan 24 14:30:38 2026\n'
b'\n'
Vert check ok!
Initializing blender file /home/keanu/projects/hcp-retinotopy/.venv/share/pycortex/db/sub-102311/anatomicals/cutsurf[hemi=lh,name=flatten].blend...
b'created by kltoomer on Sat Jan 24 14:30:30 2026\n'
b'created by kltoomer on Sat Jan 24 14:30:38 2026\n'
In new named temp file: /tmp/tmpcsb2fw00
Calling blender:
    blender -b -P /tmp/tmpcsb2fw00
Blender 4.3.2
Adding python site directory to sys.path: /home/keanu/projects/hcp-retinotopy/.venv/lib/python3.13/site-packages/cortex/blender
Adding python site directory to sys.path: /home/keanu/projects/hcp-retinotopy/.venv/lib/python3.13/site-packages
Adding python site directory to sys.path: /home/keanu/projects/hcp-retinotopy/.venv/local/lib/python3.13/dist-packages
Adding python site directory to sys.path: /home/keanu/projects/hcp-retinotopy/.venv/lib/python3/dist-packages
Adding python site directory to sys.path: /home/keanu/projects/hcp-retinotopy/.venv/lib/python3.13/dist-packages
Started init_subject in blender!
Successfully added vcolor 'curvature'
Info: Saved "cutsurf[hemi=lh,name=flatten].blend"

Blender quit
Opening blender file /home/keanu/projects/hcp-retinotopy/.venv/share/pycortex/db/sub-102311/anatomicals/cutsurf[hemi=lh,name=flatten].blend...
In new named temp file: /tmp/tmp8l5mx2a0
Detected Blender 4.3.2
Calling blender:
    blender /home/keanu/projects/hcp-retinotopy/.venv/share/pycortex/db/sub-102311/anatomicals/cutsurf[hemi=lh,name=flatten].blend
Read blend: "/home/keanu/projects/hcp-retinotopy/.venv/share/pycortex/db/sub-102311/anatomicals/cutsurf[hemi=lh,name=flatten].blend"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions