Panel charts with text annotation

Introduction

This tutorial will guide you through the process of creating fiscal data visualizations using R. We will use several R packages to import, clean, and visualize fiscal data from Excel files.

Fiscal panel charts Jamaica

In this section we will show how to make panel charts with text annotation–the narrative on top of a individual panel charts that you often see in IMF staff reports.

Panel charts of Jamaica’s public finances

This tutorial will guide you through the process of creating panel charts of the public finances of Jamaica. This chart has appeared in the 2022 Jamaica staff report.

Setup

First, we load the required R libraries and source the custom functions that we will use throughout this tutorial.

library(readxl)
library(dplyr)
library(tidyr)
library(ggpubr)
library(here)
library(gridExtra)
library(patchwork)
library(ragg)


source(here("utils/theme_and_colors_IMF.R"))
source(here("utils/Add_text_to_figure_panel.R"))

Reading the Data

The data for our charts is stored across multiple sheets within an Excel workbook. We’ll read each sheet into its own R object.

chart_1_fiscal <- read_excel(here("databases/SR charts v1.xlsx"), sheet = "Chart 1 Data")
chart_2_fiscal <- read_excel(here("databases/SR charts v1.xlsx"), sheet = "Chart 2 Data")
chart_3_fiscal <- read_excel(here("databases/SR charts v1.xlsx"), sheet = "Chart 3 Data")
chart_4_fiscal <- read_excel(here("databases/SR charts v1.xlsx"), sheet = "Chart 4 Data" )
chart_5_fiscal <- read_excel(here("databases/SR charts v1.xlsx"), sheet = "Chart 5 Data" )
chart_6_fiscal <- read_excel(here("databases/SR charts v1.xlsx"), sheet = "Chart 6 Data" )

Data Transformation

We need to transform our data into a long format that is suitable for plotting. We’ll define a function chart_long_fiscal for this purpose and apply it to our datasets.

chart_long_fiscal <- function(data){
  output <- data %>% 
    rename(label = Year) %>% 
    pivot_longer(-label,
                 names_to = "year",
                 values_to="value") %>% 
    mutate(year = as.numeric(year))
  return(output)
}
chart_1_fiscal_long <- chart_long_fiscal(chart_1_fiscal) 
chart_2_fiscal_long <- chart_long_fiscal(chart_2_fiscal)
chart_3_fiscal_long <- chart_long_fiscal(chart_3_fiscal)
chart_4_fiscal_long <- chart_long_fiscal(chart_4_fiscal)
chart_5_fiscal_long <- chart_long_fiscal(chart_5_fiscal)
chart_6_fiscal_long <- chart_long_fiscal(chart_6_fiscal)

rm(
  chart_1_fiscal, 
  chart_2_fiscal,
  chart_3_fiscal, 
  chart_4_fiscal, 
  chart_5_fiscal, 
  chart_6_fiscal 
)

Creating the Plots

With our data in the correct format, we can now create our visualizations using ggplot2.

fig_chart_1_fiscal <- 
  chart_1_fiscal_long %>%
  ggplot(aes(x = as.character(year),
             y=value)) +
  geom_bar(stat = "identity",
           fill= blue,
           position = position_dodge(0.73),
           color = "black",
           width = 0.42) +
  geom_hline(aes(yintercept = 0), 
             color = light_grey,
             linetype= "solid") +
  scale_x_discrete(expand = c(0.05,0))+
  scale_y_continuous(limits = c(-8,2), 
                     breaks = seq(-8,2,2),
                     expand = c(0,0)) +
  labs(title="Central Government Balance",
       subtitle = "(In percent of GDP)",
       # caption="Source: Bank of Jamaica (BOJ)",
       x="", y= "")+
  theme_imf_panel()



plot(fig_chart_1_fiscal)

fig_chart_2_fiscal <- 
  chart_2_fiscal_long %>%
  ggplot(aes(x = year,
             y= value,
             color= label,
             linetype = label))+
  geom_line(linewidth =1.5)+
  scale_x_continuous(limits =c(2010,2020), breaks = 2010:2020)+
  scale_y_continuous(limits = c(24,34), 
                     breaks = seq(24,34,2),
                     expand = c(0,0)) +
  labs(title="Central Government Revenues and Expenditures",
       subtitle = "(In percent of GDP)",
       # caption="Source: Bank of Jamaica (BOJ)",
       x="", y= "")+
  scale_color_manual(values = c(blue,green)) +
  scale_linetype_manual(values = c("solid","dashed")) +
  theme_imf_panel()+
  theme(legend.title = element_blank(),
        legend.position  = c(0.57,0.82),
        # legend.direction = "vertical",
        legend.background  = element_blank(),
        legend.key.height = unit(0.75, "cm"),
        legend.key.width = unit(1.5, "cm"),
        legend.spacing.x = unit(0.12,"cm"),
        legend.spacing.y = unit(0.20, "cm"))



