2

I've got almost the exact same problem as this question: Multi-row x-axis labels in ggplot line chart. The accepted answer works for me most of the way, but depending on the size of my plot, the annotations sometimes fall off my plot.

I've tried messing around with plot and legend margins relative to the y scale, but it hasn't worked as I'd hoped. This is what I've got so far:

library(magrittr)
library(ggplot2)

test <- structure(list(
    area = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L,
                       2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L),
                     .Label = c("A", "B", "C"),
                     class = "factor"),
    Year = c(2015L, 2015L, 2015L, 2015L, 2016L, 2016L, 2016L, 2016L, 2017L,
             2017L, 2017L, 2015L, 2015L, 2015L, 2015L, 2016L, 2016L, 2016L,
             2016L, 2017L, 2017L, 2017L),
    Quarter = c(1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 1L, 2L, 3L, 4L, 1L,
                2L, 3L, 4L, 1L, 2L, 3L),
    rate = c(0.52, 0.35, 0.23, 0.36, 0.21, 0.17, 0.33, 0.26, 0.3, 0.31, 0.24,
             0.24, 0.29, 0.42, 0.15, 0.36, 0.33, 0.41, 0.27, 0.34, 0.33, 0.25)),
    class = c("tbl_df", "tbl", "data.frame"),
    row.names = c(NA, -22L),
    .Names = c("area", "Year", "Quarter", "rate"))

yMax <- max(test$rate) * 1.1
yMin <- yMax/7

fig2 <- (ggplot(test,
                mapping = aes(x = interaction(Year, Quarter, lex.order = TRUE),
                              y = rate, group = area, color = area)) +
             geom_line() +
             coord_cartesian(ylim = c(0, yMax), expand = TRUE) +
             scale_x_discrete(labels = paste0("Q", rep(1:4, 3))) +
             scale_y_continuous(name = "Rate", expand = c(0,0)) +
             annotate(geom = "text", label = unique(test$Year),
                      x = 2.5 + 4 * (0:2),
                      y = -yMin,
                      size = 5, vjust = 0) +
             annotate(geom = "segment",
                      x = c(4.5, 8.5), xend = c(4.5, 8.5),
                      y = 0, yend = -yMin * 1.1) +
             theme(plot.margin = margin(b = yMin/2, unit = "native"),
                   axis.title.x = element_blank(),
                   panel.background = element_blank(),
                   axis.line = element_line(),
                   legend.position = "bottom",
                   legend.margin = margin(t = 30, unit = "native"),
                   legend.background = element_rect(fill = alpha("red", 0.5)))
) %>%
    ggplotGrob() %>% 
    (function(x) {
        x$layout$clip[x$layout$name == "panel"] <- "off"
        return(x)
    }); grid::grid.draw(fig2)

At one size, the plot looks fine, but if I increase the height of the plot, the years start to clash with the legend, and if I make it even taller, they just disappear off the bottom.

I'm confused as to why the legend margin doesn't scale along with the size of the plot, because if it did I think that would fix my issue. Also, I'm very confused why a legend margin of 30 native units is about the same size as the plot margin of ~0.04 native units?

Plot laid out as I would like (red legend background was just so I could see what was going on): regular height

Taller plot starting to have problems: taller (problem plot)

Oliver
  • 1,098
  • 1
  • 11
  • 16
  • Are you open to moving your legend to the top instead? – Djork Mar 03 '18 at 02:30
  • @Djork I'd rather not, but anyway I don't see how that would affect the year annotations falling off the bottom of the plot if it's quite tall? I'd like a solution where I don't have to think about [this](https://i.imgur.com/6TME5UB.png) happening. – Oliver Mar 04 '18 at 16:54
  • Only because the output seemed the most consistent if I moved the legend to the top. It's the `native` units that were causing the issue for me. – Djork Mar 04 '18 at 18:31
  • @Djork Oh you're right, moving the legend does mitigate the issue quite a bit. It still doesn't seem quite right though, the bottom margin still isn't consistent in pixels or in y-axis units... – Oliver Mar 05 '18 at 10:24

1 Answers1

0

@Oliver changing the plot.margin units to lines, in, cm works for me, the issue was with the scaling in native units. Would this solution work for you?

fig2 <- (ggplot(test,
                mapping = aes(x = interaction(Year, Quarter, lex.order = TRUE),
                              y = rate, group = area, color = area)) +
           geom_line() +
           coord_cartesian(ylim = c(0, yMax), expand = TRUE) +
           scale_x_discrete(labels = paste0("Q", rep(1:4, 3))) +
           scale_y_continuous(name = "Rate", expand = c(0,0)) +
           annotate(geom = "text", label = unique(test$Year),
                    x = 2.5 + 4 * (0:2),
                    y = -yMin,
                    size = 5, vjust = 0) +
           annotate(geom = "segment",
                    x = c(4.5, 8.5), xend = c(4.5, 8.5),
                    y = 0, yend = -yMin * 1.1) +
           theme(plot.margin = margin(c(1, 1, 3, 1), unit="lines"),
                 axis.title.x = element_blank(),
                 panel.background = element_blank(),
                 axis.line = element_line(),
                 legend.position = "bottom",
                 legend.margin = margin(c(3, 1, 1, 1), unit="lines"),
                 legend.background = element_rect(fill = alpha(0.5)))
                 ) %>%
  ggplotGrob() %>% 
  (function(x) {
    x$layout$clip[x$layout$name == "panel"] <- "off"
    return(x)
  }); grid.draw(fig2)

I changed the legend.background = element_rect(fill = alpha("red", 0.5)) to legend.background = element_rect(fill = alpha(0.5)) as the upper margin is being shaded red and overlapping with the secondary axis titles.

Djork
  • 3,319
  • 1
  • 16
  • 27
  • Hmm there's still an overlap with the legend, and/or a very fat margin below the plot. The reason I chose `native` units in the first place was because I thought they'd be responsive to the height of the plot. The position of the secondary x-axis labels are always going to be responsive to the height, because they're placed on the Y axis, so I imagine the plot margin and legend placement would have to be responsive too? – Oliver Mar 05 '18 at 15:42
  • Are you plotting to a file? Do you have a desired figure height/width ratio? – Djork Mar 05 '18 at 15:46
  • I'm planning to use the plot in an Rmd that I'll knit to html. I haven't figured out what the dimensions are going to be exactly, and I was hoping I wouldn't have to manually change the spacing around any time I need a bigger or smaller figure, you know? – Oliver Mar 06 '18 at 14:24