Skip to main content

BIDS-Aid

Latest Version Python Versions Source Code License Test Status codecov Code style: black Documentation Status

A toolkit for creating and managing BIDS-compliant fMRI datasets without original DICOMs. Intended for cases that require custom code and flexibility, such as when NIfTI source files lack consistent naming conventions, organized folder hierarchies, or sidecar metadata. Includes utilities for metadata reconstruction from NIfTI headers, file renaming, neurobehavioral log parsing (for E-Prime and Presentation), JSON sidecar generation, surface projection, and making surface clips/movies.

Installation

Standard Installation

pip install bidsaid[all]

Surface projection and movie writing are optional extras: bidsaid[surface] (neuromaps for the fsaverage surfaces), bidsaid[visual] (pyvista for rendering) and bidsaid[movie] (imageio with ffmpeg for writing movies). bidsaid[all] includes everything.

Development Version

git clone --depth 1 https://github.com/donishadsmith/bidsaid/
cd bidsaid
pip install -e .[all]

Features

  • File renaming: Convert arbitrary filenames to BIDS-compliant naming

  • File creation: Generate dataset_description.json and participants.tsv

  • Metadata utilities: Extract header metadata (e.g., TR, orientation, scanner info) and generate slice timing for singleband and multiband acquisitions

  • Log parsing: Load Presentation (e.g., .log) and E-Prime 3 (e.g, .edat3, .txt) files as DataFrames, or use extractor classes to generate BIDS events for block and event designs:

    Class Software Design Description
    PresentationBlockExtractor Presentation Block Extracts block-level timing with mean RT and accuracy
    PresentationEventExtractor Presentation Event Extracts trial-level timing with individual responses
    EPrimeBlockExtractor E-Prime 3 Block Extracts block-level timing with mean RT and accuracy
    EPrimeEventExtractor E-Prime 3 Event Extracts trial-level timing with individual responses
  • Auditing: Generate a table showing the presence or absence of certain files for each subject and session

  • QC: Creation and computation of certain quality control metrics (e.g., framewise displacement), censoring and temporal interpolation

  • Surface movies: Project denoised runs onto the fsaverage surfaces and write per-participant, per-task or group movies with SurfaceRenderer and MovieWriter

Quick Start

Creating BIDS-Compliant Filenames

from bidsaid.files import create_bids_file

create_bids_file(
    src_file="101_mprage.nii.gz",
    sub_id="101",
    ses_id="01",
    desc="T1w",
    dst_dir="/data/bids/sub-101/ses-01/anat",
)

Extracting Metadata from NIfTI Headers

from bidsaid.metadata import get_tr, create_slice_timing, get_image_orientation

tr = get_tr("sub-01_bold.nii.gz")
slice_timing = create_slice_timing(
    "sub-01_bold.nii.gz",
    slice_acquisition_method="interleaved",
    multiband_factor=4,
)
orientation_map, orientation = get_image_orientation("sub-01_bold.nii.gz")

Loading Raw Log Files

from bidsaid.parsers import (
    load_presentation_log,
    load_eprime_log,
    convert_edat3_to_text,
)

presentation_df = load_presentation_log("sub-01_task.log", convert_to_seconds=["Time"])

# E-Prime 3: convert .edat3 to text first, or load .txt directly
eprime_txt_path = convert_edat3_to_text("sub-01_task.edat3")
eprime_df = load_eprime_log(eprime_txt_path, convert_to_seconds=["Stimulus.OnsetTime"])

Creating BIDS Events from Presentation Logs

from bidsaid.events import PresentationBlockExtractor
import pandas as pd

extractor = PresentationBlockExtractor(
    "sub-01_task-faces.log",
    trial_types=("Face", "Place"),  # Can use regex ("Fa.*", "Pla.*")
    scanner_event_type="Pulse",
    scanner_trigger_code="99",
    convert_to_seconds=["Time"],
    rest_block_codes="crosshair",
    rest_code_pattern="fixed",
    split_cue_from_block=True,
)

