diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7c794aa --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.Rproj.user +.Rhistory +.Rdata +.httr-oauth +.DS_Store +.quarto diff --git a/economic-indicators.Rmd b/economic-indicators.Rmd new file mode 100644 index 0000000..df328fc --- /dev/null +++ b/economic-indicators.Rmd @@ -0,0 +1,525 @@ +--- +Title: Reproduce economic indicators from 'The Economist' +Date: \today() +category: Economic Indicators +tags: DBnomics, database, R, +slug: economic-indicators +authors: EconMaett +summary: We reproduce part of the economic indicators table from 'The Economist' using DBnomics. +download: https://git.nomics.world/macro/indicators +output: html_document +--- + +```{r pre, message=FALSE, warning=FALSE, echo=FALSE} +# if (!"pacman" %in% install.packages()[, "Package"]) { install.packages("pacman", repos = "http://cran.r-project.org") } +pkgs <- c("tidyverse", "rdbnomics", "zoo", "knitr", "kableExtra", "formattable") +# pak::pkg_install(pkg = pkgs, ask = FALSE) +pacman::p_load(tidyverse, rdbnomics, zoo, knitr, kableExtra, formattable) + +opts_chunk$set(fig.align = "center", message = FALSE, warning = FALSE) + +current_year <- year(Sys.Date()) +last_year <- current_year - 1 +before_last_year <- current_year - 2 + +country_list <- c( + "United States", "China", "Japan", "Britain", "Canada", + "Euro area", "Austria", "Belgium", "France", "Germany", "Greece", + "Italy", "Netherlands", "Spain", "Czech Republic", + "Denmark", "Norway", "Poland", "Russia", "Sweden", "Switzerland", "Turkey", + "Australia", "Hong Kong", "India", "Indonesia", "Malaysia", + "Pakistan", "Philippines", "Singapore", "South Korea", "Taiwan", "Thailand", + "Argentina", "Brazil", "Chile", "Colombia", "Mexico", "Peru", + "Egypt", "Israel", "Saudi Arabia", "South Africa" +) +``` + + +```{r download, echo=FALSE} +gdp <- rdb( + provider_code = "OECD", + dataset_code = "MEI", + ids = ".NAEXKP01.GPSA+GYSA.Q" +) + +gdp_level_hk_ph_th_sa_sg <- rdb( + provider_code = "IMF", + dataset_code = "IFS", + mask = "Q.HK+PH+TH+SA+SG.NGDP_R_SA_XDC" + ) |> + rename(Country = `Reference Area`) |> + mutate( + Country = case_when(Country == "Hong Kong, China" ~ "Hong Kong", TRUE ~ Country) + ) + +gdp_qoq_hk_ph_th_sa_sg <- gdp_level_hk_ph_th_sa_sg |> + arrange(Country, period) |> + group_by(Country) |> + mutate( + value = (value / lag(value) - 1) * 100, + MEASURE = "GPSA" + ) + +gdp_yoy_hk_ph_th_sa_sg <- gdp_level_hk_ph_th_sa_sg |> + arrange(Country, period) |> + mutate(quarter = quarter(period)) |> + group_by(Country, quarter) |> + mutate(value = (value / lag(value) - 1) * 100, MEASURE = "GYSA") + +gdp_my <- rdb(ids = "BI/TABEL9_1/21.Q") |> + mutate(Country = "Malaysia", MEASURE = "GYSA") + +gdp_tw <- rdb(ids = "BI/TABEL9_1/17.Q") |> + mutate(Country = "Taiwan", MEASURE = "GYSA") + +gdp_eg_pk_pe <- rdb( + provider_code = "IMF", + dataset_code = "WEO:latest", + mask = "EGY+PAK+PER.NGDP_RPCH" + ) |> + rename(Country = `WEO Country`) |> + mutate(MEASURE = "GYSA") |> + filter(year(period) < current_year) + +gdp_level_ar <- rdb(ids = "Eurostat/naidq_10_gdp/Q.SCA.KP_I10.B1GQ.AR") |> + rename(Country = `Geopolitical entity (reporting)`) + +gdp_qoq_ar <- gdp_level_ar |> + arrange(period) |> + mutate(value = (value / lag(value) - 1) * 100, MEASURE = "GPSA") + +gdp_yoy_ar <- gdp_level_ar |> + arrange(period) |> + mutate(quarter = quarter(period)) |> + group_by(quarter) |> + mutate(value = (value / lag(value) - 1) * 100, MEASURE = "GYSA") + +gdp <- bind_rows( + gdp, + gdp_qoq_hk_ph_th_sa_sg, + gdp_yoy_hk_ph_th_sa_sg, + gdp_my, + gdp_tw, + gdp_eg_pk_pe, + gdp_qoq_ar, + gdp_yoy_ar +) + +indprod <- rdb( + provider_code = "OECD", + dataset_code = "MEI", + ids = ".PRINTO01.GYSA.M" +) + +indprod_ch_au <- rdb( + provider_code = "OECD", + dataset_code = "MEI", + ids = "AUS+CHE.PRINTO01.GYSA.Q" + ) + +indprod_cn_eg_mx_my <- rdb( + provider_code = "IMF", + dataset_code = "IFS", + mask = "M.CN+EG+MX+MY.AIP_PC_CP_A_PT" + ) |> + rename(Country = `Reference Area`) + +indprod_id_pk_pe_ph_sg_za <- rdb( + provider_code = "IMF", + dataset_code = "IFS", + mask = "M.ID+PK+PE+PH+SG+ZH.AIPMA_PC_CP_A_PT" + ) |> + rename(Country = `Reference Area`) + +indprod_ar_hk_sa_th <- rdb( + provider_code = "IMF", + dataset_code = "IFS", + mask = "Q.AR+HK+SA+TH.AIPMA_PC_CP_A_PT" + ) |> + rename(Country = `Reference Area`) |> + mutate( + Country = case_when(Country == "Hong Kong, China" ~ "Hong Kong", TRUE ~ Country) + ) + +indprod <- bind_rows( + indprod, + indprod_ch_au, + indprod_cn_eg_mx_my, + indprod_id_pk_pe_ph_sg_za, + indprod_ar_hk_sa_th +) + +cpi <- rdb( + provider_code = "OECD", + dataset_code = "MEI", + ids = ".CPALTT01.GY.M" + ) + +cpi_au <- rdb( + provider_code = "OECD", + dataset_code = "MEI", + ids = "AUS.CPALTT01.GY.Q" + ) + +cpi_tw <- rdb(ids = "BI/TABEL9_2/17.Q") |> + mutate(Country = "Taiwan") + +cpi_other <- rdb( + provider_code = "IMF", + dataset_code = "IFS", + mask = "M.EG+HK+MY+PE+PH+PK+SG+TH.PCPI_PC_CP_A_PT" + ) |> + rename(Country = `Reference Area`) |> + mutate( + Country = case_when(Country == "Hong Kong, China" ~ "Hong Kong", TRUE ~ Country) + ) + +cpi <- bind_rows( + cpi, + cpi_au, + cpi_tw, + cpi_other +) + +unemp <- rdb( + provider_code = "OECD", + dataset_code = "MEI", + ids = ".LRHUTTTT.STSA.M" + ) + + +unemp_ch <- rdb( + provider_code = "OECD", + dataset_code = "MEI", + mask = "CHE.LMUNRRTT.STSA.M" +) + +unemp_br <- rdb( + provider_code = "OECD", + dataset_code = "MEI", + mask = "BRA.LRUNTTTT.STSA.M" +) + +unemp_za_ru <- rdb( + provider_code = "OECD", + dataset_code = "MEI", + mask = "ZAF+RUS.LRUNTTTT.STSA.Q" +) + +unemp_cn <- rdb(ids = "NBS/M_A0E01/A0E0101") |> + mutate(Country = "China") + +unemp_sa <- rdb(ids = "ILO/UNE_DEAP_SEX_AGE_RT/SAU.BA_627.AGE_AGGREGATE_TOTAL.SEX_T.A") |> + rename(Country = `Reference area`) |> + filter(year(period) < current_year) + +unemp_in <- rdb(ids = "ILO/UNE_2EAP_SEX_AGE_RT/IND.XA_1976.AGE_YTHADULT_YGE15.SEX_T.A") |> + rename(Country = `Reference area`) |> + filter(year(period) < current_year) + +unemp_id_pk <- rdb( + provider_code = "ILO", + dataset_code = "UNE_DEAP_SEX_AGE_EDU_RT", + mask = "IDN+PAK..AGE_AGGREGATE_TOTAL.EDU_AGGREGATE_TOTAL.SEX_T.Q" + ) |> + rename(Country = `Reference area`) + +unemp_other <- rdb( + provider_code = "ILO", + dataset_code = "UNE_DEA1_SEX_AGE_RT", + mask = "ARG+EGY+HKG+MYS+PER+PHL+SGP+THA+TWN..AGE_YTHADULT_YGE15.SEX_T.Q" + ) |> + rename(Country = `Reference area`) |> + mutate( + Country = case_when( + Country == "Hong Kong, China" ~ "Hong Kong", + Country == "Taiwan, China" ~ "Taiwan", + TRUE ~ Country + ) + ) + +unemp <- bind_rows( + unemp, + unemp_br, + unemp_za_ru, + unemp_ch, + unemp_cn, + unemp_sa, + unemp_in, + unemp_id_pk, + unemp_other +) + +forecast_gdp_cpi_ea <- rdb( + provider_code = "IMF", + dataset_code = "WEOAGG:latest", + mask = "163.NGDP_RPCH+PCPIPCH" +) + +forecast_gdp_cpi <- rdb( + provider_code = "IMF", + dataset_code = "WEO:latest", + mask = ".NGDP_RPCH+PCPIPCH" + ) |> + bind_rows(forecast_gdp_cpi_ea) |> + transmute( + Country = `WEO Country`, + var = `WEO Subject`, + value, + period + ) |> + mutate( + Country = str_trim(Country), + var = str_trim(var) + ) |> + mutate( + Country = case_when( + Country == "United Kingdom" ~ "Britain", + Country == "Hong Kong SAR" ~ "Hong Kong", + Country == "Korea" ~ "South Korea", + Country == "Taiwan Province of China" ~ "Taiwan", + TRUE ~ Country + ), + var = case_when( + var == "Gross domestic product, constant prices" ~ "GDP", + var == "Inflation, average consumer prices" ~ "CPI", + TRUE ~ var + ) + ) + +forecast_gdp_cpi <- left_join( + data.frame(Country = country_list), + forecast_gdp_cpi, + by = "Country" +) + +``` + + +```{r transform, echo=FALSE} +gdp_yoy_latest_period <- gdp |> + filter(MEASURE == "GYSA") |> + filter(!is.na(value)) |> + summarise(period = max(period)) + +gdp_yoy_latest <- gdp |> + filter(MEASURE == "GYSA") |> + inner_join(gdp_yoy_latest_period, by = join_by(period)) |> + mutate( + var = "GDP", + measure = "latest" + ) + +gdp_qoq_latest_period <- gdp |> + filter(MEASURE == "GPSA") |> + filter(!is.na(value)) |> + group_by(Country) |> + summarise(period = max(period)) + +gdp_qoq_latest <- gdp |> + filter(MEASURE == "GPSA") |> + inner_join(gdp_qoq_latest_period, by = join_by(Country, period)) |> + mutate( + var = "GDP", + measure = "quarter" + ) + +gdp_2024_2025 <- forecast_gdp_cpi |> + filter(var == "GDP" & (period == "2024-01-01" | period == "2025-01-01")) |> + mutate(measure = as.character(year(period))) + +indprod_latest_period <- indprod |> + filter(!is.na(value)) |> + group_by(Country) |> + summarise(period = max(period)) + +indprod_latest <- indprod |> + inner_join(indprod_latest_period, by = join_by(Country, period)) |> + mutate( + var = "indprod", + measure = "latest" + ) + +cpi_latest_period <- cpi |> + filter(!is.na(value)) |> + group_by(Country) |> + summarise(period = max(period)) + +cpi_latest <- cpi |> + inner_join(cpi_latest_period, by = join_by(Country, period)) |> + mutate( + var = "CPI", + measure = "latest" + ) + +cpi_2024 <- forecast_gdp_cpi |> + filter(var == "CPI" & period == "2024-01-01") |> + mutate(measure = as.character(year(period))) + +unemp_latest_period <- unemp |> + filter(!is.na(value)) |> + group_by(Country) |> + summarise(period = max(period)) + +unemp_latest <- unemp |> + inner_join(unemp_latest_period, by = join_by(Country, period)) |> + mutate( + var = "unemp", + measure = "latest" + ) +``` + + +```{r merge, echo=FALSE} +df_all <- bind_rows( + gdp_yoy_latest, + gdp_qoq_latest, + gdp_2024_2025, + indprod_latest, + cpi_latest, + cpi_2024, + unemp_latest + ) |> + mutate( + value = if_else( + condition = value >= 0, + true = paste0("+", sprintf("%.1f", round(value, 1))), + false = sprintf("%.1f", round(value, 1)) + ) + ) |> + unite(measure, c(var, measure)) + + +df_latest <- df_all |> + filter(measure %in% c("GDP_latest", "indprod_latest", "CPI_latest", "unemp_latest")) |> + mutate( + value = case_when( + `@frequency` == "quarterly" ~ paste(value, " Q", quarter(period), sep = ""), + `@frequency` == "monthly" ~ paste(value, " ", month(period, label = TRUE, abbr = TRUE, locale = "en_US.utf8"), sep = ""), + `@frequency` == "annual" ~ paste(value, " Year", sep = ""), + TRUE ~ value + ) + ) |> + mutate(value = text_spec( + if_else( + condition = year(period) == last_year, + true = paste0(value, footnote_marker_symbol(3)), + false = if_else( + condition = year(period) == before_last_year, + true = paste0(value, footnote_marker_symbol(4)), + false = value + ) + ), + link = paste( + "https://db.nomics.world", + provider_code, + dataset_code, + series_code, + sep = "/" + ), + color = "#333333", + escape = FALSE, + extra_css = "text-decoration:none" + ) + ) + +df_final <- df_all |> + filter(measure %in% c("GDP_quarter", "GDP_2024", "GDP_2025", "CPI_2024")) |> + bind_rows(df_latest) |> + mutate( + Country = case_when( + Country == "United Kingdom" ~ "Britain", + Country == "Euro area (20 countries)" ~ "Euro area", + Country == "China (People's Republic of)" ~ "China", + Country == "Korea" ~ "South Korea", + TRUE ~ Country + ) + ) |> + select(Country, value, measure) |> + spread(measure, value) |> + select(Country, GDP_latest, GDP_quarter, GDP_2024, GDP_2025, indprod_latest, CPI_latest, CPI_2024, unemp_latest) + + +df_final <- left_join( + x = data.frame(Country = country_list), + y = df_final, + by = "Country" +) +``` + + +```{r display, echo=FALSE} +names(df_final)[1] <- "" +names(df_final)[2] <- "latest" +names(df_final)[3] <- paste0("quarter", footnote_marker_symbol(1)) +names(df_final)[4] <- paste0("2024", footnote_marker_symbol(2)) +names(df_final)[5] <- paste0("2025", footnote_marker_symbol(2)) +names(df_final)[6] <- "latest" +names(df_final)[7] <- "latest" +names(df_final)[8] <- paste0("2024", footnote_marker_symbol(2)) +names(df_final)[9] <- "latest" + + +df_table <- df_final |> + knitr::kable( + format = "html", + row.names = FALSE, + escape = FALSE, + align = c("l", rep("c", 8)), + caption = "Economic data (% change on year ago)" + ) |> + kableExtra::kable_styling( + bootstrap_options = c("striped", "hover", "responsive"), + fixed_thead = TRUE, + font_size = 13 + ) |> + add_header_above( + header = c( + " " = 1, + "Gross domestic product" = 4, + "Industrial production " = 1, + "Consumer prices"= 2, + "Unemployment rate, %"=1 + ) + ) |> + column_spec(column = 1, bold = TRUE) |> + row_spec(row = seq(from = 1, to = nrow(df_final), by = 2), background = "#D5E4EB") |> + row_spec(row = c(5, 14, 22, 33, 39), extra_css = "border-bottom: 1.2px solid") |> + footnote( + general = "DBnomics (Eurostat, ILO, IMF, OECD and national sources). Click on the figures in the `latest` columns to see the full time series.", + general_title = "Source: ", + footnote_as_chunk = TRUE, + symbol = c( + "% change on previous quarter, annual rate ", + "IMF estimation/forecast", + paste0(last_year), + paste0(before_last_year) + ) + ) + +df_table +``` + +
+
+ +The aim of this blog post is to reproduce part of the economic indicators table from 'The Economist' using only free tools. We take data directly from DBnomics. The DBnomics API can be accessed through R with the rdbnomics package. All the following code is written in R, thanks to the [@Rct16] and the [@RStu16]. To update the table, just download the code here and re-run it. + +```{r pre, eval=FALSE} +``` + +# Download +```{r download, eval=FALSE} +``` + +# Transform +```{r transform, eval=FALSE} +``` + +# Merge +```{r merge, eval=FALSE} +``` + +# Display +```{r display, eval=FALSE} +``` diff --git a/economic-indicators.Rproj b/economic-indicators.Rproj new file mode 100644 index 0000000..8e3c2eb --- /dev/null +++ b/economic-indicators.Rproj @@ -0,0 +1,13 @@ +Version: 1.0 + +RestoreWorkspace: Default +SaveWorkspace: Default +AlwaysSaveHistory: Default + +EnableCodeIndexing: Yes +UseSpacesForTab: Yes +NumSpacesForTab: 2 +Encoding: UTF-8 + +RnwWeave: Sweave +LaTeX: pdfLaTeX diff --git a/economic-indicators.html b/economic-indicators.html new file mode 100644 index 0000000..5ac80ee --- /dev/null +++ b/economic-indicators.html @@ -0,0 +1,2578 @@ + + + + + + + + + + + + + +economic-indicators.knit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Economic data (% change on year ago) +
+ +
+Gross domestic product +
+
+
+Industrial production +
+
+
+Consumer prices +
+
+
+Unemployment rate, % +
+
+ +latest + +quarter* + +2024 + +2025 + +latest + +latest + +2024 + +latest +
+United States + ++3.1 +Q4 + ++0.8 + ++1.5 + ++1.8 + +-0.4 +Nov + ++3.4 +Dec + ++2.8 + ++3.7 +Jan +
+China + ++5.2 +Q4 + ++1.0 + ++4.2 + ++4.1 + ++10.7 +Nov§ + +-0.3 +Dec + ++1.7 + ++5.1 +Dec +
+Japan + +NA + +-0.7 + ++1.0 + ++0.7 + +-1.2 +Nov + +-0.5 +Jun + ++2.9 + ++2.4 +Dec +
+Britain + +NA + +-0.1 + ++0.6 + ++2.0 + +-0.1 +Nov + ++4.2 +Dec + ++3.7 + ++4.2 +Oct +
+Canada + ++1.0 +Q4 + ++0.3 + ++1.6 + ++2.4 + ++0.5 +Oct + ++3.4 +Dec + ++2.4 + ++5.8 +Dec +
+Euro area + ++0.1 +Q4 + ++0.0 + +NA + +NA + +-6.4 +Nov + ++2.9 +Dec + +NA + ++6.4 +Dec +
+Austria + +-1.3 +Q4 + ++0.2 + ++0.8 + ++1.7 + +-3.1 +Sep + ++5.6 +Dec + ++3.7 + ++5.6 +Dec +
+Belgium + ++1.6 +Q4 + ++0.4 + ++0.9 + ++1.2 + +-11.6 +Nov + ++1.4 +Dec + ++4.3 + ++5.7 +Dec +
+France + ++0.7 +Q4 + +-0.0 + ++1.3 + ++1.8 + ++0.6 +Nov + ++3.7 +Dec + ++2.5 + ++7.3 +Dec +
+Germany + +-0.2 +Q4 + +-0.3 + ++0.9 + ++2.0 + +-4.5 +Nov + ++3.7 +Dec + ++3.5 + ++3.1 +Dec +
+Greece + +NA + ++0.0 + ++2.0 + ++1.4 + ++3.0 +Nov + ++3.5 +Dec + ++2.8 + ++9.2 +Dec +
+Italy + ++0.5 +Q4 + ++0.2 + ++0.7 + ++1.0 + +-2.9 +Nov + ++0.6 +Dec + ++2.6 + ++7.2 +Dec +
+Netherlands + +NA + +-0.3 + ++1.1 + ++1.5 + +-9.7 +Nov + ++1.2 +Dec + ++4.2 + ++3.6 +Dec +
+Spain + ++2.0 +Q4 + ++0.6 + ++1.7 + ++2.1 + +-1.5 +Oct + ++3.1 +Dec + ++3.9 + ++11.7 +Dec +
+Czech Republic + +NA + +NA + ++2.3 + ++2.9 + +NA + +NA + ++4.6 + +NA +
+Denmark + +NA + +-0.7 + ++1.4 + ++1.2 + ++14.9 +Nov + ++0.7 +Dec + ++2.8 + ++5.0 +Dec +
+Norway + +NA + +-0.5 + ++1.5 + ++1.2 + +-5.6 +Nov + ++4.8 +Dec + ++3.7 + ++3.5 +Dec +
+Poland + +NA + ++1.5 + ++2.3 + ++3.4 + +-0.5 +Dec + ++6.2 +Dec + ++6.4 + ++2.7 +Dec +
+Russia + +NA + +-0.8 + ++1.1 + ++0.9 + ++5.6 +Dec + ++16.7 +Mar§ + ++6.3 + ++4.3 +Q4 +
+Sweden + ++0.0 +Q4 + ++0.1 + ++0.6 + ++2.4 + ++3.5 +Nov + ++4.4 +Dec + ++3.6 + ++8.2 +Dec +
+Switzerland + +NA + ++0.3 + ++1.8 + ++1.2 + ++2.3 +Sep + ++1.7 +Dec + ++2.0 + ++2.1 +Oct +
+Turkey + +NA + +NA + +NA + +NA + +NA + +NA + +NA + +NA +
+Australia + +NA + ++0.2 + ++1.2 + ++2.0 + +-0.2 +Q3 + ++4.1 +Nov + ++4.0 + ++3.9 +Dec +
+Hong Kong + +NA + ++0.1 + ++2.9 + ++2.9 + +-0.1 +Q4§ + ++1.6 +Mar + ++2.3 + ++6.5 +Q3 +
+India + +NA + ++1.7 + ++6.3 + ++6.3 + ++5.6 +Jan + ++4.9 +Dec + ++4.6 + ++4.7 +Year +
+Indonesia + +NA + ++0.8 + ++5.0 + ++5.0 + +-3.7 +Apr + ++2.6 +Dec + ++2.5 + ++2.5 +Q1 +
+Malaysia + +NA + +NA + ++4.3 + ++4.4 + ++3.1 +Mar + ++1.8 +Oct + ++2.7 + ++4.6 +Q3 +
+Pakistan + +NA + +NA + ++2.5 + ++3.6 + +-1.2 +Oct + ++28.3 +Jan + ++23.6 + ++6.5 +Q2 +
+Philippines + +NA + ++3.3 + ++5.9 + ++6.1 + ++4.8 +Dec§ + ++6.1 +Sep + ++3.2 + ++2.4 +Q4§ +
+Singapore + +NA + ++1.4 + ++2.1 + ++2.5 + +-10.9 +May + ++3.7 +Dec + ++3.5 + ++3.9 +Q2 +
+South Korea + ++2.2 +Q4 + ++0.6 + ++2.2 + ++2.3 + ++5.3 +Nov + ++3.2 +Dec + ++2.3 + ++3.3 +Dec +
+Taiwan + +NA + +NA + ++3.0 + ++2.8 + +NA + ++0.7 +Q4 + ++1.5 + ++3.7 +Q1 +
+Thailand + +NA + ++0.8 + ++3.2 + ++3.1 + +-6.6 +Q1 + ++2.8 +Mar + ++1.6 + ++0.9 +Q4§ +
+Argentina + +NA + ++2.7 + ++2.8 + ++3.2 + ++4.4 +Q3 + ++211.4 +Dec + ++93.7 + ++6.3 +Q2 +
+Brazil + +NA + ++0.1 + ++1.5 + ++1.9 + ++1.2 +Nov + ++4.6 +Dec + ++4.5 + ++8.0 +Nov +
+Chile + +NA + ++0.3 + ++1.6 + ++2.3 + ++0.9 +Oct + ++3.9 +Dec + ++3.6 + ++9.0 +Oct +
+Colombia + +NA + ++0.2 + ++2.0 + ++2.9 + +-6.8 +Nov + ++9.3 +Dec + ++5.2 + ++10.8 +Dec +
+Mexico + ++2.4 +Q4 + ++0.1 + ++2.1 + ++1.5 + ++0.7 +Oct + ++4.7 +Dec + ++3.8 + ++2.8 +Dec +
+Peru + +NA + +NA + ++2.7 + ++3.1 + ++20.3 +Apr + ++3.4 +Dec + ++2.9 + ++3.6 +Q4§ +
+Egypt + +NA + +NA + ++3.6 + ++5.0 + ++6.2 +Mar + ++33.6 +Dec + ++32.2 + ++7.3 +Q4§ +
+Israel + +NA + ++0.7 + ++3.0 + ++3.3 + +-3.7 +Nov + ++2.9 +Dec + ++3.0 + ++2.8 +Nov +
+Saudi Arabia + +-4.4 +Q4 + ++0.4 + ++4.0 + ++4.2 + ++1.6 +Q3 + ++1.5 +Dec + ++2.2 + ++5.6 +Year§ +
+South Africa + +NA + +-0.2 + ++1.8 + ++1.6 + +NA + ++5.2 +Dec + ++4.8 + ++31.8 +Q3 +
+Source: DBnomics +(Eurostat, ILO, IMF, OECD and national sources). Click on the figures in +the latest columns to see the full time series. +
+* % change on previous quarter, annual rate IMF +estimation/forecast 2023 § 2022 +
+



+

The aim of this blog post is to reproduce part of the economic +indicators table from +‘The +Economist’ using only free tools. We take data directly from +DBnomics. The +DBnomics API can be accessed through R with the +rdbnomics +package. All the following code is written in R, thanks to the [@Rct16] and the [@RStu16]. To update the table, just download +the code +here +and re-run it.

+
# if (!"pacman" %in% install.packages()[, "Package"]) { install.packages("pacman", repos = "http://cran.r-project.org") }
+pkgs <- c("tidyverse", "rdbnomics", "zoo", "knitr", "kableExtra", "formattable")
+# pak::pkg_install(pkg = pkgs, ask = FALSE)
+pacman::p_load(tidyverse, rdbnomics, zoo, knitr, kableExtra, formattable)
+
+opts_chunk$set(fig.align = "center", message = FALSE, warning = FALSE)
+
+current_year     <- year(Sys.Date())
+last_year        <- current_year - 1
+before_last_year <- current_year - 2
+
+country_list <- c(
+  "United States", "China", "Japan", "Britain", "Canada", 
+  "Euro area", "Austria", "Belgium", "France", "Germany", "Greece", 
+  "Italy", "Netherlands", "Spain", "Czech Republic", 
+  "Denmark", "Norway", "Poland", "Russia", "Sweden", "Switzerland", "Turkey", 
+  "Australia", "Hong Kong", "India", "Indonesia", "Malaysia",
+  "Pakistan", "Philippines", "Singapore", "South Korea", "Taiwan", "Thailand", 
+  "Argentina", "Brazil", "Chile", "Colombia", "Mexico", "Peru",
+  "Egypt", "Israel", "Saudi Arabia", "South Africa"
+)
+
+

