tidyverse / ggplot2

An implementation of the Grammar of Graphics in R
https://ggplot2.tidyverse.org
Other
6.45k stars 2.02k forks source link

Error bar line ends are not centered and have variable width when using geom_errorbar with position_jitterdodge #5818

Closed HRodenhizer closed 3 months ago

HRodenhizer commented 5 months ago

Using ggplot2 3.5.0, I have found that the line ends of error bars do not stay centered when using position_jjitterdodge, although it works properly with position_dodge. This also leads to unexpected behavior when the error bar width is set to 0 such that little nubbins of line ends of varying width appear some distance from the rest of the error bar.

First, an example that works as expected with position_dodge:

library(tidyverse)
data = tibble(
  x = factor(c('a', 'a', 'a', 'a', 'b', 'b', 'b', 'b')),
  group = factor(c('c', 'd', 'c', 'd', 'c', 'd', 'c', 'd')),
  lower = seq(0, 3, length.out = 8),
  middle = seq(1, 4, length.out = 8),
  upper = seq(2, 5, length.out = 8)
)

# looks fine
ggplot(data, aes(x = x, color = group)) +
  geom_errorbar(aes(ymin = lower, ymax = upper),
                position = position_dodge(width = 0.75))

image

Second, an example that results in error bar ends that are not centered and have variable width (unexpected):

It is unclear to me where exactly the line ends are centered. My initial guess that they might be centered using the dodge.width, doesn't appear to be true by looking at the data located at x = a, group = c.

# ends of errorbars are not centered with postion_jitterdodge
ggplot(data, aes(x = x, y = middle, color = group)) +
  geom_errorbar(aes(ymin = lower, ymax = upper),
                position = position_jitterdodge(
                  dodge.width = 0.75,
                  seed = 1
                )
  )

image

Third, the unexpected behavior persists when width = 0:

The remaining nubbins when width = 0 appear to be related to the differing widths shown in the last example.

# setting width to 0 still shows the same issue, but now the error bars are little nubbins floating off in space
ggplot(data, aes(x = x, y = middle, color = group)) +
  geom_errorbar(aes(ymin = lower, ymax = upper),
                width = 0,
                position = position_jitterdodge(
                  dodge.width = 0.75,
                  seed = 1
                )
  )

image

Related error discovered while writing this reprex:

(this is not really the main issue, and I'm happy to move it to a different issue, if that is preferred)

position_jitterdodge requires the aesthetic, y, even though geom_errorbar does not. I'm not sure if this is the expected behavior, but it seemed unexpected from my vantage point of only wanting a horizontal jitterdodge.

# does not work without y, even though geom_errorbar doesn't require y
ggplot(data, aes(x = x, color = group)) +
  geom_errorbar(aes(ymin = lower, ymax = upper),
                position = position_jitterdodge(
                  dodge.width = 0.75,
                  seed = 1
                )
  )
Error in geom_errorbar(aes(ymin = lower, ymax = upper), position = position_jitterdodge(dodge.width = 0.75, :

ℹ Error occurred in the 1st layer.
Caused by error in `setup_data()`:
! `position_jitterdodge()` requires the following
missing aesthetics: y.
teunbrand commented 5 months ago

Hi there, thanks for the report! This is quirky indeed, though it does seem like this also happened in older ggplot2 versions, so I'm reasonably sure this isn't a regression bug. It looks like the left and right positions of where the hinge appears are also jittered, but independently from the vertical part, but I'd need to dig a little bit deeper to be sure. If that is the case, we might apply the treatment in #4403 to position_jitterdodge() as well.