Welcome to this statistics coded notebook. This notebook developed with Rmd will allow to reproduce the graphics presented in the Statistics Explained article on Enforcement of Immigration Legislation statistics.

EIL main Indicators

This article presents indicators on the enforcement of immigration legislation. It provides statistics on: third country or non-European Union (EU) citizens who were refused entry at the external borders of the EU-27 1; non-EU citizens who were illegally present on the territory of an EU Member State; and non-EU citizens who were ordered to leave the territory of an EU Member State 2. Each of these indicators can be regarded as an official record of persons subject to the enforcement of EU immigration legislation, providing a general overview of the outcomes of territorial surveillance and control procedures.

knitr::opts_chunk$set(warning=F,message=F, fig.width = 10, fig.height = 6, cache=F)
library(data.table)
library(eurostat)
library(plotly)
library(tmap)
library(tidyverse)
library(DT)
#library(formatR)
countries <- setDT(get_eurostat_dic("geo")) %>%
  setnames("code_name","geo")

read_data <- function(table, names=countries){
  name <- copy(names)
  dt <- setDT(get_eurostat(table))%>%
    left_join(name, by = "geo")%>%
    select(-geo)%>%
    rename(geo=full_name)
  
  setnames(name,"geo","citizen")
  dt <- dt %>%
    left_join(name, by="citizen")
  return(dt)
}

ref_tot <- read_data("migr_eirfs")
app_tot<- read_data("migr_eipre")
ord_tot <- read_data("migr_eiord")
ret_tot <- read_data("migr_eirtn")
ret_type <- read_data("migr_eirt_vol")
ret_ass <- read_data("migr_eirt_ass")

map <- get_eurostat_geospatial(
  output_class = "sf",
  resolution = "60",
  nuts_level = "0",
  year = "2016"
)

Non-EU citizens subject to the enforcement of immigration legislation in EU Member States, 2010-2020

refused <- ref_tot[geo == "European Union - 27 countries (from 2020)" & reason == "TOTAL" & indic_mg == "TOT_REF" & citizen == "TOTAL", .(time,values)]
setnames(refused, "values","refused")

apprehended <- app_tot[geo == "European Union - 27 countries (from 2020)" & citizen == "TOTAL" & age == "TOTAL" & sex == "T", .(time,values)]
setnames(apprehended, "values","apprehended")

ordered <- ord_tot[geo == "European Union - 27 countries (from 2020)" & sex == "T" & citizen == "TOTAL" & age == "TOTAL", .(time, values)]
setnames(ordered, "values","ordered")

returned <- ret_tot[geo == "European Union - 27 countries (from 2020)" & sex == "T" & citizen =="TOTAL" & age == "TOTAL" & indic_mg == "TOT_RET", .(time,values)]
setnames(returned, "values","returned")

dt <- left_join(refused, apprehended)%>%
  left_join(ordered)%>%
  left_join(returned)

plot_ly(dt, x = ~time,y= ~refused,
               name = "Refused",type = "scatter",mode = 'lines+markers') %>%
  add_trace(y = ~apprehended, name = 'Apprehended', mode = 'lines+markers') %>%
  add_trace(y = ~ordered, name = 'Ordered to leave', mode = 'lines+markers') %>%
  add_trace(y = ~returned, name = 'Returned', mode = 'lines+markers') %>%
  layout(paper_bgcolor='gray20',
           plot_bgcolor='gray87',
           xaxis = list(color = 'black',tickangle = 0),
           yaxis = list(color = 'black', title = "Persons",exponentformat="none",separatethoudands = TRUE)
    ) %>%
  layout(hovermode = "x unified")

Non-EU citizens subject to the enforcement of immigration legislation in EU Member States EU27_2020, 2010-2020 (number)


Non-EU citizens found to be illegally present in the EU territory

Overview

Map

# print("toto")
htmltools::includeHTML("immigration-legislation-js-map.html")

Chart

