In this article, we will try to replicate/remaking a plot from The Economist article using ggplot2 package. You’ll see all the packages that will be used in this code under the Libraries tab. The article and dataset can be read and download in the Article tab. Thank you!

1 Background

1.1 Article

This article is titled “Emissions from energy production have stablished, for now”. Its about how emissions of carbon dioxide in 2019 which were related to energy had remained the same as the previous year’s, But the capacity of the Amazon to absorb the greenhouse gas is falling. Theres two plot in this article that will be combined into one image. You can look at the article here. The datasets can be downloaded here

1.2 Libraries

You can load the package into your workspace using the library() function

library(ggplot2)
library(dplyr)
## Warning: package 'dplyr' was built under R version 3.5.3
## 
## 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(reshape2)
library(png)
library(grid)
library(gridExtra)
## 
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine
library(extrafont)
## Warning: package 'extrafont' was built under R version 3.5.3
## Registering fonts with R
library(grid)
library(gtable)
library(readr)
library(pipeR)
## Warning: package 'pipeR' was built under R version 3.5.3
library(stringi)

2 Let’s begin

2.1 data import

there’s two datasets for two plots. first plot is CO2 emissions from OECD&EU nation and rest of the world we called data_co2 and second plot is CO2 emissions and electricity generation from advanced economies we called data_elec

data_co2 <- read.csv("energy-related-co2-emissions-1990-2019.csv")
data_elec <- read.csv("Electricity generation and power sector CO2 emissions in advanced economies, 1971-2019.csv")

3 First plot

3.1 data preparation

we are going to use geom_area() function to make the plot. By default, geom_area() will stack(sum) the plot by following variable. geom_area() function also works only with 3-coloumns data frame contained x(as x variable, might be year, date, etc.), y(as y/as value of object), and variable of the object. In this case, our data contains year, value of Advanced economies, and value of rest of the world. We will combine two geom_area() plot into one canvas, so we need to seperate the data based on its object variable. But before that we need to sum the advanced economies and rest of the world value to one new coloumn because rest of the wolrd area plot is actually the sum of both value.

# make new coloumn
data_co2$rotwsum <- data_co2$Advanced.economies+data_co2$Rest.of.the.World
str(data_co2)
## 'data.frame':    30 obs. of  4 variables:
##  $ tahun             : int  1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 ...
##  $ Advanced.economies: num  11.3 11.3 11.3 11.3 11.5 11.7 12 12.3 12.3 12.3 ...
##  $ Rest.of.the.World : num  9.2 9.3 9.3 9.3 9.2 9.7 9.7 9.9 10 10.1 ...
##  $ rotwsum           : num  20.5 20.6 20.6 20.6 20.7 21.4 21.7 22.2 22.3 22.4 ...
#seperate the data and make new dataframe

oecd <- data.frame(data_co2$tahun,
                   data_co2$Advanced.economies,
                   "oecd")
names(oecd) <- c("tahun","value","variable")

rotw <- data.frame(data_co2$tahun,
                   data_co2$rotwsum,
                   "rotw")
names(rotw) <- c("tahun","value","variable")

3.2 build the plot

# create canvas and input geom_area separately
canvas <- data.frame("tahun"= 1990:2019, "value"=sample(0:38, 30))

plot_area1 <- ggplot(data=canvas, aes(x=tahun, y=value))+
  geom_area(data=rotw, aes(fill=variable))+
  geom_area(data=oecd, aes(fill=variable), colour="white")+
  scale_fill_manual(values = c("#2FC1D3","#B6C8D2"))

plot_area1

3.3 Adjusting X and Y axis

