【问题标题】:Set axis tick and label to include maximum value on bar plot设置轴刻度和标签以在条形图上包含最大值
【发布时间】:2021-01-22 22:07:34
【问题描述】:

我正在使用 base R 创建多个并排的条形图(我更喜欢避免使用 ggplot,因为我经常在功能上受到限制)。我发现结果在视觉上并不令人愉悦,因为轴刻度根本不对齐:有时轴的顶部远低于最大值,有时高于最大值。有没有办法设置它,使最终的轴刻度值包括最大值?它不能完美对齐,因为每个图表都有自己的范围,因此有自己的刻度值集,但我希望至少有它,以便样式在 12 个图表中保持一致。

我正在使用函数(和循环)创建系列,因此我更喜欢自动化解决方案(而不是通过单独设置最大限制 axis() 来调整每个图表)

这是一个带有iris 数据集的简化示例。出现的问题是,第一个面板中的轴在 6 处结束,低于包括误差线 (7.2238) 在内的最大值,而在第二个面板中,轴结束于最大值之上。

library(vegan)
data(iris)

x1_mean<-tapply(iris$Sepal.Length, iris$Species, FUN=mean)
x1_sd<-tapply(iris$Sepal.Length, iris$Species, FUN=sd)


x2_mean<-tapply(iris$Petal.Width, iris$Species, FUN=mean)
x2_sd<-tapply(iris$Petal.Width, iris$Species, FUN=sd)

par(mfrow=c(1,2))
br1=barplot(x1_mean, ylim=c(0, (max(x1_mean)+max(x1_sd))*1.1))
errbar(x = br1, y = x1_mean, 
                     yplus = x1_mean+x1_sd, 
                     yminus = x1_mean-x1_sd, add = T, cex = 0)


br2=barplot(x2_mean, ylim=c(0, (max(x2_mean)+max(x2_sd))*1.1))
errbar(x = br2, y = x2_mean, 
       yplus = x2_mean+x2_sd, 
       yminus = x2_mean-x2_sd, add = T, cex = 0)

编辑/进展:

我已经设法使用par("yaxp") 提取了轴的最大值,并用它来添加一个额外的刻度,以便最后一个刻度值大于图表上的最大值。但是,它迫使我实际绘制默认图,它创建了两个图。 我还包含了我正在尝试构建的函数的简化版本(使用iris 作为示例数据集),这可能更清楚我的目标。

library(vegan)
data(iris)

barplot_adjust<- function(data, metric,...) {
  x_means<-tapply(data[,metric], list(data$Species), FUN=mean)
  x_sd<-tapply(data[,metric], list(data$Species), FUN=sd)
  br1 <- barplot(height = x_means, names.arg = names(x_sd), ylim = c(0, (max(x_means+x_sd))*1.1), 
                 main=metric, las=0,plot=TRUE,
                 ...)
   if( par("yaxp")[2]<(max(x_means+x_sd))*1.1 )
  {ymx=par("yaxp")[2]+par("yaxp")[2]/par("yaxp")[3]}else{ymx=par("yaxp")[2]}
  br1 <- barplot(height = x_means, names.arg = names(x_sd), ylim = c(0, ymx), 
                 main=metric, las=0,plot=TRUE,
                 ...)
  print(ymx)
  errbar(x = br1, y = x_means, yplus = x_means+x_sd, yminus = x_means-x_sd, add = T, cex = 0)
}

par(mfrow=c(2,2))
barplot_adjust(data=iris, metric="Sepal.Length")
barplot_adjust(data=iris, metric="Petal.Width")