plot(fig_chart_2_fiscal)

fig_chart_3_fiscal <- 
  chart_3_fiscal_long %>%
  filter(label != "Tax Revenue") %>% 
  ggplot(aes(x = as.character(year),
             y=value,
             fill = label)) +
  geom_bar(stat = "identity",
           position = "stack",
           color = "black",
           width = 0.42) +
   scale_x_discrete(expand = c(0.05,0))+
  scale_y_continuous(limits = c(0,30), 
                     breaks = seq(0,30,5),
                     expand = c(0,0)) +
  labs(title="Tax Revenue",
       subtitle = "(In percent of GDP)",
       # caption="Source: Bank of Jamaica (BOJ)",
       x="", y= "")+
  scale_fill_manual(values = c(green,blue)) +
  theme_imf_panel()+
  theme(legend.title = element_blank(),
        legend.position = c(0.5,0.92),
        legend.direction = "horizontal",
        legend.background  = element_blank(),
        legend.key.height = unit(0.45, "cm"),
        legend.key.width = unit(0.55, "cm"),
        legend.spacing.x = unit(0.2,"cm"),
        legend.spacing.y = unit(0.25, "cm"))+
  guides(fill = guide_legend(label.hjust = 1))
  
  

plot(fig_chart_3_fiscal)

fig_chart_4_fiscal <- 
  chart_4_fiscal_long %>%
  filter(label != "Current spending") %>% 
  ggplot(aes(x = as.character(year),
             y=value,
             fill = label)) +
  geom_bar(stat = "identity",
           position = "stack",
           color = "black",
           width = 0.42) +
   scale_x_discrete(expand = c(0.05,0))+
  scale_y_continuous(limits = c(0,35), 
                     breaks = seq(0,35,5),
                     expand = c(0,0)) +
  labs(title="Central Government Current Spending",
       subtitle = "(In percent of GDP)",
       # caption="Source: Bank of Jamaica (BOJ)",
       x="", y= "")+
  scale_fill_manual(values = c(green,blue)) +
  theme_imf_panel()+
  theme(legend.title = element_blank(),
        legend.position = "inside",
        legend.position.inside = c(0.5,0.9),
        legend.direction = "horizontal",
        legend.background  = element_blank(),
        legend.key.height = unit(0.45, "cm"),
        legend.key.width = unit(0.55, "cm"),
        legend.spacing.x = unit(0.25,"cm"),
        legend.spacing.y = unit(0.20, "cm"))
  


fig_chart_4_fiscal

fig_chart_5_fiscal <- 
  chart_5_fiscal_long %>%
  ggplot(aes(x = as.character(year),
             y=value)) +
  geom_bar(stat = "identity",
           fill= blue,
           position = position_dodge(0.73),
           color = "black",
           width = 0.42) +
  geom_hline(aes(yintercept = 0), 
             color = light_grey,
             linetype= "solid") +
  scale_x_discrete(expand = c(0.05,0))+
  scale_y_continuous(limits = c(0,5), 
                     breaks = seq(0,5,1),
                     expand = c(0,0)) +
  labs(title="Central Government Capital Spending",
       subtitle = "(In percent of GDP)",
       # caption="Source: Bank of Jamaica (BOJ)",
       x="", y= "")+
  theme_imf_panel()

  


plot(fig_chart_5_fiscal)

chart_6_fiscal_long <- chart_6_fiscal_long %>% 
  mutate(Year= as.character(year),
         label_chart = 
           factor(label,
                  levels = c("Primary Balance (Lhs)"
                             ,"Debt (Rhs)"),
                  labels= c("Primary Balance (top)",
                            "Debt (bottom)")))

