Skip to content

font size relative to graphic

5 messages · David Winsemius, Mike Miller

#
I am printing numbers onto horizontal bars in a bar plots, but I am 
finding it difficult to make the number always the right size.  If there 
are more bars, the bars get narrower and the font is too big.  I also find 
that if I change the size of the graph, the bars will get wider or 
narrower and the font stays about the same size.  The result depends on 
whether I view the graph in X11 or in postscript.

Is there a way to specify font size relative to bar width, or at least 
specify font size relative to graph coordinates?

Here's a bit of what I've been doing:

x.bar.plot <- barplot(as.matrix(x), horiz=TRUE, beside=TRUE, xlim=c(0,100), xlab="Score", las=1)
text(as.matrix(x), x.bar.plot-.07, as.character(as.matrix(round(x))), pos=2, col="black")

The "-.07" is something I added to make the numbers align well with the 
bars under one condition, but it doesn't always help.

Any tips would be greatly appreciated.  Thanks in advance.

Mike

--
Michael B. Miller, Ph.D.
Minnesota Center for Twin and Family Research
Department of Psychology
University of Minnesota
#
On Apr 24, 2009, at 3:14 PM, Mike Miller wrote:

            
The values returned from the barplot function are the locations of the  
bars. Why not call barplot, collect the values, and then use the  
length of the result to determine your sizes and widths?

hh <- t(VADeaths)[, 5:1]
mybarcol <- "gray20"
mp <- barplot(hh, beside = TRUE,
         col = c("lightblue", "mistyrose",
                 "lightcyan", "lavender"),
         legend = colnames(VADeaths), ylim= c(0,100),
         main = "Death Rates in Virginia", font.main = 4,
         sub = "Faked upper 2*sigma error bars", col.sub = mybarcol,
         cex.names = 1.5)

length(mp)  #  [1] 20
#
On Fri, 24 Apr 2009, David Winsemius wrote:

            
That is exactly the kind of thing I want to do, but I don't know how the 
font size can be specified so that it fits.  My bars are horizontal and 
yours (from code below) are vertical.  Your barplot output was called "mp" 
and mine was called "x.bar.plot" and here is what they looked like:
[,1] [,2] [,3] [,4] [,5]
[1,]  1.5  6.5 11.5 16.5 21.5
[2,]  2.5  7.5 12.5 17.5 22.5
[3,]  3.5  8.5 13.5 18.5 23.5
[4,]  4.5  9.5 14.5 19.5 24.5
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,]  1.5  4.5  7.5 10.5 13.5 16.5 19.5 22.5 25.5  28.5  31.5  34.5
[2,]  2.5  5.5  8.5 11.5 14.5 17.5 20.5 23.5 26.5  29.5  32.5  35.5

They are pretty similar numbers.  It seems that [1,1] element is always 
1.5 and consecutive elements in the same column differ by 1.0, but in the 
rows we see something different: mine are 3.0 apart and yours are 5.0 
apart.  So what does this tell me?  I think fonts are specified in points 
which correspond to 1/72 inches, while bars are specified in coordinates 
that are independent of inches.  So I need to know how coordinates 
correspond to inches before I can get this fixed.

Mike
#
On Apr 24, 2009, at 4:10 PM, Mike Miller wrote:

            
They do not correspond to inches, but the the numeric scale of the  
values. Here is your plot with the numbers moved so they are to the  
right of the bar ends:

txt <- "1.5  4.5  7.5 10.5 13.5 16.5 19.5 22.5 25.5  28.5  31.5  34.5
  2.5  5.5  8.5 11.5 14.5 17.5 20.5 23.5 26.5  29.5  32.5  35.5"
x <- read.table(textConnection(txt), header=FALSE)

x.bar.plot <- barplot(as.matrix(x), horiz=TRUE, beside=TRUE,  
xlim=c(0,100), xlab="Score", las=1)
text(as.matrix(x+6), x.bar.plot-.07,  
as.character(as.matrix(round(x))), pos=2, col="black")

# the rounding is what makes the dissimilar bars labeled with the same  
numbers, ... yecch.

Haven't figured out what the requirements on sizing really are;  but  
here is an example you might play with:

text(as.matrix(x+6), x.bar.plot-.07,  
as.character(as.matrix(round(x))), pos=2, col="black",
     cex= 24/length(as.matrix(x)))


David Winsemius, MD
Heritage Laboratories
West Hartford, CT
5 days later
#
In my particular situation, the trick was to figure out what worked for 
one set of bars, then determine how bar widths changed when various 
graphing parameters changed.  Then I used that information to decide on a 
"cex" (character expansion) multiplier that worked perfectly for every 
example I produced (this was called "bar_cex" in my R code, which is shown 
below).

There are a couple of neat things about the horizontal bar plot that 
everyone can use in choosing their cex.  First, when there are n sets of m 
bars per set, then the vertical distance from the lower side of the bottom 
bar to the top side of the top bar is divided into n*(m+1)-1 equal-height 
regions and every bar width (vertical distance for horizontal bars, used 
to determine character height) is 1/(n*(m+1)-1) times that total vertical 
distance.  So just find the right cex for one set of bars, say n=3, m=2, 
so that n*(m+1)-1 = 7, then use bar_cex = cex*7/(n*(m+1)-1) for other 
values of n and m.

In my situation, using pdf with letter paper, height=11, width=8.5, I also 
used a variable number of inches empty on the top of the page.  I called 
that number of inches "top_inches".  I then figured out the correct cex 
when the plot height was at a max of .78 and used (.78-top_inches/11) to 
figure cex for other values of top_inches.  After a little arithmetic I 
came up with the equation appended below for bar_cex.  It works for me, 
but it won't work for other people.  This probably will work for other 
situations:

bar_cex <- C/(n*(m+1)-1)

Where an appropriate value of C that works for one collection of 
horizontal bars (n sets of m bars per set) will work for other sets of 
bars.

Mike


bar_cex <- (51/(n*(m+1)-1))*(.78-top_inches/11)


# generate the horizontal bar plot and store values for later use
x.bar.plot <- barplot(as.matrix(x), col=rep(rev(bar.colors[1:m]),n), horiz=TRUE,
                       beside=TRUE, xlim=c(0,100), main=bar.main.title,
                       xlab=bar.x.label, las=1, cex.names=min( c(1, 16/L) ),
                       legend=labels.legend)
# add numbers to bars
text(as.matrix(x), x.bar.plot-.1, as.character(as.matrix(round(x))), pos=2,
      offset=0.1, col="black", cex=bar_cex)

If I don't subtract .1 from x.bar.plot, the text is positioned too high 
(vertically) on the horizontal bar.
On Fri, 24 Apr 2009, David Winsemius wrote: