Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ggplot: bar positions shifted right with geom_segment

Tags:

r

ggplot2

I want to add a short horizontal line to a bar plot. The left edge of the line begins at the y-axis, and the right edge extends into the plotting surface. This line denotes the mean value for the y-axis variable. I'm using geom_segment() to add the line, but this shifts the positions of the bars to the right.
How can I add the line without moving the position of the bars?

Also, why does this happen? It almost seems like geom_segment() occupies a certain area of the rendering surface, rather than printing on top of the existing graph.

Sample data frame:

df
      x        y
1 FALSE 13.02041
2  TRUE 14.37956  

Without geom_segment():

p <- ggplot(df, aes(x=x, y=y))
p + geom_bar(stat = "identity")

without line

With geom_segment():

avg.y <- 14.27065
p + geom_bar(stat = "identity") + 
    geom_segment(aes(x=0, xend=.1, y=avg.y, yend=avg.y)) 

with line

like image 865
andrew_reece Avatar asked Oct 22 '25 22:10

andrew_reece


1 Answers

In the bar plot, the bars are (implicitly) centered at 1 and 2 and extend about +/- 0.45 in either direction. So, you can change the x-range of the segment to get it positioned where you want it.

ggplot(df, aes(x, y)) +
  geom_bar(stat="identity") +
  geom_segment(aes(x=0.5, xend=2.5, y=avg.y, yend=avg.y), colour="red") +
  theme_bw() 

enter image description here

In response to your comment, let's look at the underlying structure of your original plot, using ggplot_build. Now let's look at the data element of pb. Note in the first data frame, which is the internal plot data for the bars, that the bars are positioned at x=1 and x=2. xmin and xmax show the extent of the bar widths. The second data frame is the internal segment positioning. The segment is positioned from x=0 to x=0.1. So there's nothing between 0.1 (the right edge of the segment) and 0.45 (the left edge of the FALSE bar), and this can be seen in the second plot you posted in your question.

p = ggplot(df, aes(x, y)) +
  geom_bar(stat="identity") +
  geom_segment(aes(x=0, xend=0.1, y=avg.y, yend=avg.y))

pb = ggplot_build(p)
pb$data
[[1]]
  x        y PANEL group ymin     ymax xmin xmax colour   fill size linetype alpha
1 1 13.02040     1     1    0 13.02040 0.55 1.45     NA grey35  0.5        1    NA
2 2 14.37956     1     2    0 14.37956 1.55 2.45     NA grey35  0.5        1    NA

[[2]]
  x xend        y     yend PANEL group colour size linetype alpha
1 0  0.1 14.27065 14.27065     1    -1    red  0.5        1    NA
2 0  0.1 14.27065 14.27065     1    -1    red  0.5        1    NA
like image 120
eipi10 Avatar answered Oct 25 '25 12:10

eipi10