How to automatically adjust the width of each facet for facet_wrap?

后端 未结 3 1263
情深已故
情深已故 2020-12-29 15:07

I want to plot a boxplot using ggplot2, and i have more than one facet, each facet has different terms, as follows:

library(ggplot2)

  p <- ggplot(
    d         


        
相关标签:
3条回答
  • 2020-12-29 15:25

    You can adjust facet widths after converting the ggplot object to a grob:

    # create ggplot object (no need to manipulate boxplot width here. 
    # we'll adjust the facet width directly later)
    p <- ggplot(Data,
           aes(x = trait, y = mean)) +
      geom_boxplot(aes(fill = Ref,
                       lower = mean - sd, 
                       upper = mean + sd, 
                       middle = mean, 
                       ymin = min, 
                       ymax = max),
                   lwd = 0.5,
                   stat = "identity") +
      facet_wrap(~ SP, scales = "free", nrow = 1) +
      scale_x_discrete(expand = c(0, 0.5)) + # change additive expansion from default 0.6 to 0.5
      theme_bw()
    
    # convert ggplot object to grob object
    gp <- ggplotGrob(p)
    
    # optional: take a look at the grob object's layout
    gtable::gtable_show_layout(gp)
    
    # get gtable columns corresponding to the facets (5 & 9, in this case)
    facet.columns <- gp$layout$l[grepl("panel", gp$layout$name)]
    
    # get the number of unique x-axis values per facet (1 & 3, in this case)
    x.var <- sapply(ggplot_build(p)$layout$panel_scales_x,
                    function(l) length(l$range$range))
    
    # change the relative widths of the facet columns based on
    # how many unique x-axis values are in each facet
    gp$widths[facet.columns] <- gp$widths[facet.columns] * x.var
    
    # plot result
    grid::grid.draw(gp)
    

    0 讨论(0)
  • 2020-12-29 15:44

    In general, you can determine the width of a box plot in ggplot like so:

    ggplot(data= df, aes(x = `some x`, y = `some y`)) + geom_boxplot(width = `some witdth`)
    

    In your case, you might consider setting the width of all the box plots to the range of x divided by the maximum number of elements (in the leftmost figure).

    0 讨论(0)
  • 2020-12-29 15:51

    While u/z-lin's answer works, there is a far simpler solution. Switch from facet_wrap(...) to use facet_grid(...). With facet_grid, you don't need to specify rows and columns. You are still able to specify scales= (which allows automatic adjustment of axis scales for each facet if wanted), but you can also specify space=, which does the same thing, but with the scaling of the overall facet width. This is what you want. Your function call is now something like this:

    ggplot(Data, aes(x = trait, y = mean)) +
        geom_boxplot(aes(
            fill = Ref, lower = mean-sd, upper = mean+sd, middle = mean, 
            ymin = min, ymax = max),
            lwd = 0.5, stat = "identity") +
        facet_grid(. ~ SP, scales = "free", space='free') +
        scale_x_discrete(expand = c(0, 0.5)) +
        theme_bw()
    

    Some more description of layout of facets can be found here.

    As @cdtip mentioned, this does not allow for independent y scales for each facet, which is what the OP asked for initially. Luckily, there is also a simple solution for this, which utilizes facet_row() from the ggforce package:

    library(ggforce)
    
    # same as above without facet_grid call..
    p <- ggplot(Data, aes(x = trait, y = mean)) +
      geom_boxplot(aes(
        fill = Ref, lower = mean-sd, upper = mean+sd, middle = mean, 
        ymin = min, ymax = max),
        lwd = 0.5, stat = "identity") +
      scale_x_discrete(expand = c(0, 0.5)) +
      theme_bw()
    
    p + ggforce::facet_row(vars(SP), scales = 'free', space = 'free')
    

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