How to draw Economist style graph with ggplot2 in R? | R bloggers

How to draw Economist style graph with ggplot2 in R? | R bloggers

20 minutes, 52 seconds Read

[This article was first published on Ozancan Ozdemir, and kindly contributed to R-bloggers]. (You can report a problem with the content on this page here)


Want to share your content on R bloggers? click here if you have a blog, or here if you don’t.

I think everyone would agree that Economist magazine produces very well designed images, sometimes the best in the world. The success behind their graph lies in the ability to explain complex things in a simpler way by using traditional data visualization techniques such as line graph or bar chart. They emphasize the message they want to convey rather than the aesthetics of the graph itself. They also have a clear hierarchy in their plots and use colors, fonts and lines that represent the magazine’s brand identity.

In this tutorial, we’re going to create an Economist-style chart in R using ggplot2, ggthemes, showtext, ggtextAnd grid packages. I’m going to use a dataset I’ve been collecting since 2014 on the poverty line and minimum wage in Turkey, but you can copy these codes to any dataset you want to visualize.

So let’s start by loading the necessary libraries and the dataset.

library(ggplot2)
library(readxl)
library(ggtext)
library(ggthemes)
library(showtext)

Before plotting the data, I import the font the magazine uses. They use their own signature font: Econ Sans. You can download the font from here. However, this font does not support Turkish characters such as ü, sh, i, g. So I’m importing a font similar to Econ Sans Google fonts.

font_add_google("Commissioner","Commissioner") ## import font from Google
showtext_auto() ## activate showtext

df <- read_excel("poverty_minwage_turkey.xlsx") ## load the dataset
df |> head() ## preview the dataset

# A tibble: 6 × 8
  tarih               mon          asgari           aclik  fark       
                                               
1 2014-01-01 00:00:00 Ocak 2014       846            1099  -253  
2 2014-02-01 00:00:00 Şubat 2014      846            1130  -284   
3 2014-03-01 00:00:00 Mart 2014       846            1149  -303  
4 2014-04-01 00:00:00 Nisan 2014      846            1167  -321 
5 2014-05-01 00:00:00 Mayıs 2014      846            1158  -312 
6 2014-06-01 00:00:00 Haziran 2014    846            1158  -312 

Since I want to show the difference between the Powerty Line and the minimum wage by color, where red indicates the months when the minimum wage is below the poverty line and green indicates the months when the minimum wage is above the poverty line, I will create a new variable called colour in the data set.

df$color <- ifelse(df<0,"#E3120B","forestgreen")

In addition to the color, I will also use some numbers to represent the difference between the poverty line and the minimum wage. However, I don’t use the numbers with -sign that may disturb the eyes of the audience. So I’ll add another column called label that represents the difference without a minus sign.

df$label <- gsub("-","",as.character(df$fark))

When I represent the numbers on the graph, it is not wise to show them all as I have 143 observations. Therefore, I will take a subset of the dataset through random selection. But I will purposely include the times when the difference between these two terms is maximum in either direction.

df_text <- df[c(sample(1:143,40),143,121),] # take a random sample 

Now we are ready to plot the data. In contrast to the conventional method, namely the line chart, I opt for a bar chart.

df |>     
  ggplot(aes(x = tarih, y = fark, fill = color)) + 
  geom_bar(stat = "identity", width = 25 * 24 * 60 * 60)

It is necessary to use identity in geom_bar because we already have the values ​​in the dataset. I also set the width of the bars to 25 days in seconds to avoid overlapping.

As you can see, even if we use fill argument, the bars are filled with ggplot2’s default colors. Use to activate this argument scale_fill_identity()

df |>     
  ggplot(aes(x = tarih, y = fark, fill = color)) + 
  geom_bar(stat = "identity", width = 25 * 24 * 60 * 60) +
  scale_fill_identity()

p2

Now let’s add our text labels to the bars using geom_text function. I will use the df_text dataset we previously created for this purpose.

