简体   繁体   中英

ggplot2 position_dodge affects error bar width

I am trying to make a line and point graph with errorbars. It has different factors, however some factors have only one value. I found out that if i use position_dodge, one of the single value factor has a much wider error bar compared to the other error bars in the graphs. Somehow position_dodge has an influence on the width on the error bar. I did not found anyone that had the same problem before so I hope that someone can help me.

The dummy data:

require(ggplot2)

x <- c(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,3,3,5)
y <- c(3,5,6,3,5,3,5,6,2,6,3,7,3,6,2,1,5,8,7)
se <- x*0.2
treatment <- c("A", "B","C", "D","A", "B","C", "D","A", "B","C", "D","A",    "B","C", "D","E", "F", "G" )
data <- data.frame(x, y, se ,treatment)
data$treatment <- as.factor(data$treatment)

First a plot without position_dodge - everything is fine

# Without position dodge
myplot <- ggplot(data, aes(x=x, y=y, group= treatment,  fill = treatment, colour = treatment)) +
  geom_line(stat="identity", size = 1) +
  geom_point(stat="identity", size = 3, shape = 21) + 
  geom_errorbar(aes(ymin = y-se, ymax = y+se), width = 0.2)

myplot

没有position_dodge的情节

Now a plot with position dodge:

# With position dodge
myplot <- ggplot(data, aes(x=x, y=y, group= treatment,  fill = treatment, colour = treatment)) +
  geom_line(stat="identity", size = 1, position=position_dodge(width=0.2)) +
  geom_point(stat="identity", size = 3, shape = 21, position=position_dodge(width=0.2)) + 
  geom_errorbar(aes(ymin = y-se, ymax = y+se), width = 0.2, position=position_dodge(width=0.2))

myplot

用position_dodge绘制

As you can see the error bar on the far right has a much larger width compared to the other error bars. This is probably because there are no overlapping x variables for this point, and than the error bars can have a normal size. I still would like to know how I can get the error bars to have the same width.

As @aosmith suggests, the fix for this is to scale the width of the error bar to the number of points with that x . However, this does not need to be done manually. Below I use dplyr to create a new column in the data.frame based on the number of points at that x . I've also removed the group and fill mappings since neither is needed here (provided the shape is changed to the version of a filled circle coloured by colour rather than fill ). Finally, to avoid repetition I've defined the position once and then used a variable for each geom .

library(dplyr)
data <- data %>%
  group_by(x) %>%
  mutate(
    width = 0.1 * n()
  )

pos <- position_dodge(width = 0.2)
myplot <-
  ggplot(data,
         aes(
           x = x,
           y = y,
           colour = treatment,
           width = width
         )) +
  geom_line(size = 1, position = pos) +
  geom_point(size = 3, shape = 16, position = pos) +
  geom_errorbar(aes(ymin = y - se, ymax = y + se), position = pos)

myplot

最终影像

A somewhat awkward work-around I've used in the past is to manually set the width of each error bar by using width inside of aes . The number of values within each group tells you how much to scale each error bar.

For example, if I have a group with a single value and a group with 3 values, the group of 3 width must be 3 times larger than the group of 1 width .

Your case is much more complicated, as you have a group of 1, a group of 6, and 3 groups of 4. You could start by figuring out what a good width is for the single group. I chose .1 . So the group of 6 needs to be .6 wide and the group of 4 needs to be .4 wide.

Then the trick is figuring out the order the lines are drawn for getting the widths. This is easier for simpler situations.

Plot code:

ggplot(data, aes(x = x, y = y, group = treatment,  fill = treatment, colour = treatment)) +
    geom_line(stat = "identity", size = 1, position = position_dodge(width = 0.2)) +
    geom_point(stat = "identity", size = 3, shape = 21, position = position_dodge(width = 0.2)) + 
    geom_errorbar(aes(ymin = y-se, ymax = y+se, 
                   width = c(rep(.4, 8), rep(.6, 4), rep(.4, 4), .6, .6, .1)), 
                position = position_dodge(width = 0.2))

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM