The Economist là tạp chí hàng đầu với những chart rất ấn tượng. Tuy vậy tạp chí này cũng tạo ra những misleading charts. Shara Leo - visual data journalist của tạp chí này list một loạt những chart gây hiểu lầm này cũng như phương án thay thế tại đây.
Bằng R/ggplot2 chúng ta có thể tạo barplot với những hiệu chỉnh/sửa đổi như sau:
Dưới đây là R codes để tạo ra graph trên:
# Clear R environment:
rm(list = ls())
# Load data:
library(tidyverse)
read_csv("http://infographics.economist.com/databank/Economist_pensions.csv") -> pensions_data
# Rename for all columns:
names(pensions_data) <- c("country", "pop_over65", "gov_spending")
# Remove mising:
%>% filter(!is.na(gov_spending)) -> pensions_data
pensions_data
# The Economist colors:
<- "#ed1c24"
red_icon
<- "#d9e9f0"
bgr_color_te
<- "#2dc0d2"
blue_te
<- c("Brazil", "Turkey", "Mexico", "Poland", "South Kore", "Italy",
some_countries "United States", "France", "OECD average", "Japan", "Greece")
# Extract OECD countries from web:
"https://en.wikipedia.org/wiki/OECD" %>%
::read_html() %>%
rvest::html_nodes(xpath = '//*[@id="mw-content-text"]/div[1]/div[3]') %>%
rvest::html_text() %>%
rveststr_split("\n", simplify = TRUE) %>%
as.vector() %>%
-1] -> oecd_countries
.[
# Averages for OECD countries:
%>%
pensions_data filter(country %in% oecd_countries) %>%
mutate(country = "OECD average") %>%
group_by(country) %>%
summarise(pop_over65 = mean(pop_over65),
gov_spending = mean(gov_spending)) -> data_oecd
# Joint the two data sets:
bind_rows(pensions_data, data_oecd) -> data_for_ploting
%>%
data_for_ploting mutate(text_face = case_when(country == "Brazil" ~ "bold",
== "OECD average" ~ "italic",
country TRUE ~ "plain")) -> data_for_ploting
%>% filter(country %in% some_countries) -> df1
data_for_ploting
%>% filter(!country %in% some_countries) -> df2
data_for_ploting
<- "Brazil's golden oldie blowout"
p_title
<- "Latest available"
p_subtitle
<- "Source: OECD; World Bank; Previdência Social | Graphic Designer: Nguyen Chi Dung"
p_caption
<- "Government spending\non pension benefits\n% of GDP"
left_text
library(ggrepel)
library(showtext) # Package for using extra fonts.
<- "Roboto"
my_font
# Load font for ploting:
font_add_google(name = my_font, family = my_font)
<- "Roboto Condensed"
font_y
font_add_google(name = font_y, family = font_y)
showtext_auto() # Automatically render text.
ggplot() +
geom_point(data = df1, aes(pop_over65, gov_spending), size = 6, shape = 21, fill = blue_te, stroke = 0, color = "grey30") +
geom_point(data = df2, aes(pop_over65, gov_spending), size = 6, color = blue_te, alpha = 0.4) +
geom_text_repel(data = df1 %>% filter(!country %in% c("France", "Greece", "Italy", "Japan", "United States",
"OECD average", "Poland", "Brazil", "Mexico")),
aes(pop_over65, gov_spending, label = country), force = 1, direction = "y", seed = 12,
family = my_font, size = 4.5, color = "grey20", nudge_y = 0.9) +
geom_text_repel(data = df1 %>% filter(country == "France"),
aes(pop_over65, gov_spending, label = country), force = 1, direction = "y", seed = 12,
family = my_font, size = 4.5, color = "grey20", nudge_y = 0.9) +
geom_text_repel(data = df1 %>% filter(country == "Greece"),
aes(pop_over65, gov_spending, label = country), force = 1, direction = "x", seed = 12,
family = my_font, size = 4.5, color = "grey20", nudge_x = 1.4) +
geom_text_repel(data = df1 %>% filter(country == "Italy"),
aes(pop_over65, gov_spending, label = country), force = 1, direction = "y", seed = 12,
family = my_font, size = 4.5, color = "grey20", nudge_y = 0.9) +
geom_text_repel(data = df1 %>% filter(country == "Japan"),
aes(pop_over65, gov_spending, label = country), force = 1, direction = "y", seed = 12,
family = my_font, size = 4.5, color = "grey20", nudge_y = -0.8) +
geom_text_repel(data = df1 %>% filter(country == "United States"),
aes(pop_over65, gov_spending, label = country), force = 4, direction = "x", seed = 12,
family = my_font, size = 4.5, color = "grey20", nudge_x = -2.4) +
geom_text_repel(data = df1 %>% filter(country == "OECD average"),
aes(pop_over65, gov_spending, label = country), force = 1, direction = "x", seed = 12,
family = my_font, size = 4.5, color = "grey20", nudge_x = -2.4, fontface = "italic") +
geom_text_repel(data = df1 %>% filter(country == "Poland"),
aes(pop_over65, gov_spending, label = country), force = 1, direction = "x", seed = 12,
family = my_font, size = 4.5, color = "grey20", nudge_x = -1.4) +
geom_text_repel(data = df1 %>% filter(country == "Brazil"),
aes(pop_over65, gov_spending, label = country), force = 1, direction = "y", seed = 12,
family = my_font, size = 4.5, nudge_y = 1, fontface = "bold") +
geom_text_repel(data = df1 %>% filter(country == "Mexico"),
aes(pop_over65, gov_spending, label = country), force = 1, direction = "y", seed = 12,
family = my_font, size = 4.5, color = "grey20", nudge_y = 0.9) +
theme(plot.background = element_rect(fill = bgr_color_te, color = NA)) +
theme(panel.background = element_rect(fill = bgr_color_te, color = NA)) +
labs(subtitle = left_text, x = "Population aged 65 years and over, % of total") +
scale_x_continuous(limits = c(5, 30.5), breaks = seq(5, 30, 5), expand = c(0, 0)) +
scale_y_continuous(limits = c(0, 20), breaks = seq(0, 20, 5), expand = c(0, 0), position = "right") +
theme(axis.title.y.right = element_blank()) +
theme(panel.grid.minor = element_blank()) +
theme(panel.grid.major = element_line(color = "#bdc3cb", size = 0.7)) +
theme(axis.ticks = element_blank()) +
theme(plot.subtitle = element_text(family = font_y, color = "grey10", size = 12, hjust = 1.035, vjust = 3)) +
theme(axis.text = element_text(family = font_y, color = "grey20", size = 14)) +
theme(axis.title = element_text(family = font_y, color = "grey20", size = 12)) +
theme(axis.line.x = element_line(color = "grey50", size = 1)) -> p
library(patchwork)
+
p plot_annotation(title = p_title, subtitle = p_subtitle, caption = p_caption) +
plot_annotation(theme = theme(plot.background = element_rect(fill = bgr_color_te))) +
plot_annotation(theme = theme(plot.title = element_text(family = font_y, size = 18, face = "bold", vjust = -2))) +
plot_annotation(theme = theme(plot.subtitle = element_text(family = font_y, size = 13.5, color = "grey10", vjust = -2))) +
plot_annotation(theme = theme(plot.caption = element_text(family = font_y, color = "grey40", size = 12, hjust = 0))) +
theme(plot.margin = unit(c(0.5, 0.5, 0.1, 0.7), "cm"))
# Make The Economist icon:
library(grid)
grid.rect(x = 0.045, y = 1, width = 0.05*1.5, height = 0.02, just = c("left", "top"), gp = gpar(fill = red_icon, col = red_icon))