如何使用ggplot2在y轴上添加一个y截距点

5
我有一个散点图,其中y轴的刻度在某一点改变以绘制带有一些极值数据的图形。我正在尝试在y轴上添加某种视觉提示,以指示在该点处缩放发生了更改。
以下是一个绘图示例:
library(scales)
library(ggplot2)

set.seed(104)

ggdata <- data.frame('x' = rep('a',100),
                     'y' = c(runif(90, 0, 20), runif(10, 90, 100)))

transformation <- trans_new(
  "my_transformation", 
  transform = function(x) ifelse(x <= 30, x / 5, (x - 30) / 20 + 30 / 5),
  inverse = function(x) ifelse(x <= 30 / 5, x * 5, (x - 30 / 5) * 20 + 30)
)

ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  scale_y_continuous(trans = transformation, breaks = c(0, 10, 20, 30, 50, 70, 90, 110))  

散点图

我想在y轴的“tick 30”上添加一些标记,以进行比例变换。

我考虑在坐标轴上添加双刻度线,但没有看起来像双线的linetype。 产品应该类似于这个。 我知道像scale_y_log10这样的转换,但我宁愿使用动态随数据变化的自定义比例尺。

编辑:根据@Tjebo的建议,我使用annotate为y轴断点添加了“=”:

library(scales)
library(ggplot2)

set.seed(104)

ggdata <- data.frame('x' = rep('a',100),
                     'y' = c(runif(90, 0, 20), runif(10, 90, 100)))

transformation <- trans_new(
  "my_transformation", 
  transform = function(x) ifelse(x <= 30, x / 5, (x - 30) / 20 + 30 / 5),
  inverse = function(x) ifelse(x <= 30 / 5, x * 5, (x - 30 / 5) * 20 + 30)
)

mybreaks <- c(0, 10, 20, 30, 50, 70, 90, 110)
tick_linetype <- rep("solid", length(mybreaks))
tick_linetype[4] <- "blank"

ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  annotate(geom = "point", shape = "=", x = -Inf, y = 30, size = 3) +
  scale_y_continuous(trans = transformation, breaks = mybreaks) +
  theme(axis.ticks.y = element_line(linetype = tick_linetype)) + 
  coord_cartesian(clip = 'off')

solution


以下是一些相关主题:https://dev59.com/t2w05IYBdhLWcg3wgyHI - bs93
@bs93 谢谢你提供的链接。我想制作两个图,一个包含极端值,一个不包含,这可能是一个解决方案。但我希望能够在一个图中包含所有信息。我正在处理遗传数据,所以我会有成千上万的数据,因此表格不是一种有效的方法。更准确地说,我正在处理曼哈顿图的“散点图”,我想看到较低-log10(pval)的分布以及极端值。 - J. Lee
3个回答

3

我在考虑在坐标轴上添加双刻度线,但是没有类似双线的线型。

您可以使用任何字符作为点形状,例如等号、反斜杠等。

例如:

library(scales)
library(ggplot2)

set.seed(104)

ggdata <- data.frame('x' = rep('a',100),
                     'y' = c(runif(90, 0, 20), runif(10, 90, 100)))

transformation <- trans_new(
  "my_transformation", 
  transform = function(x) ifelse(x <= 30, x / 5, (x - 30) / 20 + 30 / 5),
  inverse = function(x) ifelse(x <= 30 / 5, x * 5, (x - 30 / 5) * 20 + 30)
)

ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  annotate(geom = "point", shape = "=", x = -Inf, y = 30, size = 8, color = 'red') +
  scale_y_continuous(trans = transformation, breaks = c(0, 10, 20, 30, 50, 70, 90, 110))+
  coord_cartesian(clip = 'off')

我去掉了剪辑,但你也可以留下它。颜色只是为了突出显示。

或者,更好的方法是使用文本注释。然后你还可以更改角度-非常不错。

ggplot(data = ggdata) +
  geom_jitter(aes(x = x, y = y)) +
  annotate(geom = "text", label = "=", x = -Inf, y = 30, size = 8, color = "red", angle = 45) +
  scale_y_continuous(trans = transformation, breaks = c(0, 10, 20, 30, 50, 70, 90, 110)) +
  coord_cartesian(clip = "off")

2020年4月21日,使用 reprex软件包 (v0.3.0)创建


2
谢谢!这是我一直在寻找的最接近的答案。我不知道我可以将 annotate() 中的 x 设为 -Inf,更不用说包含它不会改变整个 x 轴的比例尺了。 - J. Lee

2
我无法完全还原您提供的外观,但也许以下一些想法对您有用。
您可以将指定值设为次要断点,仅在次要断点处添加线条(这里我无法选择确切的20值,因为那已经是一个主要断点了,但也许您可以尝试调整数字以得到您喜欢的效果)。
ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  scale_y_continuous(trans = transformation, minor_breaks=20.05,breaks = c(0, 10,20, 30, 50, 70, 90, 110))+
  theme(
    panel.grid.minor.y = element_line(1)
  )

enter image description here

另一个选择是更改标签本身。在这里,我已将值为20的标签加粗并用()括起来,但您也可以添加其他符号:
ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  scale_y_continuous(trans = transformation, minor_breaks = c(0, 10, 20, 30, 50, 70, 90, 110),
                       breaks  = c(0, 10, 20, 30, 50, 70, 90, 110), labels=c(0, 10, expression(bold(("20"))), 30, 50, 70, 90, 110))

enter image description here

您可以向图表中添加一个线段,虽然由于x轴不连续,这不是最美观的选项,但也许它会激发灵感。
ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  scale_y_continuous(trans = transformation, breaks = c(0, 10, 20, 30, 50, 70, 90, 110))+
  geom_segment(aes(x=-.01,y=19.5,xend=.01,yend=20.5),size=1.5)

enter image description here

也许您可以只在绘图的底部(或顶部)部分涂上阴影:
ggplot(data = ggdata,aes(x = x, y = y)) + 
  geom_jitter() +
  scale_y_continuous(trans = transformation,breaks = c(0, 10,20, 30, 50, 70, 90, 110))+
  annotate("rect", xmin = .4, xmax = 1.6, ymin = 0, ymax = 21,
           alpha = .2)

enter image description here


谢谢你的想法Dylan。事实上,我们有类似的想法:)!添加一条水平线可能会引起一些混淆,因为我已经用虚线表示了p值。目前,我已经在“断点”处将轴线变成了红色。虽然它并没有直观地表明刻度在那个点发生了变化,但它仍然很显眼。我仍然认为在轴上加上“/”或“X”标记会更具视觉冲击力。 - J. Lee
@J.Lee,我又想到了一个额外的想法,你可以在一个区域上加阴影。这样可能不会对图中的其他线条等造成太大影响。请查看修订后的答案。 - Dylan_Gomes

0

这个解决方案可以帮助您实现所需的坐标轴外观。顺便说一下,我想警告一下,除非您明确告诉受众,否则不要打破坐标轴。在下面的代码中,我创建了两个图,一个是用于30以下的数据,另一个是极端点的数据(并删除其x轴和标签)。然后,我使用plot.margin来设置图表边距,以便将它们放在grid.arrange中时重叠一点。您可能需要调整边距以使标签对齐。

library(scales)
library(ggplot2)
library(gridExtra)
set.seed(104)

ggdata <- data.frame('x' = rep('a',100),
                     'y' = c(runif(90, 0, 20), runif(10, 90, 100)))

p1 <- ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  scale_y_continuous(breaks = seq(0,30,5), limits = c(0,30))+
  theme(plot.margin=unit(c(0,.83,0,1), "cm")) 




p2 <- ggplot(data = ggdata) + 
  geom_jitter(aes(x = x, y = y)) +
  scale_y_continuous( breaks = seq(60,100,10), limits = c(60,100)) +
  scale_x_discrete()+
  theme(axis.title.x=element_blank(),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        plot.margin=unit(c(0,1,-0.1,1), "cm"))


grid.arrange(p2,p1)

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