events_df = pd.DataFrame(
    {
        "onset": extractor.extract_onsets(),
        "duration": extractor.extract_durations(),
        "trial_type": extractor.extract_trial_types(),
        "mean_rt": extractor.extract_mean_reaction_times(),
    }
)

Creating BIDS Events from E-Prime Logs

from bidsaid.events import EPrimeEventExtractor
import pandas as pd

extractor = EPrimeEventExtractor(
    "sub-01_task-gonogo.txt",
    trial_types="Go|NoGo",  # Can also use ("Go", "NoGo")
    onset_column_name="Stimulus.OnsetTime",
    procedure_column_name="Procedure",
    trigger_column_name="ScannerTrigger.RTTime",
    convert_to_seconds=[
        "Stimulus.OnsetTime",
        "Stimulus.OffsetTime",
        "ScannerTrigger.RTTime",
    ],
)

events_df = pd.DataFrame(
    {
        "onset": extractor.extract_onsets(),
        "duration": extractor.extract_durations(
            offset_column_name="Stimulus.OffsetTime"
        ),
        "trial_type": extractor.extract_trial_types(),
        "reaction_time": extractor.extract_reaction_times(
            reaction_time_column_name="Stimulus.RT"
        ),
    }
)

Audit BIDS Dataset

from bidsaid.audit import BIDSAuditor
from bidsaid.simulate import simulate_bids_dataset

bids_root = simulate_bids_dataset()

auditor = BIDSAuditor(bids_root)
auditor.check_raw_nifti_availability()
auditor.check_raw_sidecar_availability()
auditor.check_events_availability()
auditor.check_preprocessed_nifti_availability()

analysis_dir = bids_root / "first_level"
analysis_sub_dir = analysis_dir / "sub-1" / "ses-1"
analysis_sub_dir.mkdir(parents=True, exist_ok=True)

with open(analysis_sub_dir / "sub-1_task-rest_desc-betas.nii.gz", "w") as f:
    pass

auditor.check_first_level_availability(analysis_dir=analysis_dir, desc="betas")

Compute QC

from bidsaid.qc import create_censor_mask, compute_consecutive_censor_stats

censor_mask = create_censor_mask(
    "confounds.tsv",
    column_name="framewise_displacement",
    threshold=0.5,
    n_dummy_scans=4,
)

consecutive_censor_mean, consecutive_censor_std = compute_consecutive_censor_stats(
    censor_mask, n_dummy_scans=4
)

Surface Movies

import tempfile
from pathlib import Path

import nibabel as nib, numpy as np
from nilearn.image import smooth_img

from bidsaid.movie import (
    MovieWriter,
    compute_vmax,
    create_surface_run,
    mp4_to_gif,
    virtual_display,
)
from bidsaid.simulate import simulate_nifti_image
from bidsaid.surface import fetch_fsaverage_surfaces, get_cortex_masks
from bidsaid.visual import SurfaceRenderer


def simulate_denoised_img():
    nifti_img = simulate_nifti_image((64, 76, 64, 10))
    mask = nifti_img.get_fdata().any(axis=-1)
    data = smooth_img(nifti_img, fwhm=8).get_fdata()
    data[mask] = (data[mask] - data[mask].mean(axis=-1, keepdims=True)) / data[
        mask
    ].std(axis=-1, keepdims=True)
    data[~mask] = 0

    return nib.Nifti1Image(data.astype(np.float32), nifti_img.affine, nifti_img.header)


src_dir = Path(tempfile.mkdtemp())
denoised_files = []
for subject_id, task_name in (
    (subject_id, task_name)
    for subject_id in ("01", "02")
    for task_name in ("rest", "music")
):
    denoised_file = (
        src_dir / f"sub-{subject_id}_task-{task_name}_desc-denoised_bold.nii.gz"
    )
    nib.save(simulate_denoised_img(), denoised_file)
    denoised_files.append(denoised_file)

