Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dodge two different geoms apart in ggplot2

Let's say I have two different sources of data. One is of repeated observations, and one is just a mean +/- standard error predicted by a model.

n <- 30
obs <- data.frame(
  group = rep(c("A", "B"), each = n*3),
  level = rep(rep(c("low", "med", "high"), each = n), 2),
  yval = c(
    rnorm(n, 30), rnorm(n, 50), rnorm(n, 90),
    rnorm(n, 40), rnorm(n, 55), rnorm(n, 70)
  )
) %>%
  mutate(level = factor(level, levels = c("low", "med", "high")))

model_preds <- data.frame(
  group = c("A", "A", "A", "B", "B", "B"),
  level = rep(c("low", "med", "high"), 2),
  mean = c(32,56,87,42,51,74),
  sem = runif(6, min = 2, max = 5)
)

now I can plot these on the same graph easily enough

p <- ggplot(obs, aes(x = level, y = yval, fill = group)) +
  geom_boxplot() +
  geom_point(data = model_preds, aes(x = level, y = mean), size = 2, colour = "forestgreen") +
  geom_errorbar(data = model_preds, aes(x = level, y = mean, ymax = mean + sem, ymin = mean - sem), colour = "forestgreen", size = 1) +
  facet_wrap(~group)

enter image description here

and use that the visually look at the difference between the model predictions and the observed results.

But I think this looks a bit ugly, so ideally would want to 'dodge' the point-and-errorbars geom(s) from the boxplot geom.

If you'll forgive my quick paint drawing, something like this: enter image description here

It seems like position_dodge() might be the way to go but I haven't figured out how to combine two different geoms this way and the docs don't have any examples.

Might be that it's impossible, but thought I'd ask to check

like image 724
Robert Hickman Avatar asked Jan 17 '21 20:01

Robert Hickman


People also ask

What does position Dodge do in ggplot2?

Dodging preserves the vertical position of an geom while adjusting the horizontal position. position_dodge() requires the grouping variable to be be specified in the global or geom_* layer.

What does Geom_point () do in R?

The function geom_point() adds a layer of points to your plot, which creates a scatterplot. ggplot2 comes with many geom functions that each add a different type of layer to a plot.

What is the AES in the ggplot2 system?

Aesthetic Mapping ( aes ) In ggplot2 , aesthetic means “something you can see”. Each aesthetic is a mapping between a visual cue and a variable. Examples include: position (i.e., on the x and y axes) color (“outside” color)


1 Answers

As a consequence of the grammer of graphics, which clearly separates various aspects of plotting, there is no way to communicate information between different layers (geoms and stats) of a plot. This also means that a position adjustment cannot be shared across layers, such that they can be dodged in a multi-layer fashion.

The next best thing you could do, is to use position = position_nudge() in every layer, so that across the layers they seem dodged. You might also want to adjust the width parameter of the boxplot and errorbar for this. Example below:

library(tidyverse)

n <- 30
obs <- data.frame(
  group = rep(c("A", "B"), each = n*3),
  level = rep(rep(c("low", "med", "high"), each = n), 2),
  yval = c(
    rnorm(n, 30), rnorm(n, 50), rnorm(n, 90),
    rnorm(n, 40), rnorm(n, 55), rnorm(n, 70)
  )
) %>%
  mutate(level = factor(level, levels = c("low", "med", "high")))

model_preds <- data.frame(
  group = c("A", "A", "A", "B", "B", "B"),
  level = rep(c("low", "med", "high"), 2),
  mean = c(32,56,87,42,51,74),
  sem = runif(6, min = 2, max = 5)
)

ggplot(obs, aes(x = level, y = yval, fill = group)) +
  geom_boxplot(position = position_nudge(x = -0.3),
               width = 0.5) +
  geom_point(data = model_preds, aes(x = level, y = mean), 
             size = 2, colour = "forestgreen",
             position = position_nudge(x = 0.3)) +
  geom_errorbar(data = model_preds, 
                aes(x = level, y = mean, ymax = mean + sem, ymin = mean - sem), 
                colour = "forestgreen", size = 1, width = 0.5,
                position = position_nudge(x = 0.3)) +
  facet_wrap(~group)

Created on 2021-01-17 by the reprex package (v0.3.0)

like image 144
teunbrand Avatar answered Sep 21 '22 02:09

teunbrand