app <- app_tot[!(geo %in% c("European Union - 27 countries (from 2020)","European Union - 28 countries (2013-2020)","United Kingdom","Switzerland","Liechtenstein","Norway","Iceland")) & citizen == "TOTAL" & age == "TOTAL" & sex == "T",]
app[!(geo %in% c("Germany (until 1990 former territory of the FRG)","Greece","Spain","France","Hungary")), geo := "OTH_MS"]
app <- app[,.(geo, time, values)]
app <- dcast(app, time~geo, value.var = "values", fun.aggregate = sum)

plot_ly(app, x = ~time,y= ~`Germany (until 1990 former territory of the FRG)`,
               name = "Germany",type = "scatter",mode = 'lines+markers') %>%
  add_trace(y = ~Greece, name = 'Greece', mode = 'lines+markers') %>%
  add_trace(y = ~Spain, name = 'Spain', mode = 'lines+markers') %>%
  add_trace(y = ~France, name = 'France', mode = 'lines+markers') %>%
  add_trace(y = ~Hungary, name = 'Hungary', mode = 'lines+markers') %>%
  add_trace(y = ~OTH_MS, name = 'Other Member States', mode = 'lines+markers') %>%
  layout(paper_bgcolor='gray20',
           plot_bgcolor='gray87',
           xaxis = list(color = 'black',tickangle = 0),
           yaxis = list(color = 'black', title = "Persons",exponentformat="none",separatethoudands = TRUE)
    ) %>%
  layout(hovermode = "x unified")

Non-EU citizens found to be illegally present in the five most affected EU Member States

Non-EU citizens found to be illegally present — by sex and age

Bar chart

app_bar <- app_tot[geo == "European Union - 27 countries (from 2020)" & citizen == "TOTAL" & !(age %in% c("TOTAL","UNK","Y_LT18")) & sex != "T" & (time=="2020-01-01" | time=="2010-01-01"), sum(values, na.rm = T),.(time,sex,age)] %>% 
  dcast( age~sex+time, value.var = "V1")

app_bar[age == "Y18-34", age := '18-34 years']
app_bar[age == "Y14-17", age := '14-17 years']
app_bar[age == "Y_LT14", age := '< 14 years']
app_bar[age == "Y_GE35", age := '>= 35 years']
app_bar <- app_bar[c(3,2,1,4)]

tit3 <- "Non-EU citizens found to be illegally present in the EU-27, by sex and age - 2020 and 2010"
plot_ly(app_bar, x = ~`F_2020-01-01`, y = ~age, type = 'bar', orientation = 'h', name = 'Women 2020',
        marker = list(color = 'white',
                      line = list(color = 'gold',
                                  width = 3)),
        text = format(app_bar[,`F_2020-01-01`], 
                          big.mark = " ", 
                          scientific = FALSE),
            hoverinfo = "name+text+y")%>%
  add_trace(x = ~`F_2010-01-01`, y = ~age, type = 'bar', orientation = 'h', name = 'Women 2010',
        marker = list(color = 'orange',
                      line = list(color = 'orange',
                                  width = 3)),
        text = format(app_bar[,`F_2020-01-01`], 
                          big.mark = " ", 
                          scientific = FALSE),
            hoverinfo = "name+text+y")%>%
  add_trace(x = ~-`M_2020-01-01`, name = 'Men 2020',
            marker = list(color = 'white',
                          line = list(color = 'royalblue',
                                      width = 3)),
            text = format(app_bar[,abs(`M_2020-01-01`)],
                          big.mark = " ",
                          scientific = FALSE),
            hoverinfo = "name+text+y")%>%
  add_trace(x = ~-`M_2010-01-01`, name = 'Men 2010',
            marker = list(color = 'darkblue',
                          line = list(color = 'darkblue',
                                      width = 3)),
            text = format(app_bar[,abs(`M_2010-01-01`)],
                          big.mark = " ",
                          scientific = FALSE),
            hoverinfo = "name+text+y")%>%
  layout(barmode = 'overlay',
         xaxis = list(range = c(-350000, 100000),
                      exponentformat = "none",
                      separatethousands = TRUE, 
                      tickvals = seq(-350000, 100000, 50000), 
                      ticktext = format(abs(seq(-350000, 100000, 50000)), 
                                        big.mark=" ", 
                                        scientific = FALSE), 
                      title = "Number of persons"),
         yaxis = list(categoryorder = "array", 
                      categoryarray = app_bar[,rev(age)], 
                      title ="Age",exponentformat="none",separatethoudands = TRUE),
         title=tit3)

