0

I am plotting means of grouped data and I'm having trouble getting the legends to be right. The text is so large that one can only see the names of two groups, not all four. I have spent a long time trying to use cex-like commands to change the size, but it doesn't work. I have tried rotating them with las=3, but it doesn't work.

enter image description here

I cannot share the data, but the code is here:

plot.question = function(number){
  #which question to plot? get ID
  question = names(sorted.by.n)[number]
  #the formula
  form = paste0("DF.scored.g.scale ~ ",question)
  #fit it to data
  fit = lm(form, DF.merged.g)
  #get ANOVA results
  fit.anova = anova(fit)
  #get ANOVA p value
  p.value = round(fit.anova[[5]][2],4) #p value
  #plot it
  plotmeans(as.formula(form), DF.merged.g,
            ylab = "4 g-items sumscore",
            xlab = "Answer",
            main = paste0(questions.unique[question,"text"],"\nANOVA p=",p.value),
            cex.main = .8,
            cex.axis = .8,
            cex.lab = .8,
            cex.sub = .8,
            las=3,) #size of main title
}

Preferably, I'd like to simply make the text smaller, so it can fit. Alternatively, I'd like to rotate it so it can fit (perhaps along with a margin change). If not what else?

One can suppress the legends with xaxt="n", but then one has to add them some other way. Can it really not be done within the plotmeans() function?

LyzandeR
  • 37,047
  • 12
  • 77
  • 87
CoderGuy123
  • 6,219
  • 5
  • 59
  • 89
  • I don't think it can happen in the function. Would you be fine if this happened outside the function? – LyzandeR Nov 29 '14 at 19:19
  • If not possible otherwise, sure. I am trying to get the code to autogenerate figures like this for all questions, so it must be able to handle cases like these. – CoderGuy123 Nov 30 '14 at 03:31

1 Answers1

1

Well I tried many things and this was the only thing that worked. Apparently plotmeans() creates a plot that you cannot modify in any way. The only thing I was able to do is to overlay text as a new only-text-plot on top of the plotmeans plot.

myfactor <- factor(rep(c('cat1','cat2','cat3'),20)) #make a factor

mynum <- runif(60) #make a numeric field

plotmeans(mynum ~ myfactor,xaxt='n') #plot them

labs <- paste(names(table(myfactor)), "") #make the names

par(new=T) #create new plot

a<-rev(as.numeric(unique(myfactor))) #count the unique factors to make a vector of their numbers to serve as the positions on the x axis

text(cex=1, x=a, y=0.2, labs, xpd=TRUE, srt=35) #insert the text on the graph.
#here you need to modify y according to your data to find the best place to plot them. 
#In my case x=c(1,2,3) because I have 3 categories and y=0.2 
#because this is the lowest value of the y axis. The srt argument rotates the text.

enter image description here

You should probably be able to either fix the y axis to have standard values and then use the minimum of that number in the y argument of the text function to make a generic function, or calculate the min value of the y axis each time.

Hope that helps!

LyzandeR
  • 37,047
  • 12
  • 77
  • 87
  • Your code idea works, but then you [get results like this](http://s29.postimg.org/bz23u3a8n/broken.png). There are lots of problems. Since I had to make the y-lim the same, now things are often too zoomed out to see error bars. Text is on the plot etc. Another idea I had was to insert newlines into the levels themselves. I did this for the main title, but there does not appear to be some easy way to do this for the levels. I could modify the entire database with newlines, but I rather not. I could pull out the relevant columns and modify them before plotting them, perhaps. – CoderGuy123 Nov 30 '14 at 14:41
  • [I wrote some code based off yours](http://pastebin.com/cxCcppYX). [The result is close to right](http://s3.postimg.org/lrurl8nsz/broken2.png). I will need to extract the y-limits from the data. This is exactly as simple because the error bars also affect the y-limits. Perhaps one can live with broken error bars. – CoderGuy123 Nov 30 '14 at 15:07
  • [Tweaking it some more](http://pastebin.com/PEAWKxY5), [I get this](http://s30.postimg.org/x1o3f7bdd/broken3b.png). It is not quite optimal in cases where the means differ very little, as the visuals will always show means as being far from each other. However, it is much better than to begin with. – CoderGuy123 Nov 30 '14 at 16:57
  • Yeah. I know you might get into a few problems like that but I really searched a lot and I think this is the best you can get. Another way would be strwrap to make the labels smaller. check [here](http://stackoverflow.com/questions/7367138/text-wrap-for-plot-titles-in-r). you can then combine that with my answer. – LyzandeR Nov 30 '14 at 17:59
  • I already use a custom function for that that does the same as strwrap. It's the one called text.splitter in the code above. [Updated code here with the function](http://pastebin.com/9jsYgtYq). There are some other occasional bugs with this code tho. In cases where one group has a mean of NA/NaN, the plot function will skip it, but the text function still adds the text. The solution is to check for NA/NaN for each mean first, but I didn't implement this yet. – CoderGuy123 Dec 01 '14 at 19:07