diff --git a/app/lib/services/body_calc.dart b/app/lib/services/body_calc.dart index 92d7230..4caf5bc 100644 --- a/app/lib/services/body_calc.dart +++ b/app/lib/services/body_calc.dart @@ -41,11 +41,6 @@ const String trefethenNote = "Trefethen's new BMI = 1.3 x kg / m^2.5: corrects classic BMI, which " 'over-reads tall people and under-reads short ones.'; -/// Broca explained, shown under the ideal-weight list. -const String brocaNote = - 'Broca = height in cm - 100 (1871); it overshoots, so Broca (modified) ' - 'takes 10% off it for men and 15% for women.'; - /// The lean-mass formula the calorie table switches to with a body fat %. const String katchMcArdle = 'Katch-McArdle'; @@ -150,8 +145,9 @@ double? _perInch( /// Every ideal-body-weight formula we can evaluate, in kg. /// -/// Only Creff uses age. The BMI healthy range is [healthyRange], shown with -/// BMI; [idealSummary] averages these. +/// Only data-backed ones (Devine, its MetLife refits, Peterson); Broca, its +/// derivatives and Hamwi were dropped. The BMI healthy range is +/// [healthyRange], shown with BMI; [idealSummary] averages these. List idealWeights(Biometrics bio) { final h = bio.heightCm; final inches = h / _cmPerInch - _fiveFeetIn; @@ -168,14 +164,6 @@ List idealWeights(Biometrics bio) { 'Miller', _perInch(inches, male ? 56.2 : 53.1, male ? 1.41 : 1.36, defined: ok), ), - Formula( - 'Hamwi', - _perInch(inches, male ? 48 : 45.5, male ? 2.7 : 2.2, defined: ok), - ), - Formula('Broca', h - 100.0), - Formula('Broca (modified)', (h - 100.0) * (male ? 0.9 : 0.85)), - Formula('Lorentz', h - 100.0 - (h - 150.0) / (male ? 4.0 : 2.0)), - Formula('Creff (age)', (h - 100.0 + bio.ageYears / 10.0) * 0.9), Formula( 'Peterson (BMI 22)', 2.2 * _targetBmi + 3.5 * _targetBmi * (metres - 1.5), diff --git a/app/lib/widgets/body/body_stats_cards.dart b/app/lib/widgets/body/body_stats_cards.dart index 5355d8b..0b2f347 100644 --- a/app/lib/widgets/body/body_stats_cards.dart +++ b/app/lib/widgets/body/body_stats_cards.dart @@ -66,10 +66,9 @@ class IdealWeightCard extends StatelessWidget { '${oneDecimal(summary.$2)}-${oneDecimal(summary.$3)} kg', ), ], - const BodyNote(brocaNote), if (undefined) const BodyNote( - 'Devine, Robinson, Miller and Hamwi are undefined below 152.4 cm.', + 'Devine, Robinson and Miller are undefined below 152.4 cm.', ), ], ); diff --git a/app/pubspec.yaml b/app/pubspec.yaml index b45ac1f..e7b0612 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -2,7 +2,7 @@ name: diet_guard_app description: "Companion phone app for diet_guard: log meals on the go." publish_to: 'none' -version: 1.0.122+1 +version: 1.0.123+1 environment: sdk: ^3.12.2 diff --git a/app/test/screens/body_screen_test.dart b/app/test/screens/body_screen_test.dart index 02d9852..e6dae8c 100644 --- a/app/test/screens/body_screen_test.dart +++ b/app/test/screens/body_screen_test.dart @@ -71,7 +71,7 @@ void main() { expect(find.text('24.7'), findsOneWidget); expect(find.text('59.9-80.7 kg'), findsOneWidget); expect(find.text('Average of all'), findsOneWidget); - expect(find.textContaining('Broca = height'), findsOneWidget); + expect(find.textContaining('Broca'), findsNothing); expect(find.text('1780 kcal'), findsOneWidget); expect(find.text('n/a -- log a body-fat %'), findsNWidgets(2)); // 5000 steps over baseline x 0.747 m x 0.5 x 80 kg = 149.4 kcal, and diff --git a/app/test/widgets/body/body_widgets_test.dart b/app/test/widgets/body/body_widgets_test.dart index ef371cd..f012085 100644 --- a/app/test/widgets/body/body_widgets_test.dart +++ b/app/test/widgets/body/body_widgets_test.dart @@ -77,7 +77,7 @@ void main() { children: [BmiCard(bio: _short), IdealWeightCard(bio: _short)], ), ); - expect(find.text('n/a'), findsNWidgets(4)); + expect(find.text('n/a'), findsNWidgets(3)); expect(find.textContaining('undefined below 152.4 cm'), findsOneWidget); expect(find.text('adult categories do not apply under 20'), findsOneWidget); }); diff --git a/diet_guard/_body_calc.py b/diet_guard/_body_calc.py index 0fc2858..01e7d86 100644 --- a/diet_guard/_body_calc.py +++ b/diet_guard/_body_calc.py @@ -23,7 +23,6 @@ from diet_guard._budget_biometrics import Biometrics, mifflin_st_jeor_bmr __all__ = [ "BMI_PRIME_NOTE", - "BROCA_NOTE", "KATCH_MCARDLE", "TREFETHEN_NOTE", "BmiReport", @@ -38,7 +37,7 @@ __all__ = [ ] _CM_PER_INCH = 2.54 -# The inch-based formulas (Devine, Robinson, Miller, Hamwi) are all +# The inch-based formulas (Devine, Robinson, Miller) are all # "base + k per inch over five feet"; below five feet they are undefined. _FIVE_FEET_IN = 60.0 # Adult BMI categories are WHO's and do not apply to anyone still growing. @@ -71,10 +70,6 @@ TREFETHEN_NOTE = ( "over-reads tall people and under-reads short ones." ) KATCH_MCARDLE = "Katch-McArdle" -BROCA_NOTE = ( - "Broca = height in cm - 100 (1871); it overshoots, so Broca (modified) " - "takes 10% off it for men and 15% for women." -) def half_up(value: float, digits: int = 0) -> float: @@ -140,9 +135,11 @@ def _per_inch( def ideal_weights(bio: Biometrics) -> tuple[Formula, ...]: """Every ideal-body-weight formula we can evaluate, in kg. - Only Creff uses age -- it is the one that answers "ideal weight for my age - and height". The BMI healthy range is :func:`healthy_range`, shown with - BMI rather than here; :func:`ideal_summary` averages these. + Only data-backed ones: Devine and its MetLife-table refits (Robinson, + Miller), and Peterson (NHANES). Broca, its derivatives (modified Broca, + Lorentz, Creff) and Hamwi were dropped as unvalidated rules of thumb. + The BMI healthy range is :func:`healthy_range`, shown with BMI rather than + here; :func:`ideal_summary` averages these. """ h = bio.height_cm inches = h / _CM_PER_INCH - _FIVE_FEET_IN @@ -161,14 +158,6 @@ def ideal_weights(bio: Biometrics) -> tuple[Formula, ...]: inches, 56.2 if male else 53.1, 1.41 if male else 1.36, defined=ok ), ), - Formula( - "Hamwi", - _per_inch(inches, 48.0 if male else 45.5, 2.7 if male else 2.2, defined=ok), - ), - Formula("Broca", h - 100.0), - Formula("Broca (modified)", (h - 100.0) * (0.9 if male else 0.85)), - Formula("Lorentz", h - 100.0 - (h - 150.0) / (4.0 if male else 2.0)), - Formula("Creff (age)", (h - 100.0 + bio.age_years / 10.0) * 0.9), Formula( "Peterson (BMI 22)", 2.2 * _TARGET_BMI + 3.5 * _TARGET_BMI * (metres - 1.5) ), diff --git a/diet_guard/_body_report.py b/diet_guard/_body_report.py index db625b5..3e28a20 100644 --- a/diet_guard/_body_report.py +++ b/diet_guard/_body_report.py @@ -16,7 +16,7 @@ from diet_guard._activity_kcal import ( METHODS_NOTE, session_kcal, ) -from diet_guard._body_calc import BMI_PRIME_NOTE, BROCA_NOTE, TREFETHEN_NOTE, half_up +from diet_guard._body_calc import BMI_PRIME_NOTE, TREFETHEN_NOTE, half_up from diet_guard._body_energy import KCAL_PER_KG, MIN_TARGET_KCAL, activity_label from diet_guard._body_steps import STEP_BASELINE from diet_guard._body_store import age_on @@ -114,7 +114,6 @@ def ideal_lines(view: BodyView) -> list[str]: avg, low, high = summary lines.append(f" {'Average of all':<{_NAME_W}}{_num(avg, 1)} kg") lines.append(f" {'Ideal range':<{_NAME_W}}{_num(low, 1)}-{_num(high, 1)} kg") - lines.extend(_wrap(BROCA_NOTE, " ")) return lines diff --git a/diet_guard/tests/test_body_calc.py b/diet_guard/tests/test_body_calc.py index 15a8525..66ab760 100644 --- a/diet_guard/tests/test_body_calc.py +++ b/diet_guard/tests/test_body_calc.py @@ -18,6 +18,7 @@ from diet_guard._body_calc import ( bmr_formulas, half_up, ideal_summary, + ideal_weights, table_bmr, ) from diet_guard._body_energy import ( @@ -81,6 +82,11 @@ class TestBmr: def test_ideal_summary_is_none_when_nothing_applies(self) -> None: assert ideal_summary(()) is None + def test_only_data_backed_ideal_weight_formulas(self) -> None: + # Broca, its derivatives and Hamwi are unvalidated rules of thumb. + names = tuple(f.name for f in ideal_weights(_MAN)) + assert names == ("Devine", "Robinson", "Miller", "Peterson (BMI 22)") + class TestGoal: def test_kg_per_day_signs(self) -> None: diff --git a/docs/DOCS-body.md b/docs/DOCS-body.md index ac987f3..da08f4f 100644 --- a/docs/DOCS-body.md +++ b/docs/DOCS-body.md @@ -115,8 +115,8 @@ every formula's daily total. Heart-rate input was dropped at the user's call. ## Calculations (`_body_calc.py`, `_body_energy.py`, `_week_plan.py`) - **BMI** kg/m², BMI Prime, Trefethen; WHO bands, not applied under 20. -- **Ideal weight**: Devine, Robinson, Miller, Hamwi (undefined < 152.4 cm), - Broca, modified Broca, Lorentz, Creff (the one that uses age), Peterson; +- **Ideal weight**: Devine, Robinson, Miller (undefined < 152.4 cm), Peterson; + Broca, modified Broca, Lorentz, Creff and Hamwi were dropped (unvalidated); then their average and min-max "ideal range". The BMI 18.5-24.9 healthy range sits with BMI. - **BMR**: Mifflin-St Jeor, Harris-Benedict (1984), and with a body fat diff --git a/tests/fixtures/body_calc.json b/tests/fixtures/body_calc.json index 5df3791..29df395 100644 --- a/tests/fixtures/body_calc.json +++ b/tests/fixtures/body_calc.json @@ -27,26 +27,6 @@ "Miller", 71.5212598425197 ], - [ - "Hamwi", - 77.33858267716536 - ], - [ - "Broca", - 80.0 - ], - [ - "Broca (modified)", - 72.0 - ], - [ - "Lorentz", - 72.5 - ], - [ - "Creff (age)", - 74.7 - ], [ "Peterson (BMI 22)", 71.50000000000001 @@ -90,9 +70,9 @@ ] ], "ideal_summary": [ - 74.13307086614174, + 72.66476377952756, 71.50000000000001, - 80.0 + 74.99212598425197 ], "healthy_range": [ 59.94000000000001, @@ -361,26 +341,6 @@ "Miller", 59.84645669291338 ], - [ - "Hamwi", - 56.413385826771645 - ], - [ - "Broca", - 65.0 - ], - [ - "Broca (modified)", - 55.25 - ], - [ - "Lorentz", - 57.5 - ], - [ - "Creff (age)", - 62.550000000000004 - ], [ "Peterson (BMI 22)", 59.95 @@ -424,9 +384,9 @@ ] ], "ideal_summary": [ - 58.98359580052493, - 55.25, - 65.0 + 58.53474409448818, + 56.90944881889762, + 59.95 ], "healthy_range": [ 50.366249999999994, @@ -695,26 +655,6 @@ "Miller", null ], - [ - "Hamwi", - null - ], - [ - "Broca", - 50.0 - ], - [ - "Broca (modified)", - 42.5 - ], - [ - "Lorentz", - 50.0 - ], - [ - "Creff (age)", - 47.25 - ], [ "Peterson (BMI 22)", 48.400000000000006 @@ -758,9 +698,9 @@ ] ], "ideal_summary": [ - 47.63, - 42.5, - 50.0 + 48.400000000000006, + 48.400000000000006, + 48.400000000000006 ], "healthy_range": [ 41.625, @@ -1029,26 +969,6 @@ "Miller", 68.74566929133857 ], - [ - "Hamwi", - 72.02362204724409 - ], - [ - "Broca", - 75.0 - ], - [ - "Broca (modified)", - 67.5 - ], - [ - "Lorentz", - 68.75 - ], - [ - "Creff (age)", - 69.03 - ], [ "Peterson (BMI 22)", 67.65 @@ -1092,9 +1012,9 @@ ] ], "ideal_summary": [ - 69.78548556430445, - 67.5, - 75.0 + 68.94143700787401, + 67.65, + 70.46456692913384 ], "healthy_range": [ 56.65625, @@ -1363,26 +1283,6 @@ "Miller", 77.62755905511811 ], - [ - "Hamwi", - 89.03149606299212 - ], - [ - "Broca", - 91.0 - ], - [ - "Broca (modified)", - 81.9 - ], - [ - "Lorentz", - 80.75 - ], - [ - "Creff (age)", - 85.59 - ], [ "Peterson (BMI 22)", 79.97 @@ -1426,9 +1326,9 @@ ] ], "ideal_summary": [ - 83.52175853018372, + 80.85608267716535, 77.62755905511811, - 91.0 + 84.9527559055118 ], "healthy_range": [ 67.48985,