Non-EU citizens found to be illegally present in the EU-27, by sex and age

Table

Top 20 countries of citizenship of non-EU citizens found to be illegally present in the EU-27

app_tab <- app_tot[!(citizen %in% c("TOTAL","EUR_C_E_OTH","AME","AFR","ASI","EUR","OCE")) & age == "TOTAL" & sex == "T" & time <= "2020-01-01" & time >= "2015-01-01",sum(values,na.rm = T),.(citizen,time) ]

top20 <- app_tab[,sum(V1,na.rm=T),citizen]
setnames(top20, "V1","Total")
top20 <- top20[order(-Total)]
top20 <- top20[1:20,]

app_tab[,time:=substring(time,1,4)]
app_tab <-  dcast(app_tab, citizen~time, value.var = "V1")

app_tab <- left_join(top20, app_tab)

datatable(app_tab[1:20], rownames = FALSE, filter="top", options = list(pageLength = 10, scrollX=T))

Non-EU citizens ordered to leave the EU-27

Table

Non-EU citizens ordered to leave the territory of an EU Member State, the United Kingdom or an EFTA country, 2015-2020

ord_tab <-  ord_tot[sex == "T" & citizen == "TOTAL" & age == "TOTAL"& time >= "2015-01-01" ,sum(values,na.rm=T),.(geo,time)]
ord_tab[,time:=substring(time,1,4)]
ord_tab <-  dcast(ord_tab, geo~time, value.var = "V1")
datatable(ord_tab, rownames = FALSE, filter="top", options = list(pageLength = 10, scrollX=T) )

Bar chart

Top 20 countries of citizenship of non-EU citizens ordered to leave the EU-27, 2020 and 2019

ord_tab <-  ord_tot[geo == "European Union - 27 countries (from 2020)" & sex == "T" & age == "TOTAL"& !(citizen %in% c("TOTAL","EUR_C_E_OTH","AME","AFR","ASI","EUR","OCE")) & time <= "2019-01-01" & time >= "2018-01-01",sum(values,na.rm = T),.(full_name,time)]
ord_tab[,time:=substring(time,1,4)]
top20 <- ord_tab[time == "2019",]
top20 <- top20[order(-V1),]
top20 <- top20[1:20, .(full_name)]

ord_tab <- left_join(top20,ord_tab)
ord_tab <-  dcast(ord_tab, full_name~time, value.var = "V1")
setnames(ord_tab, names(ord_tab), c("citizen","year_1","year"))
ord_tab <- ord_tab[order(-year)]
ord_tab[,citizen := factor(citizen,levels = ord_tab[,citizen])]

plot_ly(ord_tab, x = ~citizen, y = ~year_1, type = 'bar', name = '2019')%>% 
  add_trace(y = ~year, name = '2020')%>%
  layout(barmode = 'group',
         xaxis = list(title = "Citizenship"),
         yaxis = list(title ="Number of persons",exponentformat="none",separatethoudands = TRUE),
         hovermode='x unified')

Top 20 countries of citizenship of non-EU citizens ordered to leave the EU-27, 2020 and 2019


Returns of non-EU citizens

Overview

ret_tab <-  ret_tot[geo == "European Union - 27 countries (from 2020)" & sex == "T" & !(citizen %in% c("TOTAL","EUR_C_E_OTH","EUR_OTH","AME","AFR","ASI","EUR","OCE")) & age == "TOTAL" & indic_mg == "RET_THRD" & (time =="2019-01-01" | time == "2018-01-01"), sum(values, na.rm =T ),.(full_name,time)]
ret_tab[,time:=substring(time,1,4)]
top20 <- ret_tab[time == "2019",]
top20 <- top20[order(-V1),]
top20 <- top20[1:20, .(full_name)]