surfaces = fetch_fsaverage_surfaces("10k")
cortex_masks = get_cortex_masks(surfaces["medial"])

surface_runs = [
    create_surface_run(
        denoised_file,
        surfaces["pial"],
        surfaces["white"],
        cortex_masks,
        n_interpolated_frames=47,
        interpolation_method="cubic",
    )
    for denoised_file in denoised_files
]

threshold = 1.0
vmax = compute_vmax(surface_runs, threshold=threshold)

with (
    virtual_display(),
    SurfaceRenderer(
        *surfaces["inflated"],
        sulcal_depths=surfaces["sulc"],
        color_range=(-vmax, vmax),
        threshold=threshold,
        top_spacing=80,
    ) as renderer,
):
    movie_files = MovieWriter(
        surface_runs,
        renderer,
        task_order=["rest", "music"],
        playback_speed=1,
        label_format="{subject_name}    {task_name}    t = {frame_time:.1f} s",
        task_spacing=40,
    ).write("movies", per_subject=True, per_task=True, shared=True)

gif_file = mp4_to_gif(movie_files[-1], loop=0)

Surface Movie

See the API documentation for full parameter details and additional utilities.

Metadata

Release files for bidsaid 0.35.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bidsaid 0.35.0
File Size Uploaded Provenance
bidsaid-0.35.0.tar.gz 103.9 MB Without provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for bidsaid 0.35.0
File
bidsaid-0.35.0-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
bidsaid-0.35.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details
bidsaid-0.35.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details
bidsaid-0.35.0-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details

Total release size: 105.5 MB

Release files / bidsaid-0.35.0.tar.gz

Download URL bidsaid-0.35.0.tar.gz
Size 103.9 MB
Tags Source
SHA-256 checksum
How to use checksums
f778970bf263a798a4cd2b5811854397c0150ed64eab3e31d2e99fd2d79fcb0d
BLAKE2b-256 checksum
How to use checksums
229dd8f9e1319c58850349f0a6cae98fda8b6853d57e826bfa30614f6ef11efc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.8

Release files / bidsaid-0.35.0-cp310-abi3-win_amd64.whl

Download URL bidsaid-0.35.0-cp310-abi3-win_amd64.whl
Size 305.2 kB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
7e364f39a14cbe9347a177b779786543102ca8dee2bef0d35e98607074443467
BLAKE2b-256 checksum
How to use checksums
a3d7b21370342407aba983c3cafb0ca3f151bbc936e4506e165caf4e0d2a2305
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.8

Release files / bidsaid-0.35.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL bidsaid-0.35.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 461.6 kB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
b93db18a55b4c8064e6e64d59fe6fa3e2e75300c15ca2fbe4117f31501f8bb08
BLAKE2b-256 checksum
How to use checksums
a1d3848df107689615973331f1a0e5df16335028178057debe6a6fe1da8c27a9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.8

Release files / bidsaid-0.35.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL bidsaid-0.35.0-cp310-abi3-macosx_11_0_arm64.whl
Size 412.6 kB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
e2206afcbdcefeceb91d8147f9f8a805cc62fc532d6f8b582aaa34311f0a0679
BLAKE2b-256 checksum
How to use checksums
4a5cd819fd84e1a5e788dc0fa8fa973008fd167f913536a46bf3330e8121dd3b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.8

Release files / bidsaid-0.35.0-cp310-abi3-macosx_10_12_x86_64.whl

Download URL bidsaid-0.35.0-cp310-abi3-macosx_10_12_x86_64.whl
Size 414.2 kB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
011b8e87153d602c80b6ddcd069db910bfad0e486d4c942697d9f32a6129aa81
BLAKE2b-256 checksum
How to use checksums
56acefe51a9e31d010f9e945abb13e9cfbda17f66a7767f59b1b1818723841d6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.8

Security for bidsaid 0.35.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page