df |>     
  ggplot(aes(x = tarih, y = fark, fill = color)) + 
  geom_bar(stat = "identity", width = 25 * 24 * 60 * 60) +
  scale_fill_identity() + geom_text(data = df_text,
    aes(x=tarih,y=fark,label = paste(label,"TL")),
    fontface = "bold",
    size =4,
    angle =90,
    hjust= ifelse(df$fark<0,1,-0.1),
    family="Commissioner") 

p3

Here I especially want to say something about the use of hjust argument. Since I have both positive and negative values, I want to position the labels differently according to the sign of the values. That’s why I used ifelse function for setting the hjust conditional valuation.

Now I would like to emphasize the 0 line by using geom_hline function.

df |>     
  ggplot(aes(x = tarih, y = fark, fill = color)) + 
  geom_bar(stat = "identity", width = 25 * 24 * 60 * 60) +
  scale_fill_identity() + geom_text(data = df_text,
    aes(x=tarih,y=fark,label = paste(label,"TL")),
    fontface = "bold",
    size =4,
    angle =90,
    hjust= ifelse(df$fark<0,1,-0.1),
    family="Commissioner") +
    geom_hline(yintercept=0, size = 1) 

p4

When you use the label on your plot, i.e. you use some or all of the values ​​of your y-axis, it is better to use the text on your y-axis to reduce clutter in your design. However, I try to emphasize the 0 line. To do both, I can use scale_y_continuous function breaks argument.

df |>     
  ggplot(aes(x = tarih, y = fark, fill = color)) + 
  geom_bar(stat = "identity", width = 25 * 24 * 60 * 60) +
  scale_fill_identity() + geom_text(data = df_text,
    aes(x=tarih,y=fark,label = paste(label,"TL")),
    fontface = "bold",
    size =4,
    angle =90,
    hjust= ifelse(df$fark<0,1,-0.1),
    family="Commissioner") +
    geom_hline(yintercept=0, size = 1) +
    scale_y_continuous(
    breaks = 0,
    labels = "0",
    limits = c(min(df$fark) - 1000, max(df$fark) + 1000)
  )

p5

We can make our design more informative by adding arrows that show the area where the poverty line is above the minimum wage, or vice versa. I can use that annotate command to add arrows and texts to the plot.

df |>     
  ggplot(aes(x = tarih, y = fark, fill = color)) + 
  geom_bar(stat = "identity", width = 25 * 24 * 60 * 60) +
  scale_fill_identity() + geom_text(data = df_text,
    aes(x=tarih,y=fark,label = paste(label,"TL")),
    fontface = "bold",
    size =4,
    angle =90,
    hjust= ifelse(df$fark<0,1,-0.1),
    family="Commissioner") +
    geom_hline(yintercept=0, size = 1) +
    scale_y_continuous(
    breaks = 0,
    labels = "0",
    limits = c(min(df$fark) - 1000, max(df$fark) + 1000)
  ) +
  ## arrow for below
  annotate("segment", 
         x = min(df$tarih) + 60*60*24*30, 
         xend = min(df$tarih) + 60*60*24*30,
         y = -500, yend = -1000,
         arrow = arrow(length = unit(0.3, "cm")),
         color = "#E3120B", size = 1) +
annotate("text", 
         x = min(df$tarih) + 60*60*24*60, 
         y = -1500, 
         label = "Asgari ücret, açlık sınırının altında.", 
         color = "#E3120B", fontface = "bold", 
         family = "Commissioner", size = 6, hjust = 0) +
### arrow for upper 
annotate("segment", 
         x = min(df$tarih) + 60*60*24*30, 
         xend = min(df$tarih) + 60*60*24*30,
         y = 300, yend = 900,
         arrow = arrow(length = unit(0.3, "cm")),
         color = "forestgreen", size = 1) +
annotate("text", 
         x = min(df$tarih) + 60*60*24*60, 
         y = 1500, 
         label = "Asgari ücret, açlık sınırından fazla.", 
         color = "forestgreen", fontface = "bold", 
         family = "Commissioner", size = 6, hjust = 0)

p6

