使用ggplot根据数据中的另一个字段沿x轴定位x轴文本/标签

时间:2017-03-04 11:09:36

标签: r ggplot2

我想根据另一个字段放置每个x轴文本/标签。 ggplot2中是否有本地方式来实现这一目标?目前我正在通过geom_text进行此操作。这是我的数据和情节。这个方法有两个问题 -

  1. 标签落在情节区域内
  2. 对于构面,标签应仅显示在最下面的子图中,如下所示alt text
  3. 不是所有的子图,如下面的情况(我的情节)。 (上图来自here

    library(ggplot2)
    library(magrittr)    
    
    mydata = data.frame(expand.grid(Tag = c('A','B','C'),
      Year = 2010:2011,PNo = paste0("X-",1:4)),Value = round(runif(24,1,20)))
    mydata$dist = ifelse(mydata$Tag == 'A',0,ifelse(mydata$Tag=='B',2,7))
    
    mydata %>% ggplot(aes(x = dist,y = Value,fill = factor(Year))) +
      geom_bar(stat='summary',position = 'dodge',fun.y='mean',width=1) +
      facet_wrap(~PNo,ncol=2) +
      theme(axis.text.x = element_blank(),axis.ticks.x = element_blank()) +
      geom_text(aes(x = dist,label = Tag),color = 'black',size=4,angle = 0,show.legend = F)
    

    我想根据Tag放置dist个标签。 enter image description here

2 个答案:

答案 0 :(得分:1)

我注意到你已经在其他地方接受了答案,并且你已经在这里回答了你自己的问题。但他们并没有完全回答你原来的问题。特别是,标签仍在绘图面板内。我提供了两种可能性,但都不是直截了当的。

第一个使用annotation_custom的版本。默认annotation_custom在所有面板中绘制注释。但是通过一个小的改动(取自here),可以在选定的面板中绘制注释 - 对于你的情节,下两个面板。

 library(ggplot2)
library(magrittr)    
mydata = data.frame(expand.grid(Tag = c('A', 'B', 'C'), 
             Year = 2010:2011, PNo =  paste0("X-", 1:4)), Value = round(runif(24,1,20)))
mydata$dist = ifelse(mydata$Tag == 'A', 0, ifelse(mydata$Tag == 'B', 2, 7))

# The bar plot. Note extra margin above x-axis title.
# This gives space for the annotations between the panel and the title.
p1 = mydata %>% ggplot() +
  geom_bar(aes(x = dist, y = Value, fill = factor(Year)),
             width = 1, stat = 'identity', position = "dodge") + 
  facet_wrap(~PNo, ncol = 2) +
  theme(axis.text.x = element_blank(), 
        axis.ticks.x = element_blank(),
        axis.title.x = element_text(margin = margin(t = 2, unit = "lines")))   

# Baptiste's modification to annotation_custom
annotation_custom2 = 
function (grob, xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf, data) {
  layer(data = data, stat = StatIdentity, position = PositionIdentity, 
        geom = ggplot2:::GeomCustomAnn,
        inherit.aes = TRUE, params = list(grob = grob, 
                                          xmin = xmin, xmax = xmax, 
                                          ymin = ymin, ymax = ymax))
}

# The plot with annotations. (ymin and ymax set to -Inf 
# draws the annotation at the bottom of the panel. 
# vjust = 1.5 drops them below the panel). 
for (i in 1:length(unique(mydata$Tag)))  {
   p1 = p1 + annotation_custom2(
        grob =  textGrob(label = unique(mydata$Tag)[i], vjust = 1.5,
                      gp = gpar(col = 'red', cex = 1)),
         xmin = unique(mydata$dist)[i],
         xmax = unique(mydata$dist)[i],
         ymin = -Inf,
         ymax = -Inf,
         data=data.frame(PNo=c("X-3", "X-4") ))    # The two bottom panels
} 

# The annotations are placed outside the panels. 
# Therefore, have to turn off clipping to the panels.
g1 = ggplotGrob(p1)
g1$layout$clip[grepl("panel", g1$layout$name)] = "off"

# Draw the chart
grid.newpage()
grid.draw(g1)

enter image description here

第二个绘制两个图表:p1是条形图,p2仅包含标签。诀窍是让两个图表中的x轴相同。然后,从p2中提取绘图面板,并将其放入p1中,但放入p1> s绘图面板下方的新行中。

library(ggplot2)
library(magrittr)    
mydata = data.frame(expand.grid(Tag = c('A', 'B', 'C'),
      Year = 2010:2011,PNo = paste0("X-", 1:4)),Value = round(runif(24, 1, 20)))
mydata$dist = ifelse(mydata$Tag == 'A', 0, ifelse(mydata$Tag == 'B', 2, 7))

# The bar plot
p1 = mydata %>% ggplot(aes(x = dist, y = Value, fill = factor(Year))) +
   geom_bar(stat = 'summary', position = 'dodge',fun.y = 'mean', width = 1) +
  facet_wrap(~PNo, ncol = 2) +
  theme(axis.text.x = element_blank(), axis.ticks.x = element_blank()) 

# To get the range of x values -
# so that the extent of the x-axis in p1 and in the following p2 are the same
gd = ggplot_build(p1)
xrange = gd$layout$panel_params[[1]]$x.range   # xrange used in p2 (see below)

# Plot with labels (A, B, and C) only
p2 = mydata %>% ggplot(aes(x = dist, y = Value)) +
     facet_wrap(~PNo, ncol = 2) +
     geom_label(aes(x = dist, y = 0, label = Tag), size = 6, inherit.aes = F, color = 'red') +
    ### geom_text(aes(x = dist, y = 0, label = Tag), size=6, color = 'red') +  ### Alternative style for labels
     scale_x_continuous(lim = xrange, expand = c(0,0)) +
     theme_bw() +
     theme(panel.grid = element_blank(),
           panel.border = element_rect(colour = NA)) 


# Grab a plot panel from p2
g2 = ggplotGrob(p2)
panels = subset(g2$layout, grepl("panel", g2$layout$name), t:r)
panels = subset(panels, t == min(t))

g2 = g2[unique(panels$t), min(panels$l):max(panels$r)]

# Add a row to p1 to take the plot panels
library(gtable)
library(grid)
g1 <- ggplotGrob(p1)
pos = max(subset(g1$layout, grepl("panel", g1$layout$name), t))
g1 = gtable_add_rows(g1, height = unit(2, "lines"), pos = pos)

# Add the panel (g2) to the new row
g1 = gtable_add_grob(g1,g2, t = pos + 1, l =  min(panels$l), r = max(panels$r))

# Draw the chart
grid.newpage()
grid.draw(g1)

enter image description here

答案 1 :(得分:0)

我试图自己解决问题,但面临一些问题。我在SO here上发布了另一个问题。答案和问题在一定程度上解决了这个问题。这是一个可能的解决方案。

p <- mydata %>% ggplot(aes(x = dist,y = Value,fill = factor(Year))) +geom_bar(stat='summary',position = 'dodge',fun.y='mean',width = 1) +
  facet_wrap(~PNo,ncol=2) +
  theme(axis.text.x = element_blank(),axis.ticks.x = element_blank()) +
  geom_label(data  = mydata %>% dplyr::filter(PNo %in% c('X-3','X-4')),aes(x = dist,y=0,label = Tag),size=6,inherit.aes=F,color = 'red') 
library(grid) 
gt <- ggplot_gtable(ggplot_build(p)) 
gt$layout$clip[grep("panel-2-\\d+", gt$layout$name)] <- "off"
grid.draw(gt)