【问题标题】:How can I plot with 2 different y-axes?如何使用 2 个不同的 y 轴进行绘图?
【发布时间】:2011-05-26 17:53:13
【问题描述】:

我想在 R 中叠加两个散点图,这样每组点都有自己的(不同的)y 轴(即,在图中的位置 2 和 4),但这些点似乎叠加在同一个图上。

plot 可以做到这一点吗?

编辑显示问题的示例代码

# example code for SO question
y1 <- rnorm(10, 100, 20)
y2 <- rnorm(10, 1, 1)
x <- 1:10
# in this plot y2 is plotted on what is clearly an inappropriate scale
plot(y1 ~ x, ylim = c(-1, 150))
points(y2 ~ x, pch = 2)

【问题讨论】:

  • 请提供样本数据。从美学的角度来看,这通常是一个坏主意。
  • ggplot2 特定情况下的答案和讨论:stackoverflow.com/questions/3099219/…(搜索[r] two y-axes[r] twoord.plot)——还有一些其他相关的答案,虽然(令我惊讶的是因为它是一个 R 常见问题解答)没有相同的
  • @chase - 我添加了一个问题的工作示例。感谢您就美学问题提出警告。

标签: r plot yaxis


【解决方案1】:

更新:在 R wiki http://rwiki.sciviews.org/doku.php?id=tips:graphics-base:2yaxes 上复制的材料,链接现已损坏:也可从 the wayback machine 获得

同一图上有两个不同的 y 轴

(一些材料最初由 Daniel Rajdl 2006/03/31 15:26)

请注意,很少有适合在同一个地块上使用两种不同比例尺的情况。很容易误导图形的查看者。检查以下两个关于此问题的示例和 cmets(example1example2 来自Junk Charts)以及this article by Stephen Few(其结论是“我当然不能一劳永逸地得出结论,即轴从来没有用过;只是我想不出有什么情况可以根据其他更好的解决方案来保证它们。”)另请参阅this cartoon 中的第 4 点 ...

如果你确定了,基本的方法是创建你的第一个图,设置par(new=TRUE)以防止R清除图形设备,使用axes=FALSE创建第二个图(并将xlabylab设置为为空白 - ann=FALSE 也应该可以工作)然后使用 axis(side=4) 在右侧添加一个新轴,并使用 mtext(...,side=4) 在右侧添加一个轴标签。这是一个使用一些虚构数据的示例:

set.seed(101)
x <- 1:10
y <- rnorm(10)
## second data set on a very different scale
z <- runif(10, min=1000, max=10000) 
par(mar = c(5, 4, 4, 4) + 0.3)  # Leave space for z axis
plot(x, y) # first plot
par(new = TRUE)
plot(x, z, type = "l", axes = FALSE, bty = "n", xlab = "", ylab = "")
axis(side=4, at = pretty(range(z)))
mtext("z", side=4, line=3)

plotrix 包中的twoord.plot() 会自动执行此过程,latticeExtra 包中的doubleYScale() 也是如此。

另一个例子(改编自 Robert W. Baer 的 R 邮件列表帖子):

## set up some fake test data
time <- seq(0,72,12)
betagal.abs <- c(0.05,0.18,0.25,0.31,0.32,0.34,0.35)
cell.density <- c(0,1000,2000,3000,4000,5000,6000)

## add extra space to right margin of plot within frame
par(mar=c(5, 4, 4, 6) + 0.1)

## Plot first set of data and draw its axis
plot(time, betagal.abs, pch=16, axes=FALSE, ylim=c(0,1), xlab="", ylab="", 
   type="b",col="black", main="Mike's test data")
axis(2, ylim=c(0,1),col="black",las=1)  ## las=1 makes horizontal labels
mtext("Beta Gal Absorbance",side=2,line=2.5)
box()

## Allow a second plot on the same graph
par(new=TRUE)

