
Read Eurostat regional crop and livestock statistics
Source:R/admin_stats_eurostat.R
read_admin_stats_eurostat.RdRead one of Eurostat's four regional agricultural dataflows over the SDMX-CSV dissemination API and return its rows in the source's own identifiers: the NUTS code and label exactly as Eurostat served them, the crop or animal code and label exactly as Eurostat served them, and the value converted to WHEP units. Nothing is mapped to a WHEP item code and nothing is resolved to a polity here; those are separate steps, so a change in either leaves this reader untouched.
Tables, verified live on 2026-09-02:
"apro_cpshr"– crop production by NUTS 2 region, 2000-2024."apro_cpnhr_h"– the historical companion, 1975-1999."apro_mt_ls_r"– animal populations by NUTS 2 region, 1977-2025. It carries dairy cows (A2300F) and non-dairy cows (A2300G) separately but no poultry."ef_lsk_poultry"– farm-structure-survey poultry by NUTS 2 region, census years only (2005, 2007, 2010, 2013, 2016, 2020, 2023).
No registration or key is needed. The dataflow identifier is checked against Eurostat's own dataflow registry before any data request, so a renamed table aborts naming the tables this reader knows instead of returning an empty tibble.
Arguments
- table
Dataflow to read, one of
"apro_cpshr","apro_cpnhr_h","apro_mt_ls_r"or"ef_lsk_poultry".- filters
Named list narrowing the request, any of:
geo(NUTS codes, e.g.c("FR", "FRF2")),items(crop or animal dimension codes, e.g."C1110"or"A2000") andyears(integer years; the request spans their range and the result is filtered to them exactly). An absent or empty element means "everything Eurostat serves", which for"ef_lsk_poultry"is large.- nuts_level
Integer NUTS levels to return as units, a subset of
1:3. Defaults to2L, the level every one of these tables is published at.- file
Path to an already-downloaded SDMX-CSV response to parse instead of calling the API. It must have been requested with
label=both, since the version suffix is read from the labels.- example
If
TRUE, return a small fixture instead of reading data. Defaults toFALSE.
Value
A tibble of source-native rows, one per unit x item x measure x
year, with columns source ("Eurostat_<table>"),
source_native_unit_id, source_native_unit_name,
source_native_item_code, source_native_item_name, quantity
("area", "production" or "heads"), indicator_used (the
admin-shares indicator vocabulary for area and production rows, NA
for head counts, which that vocabulary does not cover), year,
value (converted to hectares, tonnes or head), value_unit,
value_flag (Eurostat's observation flag and confidentiality status
verbatim, joined by "|" when both are present, NA when clean),
concept_break, grain, nuts_level, nuts_version,
source_version (the response's LAST UPDATE stamp verbatim) and
recorded_at. The NUTS 0 rows are attached as the "national_check"
attribute, in the same columns with grain = NA.
Units and the values this reader converts
Eurostat serves crop areas in thousand hectares (AR_THS_HA,
MAR_THS_HA), crop production in thousand tonnes (HPRD_THS_T,
HPRD_HUMD_EU_THS_T) and animal populations in thousand head
(THS_HD) or head (HD). Every response carries those units in the
measure dimension's own label, so the conversion factor is not a
constant this package asserts from outside: the reader checks each
response's label against the unit it is about to assume and aborts if
Eurostat changes it.
Humidity (HUMD_PC, HUMD_EU_PC) and yield (YLD_HUMD_EU_T_HA) rows
are dropped and counted. Yield is exactly production divided by area,
both of which this reader returns, and its tonnes-per-hectare unit is
outside this contract's value_unit vocabulary.
What the area figures mean, and the 2025 break
Eurostat's own metadata (ESMS apro_cp_esms, section 3.4, metadata
last updated 7 October 2025) states that "under the pre-SAIO data
collection, up to the 2024 reference year, the area concept was area
under cultivation, i.e. the area actually harvested, with non-harvested
areas (for example due to natural disasters) excluded", which is why
AR_THS_HA maps to indicator_used = "area_harvested". From the 2025
reference year the SAIO regulation changes that: "for cereals for the
production of grain, dry pulses and protein crops, root crops,
industrial crops, and plants harvested green, the areas refer to the
sown area", while vegetables stay on harvested area and permanent crops
on production area.
Because the new concept differs by crop group, and this reader has no
crop vocabulary, it does not relabel 2025+ rows. It flags them:
every "apro_cpshr" row with year >= 2025 gets
concept_break = TRUE, and choosing the right indicator_used for
them is the resolver's job once a crop-group vocabulary exists. As of
2026-09-02 the dataflow held no year beyond 2024, so the flag is
prospective.
NUTS versions, and why rows are deduplicated
Eurostat labels every geography whose code has been retired with the
last nomenclature in which it was valid – FR21 arrives as
"Champagne-Ardenne (NUTS 2013)". nuts_version is read from that
suffix, and a code without one is on the current nomenclature, NUTS
2024 (regulation 2023/674, in force 2024-2026; see
https://ec.europa.eu/eurostat/web/nuts/history). The suffix is
Eurostat's own retirement marker, so nuts_version means "the last
nomenclature this code was valid in", which is exactly what a later
code-system-scoped resolution step needs.
One response therefore mixes vintages: apro_cpnhr_h carries FR21
for 1989-1999 and FRF2 – a pure recoding of the same polygon – for
1990-1999. Rows for the same territory in the same year are
deduplicated keeping the newest vintage, and the dropped count, the
code pairs and any value disagreement are reported. Two rows count as
the same territory only when they share a country, a NUTS level and a
label once the version suffix is stripped; that comparison finds
recodings only, never resolves a code to a polity, and never merges
across levels, so FI2/FI20 (both labelled "Aland") and DE3/DE30
(both "Berlin") stay separate. A genuine boundary change between
vintages keeps both rows, visible, for the resolution step to settle.
Grain, and the levels this returns
NUTS 2 is grain = "admin1" and NUTS 3 is "admin2", the mapping the
admin-shares grain rule uses for EU countries. NUTS 1 rows are returned
only when asked for (nuts_level = 1L) and carry grain = NA: in some
countries NUTS 1 is a genuine first-order division (Germany's
Bundeslaender) and in others it is an aggregate of the units below it,
so which of the two it is cannot be decided per row here. Germany is
the case that forces the question – it reports crop area at NUTS 2
only up to 2004 and at NUTS 1 from 2005 onward (verified against
apro_cpshr on 2026-09-02).
NUTS 0 rows are not units at all; they are the national totals the
units should sum to, and they are returned separately as the
"national_check" attribute of the result. Supranational aggregates
(EU, EU27_2020) and composite codes that would double-count their
own members (EL41_42, served for 2007-2014 alongside EL41 and
EL42) are dropped and counted.
Examples
read_admin_stats_eurostat(example = TRUE)
#> # A tibble: 10 × 17
#> source source_native_unit_id source_native_unit_n…¹ source_native_item_c…²
#> <chr> <chr> <chr> <chr>
#> 1 Eurostat… FR21 Champagne-Ardenne (NU… C1110
#> 2 Eurostat… FRF2 Champagne-Ardenne C1110
#> 3 Eurostat… FRF2 Champagne-Ardenne C1110
#> 4 Eurostat… FRF1 Alsace C1300
#> 5 Eurostat… ES51 Cataluña C1110
#> 6 Eurostat… DE11 Stuttgart C1110
#> 7 Eurostat… FRF2 Champagne-Ardenne A2000
#> 8 Eurostat… FRF2 Champagne-Ardenne A2300F
#> 9 Eurostat… FI20 Åland A3100
#> 10 Eurostat… FRF2 Champagne-Ardenne A5000
#> # ℹ abbreviated names: ¹source_native_unit_name, ²source_native_item_code
#> # ℹ 13 more variables: source_native_item_name <chr>, quantity <chr>,
#> # indicator_used <chr>, year <int>, value <dbl>, value_unit <chr>,
#> # value_flag <chr>, concept_break <lgl>, grain <chr>, nuts_level <int>,
#> # nuts_version <chr>, source_version <chr>, recorded_at <chr>