# mengatur panjang x dan y, membuat title dan subtitle
plot_area1 <- plot_area1 + scale_x_continuous(limits = c(1989,2020),
                        expand = c(0,0),
                        breaks = c(1990, 1995, 2000, 2005, 2010, 2015, 2019),
                        labels = c("1990","95","2000","05","10","15","19"))+
  scale_y_continuous(limits = c(0,35),
                     expand = c(0,0),
                     position = "right")+
  labs(title = expression(bold(paste("Energy-related ",CO["2"]," emissions"))),
       subtitle = "Tonnes bn")

plot_area1

3.4 Adjusting theme

# load new font
#font_import()
#loadfonts(device= "win")
segoe_font <- "Segoe UI"
#mengatur theme (menghapus background, menyesuaikan grid y, axis text x)
plot_area1 <- plot_area1 + theme(
  legend.position = "none",
  text = element_text(family = segoe_font, color = "black"),
  plot.title = element_text(face="bold", size=18),
  plot.subtitle = element_text(color="#6E808A",size=16),
  panel.background = element_blank(),
  panel.grid.minor = element_blank(),
  panel.grid.major.x = element_blank(),
  panel.grid.major.y = element_line(color = "#B6C8D2", size= 0.8),
  axis.line.x = element_line(color = "black", size=0.5),
  axis.text.y = element_blank(),
  axis.text.x = element_text(color ="black",size= 10),
  axis.ticks.length = unit(5, "pt"),
  axis.ticks.y = element_blank(),
  axis.ticks.x = element_line(size = 0.75),
  axis.title = element_blank()
)

plot_area1

3.5 adjusting y axis text and legend inside the plot

#the y axis is actually inside the plot, ggplot doesnt allow axis.text.y to be placed inside plot area, so we need to create the text manually using annotation_custom() and textGrob/grid.text

#creating y axis text
grob0 <- grobTree(textGrob("0", x=0.99,y=0.03, hjust=0,
                          gp=gpar(col="black", fontsize=10)))
grob10 <- grobTree(textGrob("10", x=0.98,y=0.32, hjust=0,
                          gp=gpar(col="black", fontsize=10)))
grob20 <- grobTree(textGrob("20", x=0.98,y=0.61, hjust=0,
                          gp=gpar(col="black", fontsize=10)))
grob30 <- grobTree(textGrob("30", x=0.98,y=0.89, hjust=0,
                          gp=gpar(col="black", fontsize=10)))

plot_area1 <- plot_area1+
  annotation_custom(grob0)+
  annotation_custom(grob10)+
  annotation_custom(grob20)+
  annotation_custom(grob30)

#creating legend text inside the plot
grobrotw <- grid.text("Rest of the world", x=0.75, y=0.6,
                      gp=gpar(col="#6E808A", fontsize=14))
groboecd <- grid.text("OECD and the EU", x=0.75, y=0.2,
                      gp=gpar(col="white", fontsize=14))

plot_area1 <- plot_area1+ annotation_custom(grobrotw)+
  annotation_custom(groboecd)

plot_area1

3.6 add economist header and export as png

#export the plot1 to png and add black header 
png("Plot1x.png", width = 7, height = 5.5, units = "in", res =300)
plot_area1

grid.rect(x = 0.0575, y = 0.995,
          hjust = 1, vjust = 0,
          width = 0.05,
          gp = gpar(fill="#353535",lwd=0))
dev.off()
## png 
##   2

4 Second plot

4.1 data preparation

str(data_elec)
## 'data.frame':    49 obs. of  3 variables:
##  $ ï..tahun                  : int  1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 ...
##  $ electricity.generation    : num  3898 4226 4541 4595 4691 ...
##  $ power.sector.CO2.emmisions: num  2574 2754 2966 2957 2923 ...
#rename the coloumn so it'll easier to use

data_elec <- data_elec %>% rename(
  tahun = ï..tahun,
  elec = electricity.generation,
  power = power.sector.CO2.emmisions
)

