R 数据可视化 —— ggplot scale设置

前言

标度(scale)控制着数据映射到图形属性的具体细节,用于将数据转化为我们在视觉上能够感知的东西。如颜色、大小、位置、形状和透明度等。

每个标度都有一个对应的函数,用于将数据空间的值(即函数的定义域)映射到图形属性空间(即函数的值域)。

通过使用这些函数,就能够将我们的数据与图形属性连接起来。

图形中的每种属性都有一个默认的标度函数。在前一节的例子中,我们并没有显示使用这些标度函数,因为在默认情况下,ggplot2 会自动添加标度,而无需手动设置

标度详情

标度函数大致可以分为四类:

  • 位置标度:用于坐标轴的控制
  • 颜色标度:将数据变量映射到颜色
  • 自定义标度(manual):手动自定义数据到图形属性的映射关系
  • 非映射标度(identity):直接将变量值作为图形属性值使用,不做映射。例如,某些变量值本身代表的值颜色值(如 redblue 等),不需要再进行转换了。

各种标度函数如下

这些函数,有几个共有的参数:

  • name:设置坐标轴和图例上的标签,可以是字符串(支持 \n 换行)或数学表达值。但一般会使用 labs()xlab()ylab() 设置

  • limits:限制定义域的范围,不在该范围的数据将会被删除

  • breaks:用于控制在坐标轴或图例上显示的值,即坐标轴的刻度,如果是连续型数据,则会对数据进行分箱。

  • labels:用于设置断点处的标签,要设置 labels 必须同时设置 breaks

例如

p1 <- ggplot(mtcars) +
  geom_bar(aes(mpg)) +
  scale_x_binned(name = expression(1+exp(2)))

p2 <- ggplot(mtcars) +
  geom_bar(aes(mpg)) +
  scale_x_binned() +
  labs(title = "This is example", tag = "A", x = expression(1+exp(2)))

p3 <- ggplot(mtcars) +
  geom_bar(aes(mpg)) +
  scale_x_binned(name = expression(1+exp(2)), limits = c(10, 20), 
  )

p4 <- ggplot(mtcars) +
  geom_bar(aes(mpg)) +
  scale_x_binned(name = expression(1+exp(2)), limits = c(10, 20), 
                 breaks = seq(10, 20, 2), labels = c("A", 'B', 'C', 'D', 'E', 'F'),
  )

plot_grid(p1, p2, p3, p4, nrow = 2, ncol = 2)

在上面的例子中,我们借用 cowplotplot_grid 函数来将多张图片绘制在一起

标度函数

1. 设置图表信息

labs() 函数可以设置图表的一些信息,如标题(title)、子标题(subtitle),或使用 caption 来提供数据来源信息,使用 tag 来区分多个图表

labs(
  ...,
  title = waiver(),
  subtitle = waiver(),
  caption = waiver(),
  tag = waiver()
)

xlab(label)

ylab(label)

ggtitle(label, subtitle = waiver())
示例
p <- ggplot(mtcars, aes(mpg, wt, colour = cyl)) + geom_point()

p2 <- p + labs(colour = "Cylinders")

p3 <- p + labs(x = "New x label")

p4 <- p + labs(title = "New plot title")

p5 <- p + labs(title = "New plot title", subtitle = "A subtitle")

p6 <- p + labs(caption = "(based on data from ...)")

p7 <- p + labs(title = "title", tag = "A")

p8 <- p + labs(title = "title") + labs(title = NULL)

plot_grid(p, p2, p3, p4, p5, p6, p7, p8, nrow = 4, ncol = 2,
          labels = c("A", 'B', 'C', 'D', 'E', 'F', 'G', 'H'))

在上面的例子中,第七张图的 tag 设置为 Aplot_grid 设置的 G 重合了。

xlab()ylab()ggtitle()labs() 的特殊化,专门用于设置 xy 轴的标签和标题

2. 设置范围

我们可以使用下面三个函数来设置数据的范围,这些函数是 limits 参数的快捷方式。

lims(...)

xlim(...)

ylim(...)

在默认的情况下,超出范围的数据都会被设置为 NA 值,这意味着超出范围的数据将会被删除

示例

xlim()ylim() 函数接受两个数值,用于指定最小(左侧)或最大(右侧)的值。

如果更大的值在前面,轴的数据将会反转,你也可以将一个值设置为 NA,让 ggplot2 来推断数值范围。

p1 <- ggplot(mtcars, aes(mpg, wt)) +
  geom_point()

p2 <- ggplot(mtcars, aes(mpg, wt)) +
  geom_point() +
  xlim(15, 20)

p3 <- ggplot(mtcars, aes(mpg, wt)) +
  geom_point() +
  xlim(20, 15)

p4 <- ggplot(mtcars, aes(mpg, wt)) +
  geom_point() +
  xlim(NA, 20)

plot_grid(p1, p2, p3, p4, 
          labels = c('A', 'B', 'C', 'D')
)