【问题讨论】:

    标签: r graph bar-chart


    【解决方案1】:

    这样的事情怎么样:

    library(vegan)
    data(iris)
    
    x1_mean<-tapply(iris$Sepal.Length, iris$Species, FUN=mean)
    x1_sd<-tapply(iris$Sepal.Length, iris$Species, FUN=sd)
    yl1 <- max((x1_mean + x1_sd))
    
    x2_mean<-tapply(iris$Petal.Width, iris$Species, FUN=mean)
    x2_sd<-tapply(iris$Petal.Width, iris$Species, FUN=sd)
    yl2 <- max((x2_mean + x2_sd))
    
    
    library(Hmisc)
    par(mfrow=c(1,2))
    br1=barplot(x1_mean, ylim=c(0, (max(x1_mean)+max(x1_sd))), axes=FALSE)
    axis(2, at=round(seq(0,yl1, length=5), 1))
    errbar(x = br1, y = x1_mean, 
           yplus = x1_mean+x1_sd, 
           yminus = x1_mean-x1_sd, add = T, cex = 0)
    
    
    br2=barplot(x2_mean, ylim=c(0, (max(x2_mean)+max(x2_sd))), axes=FALSE)
    axis(2, at=round(seq(0,yl2, length=5), 1))
    errbar(x = br2, y = x2_mean, 
           yplus = x2_mean+x2_sd, 
           yminus = x2_mean-x2_sd, add = T, cex = 0)
    
    

    【讨论】:

    • 这似乎是一个好的开始,但我喜欢 R 将数据自动拆分为逻辑块 (1, 2, 3, ...) 和 (0, 0.5, 1, 1.5, ... )。必须可以从条形图中提取轴值?
    【解决方案2】:

    轴最多结束,其余的实际上是box。顺便说一句,关于四个tapplys,您可以在一个aggregate 中完成它们。 (我在这里使用我认为是more appropriate 的置信区间,但您也可以使用sd()

    FUN <- function(x) c(mean=mean(x), q=quantile(x, c(.025, .975)))
    r <- do.call(data.frame, aggregate(cbind(Sepal.Length, Petal.Width) ~ Species, iris, FUN))
    r <- t(`rownames<-`(r[-1], r[,1]))
    

    如果您喜欢基本 R,您可能希望使用 arrows 而不是 Hmisc::errbar

    op <- par(mfrow=c(1, 2))  ## set par and store defaults
    br1 <- barplot(r[1,], ylim=c(0, max(r[1:3,]))*1.1)
    arrows(br1, y0=r[2,], y1=r[3,], code=3, angle=90, length=.05)
    box()
    br2 <- barplot(r[4,], ylim=c(0, max(r[4:6,]))*1.1)
    arrows(br2, y0=r[5,], y1=r[6,], code=3, angle=90, length=.05)
    box()
    par(op)  ## restore par defaults
    

    我不太清楚您所说的 “轴刻度线不对齐”是什么意思,您可能希望两个图表都使用相同的 ylim

    op <- par(mfrow=c(1, 2))
    br1 <- barplot(r[1,], ylim=c(0, max(r))*1.1)
    arrows(br1, y0=r[2,], y1=r[3,], code=3, angle=90, length=.05)
    box()
    br2 <- barplot(r[4,], ylim=c(0, max(r))*1.1)
    arrows(br2, y0=r[5,], y1=r[6,], code=3, angle=90, length=.05)
    box()
    par(op)
    

    【讨论】:

    • 不会以最大值结束。这正是我想要的行为。 (我希望轴在不同图表之间的某个一致点结束,而不是完全相同的限制)。我该如何设置?在我的输出中,第一个面板的轴在 6 处停止,而在您的输出中,轴在 8 处停止(这是我想要的)。
    • 顺便说一句,我的实际数据和图表基于循环遍历我的数据集的属性并使用标准错误。我在问题中的示例中使用了简化版本,因为我认为它不会改变要点。
    • @user3386170 如果在每种情况下都省略box() 行会怎样?
    • 我检查过,您的输出以 8 而不是 6 结束的原因是使用 95% 百分位数的最大值是 7.7 而不是使用 sd 的 7.2238,因此它超过了算法考虑的阈值将 8 包括在刻度中。 box() 不会改变任何东西。
    • @user3386170 检查ylim=参数,轴从6切换到8的阈值。
    猜你喜欢
    • 2013-11-07
    • 1970-01-01
    • 2017-08-01
    • 2019-07-03
    • 2021-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-19
    相关资源
    最近更新 更多