 jaydoc -4 years ago 104
R Question

# Grouped bar plots with SEM errorbars using base graphics in R?

Edit: Based on comments below I decided to be more explicit. So here is an example of the data I am working on.

``````> example_data
A     B        outcome
1  2.31  1.47       Y
2  2.14  1.32       N
3  3.49  1.00       Y
4  2.12  0.62       Y
5  0.47  0.55       N
6  3.36  0.50       N
7  3.50  0.33       Y
8  1.97  0.39       Y
9  3.12  0.99       N
10 2.04  0.89       Y
11 2.78  0.36       Y
12 1.83  0.70       N
13 3.53  0.77       N
14 2.25  0.39       N
15 1.67  0.43       N
16 3.09  1.10       Y
``````

So, I have two variables
`A`
and
`B`
. They are subgroups of a larger variable, so they can be represented in the same y axis. I want to group them by another variable
`outcome`
which has two levels.

I do the following

``````> dataset <- example_data
> attach(dataset)
> means1<- tapply(A,outcome,function(x) mean(x,na.rm=TRUE))
> means2<- tapply(B,outcome,function(x) mean(x,na.rm=TRUE))
> std.err1<- tapply(A,outcome,function(x)sd(x,na.rm=TRUE)/sqrt(length(na.omit(x))))
> std.err2<- tapply(B,outcome,function(x)sd(x,na.rm=TRUE)/sqrt(length(na.omit(x))))
> matrix_means<- matrix(c(means1,means2),byrow = TRUE)
> graph<- barplot(matrix_means, beside=TRUE, space=c(0.2,0,0.2,0), axes=FALSE, ann=FALSE, col=c("white","black","red","blue"),ylim=c(0,4), names=c("Outcome-N","Outcome-Y","Outcome-N","Outcome-Y"), xpd=FALSE)
> axis(2, cex.axis=1.5)
``````

Now I also need to use the arrows function to draw the SEM bar between the mean and
`mean+sem`
of each group.

I can get the SEMs using
`tapply`
, but do not know how to place the arrows over each of the 4 bars.

``````> arrows(graph, means1, graph, means1 + std.err1, graph, means2, graph, means2 + std.err2, code=3, angle=90, length=0.1)
``````

This does not place any arrows on the plot.

Using
`base`
graphics and not
`ggplot2`
, how do I do this? Can someone help? All my other graphs were done using the
`GrapheR`
package in
`R`
, so I am trying to do this one too using base graphics so they will all look the same for my manuscript.

Thanks. AkselA

R.S. is correct, if you make an MCVE it would be a lot easier for us to understand your problem and see how to help. If your data set is very large and it's hard to make a sensible subset of it, the preloaded datasets can come in handy. You can get a list of what's available by running `data(package="datasets")`.

In this case your question is pretty general and from what you write you're already more than half-way there. The `graph` object you've made contains the relevant x-values. With the mean and SEM values you already know where the arrows should start and how far they should extend, so all you have to do is to pass this information to the `arrow` function as vectors, and you're golden.

As you haven't supplied any data to work with I'll use the `mtcars` dataset to demonstrate.

``````data(mtcars)

summ.df <- data.frame(
mean=tapply(mtcars\$hp, mtcars\$cyl, mean),
sd=tapply(mtcars\$hp, mtcars\$cyl, sd),
n=tapply(mtcars\$hp, mtcars\$cyl, length))

summ.df\$sem <- summ.df\$sd/sqrt(summ.df\$n)

par(mar=c(2.5, 2.5, 2, 1.5))
bplt <- barplot(summ.df\$mean, col="white")
arrows(bplt, summ.df\$mean+summ.df\$sem,
bplt, summ.df\$mean-summ.df\$sem,
angle=90, code=3, xpd=NA, length=0.1)
`````` The call to `arrows` is what's causing you trouble. If you read the documentation (`?arrows`) you'll see that the four first arguments are x and y coordinates for the start and end points of the arrows. For each arrow the start and end x values are the same (they're entirely vertical) and given by `graph`, while the end and start y values are given by the mean ± SEM, respectively.
``````arrows(graph, c(means1, means2) + c(std.err1, std.err2),