## Plot the second plot and put axis scale on right
plot(time, cell.density, pch=15,  xlab="", ylab="", ylim=c(0,7000), 
    axes=FALSE, type="b", col="red")
## a little farther out (line=4) to make room for labels
mtext("Cell Density",side=4,col="red",line=4) 
axis(4, ylim=c(0,7000), col="red",col.axis="red",las=1)

## Draw the time axis
axis(1,pretty(range(time),10))
mtext("Time (Hours)",side=1,col="black",line=2.5)  

## Add Legend
legend("topleft",legend=c("Beta Gal","Cell Density"),
  text.col=c("black","red"),pch=c(16,15),col=c("black","red"))

类似的配方可用于叠加不同类型的图 - 条形图、直方图等。

【讨论】:

  • 这就是为什么仅链接答案是一个坏主意的原因...... wiki.r-project.org 似乎已不复存在,我在 r-devel@r-project.org 上询问。
  • @BenBolker 你的解决方案是天才!但是我有一个问题。如果两边不止一条线,我仍然可以使用这种方法,但只能使用符号。当我尝试使用 line=plot 时,它会尝试连续绘制它们。您会碰巧提出解决此问题的技巧吗?
  • @BenBolker 如果时间是日期格式类型:“2019-01-01”怎么办。您将如何更改axis(1,pretty(range(time),10)) 行?
【解决方案2】:

顾名思义,plotrix 包中的twoord.plot() 使用两个纵坐标轴进行绘图。

library(plotrix)
example(twoord.plot)

【讨论】:

  • 光滑。感谢您提供大量示例。我也很想看到其中一个带有负值的线条和条形示例。堆叠也会很好。
【解决方案3】:

一种选择是并排制作两个地块。 ggplot2facet_wrap() 提供了一个不错的选择:

dat <- data.frame(x = c(rnorm(100), rnorm(100, 10, 2))
  , y = c(rnorm(100), rlnorm(100, 9, 2))
  , index = rep(1:2, each = 100)
  )

require(ggplot2)
ggplot(dat, aes(x,y)) + 
geom_point() + 
facet_wrap(~ index, scales = "free_y")

【讨论】:

    【解决方案4】:

    如果您可以放弃刻度/轴标签,您可以将数据重新缩放到 (0, 1) 区间。例如,这适用于染色体上不同的“摆动”轨迹,当您通常对轨迹之间的局部相关性感兴趣并且它们具有不同的尺度(以千计,Fst 0-1)时。

    # rescale numeric vector into (0, 1) interval
    # clip everything outside the range 
    rescale <- function(vec, lims=range(vec), clip=c(0, 1)) {
      # find the coeficients of transforming linear equation
      # that maps the lims range to (0, 1)
      slope <- (1 - 0) / (lims[2] - lims[1])
      intercept <- - slope * lims[1]
    
      xformed <- slope * vec + intercept
    
      # do the clipping
      xformed[xformed < 0] <- clip[1]
      xformed[xformed > 1] <- clip[2]
    
      xformed
    }
    

    然后,拥有一个包含 chrompositioncoveragefst 列的数据框,您可以执行以下操作:

    ggplot(d, aes(position)) + 
      geom_line(aes(y = rescale(fst))) + 
      geom_line(aes(y = rescale(coverage))) +
      facet_wrap(~chrom)
    

    这样做的好处是你不限于两个 trakcs。

    【讨论】:

      【解决方案5】:

      我也建议,twoord.stackplot()plotrix 包中绘制多个纵坐标轴。

      data<-read.table(text=
      "e0AL fxAL e0CO fxCO e0BR fxBR anos
       51.8  5.9 50.6  6.8 51.0  6.2 1955
       54.7  5.9 55.2  6.8 53.5  6.2 1960
       57.1  6.0 57.9  6.8 55.9  6.2 1965
       59.1  5.6 60.1  6.2 57.9  5.4 1970
       61.2  5.1 61.8  5.0 59.8  4.7 1975
       63.4  4.5 64.0  4.3 61.8  4.3 1980
       65.4  3.9 66.9  3.7 63.5  3.8 1985
       67.3  3.4 68.0  3.2 65.5  3.1 1990
       69.1  3.0 68.7  3.0 67.5  2.6 1995
       70.9  2.8 70.3  2.8 69.5  2.5 2000
       72.4  2.5 71.7  2.6 71.1  2.3 2005
       73.3  2.3 72.9  2.5 72.1  1.9 2010
       74.3  2.2 73.8  2.4 73.2  1.8 2015
       75.2  2.0 74.6  2.3 74.2  1.7 2020
       76.0  2.0 75.4  2.2 75.2  1.6 2025
       76.8  1.9 76.2  2.1 76.1  1.6 2030
       77.6  1.9 76.9  2.1 77.1  1.6 2035
       78.4  1.9 77.6  2.0 77.9  1.7 2040
       79.1  1.8 78.3  1.9 78.7  1.7 2045
       79.8  1.8 79.0  1.9 79.5  1.7 2050
       80.5  1.8 79.7  1.9 80.3  1.7 2055
       81.1  1.8 80.3  1.8 80.9  1.8 2060
       81.7  1.8 80.9  1.8 81.6  1.8 2065
       82.3  1.8 81.4  1.8 82.2  1.8 2070
       82.8  1.8 82.0  1.7 82.8  1.8 2075
       83.3  1.8 82.5  1.7 83.4  1.9 2080
       83.8  1.8 83.0  1.7 83.9  1.9 2085
       84.3  1.9 83.5  1.8 84.4  1.9 2090
       84.7  1.9 83.9  1.8 84.9  1.9 2095
       85.1  1.9 84.3  1.8 85.4  1.9 2100", header=T)
      
      require(plotrix)
      twoord.stackplot(lx=data$anos, rx=data$anos, 
                       ldata=cbind(data$e0AL, data$e0BR, data$e0CO),
                       rdata=cbind(data$fxAL, data$fxBR, data$fxCO),
                       lcol=c("black","red", "blue"),
                       rcol=c("black","red", "blue"), 
                       ltype=c("l","o","b"),
                       rtype=c("l","o","b"), 
                       lylab="Años de Vida", rylab="Hijos x Mujer", 
                       xlab="Tiempo",
                       main="Mortalidad/Fecundidad:1950–2100",
                       border="grey80")
      legend("bottomright", c(paste("Proy:", 
                            c("A. Latina", "Brasil", "Colombia"))), cex=1,
              col=c("black","red", "blue"), lwd=2, bty="n",  
              lty=c(1,1,2), pch=c(NA,1,1) )
      

      【讨论】:

        【解决方案6】:

        另一个类似于@BenBolker 接受的答案的替代方法是在添加第二组点时重新定义现有绘图的坐标。

        这是一个最小的例子。

        数据:

        x  <- 1:10
        y1 <- rnorm(10, 100, 20)
        y2 <- rnorm(10, 1, 1)
        

        剧情:

        par(mar=c(5,5,5,5)+0.1, las=1)
        
        plot.new()
        plot.window(xlim=range(x), ylim=range(y1))
        points(x, y1, col="red", pch=19)
        axis(1)
        axis(2, col.axis="red")
        box()
        
        plot.window(xlim=range(x), ylim=range(y2))
        points(x, y2, col="limegreen", pch=19)
        axis(4, col.axis="limegreen")
        
        title("my plot", adj=0)
        mtext("2nd y axis", side = 4, las=3, line=3, col="limegreen")
        mtext("1st y axis", side = 2, las=3, line=3, col="red")
        

        【讨论】:

        • 嗨,我想知道如何添加 x、y 标签和标题?谢谢!
        • @MathAvengers 在答案中添加
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-17
        相关资源
        最近更新 更多