对于 lims() 函数,接受一个 name-value 对。name 必须是图形属性,而值必须是长度为二的数值、字符串、因子或时间日期。

我们可以使用 lims 在不同的图片中设置同样的配色方案,如

small <- subset(mtcars, cyl == 4)
big <- subset(mtcars, cyl > 4)

p1 <- ggplot(small, aes(mpg, wt, colour = factor(cyl))) +
  geom_point() +
  lims(colour = c("4", "6", "8"))

p2 <- ggplot(big, aes(mpg, wt, colour = factor(cyl))) +
  geom_point() +
  lims(colour = c("4", "6", "8"))

plot_grid(p1, p2)

对于下面这个例子

last_month <- Sys.Date() - 0:59
df <- data.frame(
  date = last_month,
  price = c(rnorm(30, mean = 15), runif(30) + 0.2 * (1:30))
)

p <- ggplot(df, aes(date, price)) +
  geom_line() +
  stat_smooth()

我们可以有两种方式来设置轴的范围

p + lims(x= c(Sys.Date() - 30, NA), y = c(10, 20))

p + coord_cartesian(xlim =c(Sys.Date() - 30, NA), ylim = c(10, 20))

3. 设置值范围

除了设置坐标轴的范围,我们也可以设置图形中必须包含某个或某些值。

可以使用 expand_limits() 函数,该函数接受一个命名列表,名称必须为图形属性

示例

对于下面这张散点图

p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()

> mtcars %>% distinct(mpg) %>% summarise(min=min(.), max=max(.))
   min  max
1 10.4 33.9
> mtcars %>% distinct(wt) %>% summarise(min=min(.), max=max(.))
    min   max
1 1.513 5.424

从上面的结果中,我们可以计算出:X 轴(mpg)和 Y 轴(wt)的数据范围

下面,让我们用 expand_limits 来调整数据范围

p1 <- p + expand_limits(x = 0)

p2 <- p + expand_limits(y = c(1, 9))

p3 <- p + expand_limits(x = 0, y = 0)

plot_grid(p1, p2, p3, labels = c('A', 'B', 'C'), nrow = 1)

在图 A 中,我们设置 X 轴数据要包含 0,尽管并没有对应的值,但是 X 坐标轴还是会从 0 开始。

类似的,图 B 设置了 Y 轴需要包含 19,超过了数据的范围,相当于扩大了 Y 轴的范围

我们还可以对颜色进行设置

p1 <- ggplot(mtcars, aes(mpg, wt)) +
  geom_point(aes(colour = cyl)) +
  expand_limits(colour = seq(2, 10, by = 2))

p2 <- ggplot(mtcars, aes(mpg, wt)) +
  geom_point(aes(colour = factor(cyl))) +
  expand_limits(colour = factor(seq(2, 10, by = 2)))

plot_grid(p1, p2, labels = c('A', 'B'))

A 图设置了渐变色,B 图是离散配色。

> mtcars %>% distinct(cyl)
                  cyl
Mazda RX4           6
Datsun 710          4
Hornet Sportabout   8

我们可以看到,其实颜色的值只有三个 468,但是我们设置了 5 个不同的颜色层级。

B 图可以明显看出,210 的颜色并没有显示,因为不存在相应的数据

4. 设置间隔

可以使用 expansion() 函数设置数据与轴之间的间隔,该函数主要搭配 scale_(x|y)_continuousscale_(x|y)_discrete 使用。

# 推荐使用
expansion(mult = 0, add = 0)

# 已被弃用
expand_scale(mult = 0, add = 0)

该函数包含两个参数:

  • mult: 百分比间距,接受一个向量,如果向量长度为 1,则上下间距的间隔是一样的,如果长度为 2,则 mult[1] 为下间距,mult[2] 为上间距
  • add: 常数值单位间距,类似 mult
示例
p1 <- ggplot(mtcars) +
  geom_bar(aes(x = factor(cyl)))

p2 <- ggplot(mtcars) +
  geom_bar(aes(x = factor(cyl))) +
  scale_y_continuous(expand = expansion(mult = c(0, .1)))

p3 <- ggplot(subset(diamonds, carat > 2), aes(cut, clarity)) +
  geom_jitter() +
  scale_x_discrete(expand = expansion(add = 2))

p4 <- ggplot(subset(diamonds, carat > 2), aes(cut, price)) +
  geom_jitter() +
  scale_x_discrete(expand = expansion(add = .6)) +
  scale_y_continuous(expand = expansion(mult = .05))

plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4],
          nrow = 2)

其中,D 图所设置的间距是默认值

5. 设置透明度

alpha 透明度并不是非常有用,但它可以方便地从视觉上降低不太重要的观察结果的权重

设置透明度的函数包括:

scale_alpha(..., range = c(0.1, 1))

scale_alpha_continuous(..., range = c(0.1, 1))

scale_alpha_binned(..., range = c(0.1, 1))

scale_alpha_discrete(...)

scale_alpha_ordinal(..., range = c(0.1, 1))

其中 scale_alphascale_alpha_continuous 的别名,因为这个函数是最常用的。

其中 range 参数的值为透明度的范围,必须在 0-1 之间。

其他参数分别被 continuous_scale(), binned_scale, 和 discrete_scale() 解析

示例

首先在 aes 中设置透明度,如

p <- ggplot(mpg, aes(displ, hwy)) +
  geom_point(aes(alpha = year))

然后使用标度函数来修改透明度范围

p1 <- p + scale_alpha("cylinders")

p2 <- p + scale_alpha(range = c(0.4, 0.8))

plot_grid(p1, p2, labels = LETTERS[1:2],
          nrow = 1)

在图 A 中,我们传递了一个字符串,相当于设置了 name 参数的值,更改了图例的名称

自定义透明度

p <- ggplot(mpg, aes(displ, hwy)) +
  geom_point(aes(alpha = factor(year)))

p + scale_alpha_manual(values = c(0.1, 0.2))

6. 设置线条类型

线条的类型可以使用 0-6 之间的整数来指定,分别代表

0 = blank         1 = solid
2 = dashed        3 = dotted
4 = dotdash       5 = longdash
6 = twodash

绘制所有的线条类型

df_lines <- tibble(
  linetype = factor(0:6)
)

ggplot(df_lines) +
  geom_hline(aes(linetype = linetype, yintercept = 0), size = 2) +
  scale_linetype_discrete() +
  facet_grid(linetype ~ .) +
  theme_void(20)

在这里插入图片描述

线条类型不支持连续型数据,因为无法将连续型数据映射到线型。但是可以使用 scale_linetype_binned(),由于线型没有固定的顺序,也不推荐这样使用

示例

对于数据

> economics_long
# A tibble: 2,870 x 4
   date       variable value  value01
   <date>     <chr>    <dbl>    <dbl>
 1 1967-07-01 pce       507. 0       
 2 1967-08-01 pce       510. 0.000265
 3 1967-09-01 pce       516. 0.000762
 4 1967-10-01 pce       512. 0.000471
 5 1967-11-01 pce       517. 0.000916
 6 1967-12-01 pce       525. 0.00157 
 7 1968-01-01 pce       531. 0.00207 
 8 1968-02-01 pce       534. 0.00230 
 9 1968-03-01 pce       544. 0.00322 
10 1968-04-01 pce       544  0.00319 
# … with 2,860 more rows

我们根据 variable 变量进行分组,绘制折线图

base <- ggplot(economics_long, aes(date, value01))
base + geom_line(aes(group = variable))

注意:我们是通过设置 group = variable 来设置分组的,但是组与组之间没有区分度。

为图片添加线型和颜色

base + geom_line(aes(linetype = variable, colour=variable))

这样,每组之间的趋势就很明显了。

自定义线条映射

df <- economics_long %>% filter(variable %in% c("pop", "pce", "uempmed")) 

lt <- c("pop"=1, "pce"=3, "uempmed"=5)

ggplot(df, mapping = aes(date, value01)) +
  geom_line(aes(linetype = variable, colour=variable)) +
  scale_linetype_manual(values = lt)

7. 设置形状

scale_shape() 函数可以将离散变量映射为 6 个不同的形状。

如果你有超过 6 个类别,你将会得到一个警告信息,并且第 7 个或更后面的类别将不会在图片中显示

形状与线型一样,不支持连续型数据,也不推荐使用 scale_shape_binned 函数来设置

scale_shape(..., solid = TRUE)

scale_shape_binned(..., solid = TRUE)

其中 solid 参数控制形状是不是实心的

下面的代码展示了所有的形状

df_shapes <- data.frame(shape = 0:25)

ggplot(df_shapes, aes(0, 0, shape = shape)) +
  geom_point(aes(shape = shape), size = 5, fill = 'red') +
  scale_shape_identity() +
  facet_wrap(~shape) +
  theme_void()

取值范围为 0-25,共 26 个整数值分别代表了相应的形状。

注意:红色的形状是可以设置填充色(fill)的,其他形状只能设置轮廓颜色(colour)。

示例
dsmall <- diamonds[sample(nrow(diamonds), 100), ]

d <- ggplot(dsmall, aes(carat, price)) + geom_point(aes(shape = cut))

p2 <- d + scale_shape(solid = FALSE)

p3 <- d + scale_shape(name = "Cut of diamond")

levels(dsmall$cut) <- c("Fair", "Good", "Very Good", "Premium", "Ideal")
p4 <- ggplot(dsmall, aes(price, carat)) + geom_point(aes(shape = cut))

plot_grid(d, p2, p3, p4, labels = LETTERS[1:4])

在这里插入图片描述

注意:在绘制图 D 时,会输出警告信息,提示不建议对排序的变量设置形状

自定义形状映射

shape_map <- c("Fair"=13, "Good"=20, "Very Good"=15, "Premium"=2, "Ideal"=11)

d + scale_shape(solid = FALSE) +
  scale_shape_manual(values = shape_map)