fig_chart_6_fiscal <- 
  ggplot()+
  geom_line(data= chart_6_fiscal_long %>% 
              filter(label != "Debt (Rhs)"),
            aes(x= year,
                y= value,
                color = label_chart),
            linewidth =1.5) +
  geom_bar(data= chart_6_fiscal_long %>% 
             filter(label == "Debt (Rhs)"),
           aes(x= year,
               y= value,
               fill = label_chart),
           position = position_dodge(0.73),
           color = "black",
           width = 0.42,
           stat = "identity") +
  scale_x_continuous(limits =c(2009,2026.5),
                     breaks = 2010:2026,
                     expand = c(0,0.05)) +
  scale_y_continuous( breaks= scales::extended_breaks(n=6),
                      limits = c(0, NA),
                      expand = expansion(mult = c(0,0.2))) +
  labs(title="Primary Balance and Public Debt",
       subtitle = "(In percent of GDP)",
       # caption="Source: Bank of Jamaica (BOJ) and IMF Staff Estimates",
       x="", y= "") +
  scale_color_manual(values = c(blue)) +
  scale_fill_manual(values = c(green)) +
  facet_wrap(~label_chart, 
             scales= "free_y",
             ncol = 1) +
  theme_imf_panel()+
  theme(strip.background = element_blank(), strip.text = element_blank(),
        panel.spacing = unit(0.15, "lines"))+
  theme(legend.title = element_blank(),
        legend.position ="inside",
        legend.position.inside = c(0.5,0.57),
        # legend.direction = "vertical",
        legend.box = "horizontal",
        legend.background  = element_blank(),
        legend.key.height = unit(0.45, "cm"),
        legend.key.width = unit(0.55, "cm"),
        legend.spacing.x = unit(0.1,"cm"),
        legend.spacing.y = unit(0.1, "cm"),
        axis.text.x = element_text(angle = 45, hjust = 1, vjust = 0.95),
        plot.margin = unit(c(0.5,1,0,0.5),"lines"))+
  guides(color =guide_legend(order=2,
                             direction = "horizontal"),
         fill = guide_legend(order=2, 
                             direction = "horizontal"))
         

  


plot(fig_chart_6_fiscal)

fig_chart_1_fiscal_text <- 
  "The COVID-19 shock led to a sharp increase in central government's   \nfiscal deficit and debt levels..."
fig_chart_1_fiscal_panel <- 
  AddTextToFigure(fig_chart_1_fiscal,fig_chart_1_fiscal_text)

fig_chart_2_fiscal_text <- 
  "...the revenue-to-GDP ratio declined and the expenditure-to-GDP \nratio increased."
fig_chart_2_fiscal_panel <- 
  AddTextToFigure(fig_chart_2_fiscal,fig_chart_2_fiscal_text)

fig_chart_3_fiscal_text <- 
  "Lower tax revenues in FY 2020 were the result of a decline in GDP and GCT\ntax cuts."
fig_chart_3_fiscal_panel <- 
  AddTextToFigure(fig_chart_3_fiscal,fig_chart_3_fiscal_text,0.58)

fig_chart_4_fiscal_text <- 
  "The increase in the spending ratio was largely the result of the decline in \nGDP."
fig_chart_4_fiscal_panel <- 
  AddTextToFigure(fig_chart_4_fiscal,fig_chart_4_fiscal_text,0.58)

fig_chart_5_fiscal_text <- 
  "While capital spending was held back to make room for COVID-19 \nrelated spending..."
fig_chart_5_fiscal_panel <- 
  AddTextToFigure(fig_chart_5_fiscal,fig_chart_5_fiscal_text,0.51)

fig_chart_6_fiscal_text <- 
  "...public debt rose in FY 2020 but is on a downward path to meet the FRL \ntarget."
fig_chart_6_fiscal_panel <- 
  AddTextToFigure(fig_chart_6_fiscal,fig_chart_6_fiscal_text,0.51)

Combining and Saving the Plots

Once all individual plots are created, we can combine them into a single figure layout using patchwork.

patchwork_layout_2 <- 
  (fig_chart_1_fiscal_panel|fig_chart_2_fiscal_panel)/
  (fig_chart_3_fiscal_panel|fig_chart_4_fiscal_panel)/
  (fig_chart_5_fiscal_panel|fig_chart_6_fiscal_panel)

patchwork_output_2<- patchwork_layout_2  + plot_annotation(
  title = 'Figure 7. Fiscal Sector Developments', 
  # subtitle = '(In constant US dollars)',
  caption="Sources: Bank of Jamaica and IMF staff estimates and projections.",
  theme = theme(plot.title = element_text(color=blue,
                                          family=primary_font,face="bold",
                                          size=20, hjust = 0.5),
                
                plot.subtitle = element_text(color="black",
                                             family=primary_font,
                                             face="plain",
                                             hjust=0.5,
                                             size=20),
                plot.caption = element_text(hjust = 0,size=12,
                                            family=primary_font,
                ),
                plot.margin = margin(0.75,0.5,0.5,0.5, "lines")
  )) 

Finally, we save the combined plot to a file.

ggsave(
  here("figures/panel-figure-2-fiscal.png"),
  plot = patchwork_output_2,
  dpi = 600,
  width = 12.51,
  height = 15.64 ,
  units = "in"
)

Conclusion

In this tutorial, we have covered the steps to import, process, and visualize fiscal data in R.