Search code examples
rannotationscurve

r - How to annotate curves


I would like to add a label to each line of a curve plot, at the proper angle, as in the image below:

enter image description here

Here is my humble script:

I0 <- log(1)
b <- .1
curve(exp(I0 - b * x), 0, 50, 
      xlab = "No. of Species (R)", ylab = "Rate (I or E)", col = "blue", lwd = 2)
d <- .01
curve(exp(d * x) - 1, 0, 50, add = TRUE, col = "orange", lwd = 2)

I0 <- log(1/2)
curve(exp(I0 - b * x), 0, 50, add = TRUE, lty = 2, col = "green", lwd = 2)
d <- .014
curve(exp(d * x) - 1, 0, 50, add = TRUE, lty = 2, col = "red", lwd = 2)

title(main = "The equilibrium model of island biogeography")

This script generates the plot shown below:

enter image description here

I attempted to follow the suggestions from here, but could not figure out how to do it with my plot.

Any hints?


Solution

  • The trickiest part was figuring out how to use the aspect ratio, which I found from this email. Since we've got different plot devices, you'll want to change things like text size and how much above the line you want the text to be.

    Basically, we're just calculating the derivative of the curve at each point you want to make the annotation and adjusting for the aspect ratio of the figure window. From there, you calculate the angle in degrees. If you have to do this many times, you might want to consider making a function for each curve and its derivative.

    upshift = 0.025
    I0 <- log(1)
    b <- .1
    curve(exp(I0 - b * x), 0, 50, xlab = "No. of Species (R)", ylab = "Rate (I or E)", col = "blue", lwd = 2)
    
    # Get aspect ratio
    w <- par("pin")[1]/diff(par("usr")[1:2])
    h <- par("pin")[2]/diff(par("usr")[3:4])
    asp <- w/h
    
    angle = atan(-b * exp(I0) * exp(-b * 10) / asp) * 180 / pi
    text(10, exp(I0 - b * 10) + upshift, "Near", srt = angle)
    
    d <- .01
    curve(exp(d * x) - 1, 0, 50, add = TRUE, col = "orange", lwd = 2)
    angle = atan(d * exp(d * 30) / asp) * 180 / pi
    text(30, exp(d * 30)-1 + upshift, "Large", srt = angle)
    
    I0 <- log(1/2)
    curve(exp(I0 - b * x), 0, 50, add = TRUE, lty = 2, col = "green", lwd = 2)
    angle = atan(-b * exp(I0) * exp(-b * 10) / asp) * 180 / pi
    text(5, exp(I0 - b * 5) + upshift, "Far", srt = angle)
    
    d <- .014
    curve(exp(d * x) - 1, 0, 50, add = TRUE, lty = 2, col = "red", lwd = 2)
    angle = atan(d * exp(d * 30) / asp) * 180 / pi
    text(30, exp(d * 30)-1 + upshift, "Small", srt = angle)
    
    title(main = "The equilibrium model of island biogeography")
    

    enter image description here