CHANGES: - Added MeasuredDate as first column in regional.csv - Added MeasuredDate as first column in muscle_balance.csv - Updated README to document new column structure BENEFITS: ✅ Track regional changes over time (e.g., Arms fat % across scans) ✅ Easy time-series analysis with pandas/Excel ✅ Filter by date range for progress tracking ✅ Consistent date column across all 3 CSV files ✅ Enables queries like: 'Show me trunk fat % over last 6 months' EXAMPLE USAGE: import pandas as pd regional = pd.read_csv('regional.csv') arms = regional[regional['Region'] == 'Arms'] # Now you can track Arms progress over time! Each scan now adds: - 1 row to overall.csv - 6 rows to regional.csv (one per region) - 6 rows to muscle_balance.csv (one per limb comparison)
349 lines
12 KiB
Markdown
349 lines
12 KiB
Markdown
# BodySpec Insights
|
|
|
|
**Body composition analytics for BodySpec DEXA scan PDFs**
|
|
|
|
A Python tool to extract and analyze body composition data from BodySpec DEXA scan reports. Automatically parses measurements, computes 30+ derived metrics, and tracks your progress over time.
|
|
|
|
> **Note:** This tool is specifically designed for BodySpec PDF reports and may not work with other DEXA providers (DexaFit, Hologic, etc.).
|
|
|
|
## Features
|
|
|
|
- 📊 **Comprehensive Data Extraction**: Body fat %, lean mass, bone density, regional composition, and more
|
|
- 🧮 **Derived Metrics**: Automatically calculates FFMI, FMI, LSTI, SMI, and other body composition indices
|
|
- 📁 **Multiple Output Formats**: CSV (for spreadsheet analysis), JSON (for programmatic use), and Markdown (for readable summaries)
|
|
- 📈 **Time-Series Ready**: Append mode allows tracking progress across multiple scans
|
|
- 🎯 **Regional Analysis**: Breaks down composition by Arms, Legs, Trunk, Android, and Gynoid regions
|
|
- ⚖️ **Muscle Balance**: Tracks left/right limb symmetry
|
|
|
|
## Installation
|
|
|
|
### Prerequisites
|
|
|
|
- Python 3.7 or higher
|
|
- pip (Python package manager)
|
|
|
|
### Setup
|
|
|
|
1. **Clone or download this repository**
|
|
|
|
2. **Create a virtual environment** (recommended):
|
|
```bash
|
|
python3 -m venv venv
|
|
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
```
|
|
|
|
3. **Install dependencies**:
|
|
```bash
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
The script requires:
|
|
- `pdfplumber` - PDF text extraction
|
|
- `pandas` - Data manipulation and CSV handling
|
|
|
|
## Usage
|
|
|
|
### Basic Command
|
|
|
|
```bash
|
|
python dexa_extract.py <PDF_PATH> --height-in <HEIGHT> [--weight-lb <WEIGHT>] [--outdir <OUTPUT_DIR>]
|
|
```
|
|
|
|
### Required Arguments
|
|
|
|
- `PDF_PATH` - Path to your DEXA scan PDF report
|
|
- `--height-in` - Your height in inches
|
|
|
|
### Optional Arguments
|
|
|
|
- `--weight-lb` - Body weight in pounds (used as fallback if PDF doesn't contain total mass)
|
|
- `--outdir` - Output directory for results (default: `dexa_out`)
|
|
|
|
### Examples
|
|
|
|
**Single scan:**
|
|
```bash
|
|
python dexa_extract.py data/pdfs/2025-10-06-scan.pdf --height-in 74 --weight-lb 212 --outdir data/results
|
|
```
|
|
|
|
**Batch process multiple scans:**
|
|
```bash
|
|
# Process all PDFs in a directory (automatically skips already-processed dates)
|
|
python dexa_extract.py --batch data/pdfs --height-in 74 --outdir data/results
|
|
|
|
# Force reprocessing all files
|
|
python dexa_extract.py --batch data/pdfs --height-in 74 --outdir data/results --force
|
|
```
|
|
|
|
**Individual scans** (appends to existing files):
|
|
```bash
|
|
python dexa_extract.py data/pdfs/scan-2025-01.pdf --height-in 74 --outdir data/results
|
|
python dexa_extract.py data/pdfs/scan-2025-04.pdf --height-in 74 --outdir data/results
|
|
python dexa_extract.py data/pdfs/scan-2025-10.pdf --height-in 74 --outdir data/results
|
|
```
|
|
|
|
**Height conversion** (for reference):
|
|
- 5'8" = 68 inches
|
|
- 5'10" = 70 inches
|
|
- 6'0" = 72 inches
|
|
- 6'2" = 74 inches
|
|
- 6'4" = 76 inches
|
|
|
|
## Directory Structure
|
|
|
|
```
|
|
bodyspec-insights/
|
|
├── dexa_extract.py # Main extraction script
|
|
├── requirements.txt # Python dependencies
|
|
├── README.md # This file
|
|
├── .gitignore # Git ignore patterns
|
|
├── data/ # Data directory (gitignored)
|
|
│ ├── pdfs/ # Place your BodySpec PDF reports here
|
|
│ └── results/ # Results will be saved here
|
|
└── venv/ # Virtual environment (gitignored)
|
|
```
|
|
|
|
## Output Files
|
|
|
|
The script generates 5 files in the specified output directory:
|
|
|
|
### 1. `overall.csv`
|
|
Time-series data with one row per scan. Includes all primary metrics and derived indices.
|
|
|
|
**Columns:**
|
|
- `MeasuredDate` - Scan date (YYYY-MM-DD)
|
|
- `Height_in`, `Height_ft_in` - Height measurements
|
|
- `Weight_lb_Input`, `DEXA_TotalMass_lb`, `Adjusted_Body_Weight_lb` - Weight data
|
|
- `BodyFat_percent`, `LeanMass_percent` - Body composition percentages
|
|
- `FatMass_lb`, `LeanSoftTissue_lb`, `BoneMineralContent_lb`, `FatFreeMass_lb` - Mass measurements
|
|
- `BMI`, `FFMI`, `FMI`, `LST_Index`, `SMI`, `BMDI` - Normalized indices
|
|
- `ALM_lb` - Appendicular lean mass (arms + legs)
|
|
- `VAT_Mass_lb`, `VAT_Volume_in3`, `VAT_Index` - Visceral adipose tissue
|
|
- `Android_percent`, `Gynoid_percent`, `AG_Ratio` - Fat distribution
|
|
- `Trunk_to_Limb_Fat_Ratio` - Central adiposity indicator
|
|
- `Arms_Lean_pct`, `Legs_Lean_pct`, `Trunk_Lean_pct` - Regional lean mass distribution
|
|
- `Arm_Symmetry_Index`, `Leg_Symmetry_Index` - Left/right balance (50% = perfect)
|
|
- `RMR_cal_per_day` - Resting metabolic rate
|
|
|
|
### 2. `regional.csv`
|
|
Regional body composition breakdown (Arms, Legs, Trunk, Android, Gynoid, Total). Each scan adds 6 rows (one per region).
|
|
|
|
**Columns:**
|
|
- `MeasuredDate` - Date of scan (YYYY-MM-DD)
|
|
- `Region` - Body region name
|
|
- `FatPercent` - Fat percentage in this region
|
|
- `LeanPercent` - Lean tissue percentage in this region
|
|
- `TotalMass_lb` - Total mass of the region
|
|
- `FatTissue_lb` - Fat mass in the region
|
|
- `LeanTissue_lb` - Lean mass in the region
|
|
- `BMC_lb` - Bone mineral content in the region
|
|
|
|
### 3. `muscle_balance.csv`
|
|
Left/right limb comparison for tracking muscle symmetry. Each scan adds 6 rows (one per region).
|
|
|
|
**Columns:**
|
|
- `MeasuredDate` - Date of scan (YYYY-MM-DD)
|
|
- `Region` - Arms Total, Right Arm, Left Arm, Legs Total, Right Leg, Left Leg
|
|
- `FatPercent`, `TotalMass_lb`, `FatMass_lb`, `LeanMass_lb`, `BMC_lb`
|
|
|
|
### 4. `overall.json`
|
|
Structured JSON format containing all extracted data in a hierarchical format.
|
|
|
|
**Structure:**
|
|
```json
|
|
{
|
|
"measured_date": "2025-10-06",
|
|
"anthropometrics": { ... },
|
|
"composition": { ... },
|
|
"regional": [ ... ],
|
|
"muscle_balance": [ ... ],
|
|
"supplemental": { ... },
|
|
"bone_density": { ... }
|
|
}
|
|
```
|
|
|
|
### 5. `summary.md`
|
|
Human-readable Markdown summary of the scan results.
|
|
|
|
## Extracted Metrics
|
|
|
|
### Primary Measurements
|
|
- **Body Fat %** - Percentage of body weight that is fat
|
|
- **Lean Mass %** - Percentage of body weight that is lean tissue (complement of body fat %)
|
|
- **Fat Mass** - Total weight of fat tissue
|
|
- **Lean Soft Tissue** - Muscle, organs, and other non-bone lean tissue
|
|
- **Bone Mineral Content (BMC)** - Total bone mineral weight
|
|
- **Fat-Free Mass** - Total body weight minus fat mass
|
|
|
|
### Derived Indices (Height-Normalized)
|
|
- **BMI** - Body Mass Index (standard weight-to-height ratio)
|
|
- **FFMI** - Fat-Free Mass Index (normalized muscle mass)
|
|
- **FMI** - Fat Mass Index (normalized fat mass)
|
|
- **LSTI** - Lean Soft Tissue Index (height-adjusted lean tissue)
|
|
- **SMI** - Skeletal Muscle Index (height-adjusted appendicular lean mass)
|
|
- **BMDI** - Bone Mineral Density Index (height-adjusted bone content)
|
|
- **VAT Index** - Visceral fat normalized by height
|
|
|
|
### Regional Analysis
|
|
- **Android** - Abdominal/trunk fat (higher risk area)
|
|
- **Gynoid** - Hip/thigh fat (lower risk area)
|
|
- **A/G Ratio** - Android-to-Gynoid ratio (cardiovascular risk indicator)
|
|
- **Trunk-to-Limb Fat Ratio** - Ratio of trunk fat to limb fat (central adiposity indicator)
|
|
- **Lean Mass Distribution** - Percentage of total lean mass in arms, legs, and trunk
|
|
|
|
### Symmetry & Balance
|
|
- **Arm Symmetry Index** - Right-to-left arm lean mass balance (50% = perfect symmetry)
|
|
- **Leg Symmetry Index** - Right-to-left leg lean mass balance (50% = perfect symmetry)
|
|
|
|
### Supplemental
|
|
- **VAT (Visceral Adipose Tissue)** - Deep abdominal fat around organs
|
|
- **RMR (Resting Metabolic Rate)** - Estimated daily calorie burn at rest
|
|
- **Adjusted Body Weight** - Clinical weight used for medication dosing and nutrition calculations
|
|
- **Bone Density** - BMD (g/cm²), T-score, Z-score
|
|
|
|
## Understanding Your Results
|
|
|
|
### Body Fat % Ranges (by age and sex)
|
|
|
|
**Men:**
|
|
- Athletes: 6-13%
|
|
- Fitness: 14-17%
|
|
- Average: 18-24%
|
|
- Above Average: 25%+
|
|
|
|
**Women:**
|
|
- Athletes: 14-20%
|
|
- Fitness: 21-24%
|
|
- Average: 25-31%
|
|
- Above Average: 32%+
|
|
|
|
### FFMI (Fat-Free Mass Index)
|
|
|
|
Normalized measure of muscle mass:
|
|
- **16-17**: Below average
|
|
- **18-20**: Average/athletic
|
|
- **21-23**: Above average/very muscular
|
|
- **24-25**: Elite natural bodybuilder range
|
|
- **26+**: Typically requires enhanced training
|
|
|
|
### A/G Ratio (Android/Gynoid Ratio)
|
|
|
|
Fat distribution indicator:
|
|
- **< 1.0**: Lower risk (more fat in hips/thighs)
|
|
- **1.0-1.5**: Moderate
|
|
- **> 1.5**: Higher risk (more abdominal fat)
|
|
|
|
### Trunk-to-Limb Fat Ratio
|
|
|
|
Central adiposity indicator:
|
|
- **< 1.0**: More peripheral fat distribution (healthier)
|
|
- **1.0-1.5**: Moderate central fat
|
|
- **> 1.5**: High central fat (increased health risk)
|
|
|
|
### Symmetry Indices
|
|
|
|
Muscle balance between left and right sides:
|
|
- **50%**: Perfect symmetry
|
|
- **48-52%**: Normal range (slight asymmetry is common)
|
|
- **< 48% or > 52%**: Notable imbalance (may indicate injury, overuse, or compensation patterns)
|
|
|
|
### VAT Index
|
|
|
|
Visceral fat normalized by height:
|
|
- **< 0.30**: Low visceral fat
|
|
- **0.30-0.50**: Moderate
|
|
- **> 0.50**: High (increased metabolic risk)
|
|
|
|
### Lean Mass Distribution
|
|
|
|
Typical ranges for lean tissue distribution:
|
|
- **Arms**: 13-16% of total lean mass
|
|
- **Legs**: 32-38% of total lean mass
|
|
- **Trunk**: 46-54% of total lean mass
|
|
|
|
Higher trunk percentage may indicate good core development, while higher leg percentage suggests strong lower body development.
|
|
|
|
## Tracking Progress
|
|
|
|
The script appends data to existing CSV files, making it easy to track changes over time:
|
|
|
|
### Option 1: Batch Processing (Recommended)
|
|
```bash
|
|
# Place all your PDFs in one directory
|
|
data/pdfs/
|
|
├── scan-2025-01-15.pdf
|
|
├── scan-2025-04-20.pdf
|
|
└── scan-2025-10-06.pdf
|
|
|
|
# Process all at once (automatically skips already-processed dates)
|
|
python dexa_extract.py --batch data/pdfs --height-in 74 --outdir data/results
|
|
|
|
# Add new scans later - only new ones will be processed
|
|
cp ~/Downloads/scan-2025-12-15.pdf data/pdfs/
|
|
python dexa_extract.py --batch data/pdfs --height-in 74 --outdir data/results
|
|
```
|
|
|
|
### Option 2: Individual Processing
|
|
```bash
|
|
# Process scans as you get them
|
|
python dexa_extract.py data/pdfs/scan-2025-01.pdf --height-in 74 --outdir data/results
|
|
python dexa_extract.py data/pdfs/scan-2025-04.pdf --height-in 74 --outdir data/results
|
|
python dexa_extract.py data/pdfs/scan-2025-10.pdf --height-in 74 --outdir data/results
|
|
```
|
|
|
|
### Analyzing Results
|
|
1. Open `overall.csv` in Excel/Google Sheets to visualize trends
|
|
2. Compare `muscle_balance.csv` to track left/right symmetry improvements
|
|
3. Review `summary.md` for readable reports of each scan
|
|
4. Use `overall.json` for programmatic analysis
|
|
|
|
## Privacy & Security
|
|
|
|
⚠️ **Important:** DEXA reports contain personal health information (PHI).
|
|
|
|
- All PDF files and results are excluded from git via `.gitignore`
|
|
- Keep your `data/` directory private
|
|
- Don't commit PDFs or output files to version control
|
|
- Consider encrypting your data directory if sharing the repository
|
|
|
|
## Troubleshooting
|
|
|
|
### "Total mass is missing" error
|
|
- Ensure your PDF contains a SUMMARY RESULTS table
|
|
- Provide `--weight-lb` as a fallback
|
|
|
|
### No data extracted or null values
|
|
- **Verify your PDF is from BodySpec** - This tool only works with BodySpec reports
|
|
- Ensure the PDF is text-based, not a scanned image
|
|
- Check that your BodySpec report includes the "SUMMARY RESULTS" table
|
|
- Open an issue with a sample (redacted) PDF for support
|
|
|
|
### Import errors
|
|
- Ensure virtual environment is activated: `source venv/bin/activate`
|
|
- Reinstall dependencies: `pip install -r requirements.txt`
|
|
|
|
## Contributing
|
|
|
|
Contributions welcome! Areas for improvement:
|
|
|
|
- [ ] Automatic height detection from PDF
|
|
- [ ] Data visualization/plotting features
|
|
- [ ] GUI interface for non-technical users
|
|
- [ ] Export to additional formats (Excel, SQLite, etc.)
|
|
- [ ] Support for older BodySpec PDF formats
|
|
- [ ] Progress bar for batch processing
|
|
|
|
## License
|
|
|
|
MIT License - feel free to use and modify for personal or commercial use.
|
|
|
|
## Acknowledgments
|
|
|
|
Built for personal body composition tracking with BodySpec scans. Thanks to BodySpec for providing detailed, consistent DEXA scan reports that make automated analysis possible.
|
|
|
|
**Disclaimer:** This is an unofficial, independent tool and is not affiliated with or endorsed by BodySpec.
|
|
|
|
---
|
|
|
|
**Questions or issues?** Open an issue on GitHub or contact the maintainer.
|
|
|