Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vertical line and crossbar jitter being applied differently. #2941

Closed
rharfoot opened this issue Oct 15, 2018 · 6 comments · Fixed by #4403
Closed

Vertical line and crossbar jitter being applied differently. #2941

rharfoot opened this issue Oct 15, 2018 · 6 comments · Fixed by #4403
Labels
bug an unexpected problem or unintended behavior positions 🥇
Milestone

Comments

@rharfoot
Copy link

I have this issue - basically the different components of the geom_errorbar have jitter being applied to them differently. I posted this on stack-exchange and someone there seemed to think it might be a bug.

library(tidyverse)

Basic data set:

df <- structure(list(
Test = c("A", "B", "C", "D", "A", "C", "D"), 
mean = c(1, 100.793684, 1, 1, 51.615601, 1, 2.456456), 
sd = c(1, 2.045985, 1, 1, 4.790053, 1, 4.250668), 
lower = c(2, 102.839669, 2, 2, 56.405654, 2, 6.707124), 
upper = c(0, 98.747699, 0, 0, 46.825548, 0, -1.79421)), 
row.names = c(NA, -7L), class = c("tbl_df", "tbl", "data.frame"))

Now the code I am using:

subplot <- ggplot(df, aes(x = Test, y = mean)) +
  geom_point(aes(x= Test, y = mean), 
                position = position_jitter(width = 0.2, height = 0.2))+
  geom_errorbar(aes(ymin = lower, ymax = upper),
                width = 0.1,
                position = position_jitter(width = 0.2, height = 0.2)) 
subplot

mine_ex

Thanks.

@clauswilke
Copy link
Member

There are two separate issues here. First, you need to set the seed if you need two position_jitter() calls to produce the same jitter. Second, however, there is indeed something wrong with geom_errorbar(). The vertical lines are jittered correctly but the horizontal lines are not. geom_linerange() works fine.

library(ggplot2)

df <- structure(list(
  Test = c("A", "B", "C", "D", "A", "C", "D"), 
  mean = c(1, 100.793684, 1, 1, 51.615601, 1, 2.456456), 
  sd = c(1, 2.045985, 1, 1, 4.790053, 1, 4.250668), 
  lower = c(2, 102.839669, 2, 2, 56.405654, 2, 6.707124), 
  upper = c(0, 98.747699, 0, 0, 46.825548, 0, -1.79421)), 
  row.names = c(NA, -7L), class = c("tbl_df", "tbl", "data.frame"))

# works fine once seed is set
ggplot(df, aes(x = Test, y = mean)) +
  geom_point(aes(x= Test, y = mean), 
             position = position_jitter(width = 0.2, height = 0.2, seed = 123))+
  geom_linerange(aes(ymin = lower, ymax = upper),
                 position = position_jitter(width = 0.2, height = 0.2, seed = 123)) 

# doesn't work because the crossbars don't get jittered correctly
ggplot(df, aes(x = Test, y = mean)) +
  geom_point(aes(x= Test, y = mean), 
             position = position_jitter(width = 0.2, height = 0.2, seed = 123))+
  geom_errorbar(aes(ymin = lower, ymax = upper),
                width = 0.1,
                position = position_jitter(width = 0.2, height = 0.2, seed = 123)) 

Created on 2018-10-15 by the reprex package (v0.2.1)

@rharfoot
Copy link
Author

Thanks. I always forget to set the seed, I was initially using a jitter set before the geom_ calls, but this was having the same odd errorbar problem as in the examples above. I'll look at a work-around using geom_linerange

@clauswilke
Copy link
Member

I have found out what the problem is.

The way the jittering code is set up, it actually jitters different x or y aesthetics separately, i.e., x, xmin, and xmax all get individually jittered:

trans_x <- if (params$width > 0) function(x) jitter(x, amount = params$width)
trans_y <- if (params$height > 0) function(x) jitter(x, amount = params$height)
with_seed_null(params$seed, transform_position(data, trans_x, trans_y))

The solution could be something like the following, though I don't particularly like it:
https://github.com/clauswilke/ggplot2/blob/ed9be70c14e67e5448ac9f11aadce2cfb868764d/R/position-jitter.r#L76-L89

Also, it looks like position_jitter_dodge() may suffer from the same problem:

trans_x <- if (params$jitter.width > 0) function(x) jitter(x, amount = params$jitter.width)
trans_y <- if (params$jitter.height > 0) function(x) jitter(x, amount = params$jitter.height)
with_seed_null(params$seed, transform_position(data, trans_x, trans_y))

@rharfoot
Copy link
Author

That's interesting. I have found that if I use set.seed(123) before the plotting call it fixes the problem.
I think it would still be useful to have a fix for this inside the plotting code, as it would make sense to have all the geoms following the same jitter from within the call.

@rharfoot
Copy link
Author

Actually, ignore that - I just noticed I had changed to position_dodge and forgot to reset to position_jitter when testing. Adding a pre-called set.seed() does not fix the problem.

@paleolimbot paleolimbot added bug an unexpected problem or unintended behavior positions 🥇 labels May 23, 2019
@paleolimbot
Copy link
Member

This is just quick note that the aes_to_scale() function might be useful here if it the desired behaviour is to apply a single jitter per axis:

ggplot2:::aes_to_scale(c("x", "xmin", "xmax"))
#> [1] "x" "x" "x"

Created on 2019-05-23 by the reprex package (v0.2.1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug an unexpected problem or unintended behavior positions 🥇
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants