Add lean percentage to regional data

- Add LeanPercent column to regional.csv matching BodySpec reports
- Calculate lean percentage from lean tissue (excluding BMC) for accuracy
- Update JSON output to include lean_percent for each region
- Document new column in README
- Values now match BodySpec regional reports (e.g., Arms: 73.7%, Legs: 72.7%, Trunk: 64.4%)
This commit is contained in:
Mac DeCourcy 2025-10-06 17:44:16 -07:00
parent b046af5d25
commit 37267fbf34
2 changed files with 46 additions and 15 deletions

View file

@ -128,7 +128,14 @@ Time-series data with one row per scan. Includes all primary metrics and derived
### 2. `regional.csv`
Regional body composition breakdown (Arms, Legs, Trunk, Android, Gynoid, Total).
**Columns:** Region, FatPercent, TotalMass_lb, FatTissue_lb, LeanTissue_lb, BMC_lb
**Columns:**
- `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.

View file

@ -399,22 +399,26 @@ def process_single_pdf(pdf_path, height_in, weight_lb, outdir):
write_or_append_csv(os.path.join(outdir, "overall.csv"), overall_row, overall_cols)
# Regional table
regional_cols = ["Region","FatPercent","TotalMass_lb","FatTissue_lb","LeanTissue_lb","BMC_lb"]
regional_cols = ["Region","FatPercent","LeanPercent","TotalMass_lb","FatTissue_lb","LeanTissue_lb","BMC_lb"]
reg_rows = []
for name, r in d.get("regional", {}).items():
# Calculate lean percentage (lean tissue only, not including BMC - matches BodySpec report)
lean_pct = round(100 * r["lean_tissue_lb"] / r["total_mass_lb"], 1) if r["total_mass_lb"] > 0 else None
reg_rows.append({
"Region": name,
"FatPercent": r["fat_percent"],
"LeanPercent": lean_pct,
"TotalMass_lb": r["total_mass_lb"],
"FatTissue_lb": r["fat_tissue_lb"],
"LeanTissue_lb": r["lean_tissue_lb"],
"BMC_lb": r["bmc_lb"],
})
regional_path = os.path.join(outdir, "regional.csv")
df_regional = pd.DataFrame(reg_rows, columns=regional_cols)
if os.path.exists(regional_path):
pd.DataFrame(reg_rows).to_csv(regional_path, mode="a", header=False, index=False)
df_regional.to_csv(regional_path, mode="a", header=False, index=False)
else:
pd.DataFrame(reg_rows).to_csv(regional_path, index=False)
df_regional.to_csv(regional_path, index=False)
# Muscle balance
mb_cols = ["Region","FatPercent","TotalMass_lb","FatMass_lb","LeanMass_lb","BMC_lb"]
@ -435,10 +439,18 @@ def process_single_pdf(pdf_path, height_in, weight_lb, outdir):
pd.DataFrame(mb_rows).to_csv(mb_path, index=False)
# JSON
regional_array = [
{"region": name, **data}
for name, data in d.get("regional", {}).items()
]
regional_array = []
for name, data in d.get("regional", {}).items():
lean_pct = round(100 * (data["lean_tissue_lb"] + data["bmc_lb"]) / data["total_mass_lb"], 1) if data["total_mass_lb"] > 0 else None
regional_array.append({
"region": name,
"fat_percent": data["fat_percent"],
"lean_percent": lean_pct,
"total_mass_lb": data["total_mass_lb"],
"fat_tissue_lb": data["fat_tissue_lb"],
"lean_tissue_lb": data["lean_tissue_lb"],
"bmc_lb": data["bmc_lb"]
})
muscle_balance_array = [
{"region": name, **data}
for name, data in d.get("muscle_balance", {}).items()
@ -724,22 +736,26 @@ def main():
write_or_append_csv(os.path.join(args.outdir, "overall.csv"), overall_row, overall_cols)
# Regional table
regional_cols = ["Region","FatPercent","TotalMass_lb","FatTissue_lb","LeanTissue_lb","BMC_lb"]
regional_cols = ["Region","FatPercent","LeanPercent","TotalMass_lb","FatTissue_lb","LeanTissue_lb","BMC_lb"]
reg_rows = []
for name, r in d.get("regional", {}).items():
# Calculate lean percentage (lean tissue only, not including BMC - matches BodySpec report)
lean_pct = round(100 * r["lean_tissue_lb"] / r["total_mass_lb"], 1) if r["total_mass_lb"] > 0 else None
reg_rows.append({
"Region": name,
"FatPercent": r["fat_percent"],
"LeanPercent": lean_pct,
"TotalMass_lb": r["total_mass_lb"],
"FatTissue_lb": r["fat_tissue_lb"],
"LeanTissue_lb": r["lean_tissue_lb"],
"BMC_lb": r["bmc_lb"],
})
regional_path = os.path.join(args.outdir, "regional.csv")
df_regional = pd.DataFrame(reg_rows, columns=regional_cols)
if os.path.exists(regional_path):
pd.DataFrame(reg_rows).to_csv(regional_path, mode="a", header=False, index=False)
df_regional.to_csv(regional_path, mode="a", header=False, index=False)
else:
pd.DataFrame(reg_rows).to_csv(regional_path, index=False)
df_regional.to_csv(regional_path, index=False)
# Muscle balance
mb_cols = ["Region","FatPercent","TotalMass_lb","FatMass_lb","LeanMass_lb","BMC_lb"]
@ -761,10 +777,18 @@ def main():
# JSON (overall structured object)
# Convert regional and muscle_balance dicts to arrays
regional_array = [
{"region": name, **data}
for name, data in d.get("regional", {}).items()
]
regional_array = []
for name, data in d.get("regional", {}).items():
lean_pct = round(100 * data["lean_tissue_lb"] / data["total_mass_lb"], 1) if data["total_mass_lb"] > 0 else None
regional_array.append({
"region": name,
"fat_percent": data["fat_percent"],
"lean_percent": lean_pct,
"total_mass_lb": data["total_mass_lb"],
"fat_tissue_lb": data["fat_tissue_lb"],
"lean_tissue_lb": data["lean_tissue_lb"],
"bmc_lb": data["bmc_lb"]
})
muscle_balance_array = [
{"region": name, **data}
for name, data in d.get("muscle_balance", {}).items()