README.md
February 25, 2025 · View on GitHub
Introduction
The ecb package package provides an R interface to the European
Central Bank’s Data Portal.
To install the development version:
library(devtools)
install_github("expersso/ecb")
Example usage
The following example extracts the last twelve observations of headline
and “core” HICP inflation for a number of countries available in the
ICP database. See details below on how to use the filter parameter
and how to find and use the EDP series keys.
library(ecb)
library(ggplot2)
key <- "ICP.M.DE+FR+ES+IT+NL+U2.N.000000+XEF000.4.ANR"
filter <- list(lastNObservations = 12, detail = "full")
hicp <- get_data(key, filter)
hicp$obstime <- convert_dates(hicp$obstime)
ggplot(hicp, aes(x = obstime, y = obsvalue, color = title)) +
geom_line() +
facet_wrap(~ref_area, ncol = 3) +
theme_bw(8) +
theme(legend.position = "bottom") +
labs(x = NULL, y = "Percent per annum\n", color = NULL,
title = "HICP - headline and core\n")

Details
The filter option
The filter option of get_data() takes a named list of key-value
pairs. If left blank, it returns all data for the current version.
Available filter parameters:
startPeriod&endPeriodYYYYfor annual data (e.g. 2013)YYYY-S[1-2]for semi-annual data (e.g. 2013-S1)YYYY-Q[1-4]for quarterly data (e.g. 2013-Q1)YYYY-MMfor monthly data (e.g. 2013-01)YYYY-W[01-53]for weekly data (e.g. 2013-W01)YYYY-MM-DDfor daily data (e.g. 2013-01-01)
updatedAfter- A timestamp to retrieve the latest version of changed values in the database since a certain point in time
- Example:
filter = list(updatedAfter = 2009-05-15T14:15:00+01:00)
firstNObservations&lastNObservations- Example:
filter = list(firstNObservations = 12)retrieves the first 12 observations of all specified series
- Example:
detail- Possible options:
full/dataonly/serieskeysonly/nodata dataonlyis the default- Use
serieskeysonlyornodatato list series that match a certain query, without returning the actual data - An alternative to using
serieskeys/nodatais the convenience functionget_dimensions(), which returns a list of dataframes with dimensions and explanations (see extended example below). fullreturns both the series values and all metadata. This entails retrieving much more data than with thedataonlyoption.
- Possible options:
includeHistory(not currently implemented)false(default) returns only version currently in productiontruereturns version currently in production, as well as all previous versions
See the EDP API for more details.
Using EDP keys
The easiest way to find and learn more about EDP series key is to browse the EDP website. After finding the series one is interested in, and applying the relevant filters (frequency, geographic area, etc), one can just copy the key:
The EDP website also has provides all the necessary metadata, so it is
much easier to explore data availability (in terms of available
breakdowns, time periods, etc) directly on the website than it is to do
it directly through the ecb package.
The ecb package supports using wildcards in the series key, which
takes the form of simply leaving the wildcard dimension empty. For
example, the key ICP.M.DE.N.000000.4.ANR retrieves HICP data for
Germany (DE), while leaving the third dimension empty -
ICP.M..N.000000.4.ANR - retrieves the same data for all available
countries and country groups.
Instead of wildcarding, one can use the + operator to specify multiple
values for a dimension. For example, ICP.M.DE.N.000000+XEF000.4.ANR
retrieves both headline inflation (000000) and core inflation
(XEF000). Learning that e.g. XEF000 corresponds to core inflation
would be done by browsing the EDP website:
To remind oneself of what different values for different dimensions
mean, one can use the get_dimensions) function, which returns a list
of dataframes:
dims <- get_dimensions("ICP.M.DE.N.000000+XEF000.4.ANR")
head(dims[[1]], 8)
## dim value
## 1 FREQ M
## 2 REF_AREA DE
## 3 ADJUSTMENT N
## 4 ICP_ITEM 000000
## 5 STS_INSTITUTION 4
## 6 ICP_SUFFIX ANR
## 7 TITLE HICP - Overall index"
## 8 UNIT PCCH
Extended example
As a more extended example, we will retrieve data to plot the annual change in wages against the annual change in unemployment. Economic theory suggests a negative relationship between these two variables.
We start by retrieving the two series, using wildcards for the geographic area dimension:
unemp <- get_data("LFSI.M..S.UNEHRT.TOTAL0.15_74.T",
filter = list(startPeriod = "2000"))
wages <- get_data("MNA.A.N..W2.S1.S1._Z.COM_HW._Z._T._Z.IX.V.N",
filter = list(startPeriod = "2000"))
head(unemp)
``$
## # \text{A} \text{tibble}: 6 \times 9
## \text{freq} \text{ref\_area} \text{adjustment} \text{lfs\_indicator} \text{lfs\_breakdown} \text{age\_breakdown} \text{gender}
## <\text{chr}> <\text{chr}> <\text{chr}> <\text{chr}> <\text{chr}> <\text{chr}> <\text{chr}>
## 1 \text{M} \text{AT} \text{S} \text{UNEHRT} \text{TOTAL0} 15\text{\_74} \text{T}
## 2 \text{M} \text{AT} \text{S} \text{UNEHRT} \text{TOTAL0} 15\text{\_74} \text{T}
## 3 \text{M} \text{AT} \text{S} \text{UNEHRT} \text{TOTAL0} 15\text{\_74} \text{T}
## 4 \text{M} \text{AT} \text{S} \text{UNEHRT} \text{TOTAL0} 15\text{\_74} \text{T}
## 5 \text{M} \text{AT} \text{S} \text{UNEHRT} \text{TOTAL0} 15\text{\_74} \text{T}
## 6 \text{M} \text{AT} \text{S} \text{UNEHRT} \text{TOTAL0} 15\text{\_74} \text{T}
## # ℹ 2 \text{more} \text{variables}: \text{obstime} <\text{chr}>, \text{obsvalue} <\text{dbl}>
$`` r
head(wages)
``$
## # \text{A} \text{tibble}: 6 \times 16
## \text{freq} \text{adjustment} \text{ref\_area} \text{counterpart\_area} \text{ref\_sector} \text{counterpart\_sector}
## <\text{chr}> <\text{chr}> <\text{chr}> <\text{chr}> <\text{chr}> <\text{chr}>
## 1 \text{A} \text{N} \text{AT} \text{W2} \text{S1} \text{S1}
## 2 \text{A} \text{N} \text{AT} \text{W2} \text{S1} \text{S1}
## 3 \text{A} \text{N} \text{AT} \text{W2} \text{S1} \text{S1}
## 4 \text{A} \text{N} \text{AT} \text{W2} \text{S1} \text{S1}
## 5 \text{A} \text{N} \text{AT} \text{W2} \text{S1} \text{S1}
## 6 \text{A} \text{N} \text{AT} \text{W2} \text{S1} \text{S1}
## # ℹ 10 \text{more} \text{variables}: \text{accounting\_entry} <\text{chr}>, \text{sto} <\text{chr}>, \text{instr\_asset} <\text{chr}>,
## # \text{activity} <\text{chr}>, \text{expenditure} <\text{chr}>, \text{unit\_measure} <\text{chr}>, \text{prices} <\text{chr}>,
## # \text{transformation} <\text{chr}>, \text{obstime} <\text{chr}>, \text{obsvalue} <\text{dbl}>
\text{To} \text{get} \text{a} \text{human}-\text{readable} \text{description} \text{of} \text{a} \text{series}:
$`` r
desc <- head(get_description("LFSI.M..S.UNEHRT.TOTAL0.15_74.T"), 3)
strwrap(desc, width = 80)
## [1] "Austria; European Labour Force Survey; Unemployment rate; Total; Age 15 to 74;"
## [2] "Total; Seasonally adjusted, not working day adjusted"
## [3] "EU28 (fixed composition) as of 1 July 2013; European Labour Force Survey;"
## [4] "Unemployment rate; Total; Age 15 to 74; Total; Seasonally adjusted, not working"
## [5] "day adjusted"
## [6] "EU27 (fixed composition) as of 31 January 2020 (brexit); European Labour Force"
## [7] "Survey; Unemployment rate; Total; Age 15 to 74; Total; Seasonally adjusted, not"
## [8] "working day adjusted"
We now join together the two data sets:
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(lubridate)
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
unemp <- unemp %>%
mutate(obstime = convert_dates(obstime)) %>%
group_by(ref_area, obstime = year(obstime)) %>%
summarise(obsvalue = mean(obsvalue)) %>%
ungroup() %>%
select(ref_area, obstime, "unemp" = obsvalue)
## `summarise()` has grouped output by 'ref_area'. You can override using the
## `.groups` argument.
wages <- wages %>%
mutate(obstime = as.numeric(obstime)) %>%
select(ref_area, obstime, "wage" = obsvalue)
df <- left_join(unemp, wages)
## Joining with `by = join_by(ref_area, obstime)`
head(df)
## # A tibble: 6 × 4
## ref_area obstime unemp wage
## <chr> <dbl> <dbl> <dbl>
## 1 AT 2000 3.89 55.9
## 2 AT 2001 4.01 57.0
## 3 AT 2002 4.39 58.4
## 4 AT 2003 4.78 59.6
## 5 AT 2004 5.88 60.6
## 6 AT 2005 6.03 62.3
Finally, we plot the annual change in wages against the annual change in unemployment for all countries:
library(ggplot2)
df %>%
filter(complete.cases(.)) %>%
group_by(ref_area) %>%
mutate(d_wage = c(NA, diff(wage)) / lag(wage),
d_unemp = c(NA, diff(unemp))) %>%
ggplot(aes(x = d_unemp, y = d_wage)) +
geom_point() +
facet_wrap(~ref_area, scales = "free") +
theme_bw(8) +
theme(strip.background = element_blank()) +
geom_smooth(method = "lm") +
labs(x = "\nAnnual change in unemployment", y = "Annual change in wages\n",
title = "Relationship between wages and unemployment\n")
## `geom_smooth()` using formula = 'y ~ x'

Disclaimer
This package is in no way officially related to, or endorsed by, the ECB.