Download

+
gdp <- rdb(
+  provider_code = "OECD", 
+  dataset_code  = "MEI", 
+  ids = ".NAEXKP01.GPSA+GYSA.Q"
+)
+
+gdp_level_hk_ph_th_sa_sg <- rdb(
+  provider_code = "IMF",
+  dataset_code  = "IFS",
+  mask = "Q.HK+PH+TH+SA+SG.NGDP_R_SA_XDC"
+  ) |> 
+  rename(Country = `Reference Area`) |> 
+  mutate(
+    Country = case_when(Country == "Hong Kong, China" ~ "Hong Kong", TRUE ~ Country)
+  )
+
+gdp_qoq_hk_ph_th_sa_sg <- gdp_level_hk_ph_th_sa_sg |> 
+  arrange(Country, period) |> 
+  group_by(Country) |> 
+  mutate(
+    value = (value / lag(value) - 1) * 100,
+    MEASURE = "GPSA"
+  )
+
+gdp_yoy_hk_ph_th_sa_sg <- gdp_level_hk_ph_th_sa_sg |> 
+  arrange(Country, period) |> 
+  mutate(quarter = quarter(period)) |> 
+  group_by(Country, quarter) |> 
+  mutate(value = (value / lag(value) - 1) * 100, MEASURE = "GYSA")
+
+gdp_my <- rdb(ids = "BI/TABEL9_1/21.Q") |> 
+  mutate(Country = "Malaysia", MEASURE = "GYSA")
+
+gdp_tw <- rdb(ids = "BI/TABEL9_1/17.Q") |> 
+  mutate(Country = "Taiwan", MEASURE = "GYSA")
+
+gdp_eg_pk_pe <- rdb(
+  provider_code = "IMF", 
+  dataset_code  = "WEO:latest", 
+  mask = "EGY+PAK+PER.NGDP_RPCH"
+  ) |> 
+  rename(Country = `WEO Country`) |> 
+  mutate(MEASURE = "GYSA") |> 
+  filter(year(period) < current_year)
+
+gdp_level_ar <- rdb(ids = "Eurostat/naidq_10_gdp/Q.SCA.KP_I10.B1GQ.AR") |> 
+  rename(Country = `Geopolitical entity (reporting)`)
+
+gdp_qoq_ar <- gdp_level_ar |> 
+  arrange(period) |> 
+  mutate(value = (value / lag(value) - 1) * 100, MEASURE = "GPSA")
+
+gdp_yoy_ar <- gdp_level_ar |> 
+  arrange(period) |> 
+  mutate(quarter = quarter(period)) |> 
+  group_by(quarter) |> 
+  mutate(value = (value / lag(value) - 1) * 100, MEASURE = "GYSA")
+
+gdp <- bind_rows(
+  gdp,
+  gdp_qoq_hk_ph_th_sa_sg,
+  gdp_yoy_hk_ph_th_sa_sg,
+  gdp_my,
+  gdp_tw,
+  gdp_eg_pk_pe,
+  gdp_qoq_ar,
+  gdp_yoy_ar
+)
+
+indprod <- rdb(
+  provider_code = "OECD",
+  dataset_code  = "MEI",
+  ids = ".PRINTO01.GYSA.M"
+)
+
+indprod_ch_au <- rdb(
+  provider_code = "OECD",
+  dataset_code  = "MEI",
+  ids = "AUS+CHE.PRINTO01.GYSA.Q"
+  )
+
+indprod_cn_eg_mx_my <- rdb(
+  provider_code = "IMF",
+  dataset_code  = "IFS",
+  mask = "M.CN+EG+MX+MY.AIP_PC_CP_A_PT"
+  ) |> 
+  rename(Country = `Reference Area`)
+
+indprod_id_pk_pe_ph_sg_za <- rdb(
+  provider_code = "IMF",
+  dataset_code  = "IFS",
+  mask = "M.ID+PK+PE+PH+SG+ZH.AIPMA_PC_CP_A_PT"
+  ) |> 
+  rename(Country = `Reference Area`)
+
+indprod_ar_hk_sa_th <- rdb(
+  provider_code = "IMF",
+  dataset_code  = "IFS",
+  mask = "Q.AR+HK+SA+TH.AIPMA_PC_CP_A_PT"
+  ) |> 
+  rename(Country = `Reference Area`) |> 
+  mutate(
+    Country = case_when(Country == "Hong Kong, China" ~ "Hong Kong", TRUE ~ Country)
+  )
+
+indprod <- bind_rows(
+  indprod,
+  indprod_ch_au,
+  indprod_cn_eg_mx_my,
+  indprod_id_pk_pe_ph_sg_za,
+  indprod_ar_hk_sa_th
+)
+
+cpi <- rdb(
+  provider_code = "OECD",
+  dataset_code  = "MEI",
+  ids = ".CPALTT01.GY.M"
+  )
+
+cpi_au <- rdb(
+  provider_code = "OECD",
+  dataset_code  = "MEI",
+  ids = "AUS.CPALTT01.GY.Q"
+  )
+
+cpi_tw <- rdb(ids = "BI/TABEL9_2/17.Q") |> 
+  mutate(Country = "Taiwan")
+
+cpi_other <- rdb(
+  provider_code = "IMF",
+  dataset_code  = "IFS",
+  mask = "M.EG+HK+MY+PE+PH+PK+SG+TH.PCPI_PC_CP_A_PT"
+  ) |> 
+  rename(Country = `Reference Area`) |> 
+  mutate(
+    Country = case_when(Country == "Hong Kong, China" ~ "Hong Kong", TRUE ~ Country)
+  )
+
+cpi <- bind_rows(
+  cpi,
+  cpi_au,
+  cpi_tw,
+  cpi_other
+)
+
+unemp <- rdb(
+  provider_code = "OECD",
+  dataset_code  = "MEI",
+  ids = ".LRHUTTTT.STSA.M"
+  )
+  
+
+unemp_ch <- rdb(
+  provider_code = "OECD",
+  dataset_code  = "MEI",
+  mask = "CHE.LMUNRRTT.STSA.M"
+)
+
+unemp_br <- rdb(
+  provider_code = "OECD",
+  dataset_code  = "MEI",
+  mask = "BRA.LRUNTTTT.STSA.M"
+)
+
+unemp_za_ru <- rdb(
+  provider_code = "OECD",
+  dataset_code  = "MEI",
+  mask = "ZAF+RUS.LRUNTTTT.STSA.Q"
+)
+
+unemp_cn <- rdb(ids = "NBS/M_A0E01/A0E0101") |> 
+  mutate(Country = "China")
+
+unemp_sa <- rdb(ids = "ILO/UNE_DEAP_SEX_AGE_RT/SAU.BA_627.AGE_AGGREGATE_TOTAL.SEX_T.A") |> 
+  rename(Country = `Reference area`) |> 
+  filter(year(period) < current_year)
+
+unemp_in <- rdb(ids = "ILO/UNE_2EAP_SEX_AGE_RT/IND.XA_1976.AGE_YTHADULT_YGE15.SEX_T.A") |> 
+  rename(Country = `Reference area`) |> 
+  filter(year(period) < current_year)
+
+unemp_id_pk <- rdb(
+  provider_code = "ILO",
+  dataset_code  = "UNE_DEAP_SEX_AGE_EDU_RT",
+  mask = "IDN+PAK..AGE_AGGREGATE_TOTAL.EDU_AGGREGATE_TOTAL.SEX_T.Q"
+  ) |> 
+  rename(Country = `Reference area`)
+
+unemp_other <- rdb(
+  provider_code = "ILO",
+  dataset_code  = "UNE_DEA1_SEX_AGE_RT",
+  mask = "ARG+EGY+HKG+MYS+PER+PHL+SGP+THA+TWN..AGE_YTHADULT_YGE15.SEX_T.Q"
+  ) |> 
+  rename(Country = `Reference area`) |> 
+  mutate(
+    Country = case_when(
+      Country == "Hong Kong, China" ~ "Hong Kong", 
+      Country == "Taiwan, China" ~ "Taiwan",
+      TRUE ~ Country
+      )
+  )
+
+unemp <- bind_rows(
+  unemp,
+  unemp_br,
+  unemp_za_ru,
+  unemp_ch,
+  unemp_cn,
+  unemp_sa,
+  unemp_in,
+  unemp_id_pk,
+  unemp_other
+)
+
+forecast_gdp_cpi_ea <- rdb(
+  provider_code = "IMF",
+  dataset_code  = "WEOAGG:latest",
+  mask = "163.NGDP_RPCH+PCPIPCH"
+)
+
+forecast_gdp_cpi <- rdb(
+  provider_code = "IMF",
+  dataset_code  = "WEO:latest",
+  mask = ".NGDP_RPCH+PCPIPCH"
+  ) |> 
+  bind_rows(forecast_gdp_cpi_ea) |> 
+  transmute(
+    Country = `WEO Country`,
+    var = `WEO Subject`,
+    value,
+    period
+    ) |> 
+  mutate(
+    Country = str_trim(Country),
+    var = str_trim(var)
+  ) |> 
+  mutate(
+    Country = case_when(
+      Country == "United Kingdom" ~ "Britain",
+      Country == "Hong Kong SAR" ~ "Hong Kong",
+      Country == "Korea" ~ "South Korea",
+      Country == "Taiwan Province of China" ~ "Taiwan",
+      TRUE ~ Country
+    ),
+    var = case_when(
+      var == "Gross domestic product, constant prices" ~ "GDP",
+      var == "Inflation, average consumer prices" ~ "CPI",
+      TRUE ~ var
+    )
+  )
+
+forecast_gdp_cpi <- left_join(
+  data.frame(Country = country_list),
+  forecast_gdp_cpi, 
+  by = "Country"
+)
+
+
+

