Introduction
The BMI calculator is the perfect *second* Streamlit app: one formula, two inputs, instant feedback — but it teaches a genuinely important pattern, unit systems that reconfigure the UI. Switch between metric and imperial and watch the inputs, labels, and math all change together. If you built the unit converter, this is its health-focused cousin.
Everything fits in about 70 lines, and by the end you'll be comfortable with conditional UI, radio-driven logic, and rendering a visual scale with a progress bar.
Features
Prerequisites
pip install streamlitStep 1: Create the Script
Save as bmi_app.py:
import streamlit as st
st.set_page_config(page_title="BMI Calculator", page_icon="⚖️")
st.title("⚖️ BMI Calculator")
unit = st.radio("Unit system", ["Metric (kg, cm)", "Imperial (lb, ft/in)"], horizontal=True)
if unit.startswith("Metric"):
weight = st.number_input("Weight (kg)", min_value=1.0, max_value=500.0, value=70.0)
height_cm = st.number_input("Height (cm)", min_value=50.0, max_value=280.0, value=170.0)
height_m = height_cm / 100
else:
weight_lb = st.number_input("Weight (lb)", min_value=2.0, max_value=1100.0, value=154.0)
col1, col2 = st.columns(2)
feet = col1.number_input("Height (ft)", min_value=1, max_value=9, value=5)
inches = col2.number_input("Extra inches", min_value=0, max_value=11, value=7)
weight = weight_lb * 0.453592
height_m = (feet * 12 + inches) * 0.0254
if height_m > 0:
bmi = weight / (height_m ** 2)
if bmi < 18.5:
category, color = "Underweight", "🟡"
elif bmi < 25:
category, color = "Normal weight", "🟢"
elif bmi < 30:
category, color = "Overweight", "🟠"
else:
category, color = "Obese", "🔴"
st.metric("Your BMI", f"{bmi:.1f}")
st.markdown(f"### {color} {category}")
st.progress(min(bmi / 40, 1.0), text=f"BMI scale (0–40): you are at {bmi:.1f}")
low = 18.5 * height_m ** 2
high = 24.9 * height_m ** 2
st.info(f"Healthy weight range for your height: {low:.1f}–{high:.1f} kg")Step 2: Run the App
streamlit run bmi_app.pyToggle between unit systems, drag the inputs, and watch the category, color, and scale respond live — no button needed.
How It Works
The whole app is a branching UI. The radio's value decides which st.number_input widgets render, and because Streamlit reruns the script on every interaction, switching units swaps the form instantly. The math normalizes both systems to kilograms and meters at the top, so the BMI formula and category thresholds are written exactly once — one source of truth instead of duplicated imperial math.
The category ladder is a classic if/elif chain over WHO thresholds (18.5 / 25 / 30). The visual scale is st.progress with the BMI clamped to the 0–40 range — a one-line visualization that reads better than a number alone.
The healthy-range footer inverts the formula: instead of BMI = weight / height², it solves weight = BMI × height² at the two boundary BMIs. Algebra doing UI work.
Common Errors & Fixes
if height_m > 0: before dividing (already in the code above).key="unit" so its selection survives reruns.st.progress expects 0.0–1.0; clamp with min(bmi / 40, 1.0).Key Concepts
What to Try Next
st.tabs.FAQ
Is BMI accurate for athletes?
No — BMI ignores muscle mass, so muscular people often read "overweight." Treat it as a quick population-level screen, not a diagnosis, and consider waist measurements alongside it.
Why compute in metric internally?
One internal unit system means one tested formula. Converting at the edges (UI in, display out) is the same pivot idea the unit converter uses for temperature.
Can I use sliders instead of number inputs?
Yes — st.slider with float steps feels great for exploration; keep st.number_input for precise entry. Offering both via a checkbox takes three lines.