ret_tab <- left_join(top20,ret_tab)
ret_tab <-  dcast(ret_tab, full_name~time, value.var = "V1")
setnames(ret_tab, names(ret_tab), c("citizen","year_1","year"))
ret_tab <- ret_tab[order(-year)]
ret_tab[,citizen:=factor(citizen, levels = ret_tab[,citizen])]

plot_ly(ret_tab, x = ~citizen, y = ~year_1, type = 'bar', name = '2018')%>% 
  add_trace(y = ~year, name = '2019')%>%
  layout(barmode = 'group',
         xaxis = list(title = "Citizenship"),
         yaxis = list(title ="Number of persons",exponentformat="none",separatethoudands = TRUE),
         hovermode='x unified')

Top 20 countries of citizenship of non-EU citizens returned outside the EU-27, 2018 and 2019

Types of returns and assistance received

ret_tab2 <-  ret_type[!(citizen %in% c("TOTAL","EUR_C_E_OTH","EUR_C_E_OTH","AME","AFR","ASI","EUR","OCE")) & (time =="2020-01-01"), sum(values, na.rm =T ),.(geo,indic_mg)]

ret_tab2 <-  dcast(ret_tab2, geo~indic_mg, value.var = "V1")
ret_tab2 <- ret_tab2[,lapply(.SD, function(x) round(x/TOT_RET*100)), .SDcols=c("ENFORCE","OTH","VOLUNT"), by = geo]

plot_ly(ret_tab2, x = ~geo, y = ~ENFORCE, type = 'bar', name = 'Enforced return')%>% 
    add_trace(y = ~OTH, name = 'Other')%>%
  add_trace(y = ~VOLUNT, name = 'Voluntary return')%>%
    layout(barmode = 'stack',
           xaxis = list(title = ""),
           yaxis = list(title ="%",exponentformat="none",separatethoudands = TRUE),
           hovermode='x unified')

Non-EU citizens returned outside the EU-27 or EFTA countries, by type of return (2020)


ret_tab3 <-  ret_ass[!(citizen %in% c("TOTAL","EUR_C_E_OTH","EUR_C_E_OTH","AME","AFR","ASI","EUR","OCE")) & (time =="2019-01-01"), sum(values, na.rm =T ),.(geo,indic_mg)]

ret_tab3 <-  dcast(ret_tab3, geo~indic_mg, value.var = "V1")
ret_tab3 <- ret_tab3[,lapply(.SD, function(x) round(x/TOT_RET*100)), .SDcols=c("ASSIST","N_ASSIST","UNK"), by = geo]

plot_ly(ret_tab3, x = ~geo, y = ~ASSIST, type = 'bar', name = 'Assisted return')%>% 
    add_trace(y = ~N_ASSIST, name = 'Non assisted return')%>%
  add_trace(y = ~UNK, name = 'Unkown')%>%
    layout(barmode = 'stack',
           xaxis = list(title = ""),
           yaxis = list(title ="%",exponentformat="none",separatethoudands = TRUE),
           hovermode='x unified')

Non-EU citizens who left the EU-27 or EFTA countries, by type of assistance received, 2020


Non-EU citizens refused entry into the EU-27

Overview

ref_pie <- copy(ref_tot[geo !="European Union - 27 countries (from 2020)" & time == "2020-01-01" & reason == "TOTAL" & indic_mg == "TOT_REF" ,.(geo,values) ])
ref_pie[!(geo %in% c("Hungary","Poland","Croatia","Romania","Bulgaria")), geo := "Other"]

colors_ <- c('rgb(255,153,51)', 'rgb(255,128,0)', 'rgb(255,178,102)', 'rgb(255,204,153)', 'rgb(0,102,204)','rgb(102,178,255)')
plot_ly( data = ref_pie, labels = ~geo, values = ~values, type = "pie", textinfo = "label+percent", insidetextorientation = "radial" ,
         marker=list(colors=colors_)) 

