【问题标题】:Is there a way to align 2 independent axes in an R graph?有没有办法在 R 图中对齐 2 个独立的轴?
【发布时间】:2016-06-30 21:22:17
【问题描述】:

我正在绘制具有不同轴的图表。问题是我希望 2 个轴穿过一个点,其余的并不重要。有可能吗?

这是一个可重现的代码:

plot(x = -10:10, y = -10:10)
abline(v=0,lty = 2)
par(new =TRUE)
plot(x = -10:50, y = seq(-5,5,length.out = length(-10:50)), xaxt = "n", yaxt = "n", bty ="n")
abline(v=0,lty = 3)
axis(3, col="red",col.axis="red",las=2, cex.axis = 1)
axis(4, col="red",col.axis="red",las=2, cex.axis = 1)

这是输出:

我基本上希望垂直线在 0 处相互交叉。

还有另一种写法吗(这不是很准确,我想要一些可以自动完成的东西,而不是手动设置xlim,因为我有很多事情要做。另外,当图像已调整大小,它失去了与 2 0 的对齐):

plot(x = -10:10, y = -10:10)
abline(v=0,lty = 2)
par(new =TRUE)
plot(x = -10:50, y = seq(-5,5,length.out = length(-10:50)), 
     xaxt = "n", yaxt = "n", bty ="n",
     xlim = c(-50,50))
abline(v=0,lty = 3, lwd = 5)
axis(3, col="red",col.axis="red",las=2, cex.axis = 1)
axis(4, col="red",col.axis="red",las=2, cex.axis = 1)

输出应该使用类似于 biplot.prcomp 用于对齐箭头和轴的内容:

已编辑

使用 PCA,它只适用于 y 轴,而不适用于 x 轴。

new_lim <- function(a, type = 1) {
  newdata_ratio <-  NULL
  i <- type * 2 - 1
  old_lim <- par("usr")[i:(i+1)] + c(diff(par("usr")[i:(i+1)]) * 0.04 / 1.08, 
                                     diff(par("usr")[i:(i+1)]) * -0.04 / 1.08)
  old_ratio <- old_lim[1] / old_lim[2]
  newdata_ratio <- if (max(a) <= 0) -1.0e+6 else min(a) / max(a)
  if (old_ratio >= newdata_ratio ) {
    new_min <- min(a)
    new_max <- min(a) / old_ratio
  } else {
    new_min <- max(a) * old_ratio
    new_max <- max(a)
  }
  c(new_min, new_max)
}
s1= rnorm(50,mean = 12)
s2= rnorm(50, mean = 17)
s3= rnorm(50, mean = 20)
library(vegan)
pca=rda(cbind(s1,s2,s3))
pca.scoop=scores(pca, scaling = 2)
biplot(pca)

par(mar=c(4, 4, 4, 4))
plot(pca, xlab = "x1", ylab = "y1",
     type = c("p"),
     main= "main",
     scaling = 2,
     choices = c(1,2),
     xlim =c(min(pca.scoop$sites[,1]),max(pca.scoop$sites[,1])),
     ylim = c(min(pca.scoop$sites[,2]),max(pca.scoop$sites[,2])),
     bty = "o",#"l"
     pch=4)
abline(v = 0, lty = 2); abline(h = 0, lty = 2)

x2 <- -10:20
y2 <- seq(40, 10, length.out = length(x2))
par(new =TRUE)
plot(x2, y2, 
     xlim = new_lim(x2), 
     ylim = new_lim(y2, 2), axes = F, ann = F)
axis(3, col = "red", col.axis = "red") # axes=F is equivalent to xaxt="n", yaxt="n" and bty="n"
axis(4, col = "red", col.axis = "red") # ann=F is equivalent to xlab=NA and ylab=NA
mtext("x2", side = 3, line = 2.5, col = "red")
mtext("y2", side = 4, line = 2.5, col = "red")
# box(bty="7", col="red")  # if you want.