Let’s add more information! I will also show the poverty line and minimum age at the first and last time points. Again, I’m using annotations to add text to the plot, but I’ll use it geom_curve to add arrows, because I want to draw curved arrows.

df |>     
  ggplot(aes(x = tarih, y = fark, fill = color)) + 
  geom_bar(stat = "identity", width = 25 * 24 * 60 * 60) +
  scale_fill_identity() + geom_text(data = df_text,
    aes(x=tarih,y=fark,label = paste(label,"TL")),
    fontface = "bold",
    size =4,
    angle =90,
    hjust= ifelse(df$fark<0,1,-0.1),
    family="Commissioner") +
    geom_hline(yintercept=0, size = 1) +
    scale_y_continuous(
    breaks = 0,
    labels = "0",
    limits = c(min(df$fark) - 1000, max(df$fark) + 1000)
  ) +
  ## arrow for below
  annotate("segment", 
         x = min(df$tarih) + 60*60*24*30, 
         xend = min(df$tarih) + 60*60*24*30,
         y = -500, yend = -1000,
         arrow = arrow(length = unit(0.3, "cm")),
         color = "#E3120B", size = 1) +
annotate("text", 
         x = min(df$tarih) + 60*60*24*60, 
         y = -1500, 
         label = "Asgari ücret, açlık sınırının altında.", 
         color = "#E3120B", fontface = "bold", 
         family = "Commissioner", size = 6, hjust = 0) +
### arrow for upper 
annotate("segment", 
         x = min(df$tarih) + 60*60*24*30, 
         xend = min(df$tarih) + 60*60*24*30,
         y = 300, yend = 900,
         arrow = arrow(length = unit(0.3, "cm")),
         color = "forestgreen", size = 1) +
