BBC 新聞數據可視化 Cookbook

沒有作到信雅達的能力和時間,結合 原文去粗取精。

如何建立 BBC 風格的數據可視化圖表

BBC 的數據部門在 ggplot 的基礎上,結合自身業務開發了 bbplot 。利用 bbplot 能夠更加高效的建立供新聞出版使用的數據可視化圖表。同時 BBC 的數據部門還撰寫了本手冊供有興趣使用 bbplot 建立相似如下圖表的人使用:git

載入全部須要使用的庫

利用 pacman 的 p_load 函數一次載入全部須要使用的庫:github

# 本行代碼會未安裝 pacman 的時候安裝 pacman,若是已安裝則直接載入
if(!require(pacman)) install.packages("pacman")

pacman::p_Load('dplr', 'tidyr', 'gapminder', 'ggplot2', 'ggalt',
'forcats', 'R.utils', 'png', 'grid', ' ggpubr', bbplot)

安裝 bbplot 包

因爲 bbplot 沒有上傳到 CRAN,因此目前只能使用 devtools 安裝。ide

# 運行此行安裝 devtools 包👇
# install.packages('devtools')
devtools::install_github('bbc/bbplot')

關於 bbplot 更詳細的信息能夠在官方 github 庫查閱,本文接下來也會詳細記錄此庫的大部分使用方法及相關函數。函數

bbplot 是如何工做的

本包有兩個函數:bbc_style()finalise_plot()佈局

bbc_style():此函數不須要傳入參數,會在建立完繪圖以後被添加至 ggplot 的繪圖流程中。這個函數的做用是建立 BBC 風格的字號、字體、顏色、標尺、邊距等組件,繪圖的風格是根據設計部門的推薦和反饋定製的。字體

須要注意的是折線圖中的線條或者條形圖📊中條形的顏色不禁 bbc_style() 函數定製,須要使用標準的 ggplot 繪圖函數指定。ui

下面的代碼展現了 bbc_style() 常規使用方式。例子自己是用 gapminder 包提供的數據繪製一個簡單的折線圖。spa

# 繪圖所使用的數據來自 gapminder 包

line_df <- gapminder %>% filter(country == "Malawi")

# 繪圖
line <- ggplot(line_df, aes(x = year, y = lifeExp)) +
geom_line(colour = "#1390A1", size = 1)+
geom_hline(yintercept = 0,size = 1)+
bbc_style()+
labs(title = "Living longer",subtitle = "Life expectancy in Malawi 1952-2007")

這就是 bbc_style() 實際完成的工做。本質上是調整了 ggplot2 theme 函數的參數。設計

舉個例子,第一個參數設置了標題的字形、字號、字體以及顏色。3d

## function () 
## {
##     font <- "Helvetica"
##     ggplot2::theme(plot.title = ggplot2::element_text(family = font, 
##         size = 28, face = "bold", color = "#222222"), plot.subtitle = ggplot2::element_text(family = font, 
##         size = 22, margin = ggplot2::margin(9, 0, 9, 0)), plot.caption = ggplot2::element_blank(), 
##         legend.position = "top", legend.text.align = 0, legend.background = ggplot2::element_blank(), 
##         legend.title = ggplot2::element_blank(), legend.key = ggplot2::element_blank(), 
##         legend.text = ggplot2::element_text(family = font, size = 18, 
##             color = "#222222"), axis.title = ggplot2::element_blank(), 
##         axis.text = ggplot2::element_text(family = font, size = 18, 
##             color = "#222222"), axis.text.x = ggplot2::element_text(margin = ggplot2::margin(5, 
##             b = 10)), axis.ticks = ggplot2::element_blank(), 
##         axis.line = ggplot2::element_blank(), panel.grid.minor = ggplot2::element_blank(), 
##         panel.grid.major.y = ggplot2::element_line(color = "#cbcbcb"), 
##         panel.grid.major.x = ggplot2::element_blank(), panel.background = ggplot2::element_blank(), 
##         strip.background = ggplot2::element_rect(fill = "white"),
##         strip.text = ggplot2::element_text(size = 22, hjust = 0))
## }
## <environment: namespace:bbplot>

