17

I need to produce a series of horizontal grouped bar charts. The barplot function does not automatically adjust the margins of the plot, therefore the text gets cut off.

  graphics.off()      # close graphics windows
   test <- matrix(c(55,65,30, 40,70,55,75,6,49,45,34,20), 
                  nrow =3 , 
               ncol=4, 
               byrow=TRUE,
               dimnames = list(c("Subgroup 1", "Subgroup 2", "Subgroup 3"),
                               c(
                                 "Category 1 Long text",
                                 "Category 2 very Long text",
                                 "Category 3 short text",
                                 "Category 4 very short text"
                                 )))
  barplot(test, 
       las=2,
       beside = TRUE,
       legend=T,
       horiz=T)

enter image description here

I can't find an option to automatically move the plot further to the right, the way R dotchart function does it ( (barchart procedure in SAS adjusts the margins automatically as well). Obviously, I can always adjust the margins manually using par function.

  par(mar=c(5.1, 13 ,4.1 ,2.1))

will move the plot to the right

enter image description here

Is there an option to move the plot to the right (i.e. adjust the margins) automatically depending on the length of the text?

I can think of 2 related appproaches to do it programmatically: 1) Calculate the length of the longest text string and accordingly adjust the left margin 2) Create a dotchart plot for the data, somehow capture the margins and use the same margins in bar chart.

Is there an easier way to do it? Thanks!

thelatemail
  • 91,185
  • 12
  • 128
  • 188
Max C
  • 2,573
  • 4
  • 23
  • 28

1 Answers1

16

I think your first idea is probably the most appropriate. Something like this seems to work okay and requires not much stuffing about.

ylabels <-  c(  "1oooooooooooo",
            "2",
            "3",
            "4"
)

test <- matrix(c(55,65,30, 40,70,55,75,6,49,45,34,20), 
                  nrow =3 , 
               ncol=4, 
               byrow=TRUE,
               dimnames = list(c("Subgroup 1", "Subgroup 2", "Subgroup 3"),
                               ylabels))

# adjust to the maximum of either the default 
# or a figure based on the maximum length
par(mar=c(5.1, max(4.1,max(nchar(ylabels))/1.8) ,4.1 ,2.1))

barplot(test, 
       las=2,
       beside = TRUE,
       legend=T,
       horiz=T)

After inspecting dotchart, a more generalisable solution may also be to use:

linch <-  max(strwidth(ylabels, "inch")+0.4, na.rm = TRUE)
par(mai=c(1.02,linch,0.82,0.42))
thelatemail
  • 91,185
  • 12
  • 128
  • 188
  • Thank you! I tried your code with different text strings, the margins work fine. How did you come up with 1.8? – Max C May 08 '12 at 00:39
  • @MaxCherny - just some basic arithmetic on the nchar:margin ratio and a bit of trial and error. I can't promise it will be adaptable to different font sizes/styles but the calculations can be pretty easily adjusted as you can see. – thelatemail May 08 '12 at 01:11
  • @thelatemail - I wonder if the solution above takes into account expansion factors, say if I set cex.lab = 2, instead of the default 1. Thanks! – Alex May 25 '12 at 01:42
  • @X.He - the second solution above should - from `?strwidth` - `cex: numeric *c*haracter *ex*pansion factor; multiplied by ‘par("cex")’ yields the final character size; the default ‘NULL’ is equivalent to ‘1’.` – thelatemail May 25 '12 at 01:46
  • @X.He - although that is the overall `cex` statement - maybe not? I'm confusing myself. – thelatemail May 25 '12 at 01:53