首页 文章

在刻面ggplot中自动执行tick max和min

提问于
浏览
4

我试图在刻面的ggplot中标记每个x轴的最大值和最小值 . 我有几个具有不同x刻度和相同y刻度的刻面,x轴刻度标签相互重叠 . 我不是必须手动确定每个方面x轴的限制和中断,而是寻找一种方法来标记每个方面的最小值和最大值 .

使用 CO2 数据集的示例数据的代码(请参阅 ?CO2 ):

CO2$num <- 1:nrow(CO2)
library(reshape2)
CO2.melt <- melt(CO2,
                 id.var=c("Type",
                          "Plant",
                          "Treatment",
                          "num"))
CO2.melt <- CO2.melt[order(CO2.melt$num),]

library(ggplot2)
ggplot(CO2.melt, 
       aes(x = value, 
           y = num)) +
  geom_path(aes(color = Treatment)) +
  facet_wrap( ~ variable, scales = "free_x",nrow=1)

enter image description here

目的是复制井日志显示,例如this one .

2 回答

  • 8

    当你想为tick标签实现这个时,在分面图中使用 scales = "free_x" 会使这很难自动化 . 但是,通过一些修补和其他几个包的帮助,您还可以使用以下方法:

    1) 汇总数据以便了解在x轴上需要哪些标签/符号:

    library(data.table)
    minmax <- melt(setDT(CO2.melt)[, .(min.val = min(value), max.val = max(value),
                                       floor.end = 10*ceiling(min(value)/10),
                                       ceil.end = 10*floor((max(value)-1)/10)),
                                   variable][],
                   measure.vars = patterns('.val','.end'),
                   variable.name = 'var',
                   value.name = c('minmax','ends'))
    

    这使:

    > minmax
       variable var minmax ends
    1:     conc   1   95.0  100
    2:   uptake   1    7.7   10
    3:     conc   2 1000.0  990
    4:   uptake   2   45.5   40
    

    2) 为每个方面创建休息时间:

    brks1 <- c(95,250,500,750,1000)
    brks2 <- c(7.7,10,20,30,40,45.5)
    

    3) 创建构面:

    p1 <- ggplot(CO2.melt[CO2.melt$variable=="conc",], 
                 aes(x = value, y = num, colour = Treatment)) +
      geom_path() +
      scale_x_continuous(breaks = brks1) +
      theme_minimal(base_size = 14) +
      theme(axis.text.x = element_text(colour = c('red','black')[c(1,2,2,2,1)],
                                       face = c('bold','plain')[c(1,2,2,2,1)]),
            axis.title = element_blank(),
            panel.grid.major = element_line(colour = "grey60"),
            panel.grid.minor = element_blank())
    
    p2 <- ggplot(CO2.melt[CO2.melt$variable=="uptake",], 
                 aes(x = value, y = num, colour = Treatment)) +
      geom_path() +
      scale_x_continuous(breaks = brks2) +
      theme_minimal(base_size = 14) +
      theme(axis.text.x = element_text(colour = c('red','black')[c(1,2,2,2,2,1)],
                                       face = c('bold','plain')[c(1,2,2,2,2,1)]),
            axis.title = element_blank(),
            panel.grid.major = element_line(colour = "grey60"),
            panel.grid.minor = element_blank())
    

    4) 将图例解压缩到单独的对象中:

    library(grid)
    library(gtable)
    fill.legend <- gtable_filter(ggplot_gtable(ggplot_build(p2)), "guide-box")
    legGrob <- grobTree(fill.legend)
    

    5) 创建最终图:

    library(gridExtra)
    grid.arrange(p1 + theme(legend.position="none"), 
                 p2 + theme(legend.position="none"), 
                 legGrob, ncol=3, widths = c(4,4,1))
    

    这导致:

    enter image description here


    自动执行此操作的可能替代解决方案是使用 geom_textgeom_label . 举例说明如何实现这一目标:

    # create a summary
    library(dplyr)
    library(tidyr)
    minmax <- CO2.melt %>% 
      group_by(variable) %>% 
      summarise(minx = min(value), maxx = max(value)) %>%
      gather(lbl, val, -1)
    
    # create the plot
    ggplot(CO2.melt, aes(x = value, y = num, color = Treatment)) +
      geom_path() +
      geom_text(data = minmax, 
                aes(x = val, y = -3, label = val), 
                colour = "red", fontface = "bold", size = 5) +
      facet_wrap( ~ variable, scales = "free_x", nrow=1) +
      theme_minimal()
    

    这使:

    enter image description here

    您还可以在 ggplot 内动态获取最小值和最大值(信用额度为@eipi10) . 另一个使用 geom_label 的例子:

    ggplot(CO2.melt, aes(x = value, y = num, color = Treatment)) +
      geom_path() +
      geom_label(data = CO2.melt %>% 
                   group_by(variable) %>% 
                   summarise(minx = min(value), maxx = max(value)) %>%
                   gather(lbl, val, -1), 
                 aes(x = val, y = -3, label = val), 
                 colour = "red", fontface = "bold", size = 5) +
      facet_wrap( ~ variable, scales = "free_x", nrow=1) +
      theme_minimal()
    

    这使:

    enter image description here

  • 5

    Edit 正在更新到ggplot2 ver 3.0.0

    此方法修改ggplot构建数据中的标签(即 ggplot_build(plot) ) . 我已经删除了x轴扩展,以便最大值和最小值落在面板边界上 .

    # Packages
    library(grid)
    library(ggplot2)
    library(reshape2)
    
    # Data
    CO2$num <- 1:nrow(CO2)
    library(reshape2)
    CO2.melt <- melt(CO2,
                     id.var=c("Type",
                              "Plant",
                              "Treatment",
                              "num"))
    CO2.melt <- CO2.melt[order(CO2.melt$num),]
    
    # Plot
    (p <- ggplot(CO2.melt, 
           aes(x = value, 
               y = num)) +
      scale_x_continuous(expand = c(0, 0)) +
      geom_path(aes(color = Treatment)) +
      facet_wrap( ~ variable, scales = "free_x", nrow=1)) 
    
    # Get the build data
    gb <- ggplot_build(p)
    
    # Get number of panels
    panels = length(gb$layout$panel_params)
    
    # Get x tick mark labels
    x.labels = lapply(1:panels, function(N)   gb$layout$panel_params[[N]]$x.labels)
    
    # Get range of x values
    x.range = lapply(1:panels, function(N) gb$layout$panel_params[[N]]$x.range)
    
    # Get position of x tick mark labels
    x.pos = lapply(1:panels, function(N) gb$layout$panel_params[[N]]$x.major)
    
    # Get new x tick mark labels - includes max and min
    new.labels = lapply(1:panels, function(N) as.character(sort(unique(c(as.numeric(x.labels[[N]]), x.range[[N]])))))
    
    # Tag min and max values with "min" and "max"
    new.labelsC = new.labels
    minmax = c("min", "max")
    new.labelsC = lapply(1:panels, function(N) {
       x = c(new.labelsC[[N]][1], new.labelsC[[N]][length(new.labels[[N]])])
       x = paste0(x, "\n", minmax)
       c(x[1], new.labelsC[[N]][2:(length(new.labels[[N]])-1)], x[2])
    } )
    
    # # Get position of new labels
    new.pos = lapply(1:panels, function(N) (as.numeric(new.labels[[N]]) - x.range[[N]][1])/(x.range[[N]][2] - x.range[[N]][1]))
    
    # Put them back into the build data
    for(i in 1:panels) {
       gb$layout$panel_params[[i]]$x.labels = new.labelsC[[i]]
       gb$layout$panel_params[[i]]$x.major_source = as.numeric(new.labels[[i]])
       gb$layout$panel_params[[i]]$x.major = new.pos[[i]]
    }
    
    # Get the ggplot grob
    gp = ggplot_gtable(gb)
    
    # Add some additional space between the panels
    pos = gp$layout$l[grep("panel", gp$layout$name)] # Positions of the panels
    for(i in 1:(panels-1)) gp$widths[[pos[i]+1]] = unit(1, "cm")
    
    # Colour the min and max labels using `grid` editing functions
    for(i in 1:panels) {
       gp = editGrob(grid.force(gp), gPath(paste0("axis-b-", i), "axis", "axis", "GRID.text"), 
             grep = TRUE, gp = gpar(col = c("red", rep("black", length(new.labels[[i]])-2), "red")))
    }
    
    # Draw it
    grid.newpage()
    grid.draw(gp)
    

    enter image description here

相关问题