Transform

+
gdp_yoy_latest_period <- gdp |> 
+  filter(MEASURE == "GYSA") |> 
+  filter(!is.na(value)) |> 
+  summarise(period = max(period))
+
+gdp_yoy_latest <- gdp |> 
+  filter(MEASURE == "GYSA") |> 
+  inner_join(gdp_yoy_latest_period, by = join_by(period)) |> 
+  mutate(
+    var = "GDP",
+    measure = "latest"
+  )
+
+gdp_qoq_latest_period <- gdp |> 
+  filter(MEASURE == "GPSA") |> 
+  filter(!is.na(value)) |> 
+  group_by(Country) |> 
+  summarise(period = max(period))
+
+gdp_qoq_latest <- gdp |> 
+  filter(MEASURE == "GPSA") |> 
+  inner_join(gdp_qoq_latest_period, by = join_by(Country, period)) |> 
+  mutate(
+    var = "GDP",
+    measure = "quarter"
+  )
+
+gdp_2024_2025 <- forecast_gdp_cpi |> 
+  filter(var == "GDP" & (period == "2024-01-01" | period == "2025-01-01")) |> 
+  mutate(measure = as.character(year(period)))
+
+indprod_latest_period <- indprod |> 
+  filter(!is.na(value)) |> 
+  group_by(Country) |> 
+  summarise(period = max(period))
+
+indprod_latest <- indprod |> 
+  inner_join(indprod_latest_period, by = join_by(Country, period)) |> 
+  mutate(
+    var = "indprod",
+    measure = "latest"
+  )
+
+cpi_latest_period <- cpi |> 
+  filter(!is.na(value)) |> 
+  group_by(Country) |> 
+  summarise(period = max(period))
+
+cpi_latest <- cpi |> 
+  inner_join(cpi_latest_period, by = join_by(Country, period)) |> 
+  mutate(
+    var = "CPI",
+    measure = "latest"
+  )
+
+cpi_2024 <- forecast_gdp_cpi |> 
+  filter(var == "CPI" & period == "2024-01-01") |> 
+  mutate(measure = as.character(year(period)))
+
+unemp_latest_period <- unemp |> 
+  filter(!is.na(value)) |> 
+  group_by(Country) |> 
+  summarise(period = max(period))
+
+unemp_latest <- unemp |> 
+  inner_join(unemp_latest_period, by = join_by(Country, period)) |> 
+  mutate(
+    var = "unemp",
+    measure = "latest"
+  )
+
+
+

Merge

+
df_all <- bind_rows(
+  gdp_yoy_latest,
+  gdp_qoq_latest,
+  gdp_2024_2025,
+  indprod_latest,
+  cpi_latest,
+  cpi_2024,
+  unemp_latest
+  ) |> 
+  mutate(
+    value = if_else(
+      condition = value >= 0, 
+      true  = paste0("+", sprintf("%.1f", round(value, 1))), 
+      false = sprintf("%.1f", round(value, 1))
+        )
+    ) |> 
+  unite(measure, c(var, measure))
+
+
+df_latest <- df_all |> 
+  filter(measure %in% c("GDP_latest", "indprod_latest", "CPI_latest", "unemp_latest")) |> 
+  mutate(
+    value = case_when(
+      `@frequency` == "quarterly" ~ paste(value, " Q", quarter(period), sep = ""),
+      `@frequency` == "monthly" ~ paste(value, " ", month(period, label = TRUE, abbr = TRUE, locale = "en_US.utf8"), sep = ""),
+      `@frequency` == "annual" ~ paste(value, " Year", sep = ""),
+      TRUE ~ value
+      )
+    ) |> 
+  mutate(value = text_spec(
+    if_else(
+      condition = year(period) == last_year, 
+      true  = paste0(value, footnote_marker_symbol(3)),
+      false = if_else(
+        condition = year(period) == before_last_year, 
+        true  = paste0(value, footnote_marker_symbol(4)), 
+        false = value
+        )
+      ),
+    link = paste(
+      "https://db.nomics.world", 
+      provider_code, 
+      dataset_code, 
+      series_code, 
+      sep = "/"
+      ), 
+    color = "#333333",
+    escape = FALSE, 
+    extra_css = "text-decoration:none"
+    )
+  )
+
+df_final <- df_all |> 
+  filter(measure %in% c("GDP_quarter", "GDP_2024", "GDP_2025", "CPI_2024")) |> 
+  bind_rows(df_latest) |> 
+  mutate(
+    Country = case_when(
+      Country == "United Kingdom" ~ "Britain",
+      Country == "Euro area (20 countries)" ~ "Euro area",
+      Country == "China (People's Republic of)" ~ "China",
+      Country == "Korea" ~ "South Korea",
+      TRUE ~ Country
+    )
+  ) |> 
+  select(Country, value, measure) |> 
+  spread(measure, value) |> 
+  select(Country, GDP_latest, GDP_quarter, GDP_2024, GDP_2025, indprod_latest, CPI_latest, CPI_2024, unemp_latest)
+
+
+df_final <- left_join(
+  x = data.frame(Country = country_list), 
+  y = df_final, 
+  by = "Country"
+)
+
+
+

