如何在ggplot2中获取反转的log10比例尺?

55

我想用ggplot2制作一个带有反转的对数10底x轴的图表:

require(ggplot2)
df <- data.frame(x=1:10, y=runif(10))
p <- ggplot(data=df, aes(x=x, y=y)) + geom_point() 

然而,似乎我只能选择对数标尺或者反向标尺:

p + scale_x_reverse() + scale_x_log10() 

对数刻度,但不是倒序

p + scale_x_reverse()

反向比例尺,但不是对数

我想这是合理的,如果一个层只能有一个比例尺。当然,我可以通过在数据框中自己执行对数转换来进行欺骗,df$xLog <- log10(df$x) 但是这种解决方案似乎与ggplot的精神相悖。是否有一种方法可以在不对ggplot调用外部进行数据转换的情况下获得这种类型的图形?


2
我本以为这个也会起作用,但显然有点复杂。有一个解决方法似乎在最近的版本中已经失效了。如果 @kohske 或其他人想不出另一个解决办法,可能需要提出一个好的功能请求。 - joran
4个回答

67

[请查看@user236321的回答,那里提供了一个更现代的(2022年4月后)答案。]

@joran在评论中提供的链接给出了正确的思路(构建自己的变换),但是已经过时,因为ggplot2现在使用了新的scales包。通过查看scales包中的log_transreverse_trans,可以获得指导和灵感,可以制作一个reverselog_trans函数:

library("scales")
reverselog_trans <- function(base = exp(1)) {
    trans <- function(x) -log(x, base)
    inv <- function(x) base^(-x)
    trans_new(paste0("reverselog-", format(base)), trans, inv, 
              log_breaks(base = base), 
              domain = c(1e-100, Inf))
}

这可以简单地使用:

p + scale_x_continuous(trans=reverselog_trans(10))

这给出了图示:

在此输入图片描述

使用稍微不同的数据集以确保轴已经反转:

DF <- data.frame(x=1:10,  y=1:10)
ggplot(DF, aes(x=x,y=y)) + 
  geom_point() +
  scale_x_continuous(trans=reverselog_trans(10))

在此输入图片描述


很抱歉,这个解决方案已经不再适用了: reverselog_trans(10) 函数出错:找不到 "trans_new" 函数。 明确添加 scales::trans_new 只会导致新的错误,似乎 scales 函数已经更新了 :( - Richard
3
@Richard 我刚刚检查了一下,它可以工作,但是scales包必须附加到搜索路径中(library("scales"))。这在答案中不太清楚(并且在当时可能不是必需的)。正在更新。 - Brian Diggs
这么简单吗?!非常感谢!! - Richard
1
或者使用::符号显式地从scales包中调用函数。 trans <- function(x) -log(x, base) inv <- function(x) base^(-x) scales::trans_new(paste0("reverselog-", format(base)), trans, inv, scales::log_breaks(base = base), domain = c(1e-100, Inf)) }``` - Andrew
注意:reverselog_trans函数已经出现在CRAN https://cran.r-project.org/web/packages/ACSNMineR/index.html(可以在ACSNMineR / R / plots.R中找到)。 - flies
如果那是从包中导出的,你应该使用它来组成一个答案。这将是一个很好的补充。 - Brian Diggs

13

ggforce 包中有一个 trans_reverser() 函数可以完成这个任务。

library(ggplot2)
library(ggforce)

p <- ggplot() +
  geom_line(aes(x = 1:100, y = 1:100))

p +
  scale_x_continuous(trans = trans_reverser('log10')) +
  annotation_logticks(sides = 'tb') +
  theme_bw()

编辑:scales包的v1.2.0版本开始,这也可以使用。

library(scales)

p +
  scale_x_continuous(
    trans  = compose_trans("log10", "reverse"),
    breaks = c(100, 10, 1)
  ) +
  annotation_logticks(sides = 'tb') +
  theme_bw()

p +
  scale_x_continuous(
    trans  = compose_trans("log10", "reverse"),
    labels = label_log()
  ) +
  annotation_logticks(sides = 'tb') +
  theme_bw()

使用 reprex 包 (v0.3.0) 于2020年11月14日创建


1
日志刻度不正确。 刻度应该在每个十的幂(1、10、100)附近间隔更远,然后再靠近。 - Jeff Bezos

5

我想更新一下这个问题的答案,而且不需要编写自己的转换。截至scales版本1.2.0(于2022年4月发布),变换合成由scales包直接处理。使用scale_x_continuous(),将trans参数作为一个向量与log10reverse同时使用。你需要先使用log10,否则将会出现错误;变换按照指定的顺序应用。

p + scale_x_continuous(trans = c("log10", "reverse"))
scales::compose_trans 的文档甚至以此用法为例。

3

在ggplot函数中,可以直接在aes()说明中应用对数:

require(ggplot2)
df <- data.frame(x=1:10, y=runif(10))
p <- ggplot(data=df, aes(x = log10(x), y=y)) + geom_point() 

然后反转x轴

p + scale_x_reverse()

以这种方式,您的数据不会被改变,但是您可以扩展图形。

1
我喜欢这个答案,它很有效。除了使用 scale_x_reverse() 之外,还可以在上方写入 -log10(x) - Tapper
1
谢谢!我认为解决方案-log10(x)很好,但必须小心,因为最终会得到负值的X轴。 - Joaquín L

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接