summary(data_elec)
##      tahun           elec           power     
##  Min.   :1971   Min.   : 3898   Min.   :2574  
##  1st Qu.:1983   1st Qu.: 6014   1st Qu.:3535  
##  Median :1995   Median : 8694   Median :4349  
##  Mean   :1995   Mean   : 8341   Mean   :4217  
##  3rd Qu.:2007   3rd Qu.:10738   3rd Qu.:4916  
##  Max.   :2019   Max.   :11325   Max.   :5388

4.2 build the plot

#create the canvas

canvas2 <- ggplot(data=data_elec, aes(x=tahun))

plot_area2 <- canvas2+geom_col(data=data_elec, aes(y= power),fill="#37B5C2",width = 0.8)+
                      geom_line(data=data_elec, aes(x=tahun, y= elec * 6000/12000),
                                color="#884B55",size=1.5)+
                      scale_y_continuous(limits=c(0,6000))

# the second plot has 2 y axis, so we need to create them
plot_area2 <- plot_area2 + scale_y_continuous(sec.axis = sec_axis(~.*12000/6000), limits = c(0,6000))
## Scale for 'y' is already present. Adding another scale for 'y', which will
## replace the existing scale.
plot_area2

4.3 adjusting y axis for both axis

plot_area2 <- plot_area2 + scale_x_continuous(limits = c(1968,2022),
                         expand = c(0,0),
                         breaks = c(1971,1980,1990,2000,2010,2019),
                         labels = c("1971","80","90","2000","10","19"))+
  scale_y_continuous(breaks = c(0,2000,4000,6000),
                     sec.axis = sec_axis(~.*12000/6000,
                     breaks = c(0,4000,8000,12000)),
                     limits = c(0,6000),
                     expand = c(0,0))
## Scale for 'y' is already present. Adding another scale for 'y', which will
## replace the existing scale.
plot_area2

4.4 adjusting theme

plot_area2 <- plot_area2 + labs(title = "Advanced economies*\n",
           subtitle = "Electricity generation\nTwh\n")+
  theme(
  legend.position = "none",
  text = element_text(family = segoe_font, color = "black"),
  plot.title = element_text(face="bold", size=18, lineheight = 0.2),
  plot.subtitle = element_text(color="#884B55", lineheight = 1.1,size=12, hjust = 1,face = "bold"),
  panel.background = element_blank(),
  panel.grid.minor = element_blank(),
  panel.grid.major.x = element_blank(),
  panel.grid.major.y = element_line(color = "#B6C8D2", size= 0.8),
  axis.line.x = element_line(color = "black", size=0.5),
  axis.ticks.length = unit(5, "pt"),
  axis.text.y = element_blank(),
  axis.ticks.y = element_blank(),
  axis.ticks.x = element_line(size = 0.75),
  axis.title = element_blank()
) + coord_cartesian(clip = 'off')

#note: coord_cartesian() is needed because we need to input custom text/title outside the plot grid 

4.5 add custom title and both y axis label

# blue title and y text label
grobsub <- grid.text(expression(bold(paste(CO["2"]," emissions"))),
                      x=0.1, y=1.02, vjust = -2.3, hjust = 0.6,
                      gp=gpar(col="#37B5C2", fontsize=13, fontface="bold",fontfamily=segoe_font))

grobsub2 <- grid.text("Tonnes m",
                     x=0, y=1, vjust = -2.3, hjust=0,
                     gp=gpar(col="#37B5C2", fontsize=13, fontfamily=segoe_font))

grobc4 <- grid.text("6",
                    x=0, y=1.01, vjust= 0, hjust= 0,
                    gp=gpar(col="#37B5C2", fontsize=13, fontfamily=segoe_font))

grobc1 <- grid.text("0",
                    x=0, y=0, vjust= -0.3, hjust= 0,
                    gp=gpar(col="#37B5C2", fontsize=13, fontfamily=segoe_font))

grobc2 <- grid.text("2",
                    x=0, y=0.35, vjust= 0, hjust= 0,
                    gp=gpar(col="#37B5C2", fontsize=13, fontfamily=segoe_font))