Display

+
names(df_final)[1] <- ""
+names(df_final)[2] <- "latest"
+names(df_final)[3] <- paste0("quarter", footnote_marker_symbol(1))
+names(df_final)[4] <- paste0("2024", footnote_marker_symbol(2))
+names(df_final)[5] <- paste0("2025", footnote_marker_symbol(2))
+names(df_final)[6] <- "latest"
+names(df_final)[7] <- "latest"
+names(df_final)[8] <- paste0("2024", footnote_marker_symbol(2))
+names(df_final)[9] <- "latest"
+
+
+df_table <- df_final |> 
+  knitr::kable(
+    format = "html",
+    row.names = FALSE, 
+    escape = FALSE, 
+    align = c("l", rep("c", 8)), 
+    caption = "Economic data (% change on year ago)"
+    ) |> 
+  kableExtra::kable_styling(
+    bootstrap_options = c("striped", "hover", "responsive"), 
+    fixed_thead = TRUE, 
+    font_size = 13
+    ) |>  
+  add_header_above(
+    header = c(
+      " " = 1, 
+      "Gross domestic product" = 4, 
+      "Industrial production  " = 1, 
+      "Consumer prices"= 2, 
+      "Unemployment rate, %"=1
+      )
+    ) |>  
+  column_spec(column = 1, bold = TRUE) |> 
+  row_spec(row = seq(from = 1, to = nrow(df_final), by = 2), background = "#D5E4EB") |>  
+  row_spec(row = c(5, 14, 22, 33, 39), extra_css = "border-bottom: 1.2px solid") |>  
+  footnote(
+    general = "DBnomics (Eurostat, ILO, IMF, OECD and national sources). Click on the figures in the `latest` columns to see the full time series.",
+    general_title = "Source: ",
+    footnote_as_chunk = TRUE,
+    symbol = c(
+      "% change on previous quarter, annual rate ", 
+      "IMF estimation/forecast", 
+      paste0(last_year), 
+      paste0(before_last_year)
+      )
+    )
+
+df_table
+
+ + + + +
+ + + + + + + + + + + + + + +