[R] Question about 'text' (add lm summary to a plot)
Marc Schwartz (via MN)
mschwartz at mn.rr.com
Thu Jul 21 23:26:35 CEST 2005
[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.
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