This tutorial walks through a complete multi-domain regional analysis — from raw Eurostat data to publication-ready maps and Tableau exports. We combine economy, labour, health, and education indicators into a unified subnational dashboard covering 235+ European NUTS 2 regions.
Phase 1: Data Acquisition
Understanding the Data Model
Eurostat organizes subnational statistics using the NUTS classification:
-
NUTS 0 — Country level (e.g.,
DEfor Germany) -
NUTS 1 — Major socio-economic regions (e.g.,
DE1for Baden-Württemberg) -
NUTS 2 — Basic regions (e.g.,
DE11for Stuttgart)
Not all countries report at NUTS 2. localintel handles this through data cascading (Phase 3).
Browsing the Indicator Registry
n <- indicator_count()
cat(n$indicators, "indicators across", n$domains, "domains\n")
print(n$by_domain)Fetching Multiple Domains
# Economy
econ_data <- fetch_eurostat_batch(economy_codes(), level = 2, years = 2010:2024)
# Labour market
lab_data <- fetch_eurostat_batch(labour_codes(), level = 2, years = 2010:2024)
# Health
hlth_data <- fetch_eurostat_batch(health_system_codes(), level = 2, years = 2010:2024)
# Education
educ_data <- fetch_eurostat_batch(education_codes(), level = 2, years = 2010:2024)
# Drop any empty results
econ_data <- drop_empty(econ_data)
lab_data <- drop_empty(lab_data)
hlth_data <- drop_empty(hlth_data)
educ_data <- drop_empty(educ_data)Phase 2: Data Processing
Domain-Specific Processors
Each domain has convenience processors that filter the right dimensions:
# Economy
gdp <- process_gdp(econ_data$gdp_nuts2)
# Labour
unemp <- process_unemployment_rate(lab_data$unemployment_rate)
empl_rate <- process_eurostat(lab_data$employment_rate,
filters = list(sex = "T", age = "Y20-64"),
out_col = "employment_rate")
# Health
beds <- process_beds(hlth_data$beds)
physicians <- process_physicians(hlth_data$physicians)
# Education
tertiary <- process_education_attainment(educ_data$attain_tertiary)The Generic Processor
For datasets without a dedicated processor, use
process_eurostat():
# Tourism: nights spent
nights_raw <- get_nuts_level_robust("tour_occ_nin2", level = 2, years = 2010:2024)
nights <- process_eurostat(nights_raw,
filters = list(unit = "NR", nace_r2 = "I551-I553", c_resid = "TOTAL"),
out_col = "nights_spent")
# R&D expenditure
rd_raw <- get_nuts_level_robust("rd_e_gerdreg", level = 2, years = 2010:2024)
rd <- process_eurostat(rd_raw,
filters = list(unit = "PC_GDP", sectperf = "TOTAL"),
out_col = "rd_expenditure")Merging
Combine all indicators into one table:
all_data <- merge_datasets(gdp, unemp, empl_rate, beds, physicians, tertiary)
glimpse(all_data)Phase 3: Data Cascading
Getting Reference Data
nuts2_ref <- get_nuts2_ref()
geopolys <- get_nuts_geopolys()Generic Cascade (Any Domain)
cascaded <- cascade_to_nuts2(
all_data,
vars = c("gdp", "unemployment_rate", "employment_rate",
"beds", "physicians", "education_attainment"),
nuts2_ref = nuts2_ref,
years = 2010:2024
)
# Check coverage
cascaded %>%
summarise(across(starts_with("src_"), ~sum(!is.na(.)))) %>%
glimpse()Health-Specific Cascade (with DA/rLOS)
For health indicators, the specialized cascade also computes derived indicators:
cascaded_health <- cascade_to_nuts2_and_compute(
all_data,
vars = c("disch_inp", "disch_day", "beds", "physicians", "los"),
nuts2_ref = nuts2_ref,
years = 2010:2024
)Phase 4: Scoring
scored <- cascaded %>%
keep_eu27() %>%
transform_and_score(list(
unemp_tr = "-unemployment_rate",
gdp_tr = "safe_log10(gdp)",
beds_tr = "beds",
educ_tr = "education_attainment"
))Phase 5: Visualization
plot_best_by_country_level(
cascaded, geopolys,
var = "unemployment_rate",
years = 2022:2024,
title = "Unemployment Rate (%)",
scale = "global"
)
plot_best_by_country_level(
cascaded, geopolys,
var = "gdp",
years = 2022:2024,
title = "GDP (million EUR)"
)Phase 6: Multi-Domain Tableau Export
sf_all <- build_multi_var_sf(
cascaded, geopolys,
vars = c("gdp", "unemployment_rate", "beds", "education_attainment"),
years = 2010:2024,
var_labels = regional_var_labels(),
pillar_mapping = regional_domain_mapping()
)
pop_data <- get_population_nuts2()
nuts2_names <- get_nuts2_names()
sf_enriched <- enrich_for_tableau(sf_all, pop_data, nuts2_names)
export_to_geojson(sf_enriched, "output/multi_domain_dashboard.geojson")
export_to_excel(cascaded, "output/cascaded_multi_domain.xlsx")