## Filename: plotmath-diagnosis.R
## Paul Johnson June 25, 2010
## 20161008: Some cleanup because we needed to use this in a project.
### email me <pauljohn@ku.edu>
### DKJ wondered if I could create a figure like the one on Wikipedia.


##' Creates a plot similar to a diagnostic plot we found in Wikipedia
##'
##' Given user specified values, it draws a normal curve and marks
##' some regions
##' @param mu A single real-numbered value for the expected value
##' @param sigma A real-number for the standard deviation
##' @param file A character string for the file name of the output. If
##'     NULL, draw on screen
##' @param N Default FALSE: Show Normal-based diagnostic axis
##' @param Z Default TRUE: Show Z-score-based (standardized N)
##'     diagnostic axis
##' @param t Default FALSE: Show t-score based diagnostic axis
##' @return NULL
##' @author Paul Johnson <pauljohn@@ku.edu>
plot.diagnostic <- function(mu = 10.03, sigma = 12.57, file = NULL,
                            N = FALSE, Z = TRUE, t = FALSE){
    sigma <- round(sigma, 2)
    mu <- round(mu, 2)
    myx <- seq(mu - 3.5 * sigma,  mu + 3.5 * sigma, length.out = 500)
    myDensity <- dnorm(myx, mean = mu, sd = sigma)

    myTitle1 <- bquote (paste("x ~ Normal(", mu== .(round(mu,2)), ',', sigma== .(round(sigma,2)),")") )

    ## add half inch cor each desired axis
    height <- 4.5 + 0.5*N + 0.5*Z + 0.5*T
    if (!is.null(file)){
        pdf(file = file, height = height, width = 6.5,
            onefile = FALSE, paper = "special", pointsize=10)
    } else {
        ## dev.new(height = height, width=6.5,pointsize=9)
    }

    ## xpd needed to allow writing outside strict box of graph
    ## Expand margin below to make room for  each requested axis
    par(xpd=TRUE, ps=10, mar=c(4.5 + 4 *(0.25 + N + Z + T), 2, 3, 2))

    plot(myx, myDensity, type = "l", xlab = "", ylab = "Probability Density ",
         main = myTitle1, axes = FALSE)
    axis(2, pos = mu - 3.6*sigma)
    axis(1, pos = 0)
    lines(c(myx[1], myx[length(myx)]), c(0,0)) ### closes off axes

    ## A nested function
    addInteriorLine <- function(x, m, sd){
        for (i in 1:(length(x))){
            lines( c(x[i],x[i]), c(0, dnorm(x[i],m=m,sd=sd)), lty= 14, lwd=.2)
        }
    }

    dividers <- c(qnorm(0.025), -1, 0, 1, qnorm(0.975))
    addInteriorLine(mu + sigma * dividers, mu, sigma)

    addInteriorLabel <- function(pos1, pos2, m, s){
        area <- abs(100 * (pnorm(m + pos1 * s, m, s)- pnorm(m + pos2 * s, m, s)))
        mid <- m + 0.5 * (pos1 + pos2) * s
        text(mid, 0.5 * dnorm(mid, m, s), label = paste(round(area,2), "%"))
    }

    addInteriorLabel(dividers[1], dividers[2], mu, sigma)
    addInteriorLabel(dividers[2], dividers[3], mu, sigma)
    addInteriorLabel(dividers[3], dividers[4], mu, sigma)
    addInteriorLabel(dividers[4], dividers[5], mu, sigma)

    ## Create a formula for the Normal
    normalFormula <- expression (f(x) == frac (1, sigma* sqrt(2*pi)) * e^{~~ - ~~ frac(1,2)~~ bgroup("(", frac(x-mu,sigma),")")^2})
    ## Draw the Normal formula
    text(mu + 0.5 * sigma, max(myDensity)- 0.10 * max(myDensity),  normalFormula, pos=4) 

    criticalValue <- qnorm(0.025, mu, sigma)
    ## Then grab all myx smaller than that
    specialX <-  myx[myx <= criticalValue]

    ## mark the critical value in the graph
    ## mtext(paste(round(criticalValue, 2)), 1,  at = criticalValue, line=1.5)
    ## Take sequence parallel to values of myx inside critical region
    specialY <- myDensity[myx < criticalValue]
    ##  Polygon makes a nice shaded illustration
    polygon(c(specialX[1], specialX, specialX[length(specialX )]),
            c(0, specialY, 0), density=c(-110),
            col="gray97" )

    shadedArea <- round(pnorm(criticalValue, mean = mu, sd = sigma), 2)
    text(criticalValue, 0.25 * dnorm(criticalValue, mu, sigma), label = "2.5%",pos = 2)

    criticalValue <- qnorm(0.025, mu, sigma, lower.tail = FALSE)
    ## Then grab all myx smaller than that
    specialX <-  myx[myx >= criticalValue]

    ## mark the critical value in the graph
    ## text ( criticalValue, 0 , label= paste(round(criticalValue,2)), pos=1)
    ## Take sequence parallel to values of myx inside critical region
    specialY <- myDensity[myx > criticalValue]
                                        #  Polygon makes a nice shaded illustration
    polygon(c(specialX[1], specialX, specialX[length(specialX )]),
            c(0, specialY, 0), density = c(-110),
            col = "gray97" )

    shadedArea <- round(pnorm(criticalValue, mean = mu, sd = sigma),2)
    text(criticalValue, 0.25*dnorm(criticalValue, mu, sigma), label="2.5%",pos=4)

    b1 <- expression( mu - 1.96*sigma )
    b2 <- expression( mu - sigma )
    b3 <- expression( mu )
    b4 <- expression( mu + sigma )
    b5 <- expression( mu + 1.96*sigma )

    ## bquote creates an expression that text plotters can use
    t1 <- bquote(mu -1.96*sigma== .(eval(b1)))
    t3 <-  bquote(mu== .(mu))
    t5 <- bquote(mu +1.96*sigma== .(eval(b5)))

    mtext(as.expression(c(t1, t3, t5)), 1, at = c(eval(b1), eval(b3), eval(b5)), line=1.5)

    line = 3
    if (N) {
        axis(1, line= line, at=mu+dividers*sigma, labels=c(b1,b2,b3,b4,b5), padj=0)
        mtext("N", 1, line= line +0.25, at=mu-sigma*2.5,cex=1.5)
        line <- line + 3
    }
    if (Z) {
        axis(1, line= line, at=mu+dividers*sigma, labels=c(-1.96,-1,0,1,1.96), padj=-1)
        mtext("Z", 1, line= line +0.25, at=mu-sigma*2.5,cex=1.5)
        line <- line + 3
    }
    if (t) {
        tdividers <- qt(pnorm(dividers), df=100)
        axis(1, line = line, at=mu+sigma*tdividers, labels=round(tdividers,2), padj=-1)
        mtext("t", 1, line= line +0.25, at=mu-sigma*2.5, cex=1.5) 
    }

    if (!is.null(file))  dev.off()
}

plot.diagnostic(mu=3, sigma=7)

plot of chunk unnamed-chunk-1

plot.diagnostic(mu=3, sigma=7, N = TRUE, t = TRUE)

plot of chunk unnamed-chunk-1

plot.diagnostic(mu=600, sigma=120)

plot of chunk unnamed-chunk-1

## 20160823
## This next part seems unnecessary to me, but here we go.


##' Draw a red dotted line for a given observed value
##'
##' This decorates the previously created output of plot.diagnostic
##' @param x The point at which the marker is to be inserted
##' @param mu The expected value
##' @param sigma The standard deviation
##' @return NULL
##' @author Paul Johnson <pauljohn@@ku.edu>
markValue <- function(x=0, mu=0, sigma=10) {
    normProb <- dnorm(x, m=mu, sd=sigma)
    lines( c(x,x), c(-0.025, normProb ), col="gray90",lty=1,lwd=10)
    lines( c(x,x), c(-0.025, normProb ), col="red",lty=2,lwd=2)
    S <- ifelse(x < mu, -1, 1)
    text (x+S*0.05*sigma, 1.1*normProb, label=round(x,2))
    arrows(S*1.01*x, 1.01*normProb, x+S*0.04*sigma, 0.97*1.1*normProb, code=1, length=0.1)
}

plot.diagnostic(700, 120)
markValue(600, mu = 700, sigma = 120)

plot of chunk unnamed-chunk-1

##' Puts plot.diagnostic and markValue Together
##'
##' .. content for \details{} ..
##' @title 
##' @param x 
##' @param mu 
##' @param sigma 
##' @return 
##' @author Paul Johnson
diagnostic <- function(x=0, mu=0, sigma=1){
  plot.diagnostic(mu=mu, sigma=sigma)
  markValue(x=x, mu=mu, sigma=sigma)
}

diagnostic(88, mu=70, sigma=10)

plot of chunk unnamed-chunk-1

diagnostic(48, mu=24, sigma=10)

plot of chunk unnamed-chunk-1

diagnostic(9, mu=24, sigma=10)

plot of chunk unnamed-chunk-1