Search code examples
rggplot2facet

Adding unique axes label names in ggplot with facet_wrap


It seems like many users are trying to do what I am also trying here.

I am trying to do these things:

  1. x-axis labels to be fixed (range 0 to 1200), the x-axis to be repeated on each plot, and for the x-axis label name to be repeated and customizable for each plot
  2. y-axis labels to be free (but to be able to edit the range in the second plot to be breaks=c(0, 3, 6, 9, 12)), the y-axis to be repeated on each plot, and for the y-axis labels to be repeated and customizable for each plot

Using the below code (adapted from previous OPs and documentation):

ggplot(mapping=aes(x=dist, fill=sex)) +
   geom_histogram(data = cbind(move, panel = "A"), color="black", binwidth=10) +
   geom_vline(data = cbind(move, panel = "A"), aes(xintercept=mean(dist)), 
    color="black", linetype="dashed", size=1)+
   geom_histogram(data = cbind(settle_data, panel = "B"), color="black", binwidth=10) +
   geom_vline(data = cbind(settle_data, panel = "B"), aes(xintercept=mean(dist)), 
    color="black", linetype="dashed", size=1)+
   geom_histogram(data = cbind(recruit_data, panel = "C"), color="black", binwidth=10) +
   geom_vline(data = cbind(recruit_data, panel = "C"), aes(xintercept=mean(dist)), 
    color="black", linetype="dashed", size=1)+
    coord_cartesian(xlim=c(0,1200))+ #limits axes range without deleting points
    scale_fill_manual(values=c("gray97", "gray47"),
            name = "Sex",   
            breaks=c("F","M"),
            labels=c("Female","Male")) +
    theme_bw() +
    theme(legend.position = c(0.8,0.8), #move legend into plot
        axis.line = element_line(colour = "black"),
        axis.text=element_text(size = 20), #changes size of axes #s
        axis.title=element_text(size=20), #changes size of axes labels
        plot.caption = element_text(hjust = 0, vjust = 2.12),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.border = element_blank(),
        panel.background = element_blank(),
        text = element_text(size = 15)) +
    facet_wrap(~ panel, ncol = 1, scales='free_y', labeller=as_labeller(c(A = "Number of fixes", B = "Number of individuals", C = "Number of individuals") ), strip.position="left") +
    scale_x_continuous(breaks = seq(0,1250,by = 200)) +     
    theme(
    strip.placement = "outside",
    strip.background = element_blank(),
        axis.title.y = element_blank(),
        strip.text = element_text(size = 19))+
    labs(x = "Distance travelled from natal nest (m)")

Resulting plot (I was able to "hack" the y-axis issues I was having by moving the panel names to the left outside of the plots and act like they were axis labels):

enter image description here

The plot I want (edits circled in red): enter image description here

I cannot post the data I used for the plots, but I've created a sample dataset below:

move<- data.frame(
    dist = c(0,100,200,300,400,400,500,600,700,800,1000,1200,0,100,200,300,400,400,500,600,700,800,1000,1200,0,100,200,300,400,400,500,600,700,800,1000,1200,0,100,200,300,400,400,500,600,700,800,1000,1200),
    sex = c ("F", "M", "F", "F", "F", "M", "M", "M", "M", "M", "F","F","F", "M", "F", "F", "F", "M", "M", "M", "M", "M", "F", "F","F", "M", "F", "F", "F", "M", "M", "M", "M", "M", "F", "F","F", "M", "F", "F", "F", "M", "M", "M", "M", "M", "F", "F"))
settle_data<-data.frame(
    dist = c(0,10,20,30,400,40,50,60,700,80,1000,1200,0,10,20,30,400,40,50,60,700,80,1000,1200, 0,10,20,30,400,40,50,60,700,80,1000,1200,0,100,200,300,400,400,500,600,700,800,1000,1200,0,10,20,30,400,40,50,60,700,80,1000,1200,0,10,20,30,400,40,50,60,700,80,1000,1200,0,10,20,30,400,40,50,60,700,80,1000,1200,0,100,200,300,400,400,500,600,700,800,1000,1200),
    sex = c ("F", "M", "F", "F", "F", "M", "M", "M", "M", "M", "F","F","F", "M", "F", "F", "F", "M", "M", "M", "M", "M", "F", "F","F", "M","F", "F", "F", "M", "M", "M", "M", "M", "F", "F","F", "M", "F", "F","F", "M", "M", "M", "M", "M", "F", "F", "F", "M", "F", "F", "F", "M", "M", "M","M", "M", "F", "F","F", "M", "F", "F", "F", "M", "M", "M", "M", "M","F", "F","F", "M", "F", "F", "F", "M", "M", "M", "M", "M", "F", "F","F", "M","F", "F", "F", "M", "M", "M", "M", "M", "F", "F"))
recruit_data<- data.frame(
    dist = c(0,10,20,30,400,40,50,60,700,80,1000,1200,0,10,20,30,4,40,50,60,700,80,10,120,0,10,20,30,40,40,50,60,70,80,100,120,0,100,200,300,400,400,500,600,700,800,1000,1200),
    sex = c ("F", "M", "F", "F", "F", "M", "M", "M", "M", "M", "F","F","F", "M", "F", "F", "F", "M", "M", "M", "M", "M", "F", "F","F", "M","F", "F", "F", "M", "M", "M", "M", "M", "F", "F","F", "M", "F", "F","F", "M", "M", "M", "M", "M", "F", "F"))

Solution

  • I agree with most of the comments that it would be easier to make seperate plots. A painpoint of such an approach is often that the alignment of the axes is off. To counteract this, I'll point towards the patchwork package, that takes out most of this pain.

    library(ggplot2)
    library(patchwork)
    
    # Get some basic plots
    dat_list <- list(move, recruit_data, settle_data)
    
    plots <- lapply(dat_list, function(df) {
      ggplot(df, aes(dist, fill = sex)) +
        geom_histogram(binwidth = 10) +
        scale_x_continuous(limits = c(0, 1200)) +
        theme(legend.position = "none")
    })
    
    # Make adjustments to each plot as needed
    plots[[1]] <- plots[[1]] + labs(x = "Distance settled (m)", y = "Number of fixes") + 
      theme(legend.position = c(1,1), legend.justification = c(1,1))
    
    plots[[2]] <- plots[[2]] + labs(x = "Distance recruited (m)", y = "Number of individuals") + 
      scale_y_continuous(breaks = seq(0, 12, by = 3), limits = c(0, 12))
    
    plots[[3]] <- plots[[3]] + labs(x = "Distance from natal nest (m)", y = "Number of individuals")
    
    # Patchwork all the plots together
    plots[[1]] + plots[[2]] + plots[[3]] + plot_layout(nrow = 3)
    

    enter image description here

    And finetune to taste.