This page is the map: what is in the package, what the cut-offs are, one complete run from raw columns to every metric, and one thing about survey weights that affects every number you report.
The run is deliberately brief. Each metric family has its own article, with worked examples for a single value, a column, and adding results to a data frame. Links are at the bottom, and in the Articles menu above.
Intake’s Environmental Impacts of Foods (EIOF) database gives country-specific environmental impact values for more than 6,500 foods across seven impact areas spanning five domains of planetary health. What makes it unusual is not only its coverage but its adjustment factors: non-edible portion, processing and cooking yield, so that the form of food consumed in a dietary recall can be matched correctly to the form of food the impact data describes.
Alongside the database, Intake published a set of dietary environmental impact metrics for use with food consumption survey data. These come in three families:
| Family | Question it answers | Source | Article |
|---|---|---|---|
| Absolute threshold | Is this diet below the per capita daily share of a planetary boundary? | Table 3 | vignette("table3-absolute") |
| Relative benchmark | Where does this diet sit in a global reference distribution? | Tables 4a–4g | vignette("table4-relative") |
| Composite | Is this diet both healthy and environmentally sound? | Tables 5a, 5b | vignette("table5-composites") |
All of them are age- and sex-specific, because average dietary energy requirement differs across groups.
reiod implements those metrics in R.
It does not contain the EIOF database. It ships the
published cut-offs and applies them to impact values you have
already derived. The work of matching food items to impact factors,
applying the adjustment factors, and summing to the respondent-day
happens upstream; reiod starts where that ends. It also
does not calculate the Global Diet Quality Score — the composite metrics
take a GDQS value as an input.
So the input reiod expects is one row per
respondent-day, with the impact totals already summed:
head(eiod_demo, 3)
#> id age sex land_total_m2yr land_arable_m2yr land_pasture_m2yr ghg_kgco2e
#> 1 1 16.4 male 6.661992 9.1117404 6.257198 7.709933
#> 2 2 33.0 male 6.173535 3.6705075 1.322853 7.400251
#> 3 3 45.5 male 8.260851 0.4574517 9.283150 1.127271
#> eutroph_gpo4e water_litres biodiv_pdf gdqs
#> 1 3.062745 289.1277 1.670692e-12 26.7
#> 2 10.051376 361.7203 5.547457e-13 18.4
#> 3 8.827951 401.3645 9.416969e-13 35.0The package has no dependencies beyond base R: it
imports only stats and utils, which ship with
every R installation. The practical consequence is a plain vector API:
you pass df$biodiv_pdf, not biodiv_pdf.
Every step below is covered in depth in its own article. This is the whole workflow on the demo data, so you can see how the pieces fit before reading them one at a time.
1. The demographic group. Every cut-off is age- and
sex-specific, so this comes first
(vignette("demographic-groups")):
d <- eiod_demo
d$grp <- eiod_age_sex_group(d$age, d$sex)
table(d$grp)
#>
#> 1 2 3 4 5 6 7 8
#> 6 17 25 257 9 11 22 2532. Check the inputs
(vignette("data-checks")). Your columns can be named
anything; eiod_demo_map states which column holds which
indicator:
eiod_demo_map
#> landtotal landarable landpasture ghg
#> "land_total_m2yr" "land_arable_m2yr" "land_pasture_m2yr" "ghg_kgco2e"
#> eutroph water biodiv
#> "eutroph_gpo4e" "water_litres" "biodiv_pdf"
summary(eiod_check_data(d, impacts = eiod_demo_map,
age = "age", sex = "sex", gdqs = "gdqs"))
#> PASS - 0 error, 0 warning, 33 note3. Table 3, absolute thresholds
(vignette("table3-absolute")). One 0/1 column per
indicator, 1 meaning below the threshold:
abs7 <- eiod_absolute_all(d, d$grp, eiod_demo_map)
round(100 * colMeans(abs7, na.rm = TRUE), 1)
#> abs_landtotal abs_landarable abs_landpasture abs_ghg abs_eutroph
#> 70.2 80.8 68.7 22.2 53.5
#> abs_water abs_biodiv
#> 95.2 57.14. Tables 4a–4g, relative bands
(vignette("table4-relative")). Bands 1–10 against the fixed
global reference distribution:
band7 <- eiod_relative_all(d, d$grp, eiod_demo_map)
table(band7$band_ghg)
#>
#> 1 2 3 4 5 6 7 8 9 10
#> 249 30 65 78 29 1 4 63 23 585. Tables 5a and 5b, composites
(vignette("table5-composites")). The under-twos are set to
NA, and a message says so:
d$hesd <- eiod_hesd(d$biodiv_pdf, d$gdqs, d$grp, form = "binary")
#> 15 observation(s) aged under 2 years set to NA: the GDQS is not validated below age 2, so the HESD metric does not apply to them.
d$hdlei <- eiod_hdlei(d$biodiv_pdf, d$gdqs, d$grp, form = "binary")
#> 15 observation(s) aged under 2 years set to NA: the GDQS is not validated below age 2, so the HDLEI metric does not apply to them.6. Put the results back in your data, one row per respondent-day:
d <- cbind(d, abs7, band7)
head(d[, c("id", "grp", "abs_ghg", "band_ghg", "hesd", "hdlei")])
#> id grp abs_ghg band_ghg hesd hdlei
#> 1 1 4 0 8 0 0
#> 2 2 4 0 8 0 0
#> 3 3 4 1 1 1 0
#> 4 4 4 1 1 1 1
#> 5 5 8 0 2 0 0
#> 6 6 4 0 4 0 0These percentages are unweighted, on synthetic data. They demonstrate the code, not a finding; see Survey weights before reporting real prevalences.
ls("package:reiod")
#> [1] "eiod_absolute_all" "eiod_absolute_threshold"
#> [3] "eiod_age_sex_group" "eiod_as_sex_factor"
#> [5] "eiod_check_data" "eiod_check_demographics"
#> [7] "eiod_check_gdqs" "eiod_check_impact"
#> [9] "eiod_check_magnitude" "eiod_check_precision"
#> [11] "eiod_cutoffs" "eiod_demo"
#> [13] "eiod_demo_map" "eiod_hdlei"
#> [15] "eiod_healthy_diet" "eiod_hesd"
#> [17] "eiod_indicators" "eiod_list_indicators"
#> [19] "eiod_lookup_cutoff" "eiod_low_impact"
#> [21] "eiod_relative_all" "eiod_relative_band"
#> [23] "eiod_sustainable_diet"| Group | Functions |
|---|---|
| Demographic group | eiod_age_sex_group(),
eiod_as_sex_factor() |
| Metrics | eiod_absolute_threshold(),
eiod_relative_band(), eiod_hesd(),
eiod_hdlei() |
| Several indicators at once | eiod_absolute_all(),
eiod_relative_all() |
| Decomposed sub-indicators | eiod_healthy_diet(),
eiod_sustainable_diet(),
eiod_low_impact() |
| Data quality checks | eiod_check_data() and five component checks |
| Reference lookups | eiod_list_indicators(),
eiod_lookup_cutoff() |
| Shipped data | eiod_cutoffs, eiod_indicators,
eiod_demo, eiod_demo_map |
Units matter more here than in most analyses, because a unit error produces a confidently wrong answer rather than an obvious one. This is the function to check what the package expects:
eiod_list_indicators()
#> Seven environmental impact indicators, per capita per day:
#>
#> landtotal Total land use m2*year
#> landarable Arable land use m2*year
#> landpasture Pasture land use m2*year
#> ghg Greenhouse gas emissions kg CO2eq
#> eutroph Eutrophication potential g PO4(3-)eq
#> water Water use litres
#> biodiv Biodiversity loss PDF*year
#>
#> Values must already be summed across everything the respondent
#> consumed that day. reiod does not compute impacts from food items.
#>
#> These are the EIOF database's own units. Supply your totals as they
#> come - no indicator needs converting.
#> Changed Oct 2026: eutrophication used to need a /1000 step, because
#> the paper printed its Table 3 threshold in kg. Intake has corrected
#> that row to grams. Remove the division from older scripts.The indicator key in the first column is what you pass to every function. Your own column can be called anything — the two never have to match.
All 616 published cut-offs ship as eiod_cutoffs, in long
format:
str(eiod_cutoffs)
#> 'data.frame': 616 obs. of 15 variables:
#> $ metric : chr "abs" "abs" "abs" "abs" ...
#> $ table : chr "3" "3" "3" "3" ...
#> $ indicator : chr "biodiv" "biodiv" "biodiv" "biodiv" ...
#> $ indicator_label : chr "Biodiversity loss" "Biodiversity loss" "Biodiversity loss" "Biodiversity loss" ...
#> $ unit : chr "PDF*year" "PDF*year" "PDF*year" "PDF*year" ...
#> $ demogroup : int 1 2 3 4 5 6 7 8 1 2 ...
#> $ demogroup_label : chr "Male 0-1.9 yr" "Male 2-4.9 yr" "Male 5-9.9 yr" "Male 10+ yr" ...
#> $ sex : Factor w/ 2 levels "male","female": 1 1 1 1 2 2 2 2 1 1 ...
#> $ age_min : num 0 2 5 10 0 2 5 10 0 2 ...
#> $ age_max : num 1.9 4.9 9.9 999 1.9 4.9 9.9 999 1.9 4.9 ...
#> $ row_order : int 7 7 7 7 7 7 7 7 5 5 ...
#> $ percentile : int NA NA NA NA NA NA NA NA NA NA ...
#> $ value : num 3.69e-13 5.72e-13 7.88e-13 1.28e-12 3.57e-13 ...
#> $ value_published_str: chr "3.6896027444E-13" "5.7244838747E-13" "7.8836516181E-13" "1.2844358718E-12" ...
#> $ value_source : chr "published" "published" "published" "published" ...table(eiod_cutoffs$table, eiod_cutoffs$metric)
#>
#> abs rel
#> 3 56 0
#> 4a 0 80
#> 4b 0 80
#> 4c 0 80
#> 4d 0 80
#> 4e 0 80
#> 4f 0 80
#> 4g 0 80eiod_lookup_cutoff("ghg", metric = "abs")
#> Table 3 absolute threshold - Greenhouse gas emissions
#> unit: kg CO2eq per capita per day
#>
#> group value as printed
#> Male 0-1.9 yr 0.6155661134 0.6155661134
#> Male 2-4.9 yr 0.9550617056 0.9550617056
#> Male 5-9.9 yr 1.3152930335 1.3152930335
#> Male 10+ yr 2.1429277142 2.1429277142
#> Female 0-1.9 yr 0.5964328302 0.5964328302
#> Female 2-4.9 yr 0.8845537944 0.8845537944
#> Female 5-9.9 yr 1.2076082237 1.2076082237
#> Female 10+ yr 1.7237261333 1.7237261333
#>
#> printed at 15 significant digits.
#> `as printed` is the literal text this package ships, which has
#> never been through a numeric type. Nothing is rescaled here.Printed to 15 significant digits on purpose: the published cut-offs
need up to 14, and R’s default options(digits = 7) would
make it look as though the package had rounded the guideline. The
as printed column is the literal text transcribed from the
paper, so you can check it character for character.
subset(eiod_cutoffs,
metric == "rel" & indicator == "ghg" & demogroup == 4 &
!is.na(percentile),
select = c(percentile, value))
#> percentile value
#> 247 10 3.105870
#> 248 20 3.552641
#> 249 30 4.529023
#> 250 40 5.767824
#> 251 50 6.595250
#> 252 60 6.602176
#> 253 70 6.738681
#> 254 80 8.944839
#> 255 90 10.091426The composites define none. HESD reuses the Table 3 biodiversity threshold; HDLEI reuses the Table 4g P30. Both obtain them by calling the metric functions, so there is no second copy in the code and nothing extra in the data.
On Intake’s instruction. The value_source column marks
them:
subset(eiod_cutoffs, value_source != "published",
c(demogroup_label, metric, unit, value))
#> demogroup_label metric unit value
#> 9 Male 0-1.9 yr abs g PO4(3-)eq 7.682720
#> 10 Male 2-4.9 yr abs g PO4(3-)eq 11.919876
#> 11 Male 5-9.9 yr abs g PO4(3-)eq 16.415830
#> 12 Male 10+ yr abs g PO4(3-)eq 26.745323
#> 13 Female 0-1.9 yr abs g PO4(3-)eq 7.443923
#> 14 Female 2-4.9 yr abs g PO4(3-)eq 11.039886
#> 15 Female 5-9.9 yr abs g PO4(3-)eq 15.071844
#> 16 Female 10+ yr abs g PO4(3-)eq 21.513377Supply eutrophication in grams and convert nothing.
vignette("eutrophication") has the whole story.
reiod returns respondent-level indicator vectors and
nothing else. It applies no survey design.
Every prevalence you report should come from a design-aware estimator — the survey package, or whatever your analysis uses — or both your point estimates and your standard errors will be wrong for a complex design. The percentages printed throughout these articles are unweighted, because they are demonstrating code rather than reporting results.
Read them in this order the first time:
vignette("data-checks") — what to run
before computing anything, and why only one check is automaticvignette("demographic-groups") — the
eight age × sex cells every cut-off is scaled byvignette("table3-absolute") — Table
3vignette("table4-relative") — Tables
4a–4gvignette("table5-composites") — Tables
5a and 5bThen as needed:
vignette("precision") — the precision pre-flight check
in depthvignette("troubleshooting") — a broken dataset, fault
by faultvignette("eutrophication") — the one indicator with a
unit history