Question

I have a data.frame that includes x and y values which I want to plot (y vs. x). There are two factors, one with three levels and the other with two levels, to which each points is assigned:

df = data.frame(x=c(1:90),y=runif(90,5,10),pch=c(rep(0,30),rep(5,30),rep(6,30)),col=c(rep("red",45),rep("blue",45)),cell=c(rep("A",30),rep("B",30),rep("C",30)),group=c(rep("p",45),rep("v",45)))

As you can see, the factors are: cell and group, with respective levels: c("A","B","C") for cell and c("p","v") for group. I have three different shapes (pch) for the cell factor levels and two different colors for the group factor levels.

I want to plot the df$y vs. df$x points with pch and colors specified according to df$pch and df$col and have two legends side by side: one for the cell factor levels and the other for the group factor levels or one legend with two columns of both factors.

So far this is what I'm playing around with:

plot(df$x,df$y,pch=df$pch,col=as.character(df$col),xlim=c(min(df$x),max(df$x)+5),ylim=c(min(df$y),max(df$y)+2))
legend("topright",title="Cell",legend=c("A","B","C"),col="black",pch=c(0,5,6),bty="n",border=F)
legend(x=75,y=12,title="Group",legend=c("p","v"),col=c("red","blue"),lty=c(1,1),bty="n",border=F)

Which produces this plot: enter image description here

Which I'm not happy with since I need to adjust the locations of the two legends to get them properly aligned. I'm wondering whether there's a better, more automatic, way to achieve this.

On the same note, it would be nice to know if there's also an automatic way to figure out how much extra space in the plot is needed to fit the legends and specify that in the xlim and ylim rather than manually adjusting them.

One last thing - if possible I'd prefer a solution that's not ggplot

Was it helpful?

Solution

This is a bit hackish, but if you specify the ncol parameter in legend, you can force the legend to have multiple columns. That way you combine your two legend calls into one and let R handle the column creation/spacing.

The hackish part is that you then just need to manually set up the spacing on the legend title so that your "Cell" and "Group" labels fall where they need to be:

plot(df$x, df$y, pch=df$pch, col=as.character(df$col), 
     xlim=c(min(df$x),max(df$x)+5), ylim=c(min(df$y),max(df$y)+2))
legend("topright", title="Cell   Group", # << THIS IS THE HACKISH PART
       legend=c("A","B","C","p","v"), 
       col=c(rep("black",3),'red','blue'), pch=c(0,5,6,1,1),
       bty="n", border=F, ncol=2)

enter image description here

OTHER TIPS

You might want to have a look at ggplot2

ggplot(df, aes(y = y, x = x,shape = cell, colour = group)) + 
geom_point(aes(group = interaction(group,cell)))

which produces: enter image description here

Docs on ggplot2 http://docs.ggplot2.org/0.9.3.1/

Also, forgot to add: read ?interaction which is what I used in my geom_point call to compute a factor that represents interaction between cell and group.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top