Share of non-EU citizens refused entry into the EU-27, 2020

Bar charts

ref_tab <-  ref_tot[!(geo %in% c("European Union - 27 countries (from 2020)","European Union - 27 countries (from 2020)")) &reason == "TOTAL" & !(citizen %in% c("TOTAL","EUR_OTH","AME","AFR","ASI","EUR","OCE")) & time == "2019-01-01", sum(values, na.rm = T), .(full_name, indic_mg)]

top20 <- ref_tab[indic_mg=="TOT_REF"]
top20 <- top20[order(-V1)]
top20 <- top20[1:20,.(full_name)]

ref_tab <- left_join(top20, ref_tab)
ref_tab <-  dcast(ref_tab, full_name~indic_mg, value.var = "V1")
ref_tab <- ref_tab[order(-TOT_REF)]
ref_tab[,full_name:=factor(full_name, levels = ref_tab[,full_name])]

plot_ly(ref_tab, x = ~full_name, y = ~REF_AIR, type = 'bar', name = 'Air')%>% 
    add_trace(y = ~REF_LAND, name = 'Land')%>%
  add_trace(y = ~REF_SEA, name = 'Sea')%>%
    layout(barmode = 'stack',
           xaxis = list(title = ""),
           yaxis = list(title ="%",exponentformat="none",separatethoudands = TRUE),
           hovermode='x unified')

Top 20 countries of citizenship of non-EU citizens refused entry into the EU-27, by type of border, 2019


ref_tab2 <-  ref_tot[!(geo %in% c("European Union - 27 countries (from 2020)","European Union - 27 countries (from 2020)")) &reason != "TOTAL" &indic_mg == "TOT_REF" & !(citizen %in% c("TOTAL","EUR_OTH","AME","AFR","ASI","EUR","OCE")) & time == "2019-01-01", sum(values, na.rm = T), .(reason)]

ref_tab2[reason == "ALERT",reason := "An alert has been issued"]
ref_tab2[reason == "DOC_F",reason := "False travel document"]
ref_tab2[reason == "DOC_NVAL",reason := "No valid travel document"]
ref_tab2[reason == "FV_FRP",reason := "False Visa or Residence permit"]
ref_tab2[reason == "NRP_NVV",reason := "Non valid visa or Residence permit"]
ref_tab2[reason == "NSUBS",reason := "No sufficient means of subsistence"]
ref_tab2[reason == "PB_THRT",reason := "Person considered to be a public threat"]
ref_tab2[reason == "PERM_3",reason := "Person already stayed 3 months in a 6-months period"]
ref_tab2[reason == "STAY_NJ",reason := "Purpose and conditions of stay not justified"]
ref_tab2 <- ref_tab2[order(-V1)]
ref_tab2[,reason:=factor(reason, levels = ref_tab2[,reason])]

plot_ly(ref_tab2, x = ~reason, y = ~V1, type = 'bar', name = 'Reason')%>% 
    layout(barmode = 'stack',
           xaxis = list(title = ""),
           yaxis = list(title ="Number"),
           hovermode='x unified')

Non-EU citizens refused entry into the EU-27, by grounds of entry refusal, 2019


  1. EU aggregates are computed as the sum of the national statistics available for the EU Member States. It is possible that the statistics for the EU involve some double counting of individuals if they are found to be illegally present in more than one Member State.↩︎

  2. Statistics on the enforcement of immigration legislation refer to the concept of external borders for all EU Member States and EFTA countries, even if some of these are not in the Schengen area. The external borders of the Schengen area do not coincide with the external borders of the EU Member States due to: opt-outs for Ireland from the Schengen area; Bulgaria, Croatia, Cyprus and Romania are not yet members of the Schengen area; Iceland, Liechtenstein, Norway and Switzerland are part of the Schengen area but are not members of the EU.↩︎