2

I have two plots that are located one above the other in a Shiny app.
The two plots have the same x axis, but different y axes.

The width of the x axes is different due to the length of the y axes labels (see image below).
The goal is to align the x axes of the two plots.

Minimal example:

library(shiny)
library(ggplot2)

df <- data.frame(
  stringsAsFactors = F,
  date = as.Date.factor(c("2010-01-01", "2011-01-01", "2012-01-01")),
  var1 = c(1000000, 2000000, 1500000),
  var2 = c(10, 15, 20)
)

shinyApp(
  ui = fluidPage(
    fluidRow(column(4, offset = 4, plotOutput(outputId = "plot1"))),
    fluidRow(column(4, offset = 4, plotOutput(outputId = "plot2")))
  ),
  server = function(input, output, session) {
    output$plot1 <- renderPlot(
      ggplot(data = df, mapping = aes(x = date, y = var1)) + 
        geom_line() +
        scale_x_date(breaks = df$date)
    )
    
    output$plot2 <- renderPlot(
      ggplot(data = df, mapping = aes(x = date, y = var2)) + 
        geom_bar(stat = "identity") +
        scale_x_date(breaks = df$date)
    )
  }
)

enter image description here

Community
  • 1
  • 1
Yanir Mor
  • 581
  • 3
  • 15
  • 4
    Will this help https://stackoverflow.com/a/48164920/786542? – Tung Nov 18 '18 at 20:45
  • Thanks Tung! It definitely brings me closer. However, I need to use those plots separatly in two different divs. Do you have any idea how can I access them separatly after I'm aligning them? For example, with the patchword package I tried: `plots <- p1 + p2 + plot_layout(nrow = 2)` and then `plots$assemble$plots`, but only the first plot was accessible. – Yanir Mor Nov 19 '18 at 13:09
  • 1
    Not sure if you can do that but you can give it a try with `gtable`. See one [example](https://stackoverflow.com/a/52210907/786542) here – Tung Nov 19 '18 at 17:48
  • 1
    Thank you @Tung! The second link was super useful and completely solved the problem. I'll post the solve below – Yanir Mor Nov 21 '18 at 19:30
  • my pleasure! well done! – Tung Nov 21 '18 at 19:58

1 Answers1

2

Using the gtable package solved it (credit to @Tung and his answer).
I converted both of the plots to gtables, and then matched their .$widths.

Here is the working code:

library(shiny)
library(ggplot2)
library(grid)
library(gtable)

df <- data.frame(
  stringsAsFactors = F,
  date = as.Date.factor(c("2010-01-01", "2011-01-01", "2012-01-01")),
  var1 = c(1000000, 2000000, 1500000),
  var2 = c(10, 15, 20)
)

shinyApp(
  ui = fluidPage(
    fluidRow(column(4, offset = 4, plotOutput(outputId = "plot1"))),
    fluidRow(column(4, offset = 4, plotOutput(outputId = "plot2")))
  ),
  server = function(input, output, session) {
    p1_widths <- reactiveVal(value = NULL)

    output$plot1 <- renderPlot({
      p <- ggplot(data = df, mapping = aes(x = date, y = var1)) + 
        geom_line() +
        scale_x_date(breaks = df$date, expand = c(0, 200.75))

      g <- ggplot_gtable(data = ggplot_build(plot = p))
      p1_widths(g$widths)

      grid.draw(g)
    })

    output$plot2 <- renderPlot({
      p <- ggplot(data = df, mapping = aes(x = date, y = var2)) + 
        geom_bar(stat = "identity") +
        scale_x_date(breaks = df$date, expand = c(0, 36.5))

      g <- ggplot_gtable(data = ggplot_build(plot = p))
      g$widths <- p1_widths()

      grid.draw(g)
    })
  }
)
Yanir Mor
  • 581
  • 3
  • 15