Command-Line Interface (CLI)

MedTDA provides a powerful command-line interface for feature extraction, batch processing, and integration with pipelines.

Overview

The CLI auto-detects operating mode based on input file extension:

  • Single file mode: Input is an image file (.nii.gz, .nrrd, .png, etc.)

  • Batch mode: Input is a CSV file (.csv)

Installation

The CLI is automatically available after installing MedTDA:

pip install medtda

Two ways to run:

# As command (recommended)
medtda --version

# As module
python -m medtda --version

Basic Usage

Single File

Extract features from a single image:

medtda image.nii.gz --output-dir ./results

With mask and preprocessing:

medtda image.nii.gz --mask mask.nii.gz --output-dir ./results \\
    --normalize --spacing 1.0 1.0 1.0

Batch Processing

Create a CSV file with your cases:

id,image_path,mask_path
case001,scan1.nii.gz,mask1.nii.gz   case002,scan2.nii.gz,mask2.nii.gz
case003,scan3.nii.gz,

Process all cases:

medtda cases.csv --output-dir ./results --normalize --workers 4

Complete Example

medtda cases.csv --output-dir ./results \\
    --normalize --normalize-method minmax \\
    --spacing 1.0 1.0 1.0 \\
    --crop-roi --roi-padding 2 \\
    --filtration sublevel --max-dimension 2 \\
    --methods persistence_stats betti_curve \\
    --workers 4 --verbose

Command-Line Arguments

General Options

Input (positional, required)

Input file: image file (single mode) or CSV (batch mode)

medtda image.nii.gz ...
medtda cases.csv ...

–mask PATH

Mask file (single file mode only)

medtda image.nii.gz --mask mask.nii.gz --output-dir ./results

-o, –output-dir PATH (required)

Output directory for results

medtda image.nii.gz -o ./results
medtda image.nii.gz --output-dir /path/to/output

-c, –config PATH

YAML configuration file

medtda image.nii.gz --config config.yaml --output-dir ./results

–version

Show version and exit

medtda --version

–help, -h

Show help message and exit

medtda --help

Preprocessing Options

–spacing S [S ...]

Target voxel spacing for resampling (3D/4D only)

# Isotropic 1mm
medtda image.nii.gz -o ./results --spacing 1.0 1.0 1.0

# Anisotropic
medtda image.nii.gz -o ./results --spacing 0.5 0.5 2.0

–window CENTER WIDTH

Intensity windowing (e.g., for CT images)

# Soft tissue window
medtda ct_scan.nii.gz -o ./results --window 40 400

# Lung window
medtda ct_scan.nii.gz -o ./results --window -600 1500

–normalize

Enable intensity normalization

medtda image.nii.gz -o ./results --normalize

–normalize-method {minmax,zscore,robust}

Normalization method (default: minmax)

medtda image.nii.gz -o ./results --normalize --normalize-method minmax
medtda image.nii.gz -o ./results --normalize --normalize-method zscore
medtda image.nii.gz -o ./results --normalize --normalize-method robust

–background-value VALUE

Background value for masked regions

medtda image.nii.gz --mask mask.nii.gz -o ./results \\
    --background-value 0

–label INT

Label value for multi-label masks (default: 1)

# Extract label 2 from multi-label mask
medtda image.nii.gz --mask multilabel.nii.gz -o ./results --label 2

–crop-roi / –no-crop-roi

Enable/disable ROI cropping (default: enabled)

medtda image.nii.gz --mask mask.nii.gz -o ./results --crop-roi
medtda image.nii.gz --mask mask.nii.gz -o ./results --no-crop-roi

–roi-padding INT

Padding around ROI bounding box in pixels (default: 1)

medtda image.nii.gz --mask mask.nii.gz -o ./results --roi-padding 2

Persistent Homology Options

–filtration {sublevel,superlevel}

Filtration type (default: sublevel)

medtda image.nii.gz -o ./results --filtration sublevel
medtda image.nii.gz -o ./results --filtration superlevel

–construction {T,V}

Cubical complex construction type (default: T)

medtda image.nii.gz -o ./results --construction T
medtda image.nii.gz -o ./results --construction V

–max-dimension INT

Maximum homology dimension (default: -1 for auto-detect)

# Auto-detect based on image dimensionality
medtda image.nii.gz -o ./results --max-dimension -1

# Compute only H0 and H1
medtda image.nii.gz -o ./results --max-dimension 1

# Compute H0, H1, H2
medtda image.nii.gz -o ./results --max-dimension 2

Vectorization Options

–methods METHOD [METHOD ...]

Vectorization method(s) (default: persistence_stats)

Available methods:

  • persistence_stats - Statistical summaries

  • betti_curve - Betti number curves

  • persistence_image - 2D histogram representation

  • persistence_landscape - Landscape functions

  • persistence_silhouette - Silhouette representation

  • entropy_summary - Entropy-based features

  • persistence_lifespan - Lifespan distributions

  • persistence_tropical_coordinates - Tropical coordinates

# Single method
medtda image.nii.gz -o ./results --methods persistence_stats

# Multiple methods
medtda image.nii.gz -o ./results \\
    --methods persistence_stats betti_curve entropy_summary

–save-barcodes

Save raw persistence barcodes as pickle files

medtda image.nii.gz -o ./results --save-barcodes

Parallelization Options

-j, –workers N

Number of parallel workers for batch processing (default: 1)

  • 1 - Sequential processing (default)

  • >1 - Parallel processing with N workers

  • -1 - Use all available CPU cores

# Sequential
medtda cases.csv -o ./results --workers 1

# 4 parallel workers
medtda cases.csv -o ./results -j 4

# All CPU cores
medtda cases.csv -o ./results --workers -1

Logging Options

-v, –verbose

Enable verbose output

medtda cases.csv -o ./results --verbose

-q, –quiet

Suppress all non-error output

medtda cases.csv -o ./results --quiet

Configuration Files

YAML Format

Create a configuration file to store parameters:

# config.yaml
preprocessing:
  normalize: true
  normalize_method: minmax
  spacing: [1.0, 1.0, 1.0]
  window: null
  crop_roi: true
  roi_padding: 2
  background_value: null
  label: 1

persistent_homology:
  filtration: sublevel
  construction: T
  max_dimension: 2

vectorization:
  methods:
    - persistence_stats
    - betti_curve
  save_barcodes: false

parallel:
  workers: 4

output:
  output_dir: ./results
  verbose: true
  quiet: false

Using Config Files

# Use config file
medtda cases.csv --config config.yaml

# Override specific parameters (CLI takes precedence)
medtda cases.csv --config config.yaml --workers 8 --methods persistence_stats

Priority: CLI arguments > Config file > Defaults

Benefits

  • Reproducibility - Same parameters across runs

  • Documentation - Self-documenting pipeline

  • Sharing - Easy to share exact parameters

  • Version Control - Track parameter changes

Examples

Single File Examples

Basic extraction

medtda image.nii.gz --output-dir ./results

With mask and normalization

medtda image.nii.gz --mask mask.nii.gz --output-dir ./results --normalize

Full preprocessing

medtda ct_scan.nii.gz --mask tumor_mask.nii.gz --output-dir ./results \\
    --normalize --normalize-method minmax \\
    --spacing 1.0 1.0 1.0 \\
    --window 40 400 \\
    --crop-roi --roi-padding 2 \\
    --filtration sublevel \\
    --max-dimension 2 \\
    --methods persistence_stats betti_curve \\
    --save-barcodes \\
    --verbose

Multiple vectorization methods

medtda image.nii.gz --output-dir ./results \\
    --normalize \\
    --methods persistence_stats betti_curve entropy_summary \\
    persistence_landscape

Multi-label mask

# Process label 2 from multi-label segmentation
medtda image.nii.gz --mask multilabel_mask.nii.gz \\
    --output-dir ./results \\
    --label 2 --normalize

Batch Processing Examples

Basic batch

medtda cases.csv --output-dir ./results --normalize

Parallel processing

# 4 workers
medtda cases.csv --output-dir ./results --workers 4 --verbose

# All CPU cores
medtda cases.csv --output-dir ./results -j -1 --verbose

Complete batch workflow

medtda cases.csv --output-dir ./results \\
    --normalize --normalize-method minmax \\
    --spacing 1.0 1.0 1.0 \\
    --crop-roi --roi-padding 1 \\
    --filtration sublevel --max-dimension 2 \\
    --methods persistence_stats betti_curve \\
    --save-barcodes \\
    --workers 8 --verbose

Using configuration file

medtda cases.csv --config config.yaml --verbose

Override config values

# Use config but override workers and methods
medtda cases.csv --config config.yaml \\
    --workers 16 \\
    --methods persistence_stats

Output Files

Single File Mode

Creates 3 files in output directory:

  • <basename>_features.csv - Feature vectors (1 row)

  • <basename>_config.yaml - Configuration used

  • <basename>_barcodes.pkl - Barcodes (if --save-barcodes)

medtda scan001.nii.gz --output-dir ./results --save-barcodes --normalize

Creates:

results/
├── scan001_features.csv
├── scan001_config.yaml
└── scan001_barcodes.pkl

Batch Mode

Creates files in output directory:

  • batch_features.csv - All features (one row per case)

  • config.yaml - Configuration used

  • <id>_barcodes.pkl × N - Individual barcodes (if --save-barcodes)

medtda cases.csv --output-dir ./results --workers 4 --save-barcodes

Creates:

results/
├── batch_features.csv
├── config.yaml
├── case001_barcodes.pkl
├── case002_barcodes.pkl
└── ...

batch_features.csv Format

id,status,error_message,PersStats_H0_mean,PersStats_H0_std,...
case001,success,,0.523,0.142,...
case002,success,,0.487,0.156,...
case003,error,File not found,,,

Columns:

  • id - Case identifier

  • status - ‘success’ or ‘error’

  • error_message - Error details if failed

  • Feature columns - All TDA features

Integration with Pipelines

Shell Scripts

#!/bin/bash
# process_cohort.sh

# Process training set
medtda train_cases.csv --config config.yaml --output-dir ./train_features -j -1

# Process validation set
medtda val_cases.csv --config config.yaml --output-dir ./val_features -j -1

# Process test set
medtda test_cases.csv --config config.yaml --output-dir ./test_features -j -1

echo "Feature extraction complete!"

Makefiles

# Makefile

.PHONY: all features clean

all: features

features: results/batch_features.csv

results/batch_features.csv: cases.csv config.yaml
     medtda cases.csv --config config.yaml --output-dir results -j 8 --verbose

clean:
     rm -rf results

Python Subprocess

import subprocess

# Run CLI from Python
result = subprocess.run([
    'medtda', 'cases.csv',
    '--output-dir', './results',
    '--config', 'config.yaml',
    '--workers', '8',
    '--verbose'
], capture_output=True, text=True)

if result.returncode == 0:
    print("Success!")
else:
    print(f"Error: {result.stderr}")

Snakemake

# Snakefile

rule extract_features:
    input:
        cases="cases.csv",
        config="config.yaml"
    output:
        "results/batch_features.csv"
    threads: 8
    shell:
        "medtda {input.cases} --config {input.config} "
        "--output-dir results --workers {threads} --verbose"

Nextflow

// main.nf

process extractFeatures {
    publishDir 'results'

    input:
    path cases
    path config

    output:
    path 'batch_features.csv'

    script:
    """
    medtda ${cases} --config ${config} \\
        --output-dir . --workers ${task.cpus} --verbose
    """
}

Error Handling

Exit Codes

  • 0 - Success

  • 1 - Error (file not found, invalid input, processing failed)

  • 130 - Interrupted by user (Ctrl+C)

Checking Errors

# Run and check exit code
medtda cases.csv --output-dir ./results

if [ $? -eq 0 ]; then
    echo "Success"
else
    echo "Failed"
    exit 1
fi

Batch Error Handling

Batch processing continues even when individual cases fail:

medtda cases.csv --output-dir ./results --workers 4 --verbose

Failed cases are recorded in output CSV with:

  • status = 'error'

  • error_message field populated

Check results:

python -c "
import pandas as pd
df = pd.read_csv('results/batch_features.csv')
errors = df[df['status'] == 'error']
print(f'Failed: {len(errors)}/{len(df)}')
if len(errors) > 0:
    print(errors[['id', 'error_message']])
"

Performance Tips

Speed Optimization

# Fast processing (for large batches)
medtda cases.csv --output-dir ./results \\
    --max-dimension 1 \\              # Skip H2
    --spacing 2.0 2.0 2.0 \\          # Downsample
    --crop-roi --roi-padding 1 \\    # Reduce image size
    --methods persistence_stats \\   # Fastest method
    --workers -1                      # All cores

Memory Optimization

# Reduce memory usage
medtda cases.csv --output-dir ./results \\
    --max-dimension 1 \\              # Less memory
    --spacing 2.0 2.0 2.0 \\          # Smaller images
    --crop-roi --roi-padding 0 \\    # Minimal ROI
    --workers 4                       # Limit parallel processes

Quality Settings

# High-quality comprehensive analysis
medtda cases.csv --output-dir ./results \\
    --normalize --normalize-method minmax \\
    --spacing 1.0 1.0 1.0 \\
    --crop-roi --roi-padding 2 \\
    --filtration sublevel \\
    --construction T \\
    --max-dimension 2 \\
    --methods persistence_stats betti_curve entropy_summary \\
    --save-barcodes \\
    --workers 8 --verbose

Troubleshooting

Command not found: medtda

# Reinstall or use module form
pip install --force-reinstall medtda
# Or
python -m medtda --version

–mask ignored in batch mode

Use CSV mask_path column instead of --mask argument.

Workers argument ignored in single file mode

Parallelization only applies to batch mode. Single files process sequentially.

Output directory not created

The CLI creates the directory automatically. Check write permissions.

Different number of features per case

Check batch_features.csv for errors. Failed cases will have status='error'.

Processing very slow

  • Use parallel processing (--workers 4 or more)

  • Enable ROI cropping (--crop-roi)

  • Reduce max_dimension (--max-dimension 1)

  • Downsample (--spacing 2.0 2.0 2.0)

Full Help Output

$ medtda --help

Shows complete usage information with all arguments and examples.

Next Steps