Controlling legend size of plots in Quarto documents

My problem

I am writing a research paper in Quarto. I have included several plots, which I have generated using the plot() function (to match the original appearance of the plots, which are reproduced from one of my sources).

In some of the plots, the legend does not properly fit within the plot, like it does when I generate the plots in RStudio. This is especially a problem in the PDF version of the document. How can I control the size of the legend, so it always fits the same in different output formats?

You can view my rendered document in HTML and PDF at https://feinleib.quarto.pub/redesigning-the-filibuster-2024/.


Here are the plots with issues:

HTML:

PDF:

  • Figure 2 (p. 14)
  • Figure 3 (p. 16)
  • Figure 4 (p. 22)

Here is the code I am using to generate the plots:

Packages:

library(rlang)

Helper functions for Figs. 2-4:

#| echo: false

prob_pass <- function(x, alpha) ((x - 0.5) / 0.5) ^ alpha
benefits <- function(x) (1 - x) / 0.5
eb_pass <- function(x, alpha) prob_pass(x, alpha) * benefits(x)

## plotting helpers
# linetypes legend
plot_legend <- function(x, y, linetypes) {
  legend(x = x, y = y, 
         legend = c(expr(pi), "B", 
                    # EB or EB_K
                    expr(!!parse_expr(gsub("_K", "[K]", names(linetypes)[3])))), 
         lty = c(linetypes$pi, linetypes$B, linetypes$EB),
         box.col = "white")
}

# plot frame
plot_frame <- function(main) {
  plot(NULL, xlim = c(0.51, 1), ylim = c(0,1),
       xlab = "Coalition size", 
       ylab = "Probability of passage/expected benefits",
       main = main)
}

# plot curves
plot_curves <- function(pi_fn, b_fn, eb_fn, linetypes, ...) {
  curve(lapply(x, \(x) pi_fn(x, ...)), 
        add = T, lty = linetypes$pi)
  curve(b_fn,
        add = T, lty = linetypes$B)
  curve(lapply(x, \(x) eb_fn(x, ...)),
        add = T, lty = linetypes$EB)
}

# plot max EB
plot_max_eb <- function(eb_fn, ...) {
  max_eb <- which.max(vapply(X = seq(0.51, 1, 0.01), 
                             FUN = \(x) eb_fn(x, ...),
                             FUN.VALUE = numeric(1))) * 0.01 + 0.5
  points(max_eb, eb_fn(max_eb, ...), 
         # diamond shape
         pch = 18, cex = 2)
}

Fig. 2:

#| echo: false
#| label: fig-ws
#| fig-cap: Expected benefits of passage under WS (maximum expected benefits marked)
#| fig-asp: 1.1

plot_eb <- function(alpha) {
  linetypes <- list(pi = "dashed",
                    B = "dotted",
                    EB = "solid")
  
  # plot frame
  plot_frame(main = expr(paste(alpha, " = ", !!alpha)))
  # plot curves (pi, B, EB)
  plot_curves(pi_fn = prob_pass, b_fn = benefits, eb_fn = eb_pass, 
              linetypes = linetypes, alpha = alpha)
  # plot linetype legend
  plot_legend(x = 0.85, y = 0.75, linetypes = linetypes)
  # plot max EB
  plot_max_eb(eb_pass, alpha = alpha)
}

par(mfrow = c(2,2))
plot_eb(0.1)
plot_eb(0.25)
plot_eb(0.5)
plot_eb(0.75)

Helper functions for Figs. 3-4:

#| echo: false

prob_pass_k <- function(x, alpha, alpha_star, k) {
  ifelse(x < k,
         prob_pass(x, alpha),
         prob_pass(x, alpha_star))
}

eb_pass_k <- function(x, alpha, alpha_star, k) {
  prob_pass_k(x, alpha, alpha_star, k) * benefits(x)
}

Fig. 3:

#| echo: false
#| label: fig-wsk
#| fig-cap: Expected benefits of passage under WS~K~ with a three-fifths cloture rule (maximum expected benefits marked)
#| fig-asp: 1.1

plot_eb_k <- function(alpha, alpha_star, k) {
  linetypes <- list(pi = "dashed",
                    B = "dotted",
                    EB_K = "solid")
  
  # plot frame
  plot_frame(main = expr(paste(alpha, " = ", !!alpha, ", ",
                               alpha, "*", " = ", !!alpha_star)))
  # plot curves (pi, B, EB_K)
  plot_curves(pi_fn = prob_pass_k, b_fn = benefits, eb_fn = eb_pass_k, 
              linetypes = linetypes, alpha = alpha, 
              k = k, alpha_star = alpha_star)
  # plot linetype legend
  plot_legend(x = 0.8, y = 0.75, linetypes = linetypes)
  # plot max EB
  plot_max_eb(eb_pass_k, alpha = alpha, alpha_star = alpha_star, k = k)
}

par(mfrow = c(2,2))
plot_eb_k(alpha = 0.1, alpha_star = 0.05, k = 0.60)
plot_eb_k(alpha = 0.25, alpha_star = 0.1, k = 0.60)
plot_eb_k(alpha = 0.5, alpha_star = 0.25, k = 0.60)
plot_eb_k(alpha = 0.75, alpha_star = 0.5, k = 0.60)

Fig. 4:

#| echo: false
#| label: fig-abolish-filibuster
#| fig-cap: "Change in proponents' expected benefits after abolishing the filibuster"
#| fig-asp: 0.57

par(mfrow = c(1, 2))
plot_eb_k(alpha = 0.25, alpha_star = 0.1, k = 0.60)
plot_eb(0.1)