knitr::opts_chunk$set(
echo = TRUE,
collapse = TRUE,
comment = "#>",
fig.height = 3.5,
fig.width = 6)
Look, I just want to draw the plot’s legend-box and its caption on the same line.
Here’s what the basic plot looks like.
library(tidyverse)
#> Loading tidyverse: ggplot2
#> Loading tidyverse: tibble
#> Loading tidyverse: tidyr
#> Loading tidyverse: readr
#> Loading tidyverse: purrr
#> Loading tidyverse: dplyr
#> Warning: package 'dplyr' was built under R version 3.4.1
#> Conflicts with tidy packages ----------------------------------------------
#> filter(): dplyr, stats
#> lag(): dplyr, stats
df <- readr::read_csv("posterior.csv")
#> Parsed with column specification:
#> cols(
#> rowid = col_integer(),
#> rescor = col_double(),
#> parameter = col_character(),
#> test = col_character(),
#> value = col_double()
#> )
# To draw horizontal quantile intervals...
library(ggstance)
#> Warning: package 'ggstance' was built under R version 3.4.1
#>
#> Attaching package: 'ggstance'
#> The following objects are masked from 'package:ggplot2':
#>
#> geom_errorbarh, GeomErrorbarh
median_hilowh <- function(...) {
median_hilow(...) %>%
rename(x = y, xmin = ymin, xmax = ymax)
}
df$test <- factor(df$test, c("PPVT", "EVT", "PPVT-EVT"))
base_plot <- ggplot(df) +
aes(x = value, y = parameter, color = forcats::fct_rev(test)) +
geom_vline(xintercept = 0, size = 2, color = "white") +
stat_summaryh(fun.data = median_hilowh, geom = "linerangeh",
fun.args = list(.95), size = .5,
position = position_dodgev(height = .5)) +
stat_summaryh(fun.data = median_hilowh,
geom = "linerangeh", fun.args = list(.80), size = 1.5,
position = position_dodgev(height = .5)) +
stat_summaryh(fun.x = median, geom = "point", size = 3,
position = position_dodgev(height = .5)) +
labs(x = NULL, y = NULL) +
scale_color_discrete(
name = NULL,
breaks = c("PPVT", "EVT", "PPVT-EVT"),
guide = guide_legend(direction = "horizontal"),
labels = expression(PPVT, EVT, PPVT-EVT)) +
theme(
legend.margin = margin(11/5 * .9),
legend.justification = c(0, 0),
legend.position = "bottom"
)
base_plot
Now I add the caption
bad_plot <- base_plot +
labs(caption = "Intervals: thick 90%, thin 95%. Point: median.")
bad_plot
How can I get them on the same line?
I looked the printing method from the ggplot2 code and learned that the parts of the plot live in a table grob.
base_plot_data <- ggplot_build(base_plot)
base_plot_gtable <- ggplot_gtable(base_plot_data)
base_plot_gtable
#> TableGrob (12 x 7) "layout": 18 grobs
#> z cells name grob
#> 1 0 ( 1-12, 1- 7) background rect[plot.background..rect.201]
#> 2 5 ( 5- 5, 3- 3) spacer zeroGrob[NULL]
#> 3 7 ( 6- 6, 3- 3) axis-l absoluteGrob[GRID.absoluteGrob.172]
#> 4 3 ( 7- 7, 3- 3) spacer zeroGrob[NULL]
#> 5 6 ( 5- 5, 4- 4) axis-t zeroGrob[NULL]
#> 6 1 ( 6- 6, 4- 4) panel gTree[panel-1.gTree.158]
#> 7 9 ( 7- 7, 4- 4) axis-b absoluteGrob[GRID.absoluteGrob.165]
#> 8 4 ( 5- 5, 5- 5) spacer zeroGrob[NULL]
#> 9 8 ( 6- 6, 5- 5) axis-r zeroGrob[NULL]
#> 10 2 ( 7- 7, 5- 5) spacer zeroGrob[NULL]
#> 11 10 ( 4- 4, 4- 4) xlab-t zeroGrob[NULL]
#> 12 11 ( 8- 8, 4- 4) xlab-b zeroGrob[NULL]
#> 13 12 ( 6- 6, 2- 2) ylab-l zeroGrob[NULL]
#> 14 13 ( 6- 6, 6- 6) ylab-r zeroGrob[NULL]
#> 15 14 (10-10, 4- 4) guide-box gtable[guide-box]
#> 16 15 ( 3- 3, 4- 4) subtitle zeroGrob[plot.subtitle..zeroGrob.198]
#> 17 16 ( 2- 2, 4- 4) title zeroGrob[plot.title..zeroGrob.197]
#> 18 17 (11-11, 4- 4) caption zeroGrob[plot.caption..zeroGrob.199]
bad_plot_data <- ggplot_build(bad_plot)
bad_plot_gtable <- ggplot_gtable(bad_plot_data)
bad_plot_gtable
#> TableGrob (12 x 7) "layout": 18 grobs
#> z cells name grob
#> 1 0 ( 1-12, 1- 7) background rect[plot.background..rect.266]
#> 2 5 ( 5- 5, 3- 3) spacer zeroGrob[NULL]
#> 3 7 ( 6- 6, 3- 3) axis-l absoluteGrob[GRID.absoluteGrob.235]
#> 4 3 ( 7- 7, 3- 3) spacer zeroGrob[NULL]
#> 5 6 ( 5- 5, 4- 4) axis-t zeroGrob[NULL]
#> 6 1 ( 6- 6, 4- 4) panel gTree[panel-1.gTree.221]
#> 7 9 ( 7- 7, 4- 4) axis-b absoluteGrob[GRID.absoluteGrob.228]
#> 8 4 ( 5- 5, 5- 5) spacer zeroGrob[NULL]
#> 9 8 ( 6- 6, 5- 5) axis-r zeroGrob[NULL]
#> 10 2 ( 7- 7, 5- 5) spacer zeroGrob[NULL]
#> 11 10 ( 4- 4, 4- 4) xlab-t zeroGrob[NULL]
#> 12 11 ( 8- 8, 4- 4) xlab-b zeroGrob[NULL]
#> 13 12 ( 6- 6, 2- 2) ylab-l zeroGrob[NULL]
#> 14 13 ( 6- 6, 6- 6) ylab-r zeroGrob[NULL]
#> 15 14 (10-10, 4- 4) guide-box gtable[guide-box]
#> 16 15 ( 3- 3, 4- 4) subtitle zeroGrob[plot.subtitle..zeroGrob.261]
#> 17 16 ( 2- 2, 4- 4) title zeroGrob[plot.title..zeroGrob.260]
#> 18 17 (11-11, 4- 4) caption titleGrob[plot.caption..titleGrob.264]
So I figured I could drop the caption element from the second plot into the same row as the color guide from the first plot.
guide_row <- which(base_plot_gtable$layout$name == "guide-box")
caption_row <- which(bad_plot_gtable$layout$name == "caption")
merged_table <- gtable::gtable_add_grob(
base_plot_gtable,
bad_plot_gtable$grobs[[caption_row]],
t = base_plot_gtable$layout[guide_row, c("t")],
r = base_plot_gtable$layout[guide_row, c("r")],
b = base_plot_gtable$layout[guide_row, c("b")],
l = base_plot_gtable$layout[guide_row, c("l")])
merged_table
#> TableGrob (12 x 7) "layout": 19 grobs
#> z cells name grob
#> 1 0 ( 1-12, 1- 7) background rect[plot.background..rect.201]
#> 2 5 ( 5- 5, 3- 3) spacer zeroGrob[NULL]
#> 3 7 ( 6- 6, 3- 3) axis-l absoluteGrob[GRID.absoluteGrob.172]
#> 4 3 ( 7- 7, 3- 3) spacer zeroGrob[NULL]
#> 5 6 ( 5- 5, 4- 4) axis-t zeroGrob[NULL]
#> 6 1 ( 6- 6, 4- 4) panel gTree[panel-1.gTree.158]
#> 7 9 ( 7- 7, 4- 4) axis-b absoluteGrob[GRID.absoluteGrob.165]
#> 8 4 ( 5- 5, 5- 5) spacer zeroGrob[NULL]
#> 9 8 ( 6- 6, 5- 5) axis-r zeroGrob[NULL]
#> 10 2 ( 7- 7, 5- 5) spacer zeroGrob[NULL]
#> 11 10 ( 4- 4, 4- 4) xlab-t zeroGrob[NULL]
#> 12 11 ( 8- 8, 4- 4) xlab-b zeroGrob[NULL]
#> 13 12 ( 6- 6, 2- 2) ylab-l zeroGrob[NULL]
#> 14 13 ( 6- 6, 6- 6) ylab-r zeroGrob[NULL]
#> 15 14 (10-10, 4- 4) guide-box gtable[guide-box]
#> 16 15 ( 3- 3, 4- 4) subtitle zeroGrob[plot.subtitle..zeroGrob.198]
#> 17 16 ( 2- 2, 4- 4) title zeroGrob[plot.title..zeroGrob.197]
#> 18 17 (11-11, 4- 4) caption zeroGrob[plot.caption..zeroGrob.199]
#> 19 18 (10-10, 4- 4) layout titleGrob[plot.caption..titleGrob.264]
grid::grid.draw(merged_table)
This is all incredibly hacky, and I don’t really know what I’m doing, and maybe the ggplot2 authors should scold me for showing users how to mess up their plots, and I don’t thing the text lines up perfectly, but it worked, or at least, it’s the rat hole I stumbled down today.