【问题标题】:R, ggplot - Graphs sharing the same y-axis but with different x-axis scalesR, ggplot - 共享相同 y 轴但具有不同 x 轴刻度的图
【发布时间】:2013-01-22 11:26:54
【问题描述】:

上下文

我有一些数据集/变量,我想绘制它们,但我想以一种紧凑的方式进行。为此,我希望它们共享相同的 y 轴但不同的 x 轴,并且由于分布不同,我希望其中一个 x 轴进行对数缩放,另一个进行线性缩放。

示例

假设我有一个长尾变量(我希望 x 轴在绘制时按对数缩放):

library(PtProcess)
library(ggplot2)

set.seed(1)
lambda <- 1.5
a <- 1
pareto <- rpareto(1000,lambda=lambda,a=a)
x_pareto <- seq(from=min(pareto),to=max(pareto),length=1000)
y_pareto <- 1-ppareto(x_pareto,lambda,a)
df1 <- data.frame(x=x_pareto,cdf=y_pareto)

ggplot(df1,aes(x=x,y=cdf)) + geom_line() + scale_x_log10()

还有一个普通变量:

set.seed(1)
mean <- 3
norm <- rnorm(1000,mean=mean)
x_norm <- seq(from=min(norm),to=max(norm),length=1000)
y_norm <- pnorm(x_norm,mean=mean)
df2 <- data.frame(x=x_norm,cdf=y_norm)

ggplot(df2,aes(x=x,y=cdf)) + geom_line()

我想使用相同的 y 轴并排绘制它们。

尝试 #1

我可以用 facets 做到这一点,看起来很棒,但我不知道如何使每个 x 轴具有不同的比例(scale_x_log10() 使它们都对数缩放):

df1 <- cbind(df1,"pareto")
colnames(df1)[3] <- 'var'
df2 <- cbind(df2,"norm")
colnames(df2)[3] <- 'var'
df <- rbind(df1,df2)

ggplot(df,aes(x=x,y=cdf)) + geom_line() + 
       facet_wrap(~var,scales="free_x") + scale_x_log10()

尝试 #2

使用grid.arrange,但我不知道如何使两个绘图区域保持相同的纵横比:

library(gridExtra)
p1 <- ggplot(df1,aes(x=x,y=cdf)) + geom_line() + scale_x_log10() +
      theme(plot.margin = unit(c(0,0,0,0), "lines"),
            plot.background = element_blank()) +
      ggtitle("pareto")
p2 <- ggplot(df2,aes(x=x,y=cdf)) + geom_line() + 
      theme(axis.text.y = element_blank(), 
            axis.ticks.y = element_blank(), 
            axis.title.y = element_blank(),
            plot.margin = unit(c(0,0,0,0), "lines"),
            plot.background = element_blank()) +
      ggtitle("norm")
grid.arrange(p1,p2,ncol=2)

PS:地块的数量可能会有所不同,所以我不是专门为 2 个地块寻找答案

