Avoiding axis tick label collision in faceted ggplots

后端 未结 1 1687

In multi-panel/faceted plots, I like when it\'s feasible to squash the panels together with no space between them, e.g. using theme(panel.spacing=grid::unit(0,\"lines\"))<

1条回答
  •  梦如初夏
    2021-02-08 07:28

    EDIT Updated to ggplot2 ver 3.0.0

    One possibility might be to modify the build data. It is possible to take the limits of the original plot, and apply a multiplicative expansion factor. The relative positions of the major and minor breaks also need adjustment. Note that the function allows selection of the panels to which the expansion is to apply.

    What's the difference between this and using expand within scale_y_continuous (apart from being able to select the panels)? This function leaves the breaks (and the tick marks and grid lines) as they were in the original. It's just that they take up less space. expand, however, will compress the scale but ggplot will add new labels, grid lines and tick marks if it can.

    It would not take much to break the function - ggplot has been known to change the names of the elements of the build data in recent versions.

    dd <- data.frame(x=rep(1:3,3),
                     y=c(0.1,0.2,0.3,
                         0.1,0.4,0.6,
                         1,2,3),
                     f=factor(rep(letters[1:3],each=3)))
    library(ggplot2)
    
    
    p = ggplot(dd,aes(x,y))+
       facet_grid(f~.,scale="free")+
       geom_point()+
       theme_bw(base_size=24)+
       theme(panel.spacing=grid::unit(0,"lines"))
    
    
    expand = function(plot, mult = 0.1, applyTo) {
    # Get the build data
    gd = ggplot_build(plot)
    
    # Get the original limits,
    # and calculate the new limits,
    # expanded according to the multiplicative factor
    limits <- sapply(gd$layout$panel_params, "[[", "y.range")    # Original limits
    fac = mult*(limits[2,] - limits[1, ])  
    newlimits = rbind(limits[1, ] - fac, limits[2, ] + fac)
    
    # The range for the new limits
    range = newlimits[2, ] - newlimits[1, ]
    
    # Calculate the new y.major and y.minor relative positions
    # and put them along with the new limits back into the build data
    
    N = dim(gd$layout$panel_params)[1]  # Number of panels
    
    for(i in applyTo) {
    y.major = (gd$layout$panel_params[[i]]$y.major_source - newlimits[1, i]) / range[i]
    y.minor = (gd$layout$panel_params[[i]]$y.minor_source - newlimits[1, i]) / range[i]
    
    gd$layout$panel_params[[i]]$y.range = newlimits[, i]
    
    gd$layout$panel_params[[i]]$y.major = y.major
    gd$layout$panel_params[[i]]$y.minor = y.minor
    }
    
    # Get the gtable
    ggplot_gtable(gd)
    }
    
    
    # Plot it
    grid::grid.draw(expand(p, mult = 0.1, applyTo = 1:2))
    

    Original

    Modified

    0 讨论(0)
提交回复
热议问题