rggplot2

Is it possible to jitter two ggplot geoms in the same way?


Using position_jitter creates random jitter to prevent overplotting of data points.

In the below I have used the example of baseball statistics to illustrate my problem. When I plot the same data with two layers, the same jitter call jitters the geoms a bit differently. This makes sense because it presumably generates the random jitter independently in the two calls, but yields the problem you can see in my graph below.

p=ggplot(baseball,aes(x=round(year,-1),y=sb,color=factor(lg))) 
p=p+stat_summary(fun.data="mean_cl_normal",position=position_jitter(width=3,height=0))+coord_cartesian(ylim=c(0,40))
p+stat_summary(fun.y=mean,geom="line",position=position_jitter(width=3,height=0))

Although the error bar points and the line refer to same data, they are disjointed—the lines and points do not connect.

Is there a work-around for this? I thought position dodge might be the answer but it doesn't seem to work with these kinds of plots. Alternatively, maybe there's some way to get the mean_cl_normal call to also add the lines? alt text


Solution

  • This is easy in newer versions of ggplot2. Most (all?) geoms accept a position argument, which according the docs

    Position adjustment, either as a string, or the result of a call to a position adjustment function.

    if you call position_jitter you'll see it returns a ggproto object with a consistent seed.

    > position_jitter()
    <ggproto object: Class PositionJitter, Position, gg>
        compute_layer: function
        compute_panel: function
        height: NULL
        required_aes: x y
        seed: 1279634412
        setup_data: function
        setup_params: function
        width: NULL
        super:  <ggproto object: Class PositionJitter, Position, gg>
    

    so to jitter multiple geoms the same way you can make one of these objects and pass it to multiple geoms like so

    data(mtcars)
    
    jitterer <- position_jitter(width = .5) #comically large jitter
    mtcars %>%
      ggplot(aes(x = weight, y = hp, ymin = hp, ymax = hp + 5)) +
      geom_point(position = jitterer) +
      geom_linerange(position = jitterer) #try removing position = jitterer and enjoy the show