欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

10. ggplot2 - 轴和比例位置 (i)

最编程 2024-03-31 17:56:37
...

10 坐标轴和刻度位置

每个图都有两个对应于坐标轴的 x 和 y 刻度图形属性。通常,用户明确指定映射到 x 和 y 的变量,但有时图形属性被映射到计算变量,就像geom_histogram()那样,而且不需要明确指定。例如,和以下绘图规则相同:

ggplot(mpg, aes(x = displ)) + geom_histogram()
ggplot(mpg, aes(x = displ, y = after_stat(count))) + geom_histogram()

尽管第一个示例没有明确说明 y 的图形映射,但它仍然存在,并且与(在本例中)连续位置比例相关联。

10.1 数值缩放(Numeric)

最常见的连续位置刻度是默认的scale_x_continuous()scale_y_continuous()函数。在最简单的情况下,它们线性地从数据值映射到图上的一个位置。对于连续变量还有一些其他的位置缩放scale_x_log10()scale_x_reverse()等,其中大部分是用于提供轻松访问常用变换的函数:

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

base
base + scale_x_reverse()
base + scale_y_reverse()
image
image
image

10.1.1 界限设置(limits)

10.1.2 越界值

默认情况下,ggplot2 将超出比例限制的数据转换为NA。这意味着更改尺度的限制与视觉上放大到绘图区域并不完全相同。如果您的目标是放大图的一部分,最好使用 coord_cartesian()xlimylim参数:

base <- ggplot(mpg, aes(drv, hwy)) + 
  geom_hline(yintercept = 28, colour = "red") + 
  geom_boxplot() 

base
base + coord_cartesian(ylim = c(10, 35)) # zoom only
base + ylim(10, 35) # alters the boxplot
#> Warning: Removed 6 rows containing non-finite values (stat_boxplot).
image.png

左边和中间的图唯一的区别是后者被放大了。由于范围的限制,一些离群点没有显示出来,但箱线图本身保持不变。相比之下,在右侧的图中,其中一个箱线图发生了变化。当ylim()于设置比例限制时,所有公路里程大于 35 的观测值在统计数据(在本例中为箱线图)之前转换为NA。这使得样本中值向下移动。

虽然默认的行为是将出界限值转换为NA,但你可以通过设置尺度的oob参数来覆盖它,这是一个应用于所有尺度范围外的观察的函数。默认值是scales::censor()它用NA替换任何超出限制的值。另一个选项是scales::squish()将所有值压缩到这个范围内。下面是一个使用填充比例的例子:

df <- data.frame(x = 1:6, y = 8:13)
base <- ggplot(df, aes(x, y)) + 
  geom_col(aes(fill = x)) +                    # bar chart
  geom_vline(xintercept = 3.5, colour = "red") # for visual clarity only

base
base + scale_fill_gradient(limits = c(1, 3))
base + scale_fill_gradient(limits = c(1, 3), oob = scales::squish)
image.png

左侧显示默认填充颜色,范围从深蓝色到浅蓝色。在中间面板中,填充的图形属性的比例限制减少了,因此最右边的三个条的值被替换NA并映射到灰色阴影。在某些情况下,这是我们想要的效果,但通常不是:右侧面板通过oob适当修改函数来解决此问题。

10.1.3 扩大视觉范围

如果您有一双鹰眼,您就会注意到轴的可视范围实际上稍微超出了我在各种例子中指定的数字限制。这可确保数据不会与轴重叠,这通常(但并非总是)是可取的。

你可以用expand = c(0, 0)消除这个空间。通常最好删除此空间的一种情况是使用geom_raster()

ggplot(faithfuld, aes(waiting, eruptions)) + 
  geom_raster(aes(fill = density)) + 
  theme(legend.position = "none")

ggplot(faithfuld, aes(waiting, eruptions)) + 
  geom_raster(aes(fill = density)) + 
  scale_x_continuous(expand = c(0,0)) + 
  scale_y_continuous(expand = c(0,0)) +
  theme(legend.position = "none")
image.png

10.1.5 中断(Breaks)

在上面的示例中,我手动指定了中断,但 ggplot2 还允许您将breaks传递给函数。这个函数应该有一个参数来指定比例的限制(一个长度为 2 的数字向量),它应该返回一个中断的数字向量。您可以编写自己的 break 函数,但由于有了scales包,在许多情况下并不需要这样做,它提供了一些有用的工具:

  • scales::breaks_extended()为数字轴创建自动中断。
  • scales::breaks_log()创建适合对数轴的中断。
  • scales::breaks_pretty()为日期/时间创建“pretty”。
  • scales::breaks_width()创建等距的中断。

breaks_extended()函数是 ggplot2 中使用的标准方法,因此下面的前两个图是相同的。我可以通过设置更改所需的中断次数n = 2,如第三个图所示。请注意,breaks_extended()n当做建议而不是严格约束。如果您需要指定确切的中断,最好手动进行。

toy <- data.frame(
  const = 1, 
  up = 1:4,
  txt = letters[1:4], 
  big = (1:4)*1000,
  log = c(2, 5, 10, 2000)
)
toy
#>   const up txt  big  log
#> 1     1  1   a 1000    2
#> 2     1  2   b 2000    5
#> 3     1  3   c 3000   10
#> 4     1  4   d 4000 2000
axs <- ggplot(toy, aes(big, const)) + 
  geom_point() + 
  labs(x = NULL, y = NULL)
axs
axs + scale_x_continuous(breaks = scales::breaks_extended())
axs + scale_x_continuous(breaks = scales::breaks_extended(n = 2))
image.png

另一种有时有用的方法是指定一个固定width值来定义中断之间的间距。该breaks_width()函数用作此目的。下面的第一个示例显示了如何将宽度固定为特定值;第二个示例说明了使用offset将所有中断移动指定数量的参数:

axs + scale_x_continuous(breaks = scales::breaks_width(800))
axs + scale_x_continuous(breaks = scales::breaks_width(800, offset = 200))
axs + scale_x_continuous(breaks = scales::breaks_width(800, offset = -200))
image.png

请注意设置偏移量 200 和 -200 之间的区别。

您可以通过将它们设置为完全抑制中断NULL

axs + scale_x_continuous(breaks = NULL)
image

10.1.6 小中断(Minor breaks)

您可以通过向minor_breaks参数提供位置的数字向量来调整次要中断(出现在主要网格线之间的未标记的微弱网格线)。

小中断对于对数刻度特别有用,因为它们提供了一个清晰的视觉指示,表明刻度是非线性的。为了展示它们,我将首先创建一个包含次要中断值的向量(在转换后的比例上),%o%用于快速生成乘法表,并使用as.numeric()该表展平为向量。

mb <- unique(as.numeric(1:10 %o% 10 ^ (0:3)))
mb
#>  [1]     1     2     3     4     5     6     7     8     9    10    20    30
#> [13]    40    50    60    70    80    90   100   200   300   400   500   600
#> [25]   700   800   900  1000  2000  3000  4000  5000  6000  7000  8000  9000
#> [37] 10000

下图说明了设置小中断的效果:

log_base <- ggplot(toy, aes(log, const)) + geom_point()

log_base + scale_x_log10()
log_base + scale_x_log10(minor_breaks = mb)
image.png

breaks一样,您还可以向minor_breaks提供一个函数,例如scales::minor_breaks_n()scales::minor_breaks_width()有助于控制次要中断的函数。

10.1.7 标签(Labels)

每个中断都与一个标签相关联,可以通过将labels参数设置为 scale 函数来更改这些标签:

axs + scale_x_continuous(breaks = c(2000, 4000), labels = c("2k", "4k"))
image

在上面的示例中,我手动指定了labels向量,但 ggplot2 还允许您传递label函数。传递给的labels函数应接受中断的数字向量作为输入并返回标签的字符向量(与输入的长度相同)。scales 包提供了许多工具,可以为您自动构建标签函数。一些有用的数字数据示例包括:

  • scales::label_bytes()将数字格式化为千字节、兆字节等。
  • scales::label_comma()将数字格式化为带逗号的小数。
  • scales::label_dollar()将数字格式化为货币。
  • scales::label_ordinal()按排名顺序格式化数字:第 1、第 2、第 3 等。
  • scales::label_percent()将数字格式化为百分比。
  • scales::label_pvalue()将数字格式化为 p 值:<.05、<.01、.34 等。

下面显示了一些示例来说明如何使用这些函数:

axs + scale_y_continuous(labels = scales::label_percent())
axs + scale_y_continuous(labels = scales::label_dollar(prefix = "", suffix = "€"))
image.png

您可以使用labels = NULL. 这将从轴或图例中删除标签,同时保持其其他属性不变:

axs + scale_x_continuous(labels = NULL)
image

10.1.8 转换(Transformations)

处理连续数据时,默认是从数据空间线性映射到图形属性空间。可以使用转换覆盖此默认值。每个连续尺度都有一个trans参数,允许使用各种变换:

# convert from fuel economy to fuel consumption
ggplot(mpg, aes(displ, hwy)) + 
  geom_point() + 
  scale_y_continuous(trans = "reciprocal")

# log transform x and y axes
ggplot(diamonds, aes(price, carat)) + 
  geom_bin2d() + 
  scale_x_continuous(trans = "log10") +
  scale_y_continuous(trans = "log10")
image.png

这个变换是由一个“变换器”来完成的,它描述变换、它的逆以及如何绘制标签。您可以使用scales::trans_new()构建自己的转换器,但是,如上图所示,ggplot2理解许多由scales包提供的常见转换。下图列出了最常见的转换:

image.png

为简化起见,ggplot2 为最常见的变换提供了便利的函数:scale_x_log10()scale_x_sqrt()scale_x_reverse()在 x 轴上提供相关变换,为 y 轴提供类似的函数。因此,下面的代码生成与上一个示例中显示的相同的两个图:

ggplot(mpg, aes(displ, hwy)) + 
  geom_point() +
  scale_y_reverse()

ggplot(diamonds, aes(price, carat)) + 
  geom_bin2d() + 
  scale_x_log10() +
  scale_y_log10()

注意,没有任何东西阻止您手动执行这些转换。例如,不使用scale_x_log10()来转换比例,而是转换数据并绘制log10(x)。图形属性的外观将是相同的,但刻度标签将不同。具体来说,如果您使用变换的比例尺,轴将在原始数据空间中进行标记;如果对数据进行转换,坐标轴将在转换后的空间中进行标记。

# manual transformation
ggplot(mpg, aes(log10(displ), hwy)) + 
  geom_point()

# transform using scales
ggplot(mpg, aes(displ, hwy)) + 
  geom_point() + 
  scale_x_log10()
image.png

无论使用哪种方法,转换都发生在任何统计摘要之前。要在统计计算之后进行转换,请使用coord_trans()