annotate("text", 
         x = min(df$tarih) + 60*60*24*60, 
         y = 1500, 
         label = "Asgari ücret, açlık sınırından fazla.", 
         color = "forestgreen", fontface = "bold", 
         family = "Commissioner", size = 6, hjust = 0) + 
         geom_curve(aes(x = max(dfgeom_curve(aes(x = max(df$tarih) - 60*60*24*30, 
  y = -8000,
   xend = max(df$tarih) - 5*60*60*24*30, 
   yend = -8500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = -0.4
  )+
  annotate("text", 
         x = max(df$tarih) - 25*60*60*24*30, 
         y = -8500, 
         label = "Kasım 2025\n Açlık Sınırı:29898 TL \n Asgari Ücret: 22104 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) +
  
  geom_curve(aes(x = min(df$tarih) - 60*60*24*30, 
  y = -200,
   xend = min(df$tarih) + 3*60*60*24*30, 
   yend = -2500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = 0.4
  ) +
  annotate("text", 
         x = min(df$tarih) + 3*60*60*24*30, 
         y = -2700, 
         label = "Ocak 2014\n Açlık Sınırı:1089 TL \n Asgari Ücret: 846 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0)$tarih) - 60*60*24*30, 
  y = -8000,
   xend = max(df$tarih) - 5*60*60*24*30, 
   yend = -8500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = -0.4
  )+
  
  annotate("text", 
         x = max(df$tarih) - 25*60*60*24*30, 
         y = -8500, 
         label = "Kasım 2025\n Açlık Sınırı:29898 TL \n Asgari Ücret: 22104 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) +
  
  geom_curve(aes(x = min(df$tarih) - 60*60*24*30, 
  y = -200,
   xend = min(df$tarih) + 3*60*60*24*30, 
   yend = -2500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = 0.4
  ) +
  annotate("text", 
         x = min(df$tarih) + 3*60*60*24*30, 
         y = -2700, 
         label = "Ocak 2014\n Açlık Sınırı:1089 TL \n Asgari Ücret: 846 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0)

p7

Here we add two curved arrows pointing to the first and last time points, along with text annotations showing the poverty line and minimum wage values ​​for those months.

Finally, we can improve the overall look of the plot by adapting the theme to the Economist style. This includes adjusting text sizes, colors, and removing unnecessary gridlines.

Let’s start adding title, subtitle and caption.

df |>     
  ggplot(aes(x = tarih, y = fark, fill = color)) + 
  geom_bar(stat = "identity", width = 25 * 24 * 60 * 60) +
  scale_fill_identity() + geom_text(data = df_text,
    aes(x=tarih,y=fark,label = paste(label,"TL")),
    fontface = "bold",
    size =4,
    angle =90,
    hjust= ifelse(df$fark<0,1,-0.1),
    family="Commissioner") +
    geom_hline(yintercept=0, size = 1) +
    scale_y_continuous(
    breaks = 0,
    labels = "0",
    limits = c(min(df$fark) - 1000, max(df$fark) + 1000)
  ) +
  ## arrow for below
  annotate("segment", 
         x = min(df$tarih) + 60*60*24*30, 
         xend = min(df$tarih) + 60*60*24*30,
         y = -500, yend = -1000,
         arrow = arrow(length = unit(0.3, "cm")),
         color = "#E3120B", size = 1) +
annotate("text", 
         x = min(df$tarih) + 60*60*24*60, 
         y = -1500, 
         label = "Asgari ücret, açlık sınırının altında.", 
         color = "#E3120B", fontface = "bold", 
         family = "Commissioner", size = 6, hjust = 0) +
### arrow for upper 
annotate("segment", 
         x = min(df$tarih) + 60*60*24*30, 
         xend = min(df$tarih) + 60*60*24*30,
         y = 300, yend = 900,
         arrow = arrow(length = unit(0.3, "cm")),
         color = "forestgreen", size = 1) +
annotate("text", 
         x = min(df$tarih) + 60*60*24*60, 
         y = 1500, 
         label = "Asgari ücret, açlık sınırından fazla.", 
         color = "forestgreen", fontface = "bold", 
         family = "Commissioner", size = 6, hjust = 0) + 
         geom_curve(aes(x = max(dfgeom_curve(aes(x = max(df$tarih) - 60*60*24*30, 
  y = -8000,
   xend = max(df$tarih) - 5*60*60*24*30, 
   yend = -8500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = -0.4
  )+
  annotate("text", 
         x = max(df$tarih) - 25*60*60*24*30, 
         y = -8500, 
         label = "Kasım 2025\n Açlık Sınırı:29898 TL \n Asgari Ücret: 22104 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) +
  
  geom_curve(aes(x = min(df$tarih) - 60*60*24*30, 
  y = -200,
   xend = min(df$tarih) + 3*60*60*24*30, 
   yend = -2500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = 0.4
  ) +
  annotate("text", 
         x = min(df$tarih) + 3*60*60*24*30, 
         y = -2700, 
         label = "Ocak 2014\n Açlık Sınırı:1089 TL \n Asgari Ücret: 846 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0)$tarih) - 60*60*24*30, 
  y = -8000,
   xend = max(df$tarih) - 5*60*60*24*30, 
   yend = -8500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = -0.4
  )+
  
  annotate("text", 
         x = max(df$tarih) - 25*60*60*24*30, 
         y = -8500, 
         label = "Kasım 2025\n Açlık Sınırı:29898 TL \n Asgari Ücret: 22104 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) +
  
  geom_curve(aes(x = min(df$tarih) - 60*60*24*30, 
  y = -200,
   xend = min(df$tarih) + 3*60*60*24*30, 
   yend = -2500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = 0.4
  ) +
  annotate("text", 
         x = min(df$tarih) + 3*60*60*24*30, 
         y = -2700, 
         label = "Ocak 2014\n Açlık Sınırı:1089 TL \n Asgari Ücret: 846 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) + 
  labs(title ="Asgari Ücret ile Açlık Sınırı Arasındaki Farkın Son 11 Senede Aylara Göre Dağılımı",
subtitle = "**Açlık Sınırı**: 4 kişilik bir ailenin sağlıklı beslenmesi için gereken asgari gıda harcamasıdır.",
x = "",y="",caption  = "Net asgari ücret değeri dikkate alınmıştır.  
\n Açlık Sınırı için TÜRK-İŞ, asgari ücret için haberler kullanılmıştır.
 \n @OzancanOzdemir") 

p8

If you check the above code carefully, you can realize that I have used ** sign-in subtitle to use bold text. However, it doesn’t work immediately, but don’t worry! We will handle this inside theme section. But before that I would like to make one more change on the x-axis. On the x-axis I would like to display months and years instead of 3 year points. Therefore I will use scale_x_datetime function to adjust the x-axis.

df |>     
  ggplot(aes(x = tarih, y = fark, fill = color)) + 
  geom_bar(stat = "identity", width = 25 * 24 * 60 * 60) +
  scale_fill_identity() + geom_text(data = df_text,
    aes(x=tarih,y=fark,label = paste(label,"TL")),
    fontface = "bold",
    size =4,
    angle =90,
    hjust= ifelse(df$fark<0,1,-0.1),
    family="Commissioner") +
    geom_hline(yintercept=0, size = 1) +
    scale_y_continuous(
    breaks = 0,
    labels = "0",
    limits = c(min(df$fark) - 1000, max(df$fark) + 1000)
  ) +
  ## arrow for below
  annotate("segment", 
         x = min(df$tarih) + 60*60*24*30, 
         xend = min(df$tarih) + 60*60*24*30,
         y = -500, yend = -1000,
         arrow = arrow(length = unit(0.3, "cm")),
         color = "#E3120B", size = 1) +
annotate("text", 
         x = min(df$tarih) + 60*60*24*60, 
         y = -1500, 
         label = "Asgari ücret, açlık sınırının altında.", 
         color = "#E3120B", fontface = "bold", 
         family = "Commissioner", size = 6, hjust = 0) +
### arrow for upper 
annotate("segment", 
         x = min(df$tarih) + 60*60*24*30, 
         xend = min(df$tarih) + 60*60*24*30,
         y = 300, yend = 900,
         arrow = arrow(length = unit(0.3, "cm")),
         color = "forestgreen", size = 1) +
annotate("text", 
         x = min(df$tarih) + 60*60*24*60, 
         y = 1500, 
         label = "Asgari ücret, açlık sınırından fazla.", 
         color = "forestgreen", fontface = "bold", 
         family = "Commissioner", size = 6, hjust = 0) + 
         geom_curve(aes(x = max(dfgeom_curve(aes(x = max(df$tarih) - 60*60*24*30, 
  y = -8000,
   xend = max(df$tarih) - 5*60*60*24*30, 
   yend = -8500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = -0.4
  )+
  annotate("text", 
         x = max(df$tarih) - 25*60*60*24*30, 
         y = -8500, 
         label = "Kasım 2025\n Açlık Sınırı:29898 TL \n Asgari Ücret: 22104 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) +
  
  geom_curve(aes(x = min(df$tarih) - 60*60*24*30, 
  y = -200,
   xend = min(df$tarih) + 3*60*60*24*30, 
   yend = -2500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = 0.4
  ) +
  annotate("text", 
         x = min(df$tarih) + 3*60*60*24*30, 
         y = -2700, 
         label = "Ocak 2014\n Açlık Sınırı:1089 TL \n Asgari Ücret: 846 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0)$tarih) - 60*60*24*30, 
  y = -8000,
   xend = max(df$tarih) - 5*60*60*24*30, 
   yend = -8500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = -0.4
  )+
  
  annotate("text", 
         x = max(df$tarih) - 25*60*60*24*30, 
         y = -8500, 
         label = "Kasım 2025\n Açlık Sınırı:29898 TL \n Asgari Ücret: 22104 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) +
  
  geom_curve(aes(x = min(df$tarih) - 60*60*24*30, 
  y = -200,
   xend = min(df$tarih) + 3*60*60*24*30, 
   yend = -2500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = 0.4
  ) +
  annotate("text", 
         x = min(df$tarih) + 3*60*60*24*30, 
         y = -2700, 
         label = "Ocak 2014\n Açlık Sınırı:1089 TL \n Asgari Ücret: 846 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) + 
  labs(title ="Asgari Ücret ile Açlık Sınırı Arasındaki Farkın Son 11 Senede Aylara Göre Dağılımı",
subtitle = "**Açlık Sınırı**: 4 kişilik bir ailenin sağlıklı beslenmesi için gereken asgari gıda harcamasıdır.",
x = "",y="",caption  = "Net asgari ücret değeri dikkate alınmıştır.  
\n Açlık Sınırı için TÜRK-İŞ, asgari ücret için haberler kullanılmıştır.
 \n @OzancanOzdemir")  + 
  scale_x_datetime(date_breaks = "8 months", 
                   date_labels = "%m %Y",
                   expand = expansion(mult = c(0.01, 0.01)))

Now it’s time to wrap up this plot by setting theme settings. I will use theme_fivethirtyeight first i will update these theme settings.

df |>     
  ggplot(aes(x = tarih, y = fark, fill = color)) + 
  geom_bar(stat = "identity", width = 25 * 24 * 60 * 60) +
  scale_fill_identity() + geom_text(data = df_text,
    aes(x=tarih,y=fark,label = paste(label,"TL")),
    fontface = "bold",
    size =4,
    angle =90,
    hjust= ifelse(df$fark<0,1,-0.1),
    family="Commissioner") +
    geom_hline(yintercept=0, size = 1) +
    scale_y_continuous(
    breaks = 0,
    labels = "0",
    limits = c(min(df$fark) - 1000, max(df$fark) + 1000)
  ) +
  ## arrow for below
  annotate("segment", 
         x = min(df$tarih) + 60*60*24*30, 
         xend = min(df$tarih) + 60*60*24*30,
         y = -500, yend = -1000,
         arrow = arrow(length = unit(0.3, "cm")),
         color = "#E3120B", size = 1) +
annotate("text", 
         x = min(df$tarih) + 60*60*24*60, 
         y = -1500, 
         label = "Asgari ücret, açlık sınırının altında.", 
         color = "#E3120B", fontface = "bold", 
         family = "Commissioner", size = 6, hjust = 0) +
### arrow for upper 
annotate("segment", 
         x = min(df$tarih) + 60*60*24*30, 
         xend = min(df$tarih) + 60*60*24*30,
         y = 300, yend = 900,
         arrow = arrow(length = unit(0.3, "cm")),
         color = "forestgreen", size = 1) +
annotate("text", 
         x = min(df$tarih) + 60*60*24*60, 
         y = 1500, 
         label = "Asgari ücret, açlık sınırından fazla.", 
         color = "forestgreen", fontface = "bold", 
         family = "Commissioner", size = 6, hjust = 0) + 
         geom_curve(aes(x = max(dfgeom_curve(aes(x = max(df$tarih) - 60*60*24*30, 
  y = -8000,
   xend = max(df$tarih) - 5*60*60*24*30, 
   yend = -8500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = -0.4
  )+
  annotate("text", 
         x = max(df$tarih) - 25*60*60*24*30, 
         y = -8500, 
         label = "Kasım 2025\n Açlık Sınırı:29898 TL \n Asgari Ücret: 22104 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) +
  
  geom_curve(aes(x = min(df$tarih) - 60*60*24*30, 
  y = -200,
   xend = min(df$tarih) + 3*60*60*24*30, 
   yend = -2500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = 0.4
  ) +
  annotate("text", 
         x = min(df$tarih) + 3*60*60*24*30, 
         y = -2700, 
         label = "Ocak 2014\n Açlık Sınırı:1089 TL \n Asgari Ücret: 846 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0)$tarih) - 60*60*24*30, 
  y = -8000,
   xend = max(df$tarih) - 5*60*60*24*30, 
   yend = -8500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = -0.4
  )+
  
  annotate("text", 
         x = max(df$tarih) - 25*60*60*24*30, 
         y = -8500, 
         label = "Kasım 2025\n Açlık Sınırı:29898 TL \n Asgari Ücret: 22104 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) +
  
  geom_curve(aes(x = min(df$tarih) - 60*60*24*30, 
  y = -200,
   xend = min(df$tarih) + 3*60*60*24*30, 
   yend = -2500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = 0.4
  ) +
  annotate("text", 
         x = min(df$tarih) + 3*60*60*24*30, 
         y = -2700, 
         label = "Ocak 2014\n Açlık Sınırı:1089 TL \n Asgari Ücret: 846 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) + 
  labs(title ="Asgari Ücret ile Açlık Sınırı Arasındaki Farkın Son 11 Senede Aylara Göre Dağılımı",
subtitle = "**Açlık Sınırı**: 4 kişilik bir ailenin sağlıklı beslenmesi için gereken asgari gıda harcamasıdır.",
x = "",y="",caption  = "Net asgari ücret değeri dikkate alınmıştır.  
\n Açlık Sınırı için TÜRK-İŞ, asgari ücret için haberler kullanılmıştır.
 \n @OzancanOzdemir")  + 
  scale_x_datetime(date_breaks = "8 months", 
                   date_labels = "%m %Y",
                   expand = expansion(mult = c(0.01, 0.01))) + theme_fivethirtyeight() 

p9

Now let’s use the theme feature.

df |>     
  ggplot(aes(x = tarih, y = fark, fill = color)) + 
  geom_bar(stat = "identity", width = 25 * 24 * 60 * 60) +
  scale_fill_identity() + geom_text(data = df_text,
    aes(x=tarih,y=fark,label = paste(label,"TL")),
    fontface = "bold",
    size =4,
    angle =90,
    hjust= ifelse(df$fark<0,1,-0.1),
    family="Commissioner") +
    geom_hline(yintercept=0, size = 1) +
    scale_y_continuous(
    breaks = 0,
    labels = "0",
    limits = c(min(df$fark) - 1000, max(df$fark) + 1000)
  ) +
  ## arrow for below
  annotate("segment", 
         x = min(df$tarih) + 60*60*24*30, 
         xend = min(df$tarih) + 60*60*24*30,
         y = -500, yend = -1000,
         arrow = arrow(length = unit(0.3, "cm")),
         color = "#E3120B", size = 1) +
annotate("text", 
         x = min(df$tarih) + 60*60*24*60, 
         y = -1500, 
         label = "Asgari ücret, açlık sınırının altında.", 
         color = "#E3120B", fontface = "bold", 
         family = "Commissioner", size = 6, hjust = 0) +
### arrow for upper 
annotate("segment", 
         x = min(df$tarih) + 60*60*24*30, 
         xend = min(df$tarih) + 60*60*24*30,
         y = 300, yend = 900,
         arrow = arrow(length = unit(0.3, "cm")),
         color = "forestgreen", size = 1) +
annotate("text", 
         x = min(df$tarih) + 60*60*24*60, 
         y = 1500, 
         label = "Asgari ücret, açlık sınırından fazla.", 
         color = "forestgreen", fontface = "bold", 
         family = "Commissioner", size = 6, hjust = 0) + 
         geom_curve(aes(x = max(dfgeom_curve(aes(x = max(df$tarih) - 60*60*24*30, 
  y = -8000,
   xend = max(df$tarih) - 5*60*60*24*30, 
   yend = -8500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = -0.4
  )+
  annotate("text", 
         x = max(df$tarih) - 25*60*60*24*30, 
         y = -8500, 
         label = "Kasım 2025\n Açlık Sınırı:29898 TL \n Asgari Ücret: 22104 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) +
  
  geom_curve(aes(x = min(df$tarih) - 60*60*24*30, 
  y = -200,
   xend = min(df$tarih) + 3*60*60*24*30, 
   yend = -2500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = 0.4
  ) +
  annotate("text", 
         x = min(df$tarih) + 3*60*60*24*30, 
         y = -2700, 
         label = "Ocak 2014\n Açlık Sınırı:1089 TL \n Asgari Ücret: 846 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0)$tarih) - 60*60*24*30, 
  y = -8000,
   xend = max(df$tarih) - 5*60*60*24*30, 
   yend = -8500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = -0.4
  )+
  
  annotate("text", 
         x = max(df$tarih) - 25*60*60*24*30, 
         y = -8500, 
         label = "Kasım 2025\n Açlık Sınırı:29898 TL \n Asgari Ücret: 22104 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) +
  
  geom_curve(aes(x = min(df$tarih) - 60*60*24*30, 
  y = -200,
   xend = min(df$tarih) + 3*60*60*24*30, 
   yend = -2500),
    arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
    color = "black",
    size = 1,
    curvature = 0.4
  ) +
  annotate("text", 
         x = min(df$tarih) + 3*60*60*24*30, 
         y = -2700, 
         label = "Ocak 2014\n Açlık Sınırı:1089 TL \n Asgari Ücret: 846 TL ", 
         color = "black", fontface = "bold", 
         family = "Commissioner", size = 5, hjust = 0) + 
  labs(title ="Asgari Ücret ile Açlık Sınırı Arasındaki Farkın Son 11 Senede Aylara Göre Dağılımı",
subtitle = "**Açlık Sınırı**: 4 kişilik bir ailenin sağlıklı beslenmesi için gereken asgari gıda harcamasıdır.",
x = "",y="",caption  = "Net asgari ücret değeri dikkate alınmıştır.  
\n Açlık Sınırı için TÜRK-İŞ, asgari ücret için haberler kullanılmıştır.
 \n @OzancanOzdemir")  + 
  scale_x_datetime(date_breaks = "8 months", 
                   date_labels = "%m %Y",
                   expand = expansion(mult = c(0.01, 0.01))) + theme_fivethirtyeight() +  theme(plot.subtitle=element_markdown(family="Commissioner",size =18),
axis.title = element_blank(),
axis.text.y = element_text(face = "bold",family ="Commissioner"),
plot.background = element_rect(fill = "#f5f4ef", color = NA),
panel.background = element_rect(fill = "#f5f4ef", color = NA),
axis.text.x = element_text(face="bold",size = 12, family ="Comissioner"),
plot.title=element_text(family ="Commissioner",size = 28, face ="bold"),
plot.caption = element_markdown(color = "grey",family ="Commissioner",hjust = 0.05),
plot.margin = margin(t = 50, r = 10, b = 10, l = 10),
axis.line.x = element_line(size = 0.75,color="black"),
axis.ticks.x = element_line(size = 0.75,color="black")) 

Since I adjusted the subtitle text, remember the bold text I use element_markdown() by ggtext package. With family arguments, I set the font to “Commissioner”, the Economist style font. For the main title, I use element_text() to establish a strong visual hierarchy, setting the size to 28 and the face to bold so that it stands out as the primary headline. To style the caption at the bottom, I use element_markdown() again so I can add links or styling. I set the color to gray and use hjust = 0.05 to align it to the bottom left corner.

I use plot.background to fill the entire image area with a specific, off-white hexadecimal code (#f5f4ef)reducing the harsh contrast of a pure white background and the color favored by The Economist. To make the plot area fit in perfectly with the rest of the image, I used the panel.background to exactly the same color, so that there are no distracting edges (color = NA).

Since the title and subtitle at the top need space for The Economist’s red line, I use this plot.margin to set a large top margin of 50 units while keeping the other sides tight at 10 units. Because I want a clean, minimalist look, I use element_blank() on the axis titles to completely remove labels like “x” or “y” so the data speaks for itself.

For the text on the Y-axis, I apply the ‘Commissioner’ font and bold the face so that the categories or values ​​are easy to read against the background. I do the same for the text on the X-axis, but I explicitly set the size to 12 to ensure that the horizontal scale is clear and readable. To visually ground the graph, I use axis.line.x to draw a solid black line across the bottom and axis.ticks.x to add matching black marks, both with a consistent thickness of 0.75.

And one last signature; red line at the top. You can use grid.lines function of grid package.

p10

Then you’re ready to share your plot Economist style!


#draw #Economist #style #graph #ggplot2 #bloggers

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *