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.
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)
In reply to the update
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.
As such you'll get the correct result by calling
arrows(graph, c(means1, means2) + c(std.err1, std.err2),
graph, c(means1, means2) - c(std.err1, std.err2),
code=3, angle=90, length=0.1)