【问题讨论】:

  • 我认为你最好的选择是使用grid.arrange(方法#2)并使用width参数,直到你得到相同的纵横比/绘图区域宽度。跨度>
  • @João Pesce 帮不了你,怀疑可能需要很多脆弱的组合,但 +1 表示问得很好且立即可以理解的问题。
  • @João Pesce 您是否尝试过从theme 中删除plot.margin,看看是否有什么不同?

标签: r ggplot2


【解决方案1】:

扩展您的尝试 #2,gtable 可能会帮助您。如果两个图表中的边距相同,那么两个图中唯一改变的宽度(我认为)是 y 轴刻度标记标签和轴文本占用的空间,这反过来会改变面板的宽度.使用here 中的代码,轴文本占用的空间应该相同,因此两个面板区域的宽度应该相同,因此纵横比应该相同。但是,结果(右侧没有边距)看起来并不漂亮。所以我在 p2 的右边添加了一点边距,然后在 p2 的左边去掉了相同的量。 p1 也是如此:我在左侧添加了一点,但在右侧移除了相同的数量。

library(PtProcess)
library(ggplot2)
library(gtable)
library(grid)
library(gridExtra)

set.seed(1)
lambda <- 1.5
a <- 1
pareto <- rpareto(1000,lambda=lambda,a=a)
x_pareto <- seq(from=min(pareto),to=max(pareto),length=1000)
y_pareto <- 1-ppareto(x_pareto,lambda,a)
df1 <- data.frame(x=x_pareto,cdf=y_pareto)

set.seed(1)
mean <- 3
norm <- rnorm(1000,mean=mean)
x_norm <- seq(from=min(norm),to=max(norm),length=1000)
y_norm <- pnorm(x_norm,mean=mean)
df2 <- data.frame(x=x_norm,cdf=y_norm)

p1 <- ggplot(df1,aes(x=x,y=cdf)) + geom_line() + scale_x_log10() +
      theme(plot.margin = unit(c(0,-.5,0,.5), "lines"),
            plot.background = element_blank()) +
      ggtitle("pareto")
p2 <- ggplot(df2,aes(x=x,y=cdf)) + geom_line() + 
      theme(axis.text.y = element_blank(), 
            axis.ticks.y = element_blank(), 
            axis.title.y = element_blank(),
            plot.margin = unit(c(0,1,0,-1), "lines"),
            plot.background = element_blank()) +
      ggtitle("norm")

gt1 <- ggplotGrob(p1)
gt2 <- ggplotGrob(p2)

newWidth = unit.pmax(gt1$widths[2:3], gt2$widths[2:3])

gt1$widths[2:3] = as.list(newWidth)
gt2$widths[2:3] = as.list(newWidth)

grid.arrange(gt1, gt2, ncol=2)

编辑 要在右侧添加第三个绘图,我们需要对绘图画布进行更多控制。一种解决方案是创建一个新的 gtable,其中包含三个绘图的空间和一个右边距的附加空间。在这里,我让绘图中的边距处理绘图之间的间距。

p1 <- ggplot(df1,aes(x=x,y=cdf)) + geom_line() + scale_x_log10() +
      theme(plot.margin = unit(c(0,-2,0,0), "lines"),
            plot.background = element_blank()) +
      ggtitle("pareto")
p2 <- ggplot(df2,aes(x=x,y=cdf)) + geom_line() + 
      theme(axis.text.y = element_blank(), 
            axis.ticks.y = element_blank(), 
            axis.title.y = element_blank(),
            plot.margin = unit(c(0,-2,0,0), "lines"),
            plot.background = element_blank()) +
      ggtitle("norm")

gt1 <- ggplotGrob(p1)
gt2 <- ggplotGrob(p2)

newWidth = unit.pmax(gt1$widths[2:3], gt2$widths[2:3])

gt1$widths[2:3] = as.list(newWidth)
gt2$widths[2:3] = as.list(newWidth)

 # New gtable with space for the three plots plus a right-hand margin
gt = gtable(widths = unit(c(1, 1, 1, .3), "null"), height = unit(1, "null"))

# Instert gt1, gt2 and gt2 into the new gtable
gt <- gtable_add_grob(gt, gt1, 1, 1)
gt <- gtable_add_grob(gt, gt2, 1, 2)
gt <- gtable_add_grob(gt, gt2, 1, 3)

grid.newpage()
grid.draw(gt)

【讨论】:

  • 很好,但是你将如何为 3 个地块做到这一点,以使它们大小相同且均匀(但不过分)间隔?例如:grid.arrange(gt1, gt2, gt2, ncol=3)。
  • @JoãoPesce 我会坚持 gtable 主题,但代替 grid.arrange(),创建一个新的 gtable,其中包含三个绘图的空间和右侧边距。查看编辑。
  • 我认为这可能需要针对较新版本的 R 进行更新。从 4.0.1 版开始,在 RStudio v. 1.3.959 中运行,当我复制并粘贴两个图的代码时,完全如上(直接在 RStudio 中,或者通过使用类似 dev.new(width=6, height=4, noRStudioGD=T) 的东西创建一个外部窗口),存在各种问题:绘图和 x 轴相互融合(有图之间没有垂直空白),标题不居中。如果我直接在 R(v. 4.0.1)而不是 RStudio 中绘制它,也会发生这种情况。
【解决方案2】:

公认的答案正是人们在使用 R 进行绘图时奔跑的原因!这是我的解决方案:

library('grid')
g1 <- ggplot(...)  # however you draw your 1st plot
g2 <- ggplot(...)  # however you draw your 2nd plot
grid.newpage()
grid.draw(cbind(ggplotGrob(g1), ggplotGrob(g2), size = "last"))

这会处理 y 轴(次要和主要)指导线,以便在多个图中轻松对齐。

删除一些轴文本、统一图例……是在创建单独的图时可以处理的其他任务,或者使用gridgridExtra 包提供的其他方法。

【讨论】:

  • 这个选项对我不起作用。 Y 轴保持浮动。
【解决方案3】:

接受的答案对我来说有点太令人生畏了。所以我找到了两种方法可以用更少的努力来解决它。两者都基于您的 Attempt #2 grid.arrange() 方法。

1. 使情节 1 也没有 y 轴
theme(axis.text.y = element_blank(), 
      axis.ticks.y = element_blank(), 
      axis.title.y = element_blank()

所以所有的情节都是一样的。您不会遇到不同纵横比的问题。您将需要使用 R 或您喜欢的图像编辑应用生成单独的 y 轴。

2. 修正并尊重纵横比

添加aspect.ratio = 1 或任何您希望与theme() 的单个地块的比率。然后在你的grid.arrange() 中使用respect=TRUE

这样,您可以在 plot1 中保留 y 轴,并且在所有图中仍保持纵横比。灵感来自this answer

希望这些对您有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    • 2021-11-07
    • 2016-12-12
    • 1970-01-01
    相关资源
    最近更新 更多