Search code examples
rplotggplot2cowplot

Cowplot: How to add tick marks and corresponding data labels to a marginal plot?


R Packages: cowplot / ggplot2

Use Case: Scatter plot with marginal histograms.

Issue: For histograms, I can't add bin sizes or reference lower/ upper class intervals in the x-axis. Without these histograms are difficult to read.

In cowplot, is there any way to add tick marks and corresponding data labels (in x-axis) to marginal plots, when required? E.g. for histograms in marginal plots

Basic scatter + marginal histogram plot using cowplot

require(ggplot2)
require(cowplot)

Main Plot:

pmain <- ggplot(data = mpg, aes(x = cty, y = hwy)) + 
  geom_point() +
  xlab("City driving") +
  ylab("Highway driving") + 
  theme_grey()

Marginal plot:

xbox <- axis_canvas(pmain, axis = "x") + 
  geom_histogram(
    data = mpg,
    aes(x = cty),
    colour = "black"
  )

Combined Plot:

p1 <- insert_xaxis_grob(pmain, xbox, grid::unit(0.5, "in"), position = "top")

ggdraw(p1)

Output-1

However, I'd want the following plot xbox2 to be displayed as x-axis marginal plot:

xbox2.1 <- ggplot() + 
  geom_histogram(
    data = mpg,
    aes(x = cty),
    colour = "black"
  )
hist_tab <- ggplot_build(xbox2.1)$data[[1]]

xbox2 <- xbox2.1 +
  scale_x_continuous(
    breaks = c(round(hist_tab$xmin,1),
               round(hist_tab$xmax[length(hist_tab$xmax)],1))
  ) +
  labs(x = NULL, y = NULL) + 
  theme(
    axis.text.x = element_text(angle = 90, size=7,vjust=0.5),
    axis.line = element_blank(),
    axis.text.y=element_blank(),
    axis.ticks.y=element_blank()
  )

xbox2

Output-2

But I can't create a scatter + marginal histogram (xbox2). I get the same plot as the first one:

p2 <- insert_xaxis_grob(pmain, xbox2, grid::unit(0.5, "in"), position = "top")
ggdraw(p2)

Output-3


Solution

  • Package author here. What you're seeing is the documented behavior. From the documentation of the grob argument of insert_xaxis_grob():

    The grob to insert. This will generally have been obtained via get_panel() from a ggplot2 object, in particular one generated with axis_canvas(). If a ggplot2 plot is provided instead of a grob, then get_panel() is called to extract the panel grob.

    This function is specifically not meant to stack plots. You could turn your entire plot into a grob and then insert using this function, but I'm not sure that makes a lot of sense. What you're trying to do is equivalent to stacking two plots with the same x-axis range. I think it's better to just code it like that explicitly.

    library(cowplot)
    
    xlimits <- c(6, 38)
    
    pmain <- ggplot(data = mpg, aes(x = cty, y = hwy)) + 
      geom_point() +
      xlab("City driving") +
      ylab("Highway driving") + 
      scale_x_continuous(limits = xlimits, expand = c(0, 0)) +
      theme_grey() +
      theme(plot.margin = margin(0, 5.5, 5.5, 5.5))
    
    
    xhist <- ggplot() + 
      geom_histogram(
        data = mpg,
        aes(x = cty),
        colour = "black",
        binwidth = 1,
        center = 10
      ) +
      scale_x_continuous(limits = xlimits, expand = c(0, 0), breaks = 8:35) +
      labs(x = NULL, y = NULL) + 
      theme(
        axis.text.x = element_text(angle = 90, size=7, vjust=0.5),
        axis.line = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        plot.margin = margin(5.5, 5.5, 0, 5.5)
      )
    
    plot_grid(xhist, pmain, ncol = 1, align = "v", rel_heights = c(0.2, 1))
    

    enter image description here