r中的“scale”或“ruler”类型图表

12

我想在条形图(水平或垂直)中放置刻度线,以便像刻度盘一样显示。 enter image description here

以下是一个简单的示例:

myd <- data.frame (names = c("A", "B", "C", "D"), height = c(2.1, 3.5, 3.5,1.5))
require(ggplot2)
c <- ggplot(myd, aes(factor(names), height, fill = names))
c + geom_bar()
c + geom_bar() + coord_flip()

有没有一种简单的方法或包可以实现这个?


经过研究大部分绘图包,我相当确定没有这个功能的包。编写一个函数应该不会太难。你只需要为线段命令提供坐标即可。看起来你已经做到了这一点。 - John
2个回答

16

使用ggplot2库的解决方案相当冗长。

首先修改您的数据帧 - 根据柱形图高度中出现0.2的次数重复每个namesheight元素。

myd <- data.frame (names = c(rep("A",floor(2.1/0.2)), rep("B",floor(3.5/0.2)), rep("C",floor(3.5/0.2)), rep("D",floor(1.5/0.2))),
                   height = c(rep(2.1,floor(2.1/0.2)), rep(3.5,floor(3.5/0.2)), rep(3.5,floor(3.5/0.2)), rep(1.5,floor(1.5/0.2))))

ystartyend是小刻度线的y坐标,每根条形图按0.2序列计算。 xstart是小刻度线的x坐标。在这里,我假设条形图宽度为0.5。如果宽度较小或较大,则应更改坐标。 xend是根据刻度线宽度0.1计算的。

ystart<-c(seq(0.2,2.1,0.2),seq(0.2,3.5,0.2),seq(0.2,3.5,0.2),seq(0.2,1.5,0.2))
yend=ystart
xstart<-c(rep(0.75,floor(2.1/0.2)),rep(1.75,floor(3.5/0.2)),rep(2.75,floor(3.5/0.2)),rep(3.75,floor(1.5/0.2)))
xend<-xstart+0.1

数据帧中添加了新值。

myd <-data.frame(myd,ystart,yend,xstart,xend)

  p <- ggplot(myd, aes(factor(names), height,fill = names))
  p <- p + geom_bar(width=0.5)  

  #This line adds small ticks (segments) to bars
  p <- p + geom_segment(aes(x=xstart,y=ystart,xend=xend,yend=yend))

  #This line adds white lines at 1, 2 and 3
  p <- p + geom_hline(yintercept=c(1,2,3),color="white",lwd=1.1)

  #Next two lines removes legend and makes place for text
  p <- p + guides(fill=FALSE)
  p <- p + ylim(c(0,4))

  #Add numbers over bars
  p <- p + annotate("text",x=c(1,2,3,4),y=c(2.4,3.8,3.8,1.8),label=c("2.1","3.5","3.5","1.5"),angle=90,fontface="bold",size=5)

  #Adjustment of appearance to remove guidlines and axis ticks
  p <- p + theme_bw()
  p <- p + theme(axis.title=element_blank(),
          axis.text.y=element_blank(),
          axis.text.x=element_text(angle=90,face="bold",size=rel(1.5)),
          axis.ticks=element_blank(),
          panel.border=element_blank(),
          panel.grid=element_blank())
  print(p)

enter image description here

编辑 - 添加函数解决方案。

添加了函数 ruler.func() - 唯一需要的参数是条形图高度的向量。函数的第一部分生成数据框,第二部分制作绘图。

ruler.func<-function(gg){
seq.list<-list()
for(i in 1:length(gg)){  
  ystart<-seq(0.2,gg[i],0.2)
  yend<-ystart
  xstart<-rep(i-0.25,length(ystart))
  xend<-xstart+0.1
  nam.val<-c(LETTERS[i],rep(NA,length(ystart)-1))
  numb.val<-c(gg[i],rep(NA,length(ystart)-1))
  seq.list[[i]]<-data.frame(nam.val,numb.val,xstart,xend,ystart,yend)
}
df<-as.data.frame(do.call(rbind, seq.list))
p <- ggplot(df, aes(nam.val))
p <- p + geom_bar(aes(y=numb.val,fill=nam.val),stat="identity",width=0.5,color="black",lwd=1.1)+
    scale_x_discrete(limits=LETTERS[1:length(gg)])+
    geom_segment(aes(x=xstart,y=ystart,xend=xend,yend=yend))+
    geom_hline(yintercept=seq(1,max(gg),1),color="white",lwd=1.1)+
    guides(fill=FALSE)+
    ylim(c(0,max(gg)+0.5))+
    annotate("text",x=seq(1,length(gg),1),y=gg+0.5,label=gg,angle=90,fontface="bold",size=rel(6))+
    theme_bw()+
    theme(axis.title=element_blank(),
               axis.text.y=element_blank(),
               axis.text.x=element_text(angle=90,face="bold",size=rel(1.5)),
               axis.ticks=element_blank(),
               panel.border=element_blank(),
               panel.grid=element_blank())
print(p)
}

带有数字1.2、4.6和2.8的示例。

ruler.func(c(1.2,4.6,2.8))

在此输入图片描述


感谢您提供的出色解决方案...我希望我能创建一个函数(特别是数据生成步骤),它不仅可以在数据集中执行四个类别,而且可以执行x个类别(如所提供)。 - SHRram
2
@SHRram 添加了解决方案,也作为函数。 - Didzis Elferts

5

我的做法是使用grid包自定义网格grobs,这是绘图后的ggplot2处理过程。我使用Grid低级函数通过向ggplot2图形添加一些新的绘制来进行自定义。这里的巨大优势在于无需添加数据,可以直接使用代码。

我认为ggplot2与grid处理的混合是自定义绘图的强大工具。

#get the viewport (here we do the stuff)
library(grid)
library(plyr)
## 
grid.edit('geom_rect',gp=gpar(col='black'),grep=T)
## get the panel viewport
vp1 <- grid.get('panel',grep=T)$wrapvp
depth <- downViewport(name=vp1$name)
rects <- grid.get('geom_rect',grep=T)
for(i in 1:4){
  ## for each axis i create a view port , within it I draw my yaxis
  vpaxis <- viewport(x = rects$x[i]+rects$width[i],
                     y = rects$y[i], 
                     w = 0.005, 
                     h = rects$height[i],
                     just=c('left','top'),
                     yscale = c(0,myd$height[i])
  )
  ## I create the axis, you can customize it using the gp parameter
  gxa <- yaxisGrob(name='axiss',vp=vpaxis,
                   at = seq(0,myd$height[i],by=0.5),
                   gp=gpar(cex=.8))
  grid.draw(gxa)
}
## I put a blank background
grid.edit('background.rect',grep=T,gp=gpar(fill=NA))
###
upViewport(depth)

enter image description here

对于坐标循环,我们使用x轴,将上面的for循环更改为:

for(i in 1:4){
vpaxis <- viewport(x = rects$x[i],
                   y = rects$y[i], 
                   w = rects$width[i], 
                   h = 0,
                   just=c('left','top'),
                   clip=FALSE,
                   xscale = c(0,myd$height[i]),

)
gxa <- xaxisGrob(name='axiss',vp=vpaxis,
                 at = seq(0,myd$height[i],by=0.5),
                 gp=gpar(cex=.8))
grid.draw(gxa)
}

enter image description here


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