【问题讨论】:

    标签: r plot axis


    【解决方案1】:

    是否可以根据第一张图对齐第二张图?

    是的,是的。但这有点复杂,因为需要逻辑判断。

    此函数new_lim(a, type) 计算第一个图形的xlim(或ylim)以及图形参数中的正负比。它判断它使用哪个值作为第二个图的参数,min(第二个数据)或 max,并根据第一个图的比率计算另一个值。输出是第二个图的最小值和最大值,_lim。参数a 是第二个 x 或 y 数据。 type = 1(默认;可省略)用于xlimtype = 2type = 可省略)用于ylim

    new_lim <- function(a, type = 1) {
      newdata_ratio <-  NULL
      i <- type * 2 - 1
      old_lim <- par("usr")[i:(i+1)] + c(diff(par("usr")[i:(i+1)]) * 0.04 / 1.08, 
                                         diff(par("usr")[i:(i+1)]) * -0.04 / 1.08)
      old_ratio <- old_lim[1] / old_lim[2]
      newdata_ratio <- if (max(a) <= 0) -1.0e+6 else min(a) / max(a)
      if (old_ratio >= newdata_ratio ) {
        new_min <- min(a)
        new_max <- min(a) / old_ratio
      } else {
        new_min <- max(a) * old_ratio
        new_max <- max(a)
      }
      c(new_min, new_max)
    }
    

    [注意] 此函数需要存在第一个图形并包含第一个数据范围的零。第二个数据的范围不包括零是没有问题的。

    x2 <- -40:20
    y2 <- seq(40, 10, length.out = length(-40:20))
    
    par(mar=c(4, 4, 4, 4))
    plot(x = -15:5, y = -5:15, xlab = "x1", ylab = "y1")
    abline(v = 0, lty = 2); abline(h = 0, lty = 2)
    
    par(new =TRUE)
    plot(x2, y2, xlim = new_lim(x2), ylim = new_lim(y2, 2), axes = F, ann = F)
    axis(3, col = "red", col.axis = "red") # axes=F is equivalent to xaxt="n", yaxt="n" and bty="n"
    axis(4, col = "red", col.axis = "red") # ann=F is equivalent to xlab=NA and ylab=NA
    mtext("x2", side = 3, line = 2.5, col = "red")
    mtext("y2", side = 4, line = 2.5, col = "red")
    # box(bty="7", col="red")  # if you want.
    

    已编辑[注意]

    当您将此函数与 plot(class.rda) 一起使用并通过 Rsutdio 更改纵横比时,输出会与您想要的不同。

    x2 <- -10:20
    y2 <- seq(40, 10, length.out = length(x2))
    library(vegan) 
    s1= rnorm(50,mean = 12); s2= rnorm(50, mean = 17); s3= rnorm(50, mean = 20)
    pca=rda(cbind(s1,s2,s3))
    pca.scoop=scores(pca, scaling = 2)
    biplot(pca)
    par(new =TRUE)
    plot(x2, y2, 
         xlim = new_lim(x2), 
         ylim = new_lim(y2, 2), axes = F, ann = F)
    axis(3, col = "red", col.axis = "red")
    axis(4, col = "red", col.axis = "red")
    mtext("x2", side = 3, line = 2, col = "red")
    mtext("y2", side = 4, line = 2, col = "red")
    

    【讨论】:

    • 这很有趣。我能够重现您的代码。但是当我运行 PCA 然后尝试将两个轴与您的函数对齐时,我只能对齐 y 轴。
    • 实际上,使用豌豆的纵横比发生了一些变化,当我们重新缩放 PCA 时,它会改变函数 new_lim 中给出的比率。我想知道是否有一种方法可以纠正什么时候是一个需要被情节保留的纵横比。
    • 问题是当我在 RStudio 中调整绘图窗口的大小时。我认为,这是因为当我调整 PCA 绘图的大小和函数中的比率时,比率是不同的。如果你只运行一次代码,它就可以工作。我想目前它回答了这个问题。正如您在 biplot.prcomp 中看到的那样,您可以按照自己的方式调整绘图的大小,这不是问题。两组轴在 0 处相交。
    • 好的,我明白了你的问题,并在我的环境中重现。但是我没有想到一个好主意。如果你使用par(pty = "s"),我猜这个函数总是让两组轴像plot.prcomp()一样在0处相交,但图形是方形的......
    • 我找到了解决方法,但它会产生不同的输出。此问题的原因是使用参数asp = 1 绘制(rda.class)。如果您的asp不是1,您可以通过处理getAnywhere(plot.cca)getAnywhere(biplot.rda)asp = 1的所有内容并制作您的功能来解决此问题。
    【解决方案2】:

    这不是一个漂亮的解决方案,但只要您的 x 轴始终穿过 0 值,您就可以为这两个图设置 xlim=c(-max(c(-min(x),max(x))),max(c(-min(x),max(x))))。这将使顶部和底部轴的 x 轴始终以 0 为中心。如果您愿意,也可以对 y 轴进行同样的操作。

    # Set graphing parameters
    par(mar = c(5,4,4,4) + 0.1) # This can be reset later with "dev.off()"
    
    # Plot the first graph
    plot(x = -10:10, y = -10:10, 
         xlim=c(-max(c(-min(x),max(x))),max(c(-min(x),max(x)))),
         xlab="x-label-1",ylab="y-label-1") # Added labels to be changed
    abline(v=0,lty = 2)
    
    # Plot the second graph using new axes
    par(new =TRUE)
    plot(x = -10:50, y = seq(-5,5,length.out = length(-10:50)), 
         xaxt = "n", yaxt = "n", bty ="n",
         xlim=c(-max(c(-min(x),max(x))),max(c(-min(x),max(x)))),
         xlab=NA,ylab=NA) # Remove x- and y-axis labels
    abline(v=0,lty = 3)
    axis(3, col="red",col.axis="red",las=2, cex.axis = 1)
    axis(4, col="red",col.axis="red",las=2, cex.axis = 1)
    mtext("x-label-2", side = 3, line = 3, cex = par("cex.lab")) # Labeled secondary x-axis
    mtext("y-label-2", side = 4, line = 3, cex = par("cex.lab")) # Labeled secondary y-axis
    

    给出:

    我希望这有效!如果您想用标题标记图表,则需要使用 par(mar()) 的值。

    【讨论】:

    • 第二张图可以和第一张图对齐吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多