grobc3 <- grid.text("4",
                    x=0, y=0.69, vjust= 0, hjust= 0,
                    gp=gpar(col="#37B5C2", fontsize=13, fontfamily=segoe_font))


plot_area2 <- plot_area2+
  annotation_custom(grobsub)+
  annotation_custom(grobsub2)+
  annotation_custom(grobc1)+
  annotation_custom(grobc2)+
  annotation_custom(grobc3)+
  annotation_custom(grobc4)

# blue title and y text label
grobe1 <- grid.text("0",
                    x=1, y=0, vjust= -0.3, hjust= 1,
                    gp=gpar(col="#884B55", fontsize=13, fontfamily=segoe_font))

grobe2 <- grid.text("4",
                    x=1, y=0.35, vjust= 0, hjust= 1,
                    gp=gpar(col="#884B55", fontsize=13, fontfamily=segoe_font))

grobe3 <- grid.text("8",
                    x=1, y=0.69, vjust= 0, hjust= 1,
                    gp=gpar(col="#884B55", fontsize=13, fontfamily=segoe_font))

grobe4 <- grid.text("12",
                    x=1, y=1.01, vjust= 0, hjust= 1,
                    gp=gpar(col="#884B55", fontsize=13, fontfamily=segoe_font))

plot_area2 <- plot_area2+ 
  annotation_custom(grobe1)+
  annotation_custom(grobe2)+
  annotation_custom(grobe3)+
  annotation_custom(grobe4)

plot_area2

4.6 add economist header and export as png

png("plot2x.png", width = 7, height = 5.5, units = "in", res =300)
plot_area2

grid.rect(x = 0.0575, y = 0.995,
          hjust = 1, vjust = 0,
          width = 0.05,
          gp = gpar(fill="#353535",lwd=0))

dev.off()
## png 
##   2

5 Finishing

Finally, we need to combine both plot into one images and put economist theme (red bar above the plot) and also add source and main title

png("plotcombine.png", width=14,height=8,units="in", res=300)

img1 <- rasterGrob(as.raster(readPNG("Plot1x.png")),interpolate = FALSE)
img2 <- rasterGrob(as.raster(readPNG("plot2x.png")),interpolate = FALSE)
spacing <- rectGrob(gp=gpar(col="white"))

grid.arrange(img1,spacing,img2, ncol=3,
             widths=c(0.49,0.025,0.49))

grid.rect(x=1,y=0.995,
          hjust = 1,vjust = 0,
          gp= gpar(fill="#E5001c",lwd=0))
grid.rect(x=0.04,y=0.98,
          hjust = 1,vjust = 0,
          gp= gpar(fill="#E5001c",lwd=0))

grid.text("Flat chance\n ",
          x=0.0998,y=0.90,
          hjust = 1, vjust = 0,
          gp = gpar(fontsize=18,fontfamily=segoe_font,
                    fontface="bold"))

source_left <- "Source: IEA\nThe Economist"
grid.text(source_left, x=0, y=0.08,
          hjust = 0,vjust = 0,
          gp=gpar(fontsize=11, fontfamily=segoe_font, col="#B9C7D2"))

caption_right1 <- expression(paste(""^"*","Australia, Canada, Chile, European Union Iceland, Israel, Japan, South Korea,"))
grid.text(caption_right1,
          x=0.995,y=0.115,
          hjust=1,vjust=0,
          gp=gpar(fontsize=11, fontfamily=segoe_font, col="#B9C7D2"))

grid.text("Mexico, Norway, New Zealand, Switzerland, Turkey and United States",
x=0.995, y=0.088,
hjust=1, vjust=0,
gp=gpar(fontsize=11, fontfamily=segoe_font, col="#B9C7D2"))


dev.off()
## png 
##   2

Thats it! we successfully remaking economist article plot using ggplot2 package. Not perfect, but quite look alike. so its still something