8. 设置大小

一般只有点图和文本需要设置大小。而我们通常是将数据映射到点的面积,而不是映射到半径。

标度函数如下

scale_size(..., range = c(1, 6))

scale_radius(..., range = c(1, 6))

scale_size_binned(..., range = c(1, 6))

scale_size_area(..., max_size = 6)

scale_size_binned_area(..., max_size = 6)

如果需要将值为 0 的点映射为 0,需要使用 scale_size_area 函数

示例

例如,下面这张散点图

p <- ggplot(mpg, aes(displ, hwy, size = hwy)) +
  geom_point()

在这里插入图片描述

# 设置图例标题
p1 <- p + scale_size("Highway mpg")

# 设置点的大小范围
p2 <- p + scale_size(range = c(0, 10))

# 允许将 0 值映射为面积为 0 的点(不绘制)
p3 <- p + scale_size_area()

# 方便从看出图例中看出分箱
p4 <- p + scale_size_binned()

# This is most useful when size is a count
p5 <- ggplot(mpg, aes(class, cyl)) +
  geom_count() +
  scale_size_area()

# 将数据映射为半径,不推荐
p6 <- p + scale_radius()

plot_grid(p1, p2, p3, p4, p5, p6,
          labels = LETTERS[1:6], nrow = 3)

自定义数据大小,我们根据 cyl 的值倒序设置点的大小

ggplot(mpg, aes(displ, hwy, size = factor(cyl))) +
  geom_point() +
  scale_size_manual(
    name="cyl",
    values = c(
    "4" = 5,
    "5" = 4,
    "6" = 3,
    "8" = 2
  ))

9. 位置

一幅图有两个位置标度,即指定水平位置的 X 轴和指定竖直位置的 Y 轴。

针对不同的数据类型,标度函数又可以分为连续型、离散型和日期标度。

9.1 连续型

连续型位置标度主要是 scale_x_continuous()scale_y_continuous()。用于将连续型数据映射到 XY 轴。

每个连续型标度函数都接受一个 trans 参数,用于对输入的数据进行变换后绘图。

内置的转换函数包括:

"asn",        "atanh",       "boxcox", 
"date",       "exp",         "hms", 
"identity",   "log",         "log10", 
"log1p",      "log2",        "logit", 
"modulus",    "probability", "probit", 
"pseudo_log", "reciprocal",  "reverse", 
"sqrt"        "time"

一些常用的转换函数会有对应的简便写法,如

scale_x/y_log10()
scale_x/y_reverse() 
scale_x/y_sqrt()

scale_x_log10()scale_x_continuous(trans = "log10") 是等价的

当然,我们可以先对数据进行转换,然后再绘制图片。这样可以更好的自定义自己的转换方式

例如下面这个例子

p1 <- ggplot(diamonds, aes(log10(carat), log10(price))) +
  geom_point()

p2 <- ggplot(diamonds, aes(carat, price)) +
  geom_point() +
  scale_x_log10() +
  scale_y_log10()

plot_grid(p1, p2, labels = LETTERS[1:2])

可以看到,在绘图前后变换的数据主体是完全相同的,但是坐标轴的刻度却不一样。这将在后面的坐标系调整中进行说明

数据转换

p1 <- ggplot(mpg, aes(displ, hwy)) +
  geom_point()

p2 <- p1 + scale_y_log10()

p3 <- p1 + scale_y_sqrt()

p4 <- p1 + scale_y_reverse()

plot_grid(p1, p2, p3, p4,
          labels = LETTERS[1:4], ncol = 2)

也可以使用 scales 包定义的转换函数

p1 + scale_y_continuous(trans = scales::reciprocal_trans())

对数据进行分箱

p1 <- ggplot(mpg, aes(displ, hwy)) +
  geom_point()

p2 <- p1 + scale_x_continuous(
  breaks = c(2, 4, 6),
  label = c("two", "four", "six")
)

plot_grid(p1, p2, labels = LETTERS[1:2])

使用 scales 包中的函数为轴标签设置格式

df <- data.frame(
  x = rnorm(10) * 100000,
  y = seq(0, 1, length.out = 10)
)
p2 <- ggplot(df, aes(x, y)) + geom_point()

p3 <- p2 + scale_y_continuous(labels = scales::percent)

p4 <- p2 + scale_y_continuous(labels = scales::dollar)

p5 <- p2 + scale_x_continuous(labels = scales::comma)

plot_grid(p2, p3, p4, p5,
          labels = LETTERS[1:4], ncol = 2)

9.2 离散型

scale_x_discrete()scale_y_discrete() 两个函数用于将离散型数据映射到坐标轴上。

d <- ggplot(subset(diamonds, carat > 1), aes(cut, clarity)) +
  geom_jitter()

# 重置 X 轴的标签映射
p2 <- d + scale_x_discrete("Cut", labels = c("Fair" = "F","Good" = "G",
                                       "Very Good" = "VG","Perfect" = "P","Ideal" = "I"))

