自定义缩放轴后,ggplot2缺少标签

crl*_*wbm 7 r ggplot2 axis-labels

我正在尝试使用ggplot2和自定义X轴缩放比例scales::trans_new()。但是,当我这样做时,某些轴标签会丢失。有人可以帮我找出原因吗?

设定:

library(tidyverse)

# the data
ds <- tibble(
  myx = c(1, .5, .1, .01, .001, 0),
  myy = 1:6
)

# the custom transformation
forth_root_trans_rev <- scales::trans_new(
  name = "sign_fourth_root_rev",
  transform = function (x) { - abs(x)^(1/4) },
  inverse = function (x) { x^4 }
)
Run Code Online (Sandbox Code Playgroud)

情节1:

当我尝试绘制此图x = 0时,迷路的标签会丢失。

# plot - missing x-label at `0`
ggplot(ds, aes(x = myx, y = myy)) + 
  geom_line() + 
  geom_point() + 
  scale_x_continuous(
    trans = forth_root_trans_rev,
    breaks = sort(unique(ds$myx)),
  )
Run Code Online (Sandbox Code Playgroud)

<code> 0 </ code>处缺少x标签

剧情2

当我在图形的两边添加一些空间时,甚至会丢失更多的x标签。

# plot - missing x-labels below 0.5
ggplot(ds, aes(x = myx, y = myy)) + 
  geom_line() + 
  geom_point() +
  scale_x_continuous(
    trans = forth_root_trans_rev,
    breaks = sort(unique(ds$myx)),
    expand = expand_scale(mult = c(.1, .6))
  )
Run Code Online (Sandbox Code Playgroud)

缺少0.5以下的x标签

我认为这与这个旧问题有关:https : //github.com/tidyverse/ggplot2/issues/980。但是,我不知道如何应用此转换并保留所有x标签。

我要去哪里错了?

Z.L*_*Lin 5

这里的问题是由两个因素共同造成的:

  1. 您的 x 轴值(转换后)落在 [-1, 0] 范围内,因此任何扩展(无论是加法还是乘法)都会微移最终范围以涵盖正值和负值。

  2. 您的自定义转换在该区域中不是一对一的[<some negative number>, <some positive number>]

它是如何发生的

在用于构建 ggplot 对象的所有代码深处的某个地方(您可以ggplot2:::ggplot_build.ggplot在打印绘图之前运行并单步执行layout$setup_panel_params(),但我不建议临时用户这样做......兔子洞真的很深),x 轴休息时间按以下方式计算:

  1. 获取转换值的限制(在c(1, .5, .1, .01, .001, 0)问题中,这将是(-1, 0))。
  2. 如果适用,请向限制添加扩展(连续轴的默认扩展为两侧各 5%,因此限制变为(-1.05, 0.05))。
  3. 对极限应用逆变换(采用x^4极限产生(1.215506, 0.000006))。
  4. 对用户输入的中断和限制应用转换(对于中断,c(1, .5, .1, .01, .001, 0)变为(-1.0000000, ..., 0.0000000),但对于限制,(1.215506, 0.000006)现在变为(-1.05, -0.05),它比更窄(-1.05, 0.05))。
  5. 超出限制范围的突破将被删除(由于限制现在停止于 -0.05,0 处的突破将被删除)。

如何解决这个问题

您可以使用 来修改您的转换sign()以保留正/负值,以便转换在整个范围内是一对一的,正如 Hadley 在您链接的 GH 问题的讨论中所建议的那样。例如:

# original
forth_root_trans_rev <- scales::trans_new(
  name = "sign_fourth_root_rev",
  transform = function (x) { - abs(x)^(1/4) },
  inverse = function (x) { x^4 }
)

# new
forth_root_trans_rev2 <- scales::trans_new(
  name = "sign_fourth_root_rev",
  transform = function (x) { -sign(x) * abs(x)^(1/4) },
  inverse = function (x) { -sign(x) * abs(x)^4 }
)

library(dplyr)
library(tidyr)

# comparison of two transformations
# y1 shows a one-to-one mapping in either (-Inf, 0] or [0, Inf) but not both;
# y2 shows a one-to-one mapping in (-Inf, Inf)
data.frame(x = seq(-1, 1, 0.01)) %>%
  mutate(y1 = x %>% forth_root_trans_rev$transform() %>% forth_root_trans_rev$inverse(),
         y2 = x %>% forth_root_trans_rev2$transform() %>% forth_root_trans_rev2$inverse()) %>%
  gather(trans, y, -x) %>%
  ggplot(aes(x, y, colour = trans)) +
  geom_line() +
  geom_vline(xintercept = 0, linetype = "dashed") +
  facet_wrap(~trans)
Run Code Online (Sandbox Code Playgroud)

比较图

用法

p <- ggplot(ds, aes(x = myx, y = myy)) + 
  geom_line() + 
  geom_point() + 
  theme(panel.grid.minor = element_blank())

p + 
  scale_x_continuous(
    trans = forth_root_trans_rev2,
    breaks = sort(unique(ds$myx))
  )
p + 
  scale_x_continuous(
    trans = forth_root_trans_rev2,
    breaks = sort(unique(ds$myx)),
    expand = expand_scale(mult = c(.1, .6)) # with different expansion factor, if desired
  )
Run Code Online (Sandbox Code Playgroud)

地块