pymulantest / app.py
SallySims's picture
Update app.py
81246cd verified
# app.py
import streamlit as st
import pandas as pd
import numpy as np
st.title("pymulantest: a batch Anthropometric Indices (27) estimator: data needed age, sex, weight, height, waist circumference, hip circumference")
# Upload a CSV file
uploaded_file = st.file_uploader("Upload your CSV file", type=["csv"])
class AnthropometricAgent:
def __init__(self):
self.required_cols = ['height_cm', 'weight_kg', 'age', 'sex', "wc_cm", "hip_cm"]
def validate_input(self, df):
missing_columns = [col for col in self.required_cols if col not in df.columns]
if missing_columns:
raise ValueError(f"Missing required columns: {', '.join(missing_columns)}")
mask = (df['height_cm'].between(50, 250)) & (df['weight_kg'].between(10, 500)) & (df['age'].between(0, 120))
if not mask.all():
raise ValueError("Data contains unrealistic values.")
return True
def calculate_indices(self, df):
df['sex'] = df['sex'].replace({'male': 0, 'female': 1, 0: 0, 1: 1}).fillna(-1).astype(int)
if (df['sex'] == -1).any():
raise ValueError("Invalid sex values. Use 'male', 'female', 0, or 1.")
def bmi(w, h): return w / ((h/100) ** 2)
def bfp(b, a, s): return (1.20 * b) + (0.23 * a) - (16.2 if s == 0 else 5.4)
df['bmi'] = df.apply(lambda r: bmi(r['weight_kg'], r['height_cm']), axis=1)
df['bfp'] = df.apply(lambda r: bfp(r['bmi'], r['age'], r['sex']), axis=1)
df['whtr'] = df['wc_cm'] / df['height_cm']
df['whr'] = df['wc_cm'] / df['hip_cm']
df['bmi_category'] = pd.cut(df['bmi'], [0, 18.5, 25, 30, np.inf], labels=['underweight', 'normal', 'overweight', 'obese'])
return df.round(2)
agent = AnthropometricAgent()
if uploaded_file is not None:
try:
df = pd.read_csv(uploaded_file)
agent.validate_input(df)
result_df = agent.calculate_indices(df)
st.success("✅ Successfully processed the data!")
st.write("### Sample of Results")
st.dataframe(result_df.head())
csv = result_df.to_csv(index=False).encode()
st.download_button("Download Processed Data as CSV", csv, "processed_data.csv", "text/csv")
except Exception as e:
st.error(f"❌ Error: {e}")