p3 <- d + scale_x_discrete(limits = c("Fair","Ideal"))

p4 <- d + xlim("Fair","Ideal", "Good") + ylim("I1", "IF")

plot_grid(d, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

对标签进行重排

p1 <- ggplot(mpg, aes(manufacturer, cty)) + geom_point()

p2 <- ggplot(mpg, aes(reorder(manufacturer, cty), cty)) + geom_point()

p3 <- ggplot(mpg, aes(reorder(manufacturer, displ), cty)) + geom_point()

p4 <- ggplot(mpg, aes(reorder(manufacturer, displ), cty)) +
  geom_point() +
  scale_x_discrete(labels = abbreviate)

plot_grid(d, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

D 图中,我们使用 abbreviate 函数将 X 轴的标签设置为简写

9.3 日期和时间

虽然日期和时间也是连续型的,但是在标注坐标轴时还是有些不一样的。

共支持三种类型的时间日期,其中 scale_*_date 处理 Date 类型,scale_*_datetime 用于处理 POSIXct 类型的时间,scale_*_time 用于处理 hms 类型的时间

这些函数主要有三个特殊的参数

  • date_breaks:一个字符串,用于设置时间间隔。如 "2 weeks""10 years"

如果同时指定 breakdate_breaks,则以 date_breaks 为准

  • date_labels:一个字符串,为 labels 提供格式化规范。

如果同时指定了 labeldate_labels,则以 date_labels 为准

常用的数据格式编码有:

更详细的格式介绍可以参考:

https://rdrr.io/r/base/strptime.html

  • date_minor_breaks:一个字符串,给出次要标签之间的时间间距。如 "2 weeks""10 years"

如果同时指定了 minor_breaksdate_minor_breaks,则以 date_minor_breaks 为准。

对于如下例子

last_month <- Sys.Date() - 0:29
df <- data.frame(
  date = last_month,
  price = runif(30)
)
base <- ggplot(df, aes(date, price)) +
  geom_line()

设置格式

p1 <- p + scale_x_date(date_labels = "%b %d")

p2 <- p + scale_x_date(date_breaks = "1 week", date_labels = "%W")

p3 <- p + scale_x_date(date_minor_breaks = "1 day")
# 限制范围
p4 <- p + scale_x_date(limits = c(Sys.Date() - 7, NA))

plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

注意:在这里会有一个问题,就是英文月份无法显示。那该如何设置呢?

首先,尝试使用如下命令来设置

Sys.setlocale("LC_TIME", "English")

如果在运行该命令式报出如下错误

> Sys.setlocale("LC_TIME", "English") 
[1] ""
Warning message:
In Sys.setlocale("LC_TIME", "English") :
操作系统报告说无法执行将本地化设成"English"的请求

这个问题的原因可能是系统语言的问题,网上有人推荐说更改系统语言。但是这样改很麻烦,所以我尝试了如下代码

Sys.setlocale("LC_TIME", "C")

再次运行,已经解决了该问题了。不需要更改系统语言

10. 颜色

除了前面讲的位置标度之外,最常用的就是颜色属性的修改了。

配色也是一门艺术,像我这种没有艺术细胞的人就只能看着哪种配色方案漂亮就将就着用了🤣😂

10.1 ColorBrewer 配色

ColorBrewer 提供了 sequential, divergingqualitative 三种不同的配色类型,每种类型又有不同的配色方案。

有三个不同的标度函数来设置

# 针对离散型数据
scale_*_brewer()
# 针对连续型数据
scale_*_distiller()
# 针对分箱数据
scale_*_fermenter()

其中 * 代表 colour(轮廓颜色) 和 fill(填充色)。

palette 参数的值可以是下列字符串之一

  1. Diverging(双色渐变系)
BrBG, PiYG, PRGn, PuOr, RdBu, RdGy, RdYlBu, RdYlGn, Spectral
  1. Qualitative(多色系)
Accent, Dark2, Paired, Pastel1, Pastel2, Set1, Set2, Set3
  1. Sequential(单色系)
Blues, BuGn, BuPu, GnBu, Greens, Greys, Oranges, OrRd, PuBu, PuBuGn, PuRd, Purples, RdPu, Reds, YlGn, YlGnBu, YlOrBr, YlOrRd

示例

对于如下数据

dsamp <- diamonds[sample(nrow(diamonds), 1000), ]

我们可以为 colour 设置变量

(d <- ggplot(dsamp, aes(carat, price)) +
    geom_point(aes(colour = clarity)))

但是我觉得这种配色不太好看,想换一种。我们进行如下尝试

p1 <- d + scale_colour_brewer()

p2 <- d + scale_colour_brewer(palette = "Greens")

p3 <- d + scale_colour_brewer(palette = "Set1")

p4 <- d + scale_colour_brewer(palette = "Spectral")

plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

en...,这样来看,图 C 是比较好看的,图 D 看起来也行,单色系的就差了点喽。

连续型数据的设置方式也是类似的

d1 <- ggplot(dsamp, aes(carat, price)) +
  geom_point(aes(colour = depth))

d2 <- d + scale_colour_distiller(palette = "Greens")

d3 <- d + scale_colour_distiller(palette = "Set1")

d4 <- d + scale_colour_distiller(palette = "Spectral")

plot_grid(d1, d2, d3, d4, labels = LETTERS[1:4], nrow = 2)

为分箱数据配色

ggplot(dsamp, aes(carat, price)) +
  geom_point(aes(colour=depth)) +
  scale_colour_fermenter(palette = "Spectral")

为每个分箱设置颜色相同的配色

ggplot(dsamp, aes(carat, price, colour=price)) +
  geom_point() +
  scale_x_binned() +
  scale_colour_fermenter(palette = "Spectral")

获取更多的配色方案,可以访问 ColorBrewer 的网页:

http://colorbrewer2.org

配色好看,获取简单,推荐使用

还有一个网站
https://www.webdesignrankings.com/resources/lolcolors/

配色也还可以,只是都是 4 种颜色的。

10.2 渐变色

根据颜色梯度,可以将设置渐变色的函数分为三种:

  • scale_*_gradient:双色渐变,使用 lowhigh 两个参数控制两端的颜色

  • scale_*_gradient2:三色渐变,有 lowmidhigh 三个参数,lowhigh 作用同上,mid 默认值为 0 表示中点的颜色,可以使用 midpoint 参数设置中点位置

  • scale_*_gradientn:多色渐变,为 colours 参数设置一个颜色向量,不加其他参数会选择范围内的均匀分布值,离散型颜色可以指定 values 参数。

示例

对于如下数据

df <- data.frame(
  x = runif(100),
  y = runif(100),
  z1 = rnorm(100),
  z2 = abs(rnorm(100))
)

df_na <- data.frame(
  value = seq(1, 20),
  x = runif(20),
  y = runif(20),
  z1 = c(rep(NA, 10), rnorm(10))
)

其默认配色为浅蓝色到深蓝色的双色渐变

# 默认双色渐变
p1 <- ggplot(df, aes(x, y)) +
  geom_point(aes(colour = z2))

# 调整双色渐变区间
p2 <- ggplot(df, aes(x, y)) +
  geom_point(aes(colour = z2)) +
  scale_colour_gradient(low = "white", high = "black")

# 三色渐变
p3 <- ggplot(df, aes(x, y)) +
  geom_point(aes(colour = z1)) +
  scale_colour_gradient2()

# 调整三色渐变区间
p4 <- ggplot(df, aes(x, y)) +
  geom_point(aes(colour = z1)) +
  scale_colour_gradient2(low = "green", high = "blue", midpoint = 1)

plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

自定义颜色范围,以及 NA 值的处理

# 自定义颜色范围,使用函数来生成 10 个连续的颜色
p5 <- ggplot(df, aes(x, y)) +
  geom_point(aes(colour = z1)) +
  scale_colour_gradientn(colours = topo.colors(10))

p6 <- ggplot(df, aes(x, y)) +
  geom_point(aes(colour = z1)) +
  scale_colour_gradientn(colours = rainbow(10))

# 去除 NA 值
p7 <- ggplot(df_na, aes(x = value, y)) +
  geom_bar(aes(fill = z1), stat = "identity") +
  scale_fill_gradient(low = "yellow", high = "red", na.value = NA)

p8 <- ggplot(df_na, aes(x, y)) +
  geom_point(aes(colour = z1)) +
  scale_colour_gradient(low = "yellow", high = "red", na.value = NA)

plot_grid(p5, p6, p7, p8, labels = LETTERS[1:4], nrow = 2)

10.3 灰色渐变

使用 startend 控制灰度范围

示例

默认颜色

p <- ggplot(mtcars, aes(mpg, wt)) + geom_point(aes(colour = factor(cyl)))

p + scale_colour_grey()

更改设置

# 设置终端灰度
p1 <- p + scale_colour_grey(end = 0.5)
# 更改主题
p2 <- p + scale_colour_grey() + theme_bw()

# 缺失值
miss <- factor(sample(c(NA, 1:5), nrow(mtcars), replace = TRUE))

p3 <- ggplot(mtcars, aes(mpg, wt)) +
  geom_point(aes(colour = miss)) +
  scale_colour_grey()
# 更改缺失值的颜色
p4 <- ggplot(mtcars, aes(mpg, wt)) +
  geom_point(aes(colour = miss)) +
  scale_colour_grey(na.value = "green")


plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

10.4 分箱渐变色

分箱渐变色与渐变色类似,只是应用的数据不同。也有三个函数,对应于双色、三色以及多色渐变

scale_*_steps()
scale_*_steps2()
scale_*_stepsn()

用起来和渐变色很相似

df <- data.frame(
  x = runif(100),
  y = runif(100),
  z1 = rnorm(100)
)

p1 <- ggplot(df, aes(x, y)) +
  geom_point(aes(colour = z1))

p2 <- ggplot(df, aes(x, y)) +
  geom_point(aes(colour = z1)) +
  scale_colour_steps(low = "skyblue", high = "blue")

p3 <- ggplot(df, aes(x, y)) +
  geom_point(aes(colour = z1)) +
  scale_colour_steps2()

p4 <- ggplot(df, aes(x, y)) +
  geom_point(aes(colour = z1)) +
  scale_colour_stepsn(colours = terrain.colors(10))

plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

10.5 色轮颜色

这种设置方式主要用于将离散型数据均匀地映射到色轮上的颜色。

这种配色方案被称为 HLC,包含三部分:

  • 色相(hue):0-360 之间的值(代表角度),代表颜色。如红、黄、蓝等

  • 亮度(luminance):表示颜色的明亮程度,0 表示黑色,100 表示白色

  • 色度(chroma):颜色的纯度,色度为 0 表示灰色,最大值根据色相和亮度的组合而变化

而标度函数

scale_*_hue(
  ...
  h = c(0, 360) + 15,
  c = 100,
  l = 65,
)

有对应的参数 hcl 用于设置这些值。

示例
dsamp <- diamonds[sample(nrow(diamonds), 1000), ]
d <- ggplot(dsamp, aes(carat, price)) + 
  geom_point(aes(colour = clarity))

p1<- d + scale_colour_hue()

p2 <- d + scale_colour_hue("Clarity")

p3 <- d + scale_colour_hue(expression(clarity[beta]))


d + scale_colour_hue(l = 40, c = 30)

plot_grid(d, p1, p2, p3, labels = LETTERS[1:4], nrow = 2)

调整亮度和色相

p1 <- d + scale_colour_hue(l = 40, c = 30)

p2 <- d + scale_colour_hue(l = 70, c = 30)

p3 <- d + scale_colour_hue(l = 70, c = 150)

p4 <- d + scale_colour_hue(l = 80, c = 150)

plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

设置色相的范围

p1 <- d + scale_colour_hue(h = c(0, 90))

p2 <- d + scale_colour_hue(h = c(90, 180))

p3 <- d + scale_colour_hue(h = c(180, 270))

p4 <- d + scale_colour_hue(h = c(270, 360))

plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

设置透明度

d <- ggplot(dsamp, aes(carat, price, colour = clarity))

p2 <- d + geom_point(alpha = 0.9)

p3 <- d + geom_point(alpha = 0.5)

p4 <- d + geom_point(alpha = 0.2)

plot_grid(p2, p3, p4, labels = LETTERS[1:4], nrow = 3)

这个图设置透明度之后好看多了

NA 值设置特殊的颜色

miss <- factor(sample(c(NA, 1:5), nrow(mtcars), replace = TRUE))

p1 <- ggplot(mtcars, aes(mpg, wt)) + geom_point(aes(colour = miss))

p2 <- ggplot(mtcars, aes(mpg, wt)) +
  geom_point(aes(colour = miss)) +
  scale_colour_hue(na.value = "black")

plot_grid(p1, p2, labels = LETTERS[1:4], nrow = 2)

10.6 Viridis 配色

viridis 提供的颜色映射,让无论是在彩色还是黑白图片均能够很容易看出区别。

它还被设计能够让色盲观众也能看清

示例

对于如下数据

> dsamp <- diamonds[sample(nrow(diamonds), 1000), ]
> dsamp
# A tibble: 1,000 x 10
   carat cut       color clarity depth table price     x     y     z
   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
 1  1.01 Very Good E     SI1      62.1    56  5461  6.43  6.48  4.01
 2  0.91 Premium   F     SI2      61.7    58  3609  6.22  6.29  3.86
 3  1.26 Very Good H     SI1      60.6    60  6546  6.97  7     4.23
 4  1.31 Premium   H     VS2      61.4    59  7550  7.01  6.96  4.29
 5  1.53 Very Good D     SI1      59.2    57 11873  7.52  7.55  4.46
 6  1.5  Ideal     H     SI2      62.4    58  8471  7.29  7.26  4.54
 7  1.24 Premium   F     VS1      61.5    57  9333  6.97  6.86  4.25
 8  1.14 Premium   H     SI1      59.3    59  5458  6.8   6.76  4.02
 9  0.62 Very Good E     SI2      63.4    56  1426  5.4   5.45  3.44
10  0.72 Premium   G     VS2      62.9    57  2795  5.73  5.65  3.58
# … with 990 more rows

默认的颜色设置方式会根据因子的顺序上色

ggplot(dsamp, aes(carat, price)) +
  geom_point(aes(colour = clarity))

viridis_d 函数用于离散数据配色,可以使用 option 参数设置不同的调色板

# viridis_d 用于离散数据
txsamp <- subset(txhousing, city %in%
                   c("Houston", "Fort Worth", "San Antonio", "Dallas", "Austin"))
d <- ggplot(data = txsamp, aes(x = sales, y = median)) +
    geom_point(aes(colour = city))

# 设置配色和标签
p1 <- d + scale_colour_viridis_d("City\nCenter")

# 选择调色板,使用 ?scales::viridis_pal 获取更多细节
p2 <- d + scale_colour_viridis_d(option = "plasma")

p3 <- d + scale_colour_viridis_d(option = "inferno")

plot_grid(d, p1, p2, p3, labels = LETTERS[1:4], nrow = 2)

设置填充色

# 设置填充色
p <- ggplot(txsamp, aes(x = median, fill = city)) +
  geom_histogram(position = "dodge", binwidth = 15000)
p1 <- p + scale_fill_viridis_d()

# 反转颜色
p2 <- p + scale_fill_viridis_d(direction = -1)

plot_grid(p1, p2, labels = LETTERS[1:4], nrow = 2)

连续型数据及分箱数据颜色设置

# 连续型数据
v <- ggplot(faithfuld) +
    geom_tile(aes(waiting, eruptions, fill = density))

p2 <- v + scale_fill_viridis_c()

p3 <- v + scale_fill_viridis_c(option = "plasma")
# 分箱数据
p4 <- v + scale_fill_viridis_b()

plot_grid(v, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

10.6 连续型和离散型

其实使用上面的函数已经够了,下面的操作也只是对上面的函数进行整合,功能都是一样的。

连续型

对于连续型数据的配色方案,其实我们上面也都涉及到。在这里我们要使用的是下面两个函数

scale_colour_continuous(
  ...,
  type = getOption("ggplot2.continuous.colour", default = "gradient")
)

scale_fill_continuous(
  ...,
  type = getOption("ggplot2.continuous.fill", default = "gradient")
)

这两个函数主要是通过获取 ggplot2.continuous.colourggplot2.continuous.fill 两个选项的值来设置颜色的,默认是渐变色

type 参数还可以设置为:

  • "viridis"
  • 返回连续颜色向量的函数
示例

对于如下数据

> faithfuld
# A tibble: 5,625 x 3
   eruptions waiting density
       <dbl>   <dbl>   <dbl>
 1      1.6       43 0.00322
 2      1.65      43 0.00384
 3      1.69      43 0.00444
 4      1.74      43 0.00498
 5      1.79      43 0.00542
 6      1.84      43 0.00574
 7      1.88      43 0.00592
 8      1.93      43 0.00594
 9      1.98      43 0.00581
10      2.03      43 0.00554
# … with 5,615 more rows

我们可以绘制一张热图

v <- ggplot(faithfuld, aes(waiting, eruptions, fill = density)) +
  geom_tile()

更改颜色方案

p1 <- v + scale_fill_continuous(type = "gradient")

p2 <- v + scale_fill_continuous(type = "viridis")

p3 <- v + scale_fill_gradient()

p4 <- v + scale_fill_viridis_c()

plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

可以看到,ACBD 是一样的。

离散型

类似于连续型设置颜色的函数,离散型函数也是通过获取两个选项的值来设置颜色的

scale_colour_discrete(
  ...,
  type = getOption("ggplot2.discrete.colour", getOption("ggplot2.discrete.fill"))
)

scale_fill_discrete(
  ...,
  type = getOption("ggplot2.discrete.fill", getOption("ggplot2.discrete.colour"))
)

例如,我们要绘制如下图形

ggplot(mpg, aes(cty, colour = factor(class), fill = factor(class))) +
  geom_density(alpha = 0.2) 

默认是以 scale_fill_hue() 配色方案

使用 scale_*_discrete 来更改配色

okabe <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")

ggplot(mpg, aes(cty, colour = factor(class), fill = factor(class))) +
  geom_density(alpha = 0.2) +
  scale_color_discrete(type = okabe) +
  scale_fill_discrete(type = okabe)

也可以通过设置 ggplot2.discrete.colourggplot2.discrete.fill 的值来更改配色

withr::with_options(
  list(ggplot2.discrete.fill = okabe),
  print(plot_cty(class))
)

还可以根据颜色变量的取值数目,设置默认的配色

discrete_palettes <- list(
  c("skyblue", "orange"),
  RColorBrewer::brewer.pal(3, "Set2"),
  RColorBrewer::brewer.pal(6, "Accent")
)

p1 <- plot_cty(year) + scale_fill_discrete(type = discrete_palettes)
p2 <- plot_cty(drv) + scale_fill_discrete(type = discrete_palettes)
p3 <- plot_cty(fl) + scale_fill_discrete(type = discrete_palettes)
# 也可以传递返回离散颜色的函数
p4 <- plot_cty(class) + scale_fill_discrete(type = scale_fill_brewer)

plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

在上面的例子中(图 A-C),我们在列表中根据离散数据的取值数目(因子的 level)设置不同的配色。

在只有 1-2level 时使用的是 skyblueorange,有 3level 使用 Set2 配色,4-6level 使用 Accent 配色。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

名本无名

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值