能夠經過修改或添加 theme 函數的參數來調整圖表樣式。不過必定要在調用了 bbc_style() 以後再調用theme(),不然的話 bbc_style() 會覆蓋掉你的調整。

下面的代碼會給圖片添加網格線:

theme(panel.grid.major.x = element_line(color = "#cbcbcb"),
panel.grid.major.y = element_blank())

保存繪製完畢的圖表

添加完bbc_style()後還須要一步操做纔可讓你的圖表能夠公佈。finalise_plot() 可以使圖表的標題和副標題左對齊、添加信息來源、在圖表右下腳添加照片。它還能將圖表保存至指定的位置。這個函數有5個參數:

finalise_plot(plot_name, source, save_filepath, width_pixels = 640, height_pixels = 450)

  • plot_name: 圖表的名字。好比上面繪製的表格 plot_name"line"
  • source:須要在圖表左下角暫時的來源文字,須要在文字前先打上 "Source:",好比 `source = "Source: ONS"。
  • svae_filepath:圖表的保存路徑,須要包括.png 後綴。
  • width_pixels:默認 640 px。
  • hieght_pixels:,默認 450 px。
  • logo_image_path:指定在圖表右下角須要展現的 logo 保存的位置。默認是一個 png 格式的佔位文件,顏色和圖表的背景色同樣。若是你不須要展現 logo, 則無需調整此參數。當你想給圖表增長 logo 時,經過此參數指定 logo 的位置便可。
finalise_plot(plot_name = my_line_plot,
              source = "Source: Gapminder",
              save_filepath = "filename_that_my_plot_should_be_saved_to.png",
              width_pixels = 640,
              height_pixels = 450,
              logo_image_path = "placeholder.png")

經過 finalise_plot() 函數,能夠在圖片發佈前作最後的微調並保存圖片。

由於 RStudio 的 plot 面板展現的圖表可能與最終保存的圖表不同,因此應該儘早保存並查看保存後圖表避免出錯。

因此,如何保存咱們以前繪製的圖表呢?

finalise_plot(plot_name = line,
              source = "Source: Gapminder",
              save_filepath = "images/line_plot_finalised_test.png",
              width_pixels = 640,
              height_pixels = 550)

繪製折線圖

#Prepare data
line_df <- gapminder %>%
  filter(country == "China") 

#Make plot
line <- ggplot(line_df, aes(x = year, y = lifeExp)) +
  geom_line(colour = "#1380A1", size = 1) +
  geom_hline(yintercept = 0, size = 1, colour="#333333") +
  bbc_style() +
  labs(title="Living longer",
       subtitle = "Life expectancy in China 1952-2007")

繪製多重線圖

#Prepare data
multiple_line_df <- gapminder %>%
  filter(country == "China" | country == "United States") 

#Make plot
multiple_line <- ggplot(multiple_line_df, aes(x = year, y = lifeExp, colour = country)) +
  geom_line(size = 1) +
  geom_hline(yintercept = 0, size = 1, colour="#333333") +
  scale_colour_manual(values = c("#FAAB18", "#1380A1")) +
  bbc_style() +
  labs(title="Living longer",
       subtitle = "Life expectancy in China and the US")

繪製條形圖

#Prepare data
bar_df <- gapminder %>%
  filter(year == 2007 & continent == "Africa") %>%
  arrange(desc(lifeExp)) %>%
  head(5)

#Make plot
bars <- ggplot(bar_df, aes(x = country, y = lifeExp)) +
  geom_bar(stat="identity", 
           position="identity", 
           fill="#1380A1") +
  geom_hline(yintercept = 0, size = 1, colour="#333333") +
  bbc_style() +
  labs(title="Reunion is highest",
       subtitle = "Highest African life expectancy, 2007")

繪製堆疊圖

#prepare data
stacked_df <- gapminder %>% 
  filter(year == 2007) %>%
  mutate(lifeExpGrouped = cut(lifeExp, 
                    breaks = c(0, 50, 65, 80, 90),
                    labels = c("Under 50", "50-65", "65-80", "80+"))) %>%
  group_by(continent, lifeExpGrouped) %>%
  summarise(continentPop = sum(as.numeric(pop)))

#set order of stacks by changing factor levels
stacked_df$lifeExpGrouped = factor(stacked_df$lifeExpGrouped, levels = rev(levels(stacked_df$lifeExpGrouped)))

#create plot
stacked_bars <- ggplot(data = stacked_df, 
                       aes(x = continent,
                           y = continentPop,
                           fill = lifeExpGrouped)) +
  geom_bar(stat = "identity", 
           position = "fill") +
  bbc_style() +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_viridis_d(direction = -1) +
  geom_hline(yintercept = 0, size = 1, colour = "#333333") +
  labs(title = "How life expectancy varies",
       subtitle = "% of population by life expectancy band, 2007") +
  theme(legend.position = "top", 
        legend.justification = "left") +
  guides(fill = guide_legend(reverse = TRUE))

這個例子中展現的是比例,有些時候須要展現準確的數字。只須要將 position = "fill" 修改成 position = "identity" 就行。

繪製分組條形圖

繪製分組條形圖和繪製條形圖的方法差很少,只須要將 position = "identity" 修改成 position = "dodge" 並設置 fill 便可。

#Prepare data
grouped_bar_df <- gapminder %>%
 filter(year == 1967 | year == 2007) %>%
 select(country, year, lifeExp) %>%
 spread(year, lifeExp) %>%
 mutate(gap = `2007` - `1967`) %>%
 arrange(desc(gap)) %>%
 head(5) %>%
 gather(key = year, 
        value = lifeExp,
        -country,
        -gap) 
 
#Make plot
grouped_bars <- ggplot(grouped_bar_df, 
                      aes(x = country, 
                          y = lifeExp, 
                          fill = as.factor(year))) +
 geom_bar(stat="identity", position="dodge") +
 geom_hline(yintercept = 0, size = 1, colour="#333333") +
 bbc_style() +
 scale_fill_manual(values = c("#1380A1", "#FAAB18")) +
 labs(title="We're living longer",
      subtitle = "Biggest life expectancy rise, 1967-2007")

繪製啞鈴圖

library("ggalt")
library("tidyr")

#Prepare data
dumbbell_df <- gapminder %>%
  filter(year == 1967 | year == 2007) %>%
  select(country, year, lifeExp) %>%
  spread(year, lifeExp) %>%
  mutate(gap = `2007` - `1967`) %>%
  arrange(desc(gap)) %>%
  head(10)

#Make plot
ggplot(dumbbell_df, aes(x = `1967`, xend = `2007`, y = reorder(country, gap), group = country)) + 
  geom_dumbbell(colour = "#dddddd",
                size = 3,
                colour_x = "#FAAB18",
                colour_xend = "#1380A1") +
  bbc_style() + 
  labs(title="We're living longer",
       subtitle="Biggest life expectancy rise, 1967-2007")

繪製直方圖

hist_df <- gapminder %>%
  filter(year == 2007)

ggplot(hist_df, aes(lifeExp)) +
  geom_histogram(binwidth = 5, colour = "white", fill = "#1380A1") +
  geom_hline(yintercept = 0, size = 1, colour="#333333") +
  bbc_style() +
  scale_x_continuous(limits = c(35, 95),
                     breaks = seq(40, 90, by = 10),
                     labels = c("40", "50", "60", "70", "80", "90 years")) +
  labs(title = "How life expectancy varies",
       subtitle = "Distribution of life expectancy in 2007")

調整圖例

移除圖例

有時候直接用文字註釋來識別數據會比圖例的效果更好。

使用 guides(colour = FALSE)來刪除指定的元素。

multiple_line + guides(colours = FALSE)

也能夠一次性移除全部的圖例theme(legned.position = "none")

multiple_line + theme(legend.position ="none")

調整圖例的位置

圖例默認展現在圖表的上方,可使用 legend.position = right/left/bottom 將圖例移動至其它位置:

mulitiple_line + theme(legend.position = "right")

若是須要精確指定圖例的位置,能夠給 legend.position傳入座標參數。
legend.position = c(0.98,0.1)會將圖例移動至右下方。c(0,0)是左下角,c(1,0) 是右下角,c(0,1)是左上角。

若是想知道最終的圖表中圖例的實際位置,須要先經過finalise_plot()函數將圖表保存後,查看實際的圖片。由於位置和圖片的大小有關。

multiple_line + theme(legend.position = c(0.115,1.05),
                      legend.direction = "horizontal") +  
  labs(title="Living longer",
       subtitle = "Life expectancy in China and the US\n")

若是想讓圖例左對齊,設置一個負邊距是比較簡單的辦法。語法是 margin(top, right, bottom, left),但這須要屢次保存和查看圖片來找到正確的數字。

+ theme(legend.margin = margin(0, 0, 0, -200)

刪除圖例文字

經過調整 theme() 來刪除標題。記住,對 theme()的全部修改都要放在bbc_style()以後。

+ theme(legend.title = element_blank())

讓圖例逆序

有時候須要調整圖例的順序,使得圖例和圖形的順序一致。

+ guides(fill = guide_legned(reverse = TRUE))

圖例從新佈局

若是圖例特別多,出於美觀考慮,咱們可能須要對圖例從新佈局。

經過給 guides 傳遞參數能夠指定圖例的行數,下面的例子展現瞭如何建立一個共4行的圖例:

+ guides(fill = guide_legend(nrow = 4, byrow = T)

調整圖例的標誌

guides 傳入 override.aes 參數會在不影響原圖表的狀況下修改圖例的默認樣式。

+gides(fill = guide_legned(override.aes = list(size = 4)))

給圖例添加間隙

默認的 ggplot 圖例幾乎沒有間隙。能夠調整 scale labels manually 來增長間隙。

舉個例子:

若是你有一個圖形,顏色是根據數據來設置的,這時候你會有一個關於顏色的圖例。微調標籤就能調整圖例的間距:

+ scale_colour_manual(labels = function(x) paste0(" ",x," ")

若是你的圖例展現的信息有變化,上面的代碼也要相應做出修改。好比 fill,須要修改成 scale_fill_manual()

調整座標軸

變換座標軸

coord_flip()能夠將橫座標修改成縱座標。

bars <- bars + coord_filp()

添加/移除網格線

bbplot 默認只有水平網格線。若是要添加垂直網格線,能夠
panel.grid.major.x = element_line
(一樣的,移除水平網格線panel.grid.major.y = element_blank())

bars <- bars + coord_flip() +
  theme(panel.grid.major.x = element_line(color="#cbcbcb"), 
        panel.grid.major.y=element_blank())
## 新添加的座標系會代替原有的座標系。

修改座標軸的文字

可使用 scale_y_continuous 或者 scale_x_continuous 任意修改座標軸標籤。

bars <- bars + scale_y_continuous(limits=c(0,85),
                   breaks = seq(0, 80, by = 20),
                   labels = c("0","20", "40", "60", "80 years"))

bars

在指定座標軸標籤的同時,也指定了座標軸的區間(limits)。

給座標軸標籤添加千位符號

經過 scale_y_continuous 能夠給座標軸標籤添加千位符號。第一種辦法是:

+ scale_y_continuous(labels = function(x) format(x, big.mark = ",",
                                                 scientific = FALSE))

這個辦法有點麻煩。第二個辦法須要用到 scale包,可是簡單點:

+ scale_y_cpntinuous(labels = scales::comma)

給座標軸標籤添加 %

經過 scale_y_continuous 很容易作到:

+ scale_y_continuous(labels = function(x) paste0(x, "%")

限定繪圖範圍

比較麻煩的方法是使用scale_y_continuous來指定繪圖範圍,可是若是不須要設置座標軸標籤的話,使用 xlimylim 就行:

bars + ylim(c(0,500))

給座標軸添加 title

默認的 theme 座標軸是沒有 title 的,不過能夠手工添加:

+ theme(axis.title = element_text(size = 18))

修改座標軸 title

添加了座標軸 title 後,默認的 title 是變量名。能夠經過 labs()修改成任意的 title。

+labs(x = "I'm an axis",
      y = "")

修改座標軸刻度

可使用axis.ticks.x 或者 axis.ticks.y修改座標軸刻度:

multiple_line+ theme(
    axis.ticks.x = element_line(colour = "#333333"),
    axis.ticks.length = unit(0.26,"cm")
)

添加註釋

添加一條註釋

最簡單的添加註釋的辦法是使用 geom_label:

multiple_line + geom_label(aes(x = 1980, y = 45, label = "I'm an annotation!"),hjust = 0, vjust = 0.5, colour = "#555555", fill = "white", label.size = NA, family = "Helvetica", size = 6)

註釋準確的位置和 xy 參數以及文本對齊方式有關。

使用 \n 進行換行,使用 lineheight 設置行高。

multiple_line <- multiple_line + 
  geom_label(aes(x = 1980, y = 45, label = "I'm quite a long\nannotation over\nthree rows"), 
             hjust = 0, 
             vjust = 0.5, 
             lineheight = 0.8,
             colour = "#555555", 
             fill = "white", 
             label.size = NA, 
             family="Helvetica", 
             size = 6)

在咱們的案例中試一下:

multiple_line <- multiple_line + 
  theme(legend.position = "none") + 
  xlim(c(1950, 2011)) +
  geom_label(aes(x = 2007, y = 79, label = "US"), 
             hjust = 0, 
             vjust = 0.5, 
             colour = "#1380A1", 
             fill = "white", 
             label.size = NA, 
             family="Helvetica", 
             size = 6) +
  geom_label(aes(x = 2007, y = 72, label = "China"), 
             hjust = 0, 
             vjust = 0.5, 
             colour = "#FAAB18", 
             fill = "white", 
             label.size = NA, 
             family="Helvetica", 
             size = 6)

左對齊/右對齊文本

hjustvjust 控制文本的水平和垂直對齊。它們的取值範圍爲 0 ~ 1。0 表示左(底部)對齊,1 表示右(頂部)對齊。

根據數據添加標籤

以上方法在添加文本標籤時頗有用,可是重複使用以上方法爲圖表添加註釋會讓工做變得很枯燥。

因此,若是你想給全部的數據點添加標籤,能夠直接根據數據來設置位置。

labelled.bars <- bars + geom_label(aes(x = country, y = lifeExp, label = round(lifeExp, 0)),
    hjust =1,
    vjust =0.5
    colour = "white",
    fill = NA,
    label.size = NA,
    family = "Helvetica",
    size = 6)

baelled.bars

上面的代碼自動給每一個國家都加上了文本標籤,免去了添加5次 geom_label 的麻煩。

爲條形圖添加左對齊的標籤

若是你想給條形圖添加左對齊的標籤,只須要根據數據集設置 x 參數,而後專門直接設置y參數就行。

labelled.bars.v2 <- bars +
 geom_label(aes(x = country, y = 4, label = round(lifeExp, 0)),
    hjust = 0,
    vjusy = 0.5,
    colour = "white",
    fill = NA,
    label.size = NA,
    family = "Helvetica",
    size = 6)

labelled.bars.v2

條形圖重排序

有時候,須要從新排列條形的順序。爲了達到這個目的,須要在繪圖前設置數據的 factor levels。明確在繪製分類數據時想使用的順序。

dataset$column <- factor(dataset$column, levels = c("18-24","25-64","65+"))

這也能夠用於堆疊圖。

按狀況設置條形顏色

經過 ifelse()能夠根據狀況設置 fill、alpha、size 等元素的值。

fill = ifelse(logical_condition, fill_if_true, fill_if_false)

ggplot(bar_df, aes(x = reorder(country, lifeExp),y =lifeExp))+
    geom_bar(stat = "identify", position = "Identity", fill = ifelse(
    bar_df$country == "#Mauritius","#1380A1","#ddddddd"))+
    coord_filp()+
    labs(title = "Reunion is highest", subtitle = "Hightest African life expectancy, 2007")+
    theme(panel.grid.major.x = element_line(color = "#cbcbcb"),
    panel.grid.major.y = element_blank())

(未完)

相關文章
相關標籤/搜索