Tidy Access to Spanish INE Demographic Data

Provides tidy, harmonized access to demographic data from the Spanish National Statistics Institute (INE) fenomenos demograficos domain, including population, births, and deaths, retrieved live via the official 'ineapir' API wrapper, with optional spatial integration at municipality and province level via 'mapSpain'. Mortality indicators follow the Human Mortality Database Methods Protocol, including the average age at death in infancy method of Andreev and Kingkade (2015) .


inedemogR

CRAN status CRAN downloads

inedemogR provides tidy access to demographic data from the Spanish National Statistics Institute (INE), specifically its "fenómenos demográficos" domain: population, births, and deaths. Data is retrieved live via the official ineapir API wrapper and tidied into long/wide data frames, with optional spatial integration via mapSpain and sf.

Installation

Install the released version from CRAN with:

install.packages("inedemogR")

Version 0.2.0 corrects numerical errors in 0.1.0 (the Andreev-Kingkade a0, old-age smoothing, the ESP 2013 weights, abridged tables, the Pollard decomposition, fertility conventions and missing-data handling); see NEWS.md. Results computed with 0.1.0 should be recomputed with 0.2.0 or later.

You can install the development version of inedemogR from GitHub with:

# install.packages("pak")
pak::pak("jrcarob/inedemogR_package")

or

# install.packages("devtools")
devtools::install_github("jrcarob/inedemogR_package")

Example

library(inedemogR)

# List available indicators and the INE tables they're wired to
list_ine_indicators()

# Fetch population data for municipalities in 2023 (real INE data)
pop_data <- get_ine_demog(indicator = "population_total", year = 2023)

# Fetch births and deaths by province in the same call
vital_stats <- get_ine_demog(
  indicator = c("births_total", "deaths_total"),
  year = 2023
)

# Fetch the same population data with geometries attached
pop_sf <- get_ine_demog(
  indicator = "population_total",
  year = 2023,
  region = "^Sevilla$",
  geometry = TRUE
)

Indicators are only available at the geographic level their source INE table is actually published at: population_total is municipality-level, births_total/deaths_total are province-level. Requesting indicators that span different levels in one call raises an error rather than silently mixing granularities — see list_ine_indicators().

Two workflows

inedemogR supports two deliberately parallel, complementary workflows — neither subsumes the other, since they operate at different geographic and demographic granularities.

Workflow (a): export and work with files. download_ine_data() runs the province-level SHMD mortality pipeline (births, deaths, population, exposure-to-risk, central death rates, period life tables, per HMD Methods Protocol V6) and writes the results to a folder as CSV and/or HMD-format .txt files, for use outside R:

download_ine_data("ine_data")

Workflow (b): stay in R. For quick multi-geo-level choropleths of total counts, use get_ine_demog()/get_ine_geo()/plot_ine_map() (see the example above). For age-structured demographic analysis — dependency ratios, aging index, sex ratio, population pyramids, life expectancy — use the province-level, age/sex-disaggregated functions behind download_ine_data() directly:

pop <- get_ine_population()

# Summary indicators (one row per province x year)
age_dependency_ratio(pop$data)
aging_index(pop$data)
sex_ratio(pop$data)

# Charts
plot_population_pyramid(pop$data, year = max(pop$data$year), region = "A Coruna")

# Life expectancy: full pipeline through life tables, then map it,
# bridging this province-level analysis back onto get_ine_geo()'s
# spatial layer
deaths <- get_ine_deaths()
exposure <- compute_exposure(pop$data, deaths$data_provinces)
rates <- compute_death_rates(deaths$data_provinces, exposure$data)
lt <- build_life_tables(rates$mx_1x1)
le <- life_expectancy_summary(lt$fltper, sex = "female")
map_life_expectancy(le, year = max(le$year), sex = "female")

Note crude_birth_rate() computes a crude birth rate (births/population), not a total fertility rate. For a true TFR, use get_ine_births_by_age() (age-of-mother birth counts) with age_specific_fertility_rate()/total_fertility_rate():

births_age <- get_ine_births_by_age()
asfr <- age_specific_fertility_rate(births_age$data, pop$data)
total_fertility_rate(asfr)

Status

inedemogR is under active development. System A (get_ine_demog(), get_ine_geo(), list_ine_indicators(), plot_ine_map()) implements live retrieval and mapping of municipality/province-level total counts. Migration indicators are not included in this release. System B (get_ine_births()/get_ine_deaths()/get_ine_population(), compute_exposure(), compute_death_rates(), build_life_tables(), download_ine_data()) implements a province-level, age/sex-disaggregated SHMD mortality pipeline, with summary indicators (age_dependency_ratio(), aging_index(), sex_ratio(), crude_birth_rate(), life_expectancy_summary()) and charts (plot_population_pyramid(), plot_demog_trend(), map_life_expectancy()) built on top. A comprehensive tutorial covering every function, the mortality-pipeline mathematics, and full worked examples is available via vignette("inedemogR-tutorial"). Cleaning/harmonization helpers and projections are planned.

Validation and reproducibility

The reproducibility/ folder of the GitHub repository (it is not part of the CRAN package) contains the INE inputs used in the SoftwareX article, frozen on 5 October 2026 with their provenance, INE's published reference series, and the scripts that regenerate every reported number, table and figure offline. From a clone of the repository:

Rscript reproducibility/01_validation.R        # benchmark vs INE, sensitivity, bootstrap
Rscript reproducibility/02_manuscript_numbers.R  # every number in the article
Rscript reproducibility/03_figures.R             # the article's figures
Rscript reproducibility/04_rate_benchmark.R      # grouped death rates vs INE
Rscript reproducibility/05_fertility_benchmark.R # TFR and mean age at childbearing vs INE

Across 2002-2024, provincial e0 and e65 agree with INE's published tables within 0.25 years for every province whose INE table closes at 95+ (see reproducibility/output/validation_summary.md in the repository), and provincial TFR and mean age at childbearing agree with INE's published series within 0.01 in 99% and 98% of province-years, 1975-2024. Life tables are built from 2002 onwards; INE's earlier provincial populations are top-coded at 85+.

Tests: devtools::test() runs the fixed-input suite. The full pipeline on live INE data runs when the environment variable INEDEMOGR_LIVE_TESTS=true is set (weekly in the repository's continuous integration).

Citation

If you use inedemogR in your work, please cite it. Run citation("inedemogR") for the current entry, or use:

Caro-Barrera, J. R. (2026). inedemogR: Tidy Access to Spanish INE Demographic Data. R package version 0.2.0. https://CRAN.R-project.org/package=inedemogR

@Manual{inedemogR,
  title  = {inedemogR: Tidy Access to Spanish INE Demographic Data},
  author = {J. R. Caro-Barrera},
  year   = {2026},
  note   = {R package version 0.2.0},
  url    = {https://CRAN.R-project.org/package=inedemogR},
}

Reference manual

It appears you don't have a PDF plugin for this browser. You can click here to download the reference manual.

install.packages("inedemogR")

0.2.0 by J. R. Caro-Barrera, 7 days ago


Browse source code at https://github.com/cran/inedemogR


Authors: J. R. Caro-Barrera [aut, cre, cph]


Documentation:   PDF Manual  


MIT + file LICENSE license


Imports dplyr, ggplot2, httr2, ineapir, mapSpain, purrr, readr, rlang, scales, sf, stringi, stringr, tibble, tidyr

Suggests mockery, R.rsp, testthat, withr


See at CRAN