ggplot2图表,如何从特定点开始缩放坐标轴

5
如何使用ggplot2缩放轴,并从特定点开始。假设我们有一个范围从0到100的范围,大多数值在1到10的范围内,而一个值在100处。
require('data.table')
require('ggplot2')

test <- data.table(x=1:10,y=c(seq(1,9),100))

ggplot(test, aes(x=x,y=y)) + geom_point(size=5)

enter image description here

我想创建一个图表,y轴的刻度为1到10,间隔为1,之后再按10递增,这样值为9和100之间的空间在图表中会变得“更小”。 更新: eipi10的方法完美地实现了我的目标。只有一个问题困扰着我:如何去掉第二个图例并保持最终图表的正确比例?

enter image description here

以及绘图的代码:

test <- data.table(x=1:10,y=c(seq(1,9),100))

p1 = ggplot(test, aes(x=x,y=y,color=x)) + 
  geom_point(size=5) +
  scale_x_continuous(limits=c(0,10)) +
  coord_cartesian(ylim=c(-0.1,10)) +
  scale_y_continuous(breaks=0:10) +
  theme(plot.margin=unit(c(0,0.5,0,0),"lines"))

p2 = ggplot(test, aes(x=x,y=y,color=x)) + 
  geom_point(size=5) + #geom_point(size=5,show.legend=FALSE) +
  scale_x_continuous(limits=c(0,10)) +
  coord_cartesian(ylim=c(40,110)) +
  scale_y_continuous(breaks=c(50,100)) +
  theme(plot.margin=unit(c(0,0.5,-0.5,0), "lines"),
       axis.title.x=element_blank(),
       axis.ticks.x=element_blank(),
       axis.text.x=element_blank(),
       legend.position="none") +
 labs(y="")

gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
maxWidth = grid::unit.pmax(gA$widths[2:5], gB$widths[2:5])
gA$widths[2:5] <- as.list(maxWidth)
gB$widths[2:5] <- as.list(maxWidth)
grid.arrange(gB, gA, ncol=1, heights=c(0.15,0.85))

更新2:

下面是最终结果的一个例子。再次感谢eipi10及其出色的支持!在此输入图像描述


(1) 这正好处于一个可以接受的小修改/澄清和变色龙问题之间的界线上... (2) 如果ggplot元素有一个“幻影”特性就好了,你可以指定分配空间但不绘制任何内容。 - Ben Bolker
1
我认为不应该期望原帖作者事先知道包含图例会导致绘图对齐出现新问题,因此在我看来,关于图例的后续讨论与原始问题并不不合理。处理图例也需要类似的“grob体操”,使整体解决方案相对一致和自包含。 - eipi10
1个回答

5
一种日志转换可以实现这一点:
require('data.table')
require('ggplot2')
library(scales)

test <- data.table(x=1:10,y=c(seq(1,9),100))

ggplot(test, aes(x=x,y=y)) + 
  geom_point(size=5) +
  scale_y_log10(breaks=c(1,3,10,30,100))

enter image description here

更新: 使用ggplot2没有简单的方法来实现破坏性轴(因为ggplot2不允许您(轻松地)执行被认为是不好的做法的操作),但这里有一种方法可以获得您想要的结果。(只是不要告诉Hadley我告诉了你。)

library(data.table)
library(ggplot2)
library(scales)
library(grid)
library(gridExtra)

test <- data.table(x=1:10,y=c(seq(1,9),100))

总体策略是制作两个单独的图,一个用于y>=10,另一个用于y<10,然后将它们放在一起。我们将改变绘图边距以控制底部图形顶部和顶部图形底部之间的空间量。我们还将在顶部图形上去除x轴刻度和标签。
底部图形(y < 10):
p1 = ggplot(test[test$y<10,], aes(x=x,y=y)) + 
  geom_point(size=5) +
  scale_x_continuous(limits=c(0,10)) +
  coord_cartesian(ylim=c(-0.1,10)) +
  scale_y_continuous(breaks=0:10) +
  theme(plot.margin=unit(c(0,0.5,0,0),"lines"))

顶部图表(y >= 10)。对于此图表,我们将去除x轴标签和刻度线:

p2 = ggplot(test[test$y>=10,], aes(x=x,y=y)) + 
  geom_point(size=5) +
  scale_x_continuous(limits=c(0,10)) +
  coord_cartesian(ylim=c(10.0,110)) +
  scale_y_continuous(breaks=c(50,100)) +
  theme(plot.margin=unit(c(0,0.5,-0.5,0), "lines"),
        axis.title.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.text.x=element_blank()) +
  labs(y="")

左对齐两个图表(基于此SO答案):

gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
maxWidth = grid::unit.pmax(gA$widths[2:5], gB$widths[2:5])
gA$widths[2:5] <- as.list(maxWidth)
gB$widths[2:5] <- as.list(maxWidth)

将两个图表排列在一起。 heights 参数确定分配给每个图表的垂直空间比例:

grid.arrange(gB, gA, ncol=1, heights=c(0.15,0.85))

enter image description here

更新2: 为了包含图例,并确保图表正确地右对齐,请执行以下操作:

1)运行您更新后的问题中的代码,创建绘图p1p2,其中只有p1有一个图例。

2)使用下面的函数(来自此SO答案)将图例提取为单独的grob。

3)从p1中删除图例。

4)使用grid.arrangearrangeGrob布置图表和图例。

# Function to extract the legend as a stand-alone grob
g_legend<-function(a.gplot){
  tmp <- ggplot_gtable(ggplot_build(a.gplot))
  leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
  legend <- tmp$grobs[[leg]]
  legend
}

# Extract the legend from p1
leg = g_legend(p1)

# Remove the legend from p1
p1 = p1 + theme(legend.position="none")

# Left justify the two plots
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
maxWidth = grid::unit.pmax(gA$widths[2:5], gB$widths[2:5])
gA$widths[2:5] <- as.list(maxWidth)
gB$widths[2:5] <- as.list(maxWidth)

# Lay out the plots and the legend
grid.arrange(arrangeGrob(gB, gA, ncol=1, heights=c(0.15,0.85)),
             leg, ncol=2, widths=c(0.9,0.1))

enter image description here


有没有办法在图形中间剪掉一部分?我希望保持点x=1:9的线性关系易于看到...比如说从y=15到y=95剪掉。 - RandomDude
正是我想要的!感谢您的完美支持! - RandomDude
似乎 show.legend 不起作用。图例仍然可见。 - RandomDude
请查看我的更新帖子,我已经添加了一行代码作为注释,其中包括 show.legend=FALSE。同时,我删除了 legend.position="none" - RandomDude
只是一条提醒 - 你的空格键坏了。 - MS Berends
显示剩余4条评论

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