第 15 章 ggplot2之标度

这一章我们一起学习ggplot2中的scales语法,推荐大家阅读Hadley Wickham最新版的《ggplot2: Elegant Graphics for Data Analysis》,但如果需要详细了解标度参数体系,还是要看ggplot2官方文档

15.1 标度

13章,我们了解到ggplot2中,映射是数据转化到图形属性,这里的图形属性是指视觉可以感知的东西,比如大小,形状,颜色和位置等。我们今天讨论的标度(scale)是控制着数据到图形属性映射的函数,每一种标度都是从数据空间的某个区域(标度的定义域)到图形属性空间的某个区域(标度的值域)的一个函数。

简单点来说,标度是用于调整数据映射的图形属性。 在ggplot2中,每一种图形属性都拥有一个默认的标度,也许你对这个默认的标度不满意,可以就需要学习如何修改默认的标度。比如, 系统默认"a"对应红色,"b"对应蓝色,我们想让"a"对应紫色,"b"对应橙色。

15.2 图形属性和变量类型

还是用我们熟悉的ggplot2::mpg,可能有同学说,我画图没接触到scale啊,比如

library(tidyverse)
mpg %>% 
  ggplot(aes(x = displ, y = hwy)) + 
  geom_point(aes(colour = class)) 

能画个很漂亮的图,那是因为ggplot2默认缺省条件下,已经很美观了。(据说Hadley Wickham很后悔使用了这么漂亮的缺省值,因为很漂亮了大家都不认真学画图了。马云好像也说后悔创立了阿里巴巴?)

事实上,根据映射关系和变量名,我们将标度写完整,应该是这样的

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point(aes(colour = class)) +
  
  scale_x_continuous() + 
  scale_y_continuous() + 
  scale_colour_discrete()

如果每次都要手动设置一次标度函数,那将是比较繁琐的事情。因此ggplot2使用了默认了设置,如果不满意ggplot2的默认值,可以手动调整或者改写标度,比如

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point(aes(colour = class)) +
  
  scale_x_continuous(name = "这是我的x坐标") + 
  scale_y_continuous(name = "这是我的y坐标") + 
  scale_colour_brewer()

15.3 坐标轴和图例是同样的东西

15.4 丰富的标度体系

注意到,标度函数是由"_"分割的三个部分构成的 - scale - 视觉属性名 (e.g., colour, shape or x) - 标度名 (e.g., continuous, discrete, brewer).

每个标度函数内部都有丰富的参数系统

scale_colour_manual(
  palette = function(), 
  limits = NULL,
  name = waiver(),
  labels = waiver(),
  breaks = waiver(),
  minor_breaks = waiver(),
  values = waiver(),
  ...
)
  • 参数name,坐标和图例的名字,如果不想要图例的名字,就可以 name = NULL

  • 参数limits, 坐标或图例的范围区间。连续性c(n, m),离散型c("a", "b", "c")

  • 参数breaks, 控制显示在坐标轴或者图例上的值(元素)

  • 参数labels, 坐标和图例的间隔标签

    • 一般情况下,内置函数会自动完成
    • 也可人工指定一个字符型向量,与breaks提供的字符型向量一一对应
    • 也可以是函数,把breaks提供的字符型向量当做函数的输入
    • NULL,就是去掉标签
  • 参数values 指的是(颜色、形状等)视觉属性值,

    • 要么,与数值的顺序一致;
    • 要么,与breaks提供的字符型向量长度一致
    • 要么,用命名向量c("数据标签" = "视觉属性")提供
  • 参数expand, 控制参数溢出量

  • 参数range, 设置尺寸大小范围,比如针对点的相对大小

下面,我们通过具体的案例讲解如何使用参数,把图形变成我们想要的模样。

15.5 案例详解

先导入一个数据

gapdata <- read_csv("./demo_data/gapminder.csv")
newgapdata <- gapdata %>% 
  group_by(continent, country) %>% 
  summarise(
    across(c(lifeExp, gdpPercap, pop), mean)
  )
newgapdata
## # A tibble: 142 x 5
## # Groups:   continent [5]
##    continent country          lifeExp gdpPercap     pop
##    <chr>     <chr>              <dbl>     <dbl>   <dbl>
##  1 Africa    Algeria             59.0     4426.  1.99e7
##  2 Africa    Angola              37.9     3607.  7.31e6
##  3 Africa    Benin               48.8     1155.  4.02e6
##  4 Africa    Botswana            54.6     5032.  9.71e5
##  5 Africa    Burkina Faso        44.7      844.  7.55e6
##  6 Africa    Burundi             44.8      472.  4.65e6
##  7 Africa    Cameroon            48.1     1775.  9.82e6
##  8 Africa    Central African~    43.9      959.  2.56e6
##  9 Africa    Chad                46.8     1165.  5.33e6
## 10 Africa    Comoros             52.4     1314.  3.62e5
## # ... with 132 more rows
newgapdata %>% 
  ggplot(aes(x = gdpPercap, y = lifeExp)) +
    geom_point(aes(color = continent, size = pop)) +
    scale_x_continuous()

newgapdata %>% 
  ggplot(aes(x = gdpPercap, y = lifeExp)) +
    geom_point(aes(color = continent, size = pop)) +
    scale_x_log10()

newgapdata %>% 
  ggplot(aes(x = gdpPercap, y = lifeExp)) +
    geom_point(aes(color = continent, size = pop)) +
    scale_x_log10(breaks = c(500, 1000, 3000, 10000, 30000),
                  labels = scales::dollar)

newgapdata %>% 
  ggplot(aes(x = gdpPercap, y = lifeExp)) +
    geom_point(aes(color = continent, size = pop)) +
    scale_x_log10(
      name = "人均GDP",
      breaks = c(500, 1000, 3000, 10000, 30000),
      labels = scales::unit_format(unit = "美元"))

newgapdata %>% 
  ggplot(aes(x = gdpPercap, y = lifeExp)) +
    geom_point(aes(color = continent, size = pop)) +
    scale_x_log10() +
    scale_color_viridis_d()

离散变量映射到色彩的情形,可以使用ColorBrewer色彩。

newgapdata %>% 
  ggplot(aes(x = gdpPercap, y = lifeExp)) +
    geom_point(aes(color = continent, size = pop)) +
    scale_x_log10() +
    scale_color_brewer(type = "qual", palette = "Set1")

newgapdata %>% 
  ggplot(aes(x = gdpPercap, y = lifeExp)) +
    geom_point(aes(color = continent, size = pop)) +
    scale_x_log10() +
    scale_color_manual(
      name = "五大洲",
      values = c("Africa" = "red", "Americas" = "blue", "Asia" = "orange",
                 "Europe" = "black", "Oceania" = "gray"),
      breaks = c("Africa", "Americas", "Asia", "Europe", "Oceania"),
      labels = c("非洲", "美洲", "亚洲", "欧洲", "大洋洲")
    ) +
   scale_size(
     name = "人口数量",
     breaks = c(2e8, 5e8, 7e8),
     labels = c("2亿", "5亿", "7亿")
   )

15.6 用标度还是主题?

那什么时候用标度,什么时候用主题?这里有个原则:主题风格不会增加标签,也不会改变变量的范围,主题只会改变字体、大小、颜色等等。

15.7 小测试

用 ggplot2 重复这张lego图