[R] Question about 'text' (add lm summary to a plot)

Dan Bolser dmb at mrc-dunn.cam.ac.uk
Fri Jul 22 13:42:07 CEST 2005


On Thu, 21 Jul 2005, Marc Schwartz (via MN) wrote:

>[Note: the initial posts have been re-arranged to attempt to maintain
>the flow from top to bottom]
>
>> >Dan Bolser writes:
>> > > 
>> > > I would like to annotate my plot with a little box containing the slope,
>> > > intercept and R^2 of a lm on the data.
>> > > 
>> > > I would like it to look like...
>> > > 
>> > >  +----------------------------+
>> > >  | Slope     :   3.45 +- 0.34 |
>> > >  | Intercept : -10.43 +- 1.42 |
>> > >  | R^2       :   0.78         |
>> > >  +----------------------------+
>> > > 
>> > > However I can't make anything this neat, and I can't find out how to
>> > > combine this with symbols for R^2 / +- (plus minus).
>> > > 
>> > > Below is my best attempt (which is franky quite pour). Can anyone
>> > > improve on the below?
>> > > 
>> > > Specifically, 
>> > > 
>> > > aligned text and numbers, 
>> > > aligned decimal places, 
>> > > symbol for R^2 in the text (expression(R^2) seems to fail with
>> > > 'paste') and +- 
>> > > 
>> > > 
>> > > 
>> > > Cheers,
>> > > Dan.
>> > > 
>> > > 
>> > > dat.lm <- lm(dat$AVG_CH_PAIRS ~ dat$CHAINS)
>> > > 
>> > > abline(coef(dat.lm),lty=2,lwd=1.5)
>> > > 
>> > > 
>> > > dat.lm.sum <- summary(dat.lm)
>> > > dat.lm.sum
>> > > 
>> > > attributes(dat.lm.sum)
>> > > 
>> > > my.text.1 <-
>> > >   paste("Slope : ",     round(dat.lm.sum$coefficients[2],2),
>> > >         "+/-",          round(dat.lm.sum$coefficients[4],2))
>> > > 
>> > > my.text.2 <-
>> > >   paste("Intercept : ", round(dat.lm.sum$coefficients[1],2),
>> > >         "+/-",          round(dat.lm.sum$coefficients[3],2))
>> > > 
>> > > my.text.3 <-
>> > >   paste("R^2 : ",       round(dat.lm.sum$r.squared,2))
>> > > 
>> > > my.text.1
>> > > my.text.2
>> > > my.text.3
>> > > 
>> > > 
>> > > ## Add legend
>> > > text(x=3,
>> > >      y=300,
>> > >      paste(my.text.1,
>> > >            my.text.2,
>> > >            my.text.3,
>> > >            sep="\n"),
>> > >      adj=c(0,0),
>> > >      cex=1
>
>
>> On Thu, 21 Jul 2005, Christoph Buser wrote:
>> 
>> >Dear Dan
>> >
>> >I can only help you with your third problem, expression and
>> >paste. You can use:
>> >
>> >plot(1:5,1:5, type = "n")
>> >text(2,4,expression(paste("Slope : ", 3.45%+-%0.34, sep = "")), pos = 4)
>> >text(2,3.8,expression(paste("Intercept : ", -10.43%+-%1.42)), pos = 4)
>> >text(2,3.6,expression(paste(R^2,": ", "0.78", sep = "")), pos = 4)
>
>> >I do not have an elegant solution for the alignment.
>
>
>On Thu, 2005-07-21 at 19:55 +0100, Dan Bolser wrote:
>> Cheers for this.
>> 
>> I was trying to get it to work, but the problem is that I need to replace
>> the values above with variables, from the following code...
>> 
>> 
>> dat.lm <- lm(dat$AVG_CH_PAIRS ~ dat$CHAINS)
>> dat.lm.sum <- summary(dat.lm)
>> 
>> my.slope.1 <- round(dat.lm.sum$coefficients[2],2)
>> my.slope.2 <- round(dat.lm.sum$coefficients[4],2)
>> 
>> my.inter.1 <- round(dat.lm.sum$coefficients[1],2)
>> my.inter.2 <- round(dat.lm.sum$coefficients[3],2)
>> 
>> my.Rsqua.1 <- round(dat.lm.sum$r.squared,2)
>> 
>> 
>> Anything I try results in either the words 'paste("Slope:", my.slope.1,
>> %+-%my.slope.2,sep="")' being written to the plot, or just
>> 'my.slope.1+-my.slope2' (where the +- is correctly written).
>> 
>> I want to script it up and write all three lines to the plot with
>> 'sep="\n"', rather than deciding three different heights.
>
>
>> Thanks very much for what you gave, its a good start for me to figure out 
>> how I am supposed to be telling R what to do!
>> 
>> Any way to just get fixed width fonts with text? (for the alignment
>> problem)
>
>
>Dan,
>
>Here is one approach. It may not be the best, but it gets the job done.
>You can certainly take this and encapsulate it in a function to automate
>the text/box placement and to pass values as arguments.
>
>A couple of quick concepts:
>
>1. As far as I know, plotmath cannot do multiple lines, so each line in
>your box needs to be done separately.
>
>2. The horizontal alignment is a bit problematic when using expression()
>or bquote() since I don't believe that multiple spaces are honored as
>such after parsing. Thus I break up each component (label, ":" and
>values) into separate text() calls. The labels are left justified.
>
>3. The alignment for the numeric values are done with right
>justification. So, as long as you use a consistent number of decimals in
>the value outputs (2 here), you should be OK. This means you might need
>to use formatC() or sprintf() to control the numeric output values on
>either side of the +/- sign.
>
>4. In the variable replacement, note the use of substitute() and the
>list of x and y arguments as replacement values in the expressions.
>
>
>
># Set your values
>my.slope.1 <- 3.45
>my.slope.2 <- 0.34
>
>my.inter.1 <- -10.43
>my.inter.2 <- 1.42
>
>my.Rsqua <- 0.78
>
>
># Create the initial plot as per Christoph's post
>plot(1:5, 1:5, type = "n")
>
>
>#-------------------------------------
># Do the Slope
>#-------------------------------------
>
>text(1, 4.5,  "Slope", pos = 4)
>text(2, 4.5, ":")
>text(3, 4.5, substitute(x %+-% y, 
>                        list(x = my.slope.1, 
>                             y = my.slope.2)),
>     pos = 2)
>
>
>#-------------------------------------
># Do the Intercept
>#-------------------------------------
>
>text(1, 4.25, "Intercept", pos = 4)
>text(2, 4.25, ":")
>text(3, 4.25, substitute(x %+-% y, 
>                         list(x = my.inter.1, 
>                              y = my.inter.2)),
>     pos = 2)
>
>
>#-------------------------------------
># Do R^2
>#-------------------------------------
>
>text(1, 4.0, expression(R^2), pos = 4)
>text(2, 4.0, ":")
>text(3, 4.0,  substitute(x, list(x = my.Rsqua)),
>     pos = 2)
>
>
>#-------------------------------------
># Do the Box
>#-------------------------------------
>
>rect(1, 3.75, 3, 4.75)
>
>
>You can adjust the x,y coordinates for the various text elements as you
>may require and can also calculate them based upon the xlim, ylim of
>your actual plot. You can also modify the 'cex' argument to text() for
>adjusting the sizes of the fonts in use.


I have been trying many different combinations of the suggestions so
far...

bquote, substitute, expression, paste, etc.

Also I was trying to use the 'expression' part of the 'legend' function to
make thing easier (make new lines, make columns, make rectangles)...

So far all in vain. 

I am sure a fairly neat solution is possible using 'legend' and
'expression', but I cant get a legend which contains a variable
substituted value *and* a special symbol.

Can anyone show me an example of this simple step, and then I can try to
build on that.


Thanks all for suggestions, its one of those 'it seems so easy' problems
(for me).

P.S. Whats with the documentation for bquote?



>BTW, to use a monospaced font, you can set par(family = "mono").
>See ?par for more information.
>
>HTH,
>
>Marc Schwartz
>
>




More information about the R-help mailing list