Frequently Asked Questions
This page addresses common questions, issues, and best practices when using MedTDA.
Installation and Setup
How do I install MedTDA?
Basic installation:
pip install medtda
From source:
git clone https://github.com/dashtiali/medtda.git
cd medtda
pip install -e .
With optional dependencies:
pip install medtda[visualization,notebook]
See Installation for detailed instructions.
What are the system requirements?
Minimum:
Python 3.10+
4 GB RAM
NumPy, SciPy
Recommended:
Python 3.9+
16 GB RAM
GUDHI, scikit-learn
GPU (for large-scale processing)
Can I use MedTDA on Windows/Mac/Linux?
Yes! MedTDA is cross-platform and works on:
Windows 10/11
macOS 10.14+
Linux (Ubuntu 18.04+, CentOS 7+, etc.)
Installation is the same on all platforms via pip.
Dependencies won’t install - what should I do?
Common solutions:
Update pip:
pip install --upgrade pip
Use conda for difficult packages:
conda install -c conda-forge gudhi numpy scipy
Check Python version:
python --version # Should be 3.8+
Install build tools (if compiling from source):
Linux:
sudo apt-get install build-essentialmacOS:
xcode-select --installWindows: Install Visual Studio Build Tools
Getting Started
Where should I start?
Read the Quick Start (5-minute introduction)
Try the Interactive Tutorial (interactive tutorial)
Explore Basic Usage (practical examples)
Consult User Guide for in-depth coverage
What file formats are supported?
3D Medical Images:
NIFTI (
.nii,.nii.gz) ✓ RecommendedDICOM (
.dcm) ✓NRRD (
.nrrd,.nhdr) ✓Analyze (
.hdr/.img) ✓
2D Images:
PNG (
.png) ✓TIFF (
.tiff,.tif) ✓JPEG (
.jpg,.jpeg) ✓
Arrays:
NumPy arrays (directly in Python) ✓
See Loaders for loading different formats.
Can I use 2D images?
Yes! MedTDA works with any dimensionality:
2D images: H0 (connected components) and H1 (loops)
3D images: H0, H1, and H2 (voids)
For 2D, set max_dimension=1:
from medtda import FeatureExtractor
extractor = FeatureExtractor(max_dimension=1)
features = extractor.execute('2d_image.png')
Common Errors and Solutions
ValueError: Image and mask shapes don’t match
Problem: Image and mask have different dimensions.
Solution:
Check shapes:
from medtda.loaders import load_image, load_mask image, _ = load_image('image.nii.gz') mask, _ = load_mask('mask.nii.gz') print(f"Image: {image.shape}") print(f"Mask: {mask.shape}")
Resample mask to match image:
from medtda.utils import resample_mask mask_resampled = resample_mask(mask, image.shape)
Verify loading:
from medtda.loaders import validate_compatibility validate_compatibility(image, mask)
MemoryError: Unable to allocate array
Problem: Image too large for available RAM.
Solutions:
Downsample the image:
extractor = FeatureExtractor( spacing=(2.0, 2.0, 2.0) # Halve resolution each axis )
Crop to ROI:
extractor = FeatureExtractor( crop_to_roi=True, roi_padding=5 )
Process 2D slices instead of 3D volume
Use a machine with more RAM
Empty barcodes / No features detected
Problem: Persistent homology returns no features.
Possible causes:
ROI too small or homogeneous:
# Check ROI size import numpy as np roi_voxels = np.sum(mask > 0) print(f"ROI voxels: {roi_voxels}")
Wrong filtration type:
# Try both sublevel and superlevel extractor_sub = FeatureExtractor(filtration_type='sublevel') extractor_sup = FeatureExtractor(filtration_type='superlevel')
Need normalization:
extractor = FeatureExtractor(normalize=True)
RuntimeError: GUDHI failed to compute
Problem: Underlying GUDHI library error.
Solutions:
Check image values:
import numpy as np # Check for NaN/Inf if np.isnan(image).any(): image = np.nan_to_num(image, nan=0.0) if np.isinf(image).any(): image = np.nan_to_num(image, posinf=0.0, neginf=0.0)
Normalize first:
extractor = FeatureExtractor( normalize=True, normalize_method='robust' )
Reduce max_dimension:
extractor = FeatureExtractor(max_dimension=1) # Skip H2
Feature Extraction Questions
Which vectorization method should I use?
Quick guide:
Need interpretable features? →
PersStatsFor machine learning? →
PersImageWant to see evolution over scale? →
BettiCurveStatistical analysis? →
PersLandscapeSingle complexity measure? →
EntropySummary
How do I choose between sublevel and superlevel?
Sublevel filtration (default):
Grows components from low to high intensities
Good for dark features (e.g., vessels in angiography, cells in microscopy)
Most common choice
Superlevel filtration:
Grows components from high to low intensities
Good for bright features (e.g., lesions in T2 MRI, enhancing tumors)
Try both and visualize to decide:
from medtda import FeatureExtractor
# Sublevel
extractor_sub = FeatureExtractor(filtration_type='sublevel')
features_sub, barcodes_sub = extractor_sub.execute(image, return_barcodes=True)
# Superlevel
extractor_sup = FeatureExtractor(filtration_type='superlevel')
features_sup, barcodes_sup = extractor_sup.execute(image, return_barcodes=True)
# Compare number of features
print(f"Sublevel: {len(barcodes_sub[1])} H1 features")
print(f"Superlevel: {len(barcodes_sup[1])} H1 features")
What dimensions should I compute (H0, H1, H2)?
Homology dimensions:
H0 (dimension 0): Connected components
Always present
Counts separate objects/regions
H1 (dimension 1): Loops/holes
Cavities, vessels, circular structures
Most informative for many applications
H2 (dimension 2): Voids/cavities
Only for 3D images
Computationally expensive
Often less informative than H0/H1
Recommendations:
2D images:
max_dimension=1(H0, H1)3D exploratory analysis:
max_dimension=1(faster)3D detailed analysis:
max_dimension=2(complete)
# Fast: H0 and H1 only
extractor = FeatureExtractor(max_dimension=1)
# Complete: H0, H1, and H2
extractor = FeatureExtractor(max_dimension=2)
How many features will I get?
It depends on the vectorization method:
Method |
Feature Count |
Notes |
|---|---|---|
|
13 |
Fixed size |
|
100 (default) |
Configurable via |
|
400 (20×20) |
|
|
500 (5×100) |
|
|
1 |
Single value per dimension |
|
100 (default) |
Configurable |
Configuring size:
extractor = FeatureExtractor(vectorization_method='PersImage')
extractor.set_vectorization_params(
'PersImage',
resolution=30 # 30×30 = 900 features
)
Performance and Optimization
How long does processing take?
Typical times (256×256×128 image on standard desktop):
Preprocessing: 1-5 seconds
Persistent homology: 5-30 seconds
Vectorization: 0.1-2 seconds
Total: ~10-40 seconds per image
Factors affecting speed:
Image size (biggest factor)
Number of voxels in ROI
max_dimension(H2 is slow)Vectorization method
Hardware (CPU, RAM)
How can I speed up processing?
Top strategies:
Downsample images:
extractor = FeatureExtractor(spacing=(2.0, 2.0, 2.0))
Crop to ROI:
extractor = FeatureExtractor(crop_to_roi=True)
Reduce max_dimension:
extractor = FeatureExtractor(max_dimension=1) # Skip H2
Use faster vectorization:
extractor = FeatureExtractor( vectorization_method='PersStats' # Fastest
Parallel batch processing:
from multiprocessing import Pool with Pool(processes=8) as pool: results = pool.map(process_image, image_paths)
How much RAM do I need?
Estimate:
Small images (128³): 2-4 GB
Medium images (256³): 8-16 GB
Large images (512³): 32-64 GB
Reduce memory usage:
Downsample with
spacingCrop with
crop_to_roi=TrueProcess one image at a time
Use
max_dimension=1
Can I use GPU acceleration?
Currently, MedTDA uses CPU-based libraries (GUDHI, NumPy). GPU acceleration is not yet supported but is planned for future releases.
For batch processing, CPU multiprocessing provides good parallelization:
from medtda import FeatureExtractor
from multiprocessing import Pool
def process(img_path):
extractor = FeatureExtractor()
return extractor.execute(img_path)
with Pool(8) as pool: # 8 parallel processes
results = pool.map(process, image_paths)
Machine Learning Integration
How do I integrate features with scikit-learn?
from medtda import FeatureExtractor
from sklearn.ensemble import RandomForestClassifier
import numpy as np
# Extract features for all samples
extractor = FeatureExtractor(
normalize=True,
vectorization_method='PersImage'
)
X = []
for img_path in training_images:
features = extractor.execute(img_path)
# features is a flat dict: {'PersImage_H0_f0': ..., 'PersImage_H1_f0': ..., ...}
X.append(list(features.values()))
X = np.array(X)
# Train
clf = RandomForestClassifier()
clf.fit(X, y_train)
See Batch Workflow for complete examples.
Should I normalize features?
Image normalization: Yes, always recommended:
extractor = FeatureExtractor(normalize=True)
Feature scaling for ML:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
How do I do feature selection?
from sklearn.feature_selection import SelectKBest, f_classif
# Select top 50 features
selector = SelectKBest(f_classif, k=50)
X_train_selected = selector.fit_transform(X_train, y_train)
X_test_selected = selector.transform(X_test)
# Get selected feature indices
selected_idx = selector.get_support()
Can I combine multiple vectorization methods?
Yes! This often improves performance:
from medtda import FeatureExtractor
import numpy as np
extractor = FeatureExtractor(normalize=True)
extractor.enable_vectorization_methods([
'PersStats',
'BettiCurve',
'PersImage'
])
features = extractor.execute(image)
# features is a flat dict with all method features combined
# e.g., {'PersStats_H0_mean': ..., 'BettiCurve_H0_f0': ..., 'PersImage_H0_f0': ...}
combined = np.array(list(features.values()))
Results Interpretation
What do the barcode plots mean?
Persistence barcodes show features as horizontal bars:
X-axis: Filtration value (intensity threshold)
Length: Persistence (how long feature survives)
Longer bars = more significant features
Short bars = noise
By dimension:
H0 bars: Connected components merging
H1 bars: Loops appearing and disappearing
H2 bars: Voids filling
See Barcodes and Diagrams for details.
How do I interpret persistence statistics?
The PersStats method returns 13 values per dimension:
Count: Number of features
Mean: Average persistence
Std: Standard deviation of persistence
Min: Smallest persistence
25%: First quartile
50%: Median
75%: Third quartile
8. Max: Largest persistence 9-13. Additional statistics (skewness, kurtosis, etc.)
Interpretation:
High count: Many topological features
High mean/max: Prominent features
High std: Diverse feature scales
What’s a “good” persistence value?
It depends on your application!
Absolute values depend on image intensities and normalization
Relative comparisons are meaningful (within same preprocessing)
Statistical significance: Compare to random/null distribution
General guidance:
Features with persistence < 1% of max are often noise
Focus on top 10-20% most persistent features
Domain knowledge helps interpret what’s “significant”
Why are my features all similar/different between groups?
All similar (low variance):
Images are actually similar (expected)
ROIs too small → extract larger context
Wrong filtration type → try both sublevel/superlevel
Need different vectorization method
Too different (high variance):
Preprocessing inconsistent → standardize pipeline
Image quality varies → add quality control
ROI placement varies → improve segmentation
Outliers present → check and remove
Troubleshooting
Code runs but gives unexpected results
Checklist:
✓ Image loaded correctly?
✓ Mask matches image?
✓ Normalization applied?
✓ Correct filtration type?
✓ ROI not empty?
✓ Preprocessing consistent?
Debug by visualizing:
import matplotlib.pyplot as plt
from medtda.plotting import plot_persistence_diagram
# Visualize processed image
plt.imshow(processed[:, :, processed.shape[2]//2], cmap='gray')
plt.show()
# Plot persistence diagram
_, barcodes = extractor.execute(image, return_barcodes=True)
plot_persistence_diagram(barcodes)
plt.show()
“Module not found” errors
Problem: Import fails.
Solutions:
Verify installation:
pip list | grep medtda
Reinstall:
pip uninstall medtda pip install medtda
Check Python environment:
which python which pip
Use correct environment:
# Activate environment first conda activate myenv # Then install pip install medtda
Processing hangs / takes forever
Possible causes:
Image too large → downsample or crop
Computing H2 on large image → use
max_dimension=1Very complex image → increase
spacingto reduce resolutionInsufficient RAM → close other programs, use smaller images
Add timeout:
import signal
def timeout_handler(signum, frame):
raise TimeoutError("Processing took too long")
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(300) # 5 minute timeout
try:
features = extractor.execute(image)
except TimeoutError:
print("Processing timed out")
finally:
signal.alarm(0)
Where to Get Help
I read the FAQ but still have questions
Search documentation: Use search box (top right)
Check examples: Examples
GitHub Issues: Search existing issues
Ask a question: Open new issue
Discussions: GitHub Discussions
How do I report a bug?
Open a bug report with:
MedTDA version:
medtda.__version__Python version:
python --versionOperating system
Minimal code to reproduce
Error message / unexpected output
Expected behavior
Can I request a feature?
Yes! Open a feature request describing:
What you want to do
Why current functionality doesn’t work
Proposed solution (if any)
Example use case
How can I contribute?
See Contributing to MedTDA for:
Code contributions
Documentation improvements
Bug reports
Feature suggestions
Example notebooks
See Also
Installation - Installation guide
Quick Start - Quick start tutorial
User Guide - Complete user guide
troubleshooting - Detailed troubleshooting
Contributing to MedTDA - How to contribute