https://github.com/cran/lattice
Revision d21d7df76446834d6a89c768064d8f0a2fef6714 authored by Deepayan Sarkar on 21 May 2005, 00:00:00 UTC, committed by Gabor Csardi on 21 May 2005, 00:00:00 UTC
1 parent 8deee61
Raw File
Tip revision: d21d7df76446834d6a89c768064d8f0a2fef6714 authored by Deepayan Sarkar on 21 May 2005, 00:00:00 UTC
version 0.12-1
Tip revision: d21d7df
qqmath.R




### Copyright (C) 2001-2005  Deepayan Sarkar <Deepayan.Sarkar@R-project.org>
###
### This file is part of the lattice library for R.
### It is made available under the terms of the GNU General Public
### License, version 2, or at your option, any later version,
### incorporated herein by reference.
###
### This program is distributed in the hope that it will be
### useful, but WITHOUT ANY WARRANTY; without even the implied
### warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
### PURPOSE.  See the GNU General Public License for more
### details.
###
### You should have received a copy of the GNU General Public
### License along with this program; if not, write to the Free
### Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
### MA 02111-1307, USA




## Reimplementation of qqmath




prepanel.default.qqmath <-
    function(x,
             f.value = NULL,
             distribution = qnorm,
             qtype = 7,
             groups = NULL,
             subscripts, ...)
{
    if (!is.numeric(x)) x <- as.numeric(x)
    distribution <-
        if (is.function(distribution)) distribution 
        else if (is.character(distribution)) get(distribution)
        else eval(distribution)
    nobs <- sum(!is.na(x))
    getxx <- function(x, f.value = NULL,
                      nobs = sum(!is.na(x)))
    {
        if (is.null(f.value))
            distribution(ppoints(nobs))
        else
            distribution(f.value(nobs))
    }
    getyy <- function(x, f.value = NULL,
                      nobs = sum(!is.na(x)))
    {
        if (is.null(f.value))
            sort(x)
        else
            quantile(x, f.value(nobs),
                     names = FALSE,
                     type = qtype,
                     na.rm = TRUE)
    }
    if (!nobs)
        list(xlim = c(NA, NA),
             ylim = c(NA, NA),
             dx = NA, dy = NA)
    else if (!is.null(groups))
    {
        sx <- split(x, groups[subscripts])
        xxlist <- lapply(sx, getxx, f.value = f.value)
        yylist <- lapply(sx, getyy, f.value = f.value)
        list(xlim = range(unlist(xxlist), na.rm = TRUE),
             ylim = range(unlist(yylist), na.rm = TRUE),
             dx = unlist(lapply(xxlist, diff)),
             dy = unlist(lapply(yylist, diff)))
    }
    else 
    {
        xx <- getxx(x, f.value, nobs)
        yy <- getyy(x, f.value, nobs)
        list(xlim = range(xx),
             ylim = range(yy),
             dx = diff(xx),
             dy = diff(yy))
    }
}





panel.qqmath <-
    function(x,
             f.value = NULL,
             distribution = qnorm,
             qtype = 7,
             groups = NULL, ...)
{
    x <- as.numeric(x)
    distribution <-
        if (is.function(distribution)) distribution 
        else if (is.character(distribution)) get(distribution)
        else eval(distribution)
    nobs <- sum(!is.na(x))
    if (!is.null(groups))
        panel.superpose(x, y = NULL,
                        f.value = f.value,
                        distribution = distribution,
                        qtype = qtype,
                        groups = groups,
                        panel.groups = panel.qqmath,
                        ...)
    else if (nobs)
    {
        if (is.null(f.value)) # exact data instead of quantiles
            panel.xyplot(x = distribution(ppoints(nobs)),
                         y = sort(x),
                         ...)
        else
            panel.xyplot(x = distribution(f.value(nobs)), 
                         y =
                         quantile(x, f.value(nobs),
                                  names = FALSE,
                                  type = qtype,
                                  na.rm = TRUE),
                         ...)
    }
}





## qqmath2 <-
##     function(formula,
##              data = parent.frame(),
##              prepanel = prepanel.default.qqmath,
##              panel = "panel.qqmath",
##              groups = NULL,
##              distribution = qnorm,
##              f.value = NULL,
##              xlab = paste(deparse(substitute(distribution)), collapse = ""),
##              ylab,
##              ...,
##              subset = TRUE)
## {
##     dots <- list(...)
##     groups <- eval(substitute(groups), data, parent.frame())
##     subset <- eval(substitute(subset), data, parent.frame())

##     right.name <- deparse(substitute(formula))
##     try(formula <- eval(formula), silent = TRUE)
##     foo <- substitute(formula)

##     if (!(is.call(foo) && foo[[1]] == "~")) {
##         formula <- as.formula(paste("~", right.name))
##         environment(formula) <- parent.frame()
##     }
##     if (missing(ylab))
##     {
##         fright <- formula[[2]]
##         if (length(fright) == 3 && fright[[1]] == "|")
##             fright <- fright[[2]]
##         ylab <- paste(deparse(fright), collapse = "")
##     }
##     call.list <-
##         c(list(formula = formula,
##                data = data,
##                prepanel = prepanel,
##                panel = panel,
##                groups = groups,
##                panel.groups = NULL,
##                distribution = distribution,
##                f.value = f.value,
##                xlab = xlab,
##                ylab = ylab,
##                subset = subset),
##           dots)
##     ans <- do.call("densityplot", call.list)
##     ans$call <- match.call()
##     ans
## }




qqmath <-
    function(formula,
             data = parent.frame(),
             allow.multiple = is.null(groups) || outer,
             outer = !is.null(groups),
             distribution = qnorm,
             f.value = NULL,
             auto.key = FALSE,
             aspect = "fill",
             panel = "panel.qqmath",
             ## panel = if (is.null(groups)) "panel.densityplot" else "panel.superpose",
             prepanel = NULL,
             scales = list(),
             strip = TRUE,
             groups = NULL,
             xlab,
             xlim,
             ylab,
             ylim,
             drop.unused.levels = lattice.getOption("drop.unused.levels"),
             ...,
             default.scales = list(),
             subscripts = !is.null(groups),
             subset = TRUE)
{
    ## dots <- eval(substitute(list(...)), data, parent.frame())
    dots <- list(...)
    
    ## Step 1: Evaluate x, y, etc. and do some preprocessing
    
    groups <- eval(substitute(groups), data, parent.frame())
    subset <- eval(substitute(subset), data, parent.frame())

    right.name <- deparse(substitute(formula))
    try(formula <- eval(formula), silent = TRUE)
    foo <- substitute(formula)

    if (!inherits(formula, "formula"))
        formula <- as.formula(paste("~", formname))
    
    form <-
        latticeParseFormula(formula, data, subset = subset,
                            groups = groups, multiple = allow.multiple,
                            outer = outer, subscripts = TRUE,
                            drop = drop.unused.levels)

    groups <- form$groups

    if (!is.function(panel)) panel <- eval(panel)
    if (!is.function(strip)) strip <- eval(strip)

    if ("subscripts" %in% names(formals(panel))) subscripts <- TRUE
    if (subscripts) subscr <- form$subscr

    prepanel <-
        if (is.function(prepanel)) prepanel 
        else if (is.character(prepanel)) get(prepanel)
        else eval(prepanel)

    cond <- form$condition
    number.of.cond <- length(cond)
    x <- form$right
    if (number.of.cond == 0)
    {
        strip <- FALSE
        cond <- list(gl(1, length(x)))
        number.of.cond <- 1
    }

    dist.name <- paste(deparse(substitute(distribution)), collapse = "")
    if (missing(xlab)) xlab <- dist.name
    if (missing(ylab)) ylab <- form$right.name

    ## create a skeleton trellis object with the
    ## less complicated components:
    foo <-
        do.call("trellis.skeleton",
                c(list(cond = cond,
                       aspect = aspect,
                       strip = strip,
                       panel = panel,
                       xlab = xlab,
                       ylab = ylab,
                       xlab.default = dist.name,
                       ylab.default = form$right.name),
                  dots))

    dots <- foo$dots # arguments not processed by trellis.skeleton
    foo <- foo$foo
    foo$call <- match.call()

    ## Step 2: Compute scales.common (leaving out limits for now)

    ## scales <- eval(substitute(scales), data, parent.frame())
    if (is.character(scales)) scales <- list(relation = scales)
    scales <- updateList(default.scales, scales)
    foo <- c(foo, do.call("construct.scales", scales))


    ## Step 3: Decide if limits were specified in call:
    
    have.xlim <- !missing(xlim)
    if (!is.null(foo$x.scales$limit)) {
        have.xlim <- TRUE
        xlim <- foo$x.scales$limit
    }
    have.ylim <- !missing(ylim)
    if (!is.null(foo$y.scales$limit)) {
        have.ylim <- TRUE
        ylim <- foo$y.scales$limit
    }

    ## Step 4: Decide if log scales are being used:

    have.xlog <- !is.logical(foo$x.scales$log) || foo$x.scales$log
    have.ylog <- !is.logical(foo$y.scales$log) || foo$y.scales$log

    ## This is slightly weird because 'x' is eventually plotted in the
    ## Y-axis
    if (have.xlog)
    {
        warning("Can't have log X-scale")
        have.xlog <- FALSE
        foo$x.scales$log <- FALSE
    }
    if (have.ylog)
    {
        ylog <- foo$y.scales$log
        ybase <-
            if (is.logical(ylog)) 10
            else if (is.numeric(ylog)) ylog
            else if (ylog == "e") exp(1)
        
        x <- log(x, ybase)
        if (have.ylim) ylim <- log(ylim, ybase)
    }


    ## Step 5: Process cond

    cond.max.level <- unlist(lapply(cond, nlevels))


    ## Old NA-handling:
    ##     id.na <- is.na(x)
    ##     for (var in cond)
    ##         id.na <- id.na | is.na(var)
    ##     if (!any(!id.na)) stop("nothing to draw")

    ## new NA-handling: will retain NA's in x

    id.na <- do.call("pmax", lapply(cond, is.na))
    if (!any(!id.na)) stop("nothing to draw")



    ## Step 6: Evaluate layout, panel.args.common and panel.args

    foo$panel.args.common <-
        c(list(distribution = distribution,
               f.value = f.value),
          dots)

    if (subscripts)
    {
        foo$panel.args.common$groups <- groups
    }

    nplots <- prod(cond.max.level)
    if (nplots != prod(sapply(foo$condlevels, length))) stop("mismatch")
    foo$panel.args <- vector(mode = "list", length = nplots)


    cond.current.level <- rep(1, number.of.cond)


    for (panel.number in seq(length = nplots))
    {
        id <- !id.na
        for(i in seq(length = number.of.cond))
        {
            var <- cond[[i]]
            id <- id &
            if (is.shingle(var))
                ((var >=
                  levels(var)[[cond.current.level[i]]][1])
                 & (var <=
                    levels(var)[[cond.current.level[i]]][2]))
            else (as.numeric(var) == cond.current.level[i])
        }

        foo$panel.args[[panel.number]] <-
            list(x = x[id])
        if (subscripts)
            foo$panel.args[[panel.number]]$subscripts <-
                subscr[id]

        cond.current.level <-
            cupdate(cond.current.level,
                    cond.max.level)
    }

    more.comp <-
        c(limits.and.aspect(prepanel.default.qqmath,
                            prepanel = prepanel, 
                            have.xlim = have.xlim, xlim = xlim, 
                            have.ylim = have.ylim, ylim = ylim, 
                            x.relation = foo$x.scales$relation,
                            y.relation = foo$y.scales$relation,
                            panel.args.common = foo$panel.args.common,
                            panel.args = foo$panel.args,
                            aspect = aspect,
                            nplots = nplots,
                            x.axs = foo$x.scales$axs,
                            y.axs = foo$y.scales$axs),
          cond.orders(foo))
    foo[names(more.comp)] <- more.comp

    if (is.null(foo$legend) && !is.null(groups) &&
        (is.list(auto.key) || (is.logical(auto.key) && auto.key)))
    {
        foo$legend <-
            list(list(fun = "drawSimpleKey",
                      args =
                      updateList(list(text = levels(as.factor(groups)),
                                      points = TRUE,
                                      rectangles = FALSE,
                                      lines = FALSE),
                                 if (is.list(auto.key)) auto.key else list())))
        foo$legend[[1]]$x <- foo$legend[[1]]$args$x
        foo$legend[[1]]$y <- foo$legend[[1]]$args$y
        foo$legend[[1]]$corner <- foo$legend[[1]]$args$corner

        names(foo$legend) <- 
            if (any(c("x", "y", "corner") %in% names(foo$legend[[1]]$args)))
                "inside"
            else
                "top"
        if (!is.null(foo$legend[[1]]$args$space))
            names(foo$legend) <- foo$legend[[1]]$args$space
    }
    class(foo) <- "trellis"
    foo
}














##############################################


panel.qqmathline <-
    function(x, y = x,
             distribution = qnorm,
             p = c(0.25, 0.75),
             qtype = 7,
             groups = NULL, 
             ...)
{
    y <- as.numeric(y)
    stopifnot(length(p) == 2)
    distribution <-
        if (is.function(distribution)) distribution 
        else if (is.character(distribution)) get(distribution)
        else eval(distribution)
    nobs <- sum(!is.na(y))
    if (!is.null(groups))
        panel.superpose(x = y, y = NULL,
                        distribution = distribution,
                        p = p,
                        qtype = qtype,
                        groups = groups,
                        panel.groups = panel.qqmathline,
                        ...)
    else if (nobs)
    {
        yy <-
            quantile(y, p, names = FALSE,
                     type = qtype, na.rm = TRUE)
        xx <- distribution(p)
        r <- diff(yy)/diff(xx)
        panel.abline(c( yy[1]-xx[1]*r , r), ...)
    }
}


prepanel.qqmathline <-
    function(x, y = x,
             distribution = qnorm,
             p = c(0.25, 0.75),
             qtype = 7,
             groups = NULL,
             subscripts = TRUE,
             ...)
{
    ans <-
        prepanel.default.qqmath(x,
                                distribution = distribution,
                                qtype = qtype,
                                groups = groups,
                                subscripts = subscripts,
                                ...)
    y <- as.numeric(y)
    stopifnot(length(p) == 2)
    distribution <-
        if (is.function(distribution)) distribution 
        else if (is.character(distribution)) get(distribution)
        else eval(distribution)
    nobs <- sum(!is.na(y))
    getdy <- function(x)
    {
        diff(quantile(x, p, names = FALSE,
                      type = qtype,
                      na.rm = TRUE))
    }
    dy <- 
        if (!is.null(groups)) sapply(split(y, groups[subscripts]), getdy)
        else getdy(y)
    if (!all(is.na(dy)))
    {
        ans$dy <- dy[!is.na(dy)]
        ans$dx <- rep(diff(distribution(p)), length(ans$dy))
    }
    ans
}


## panel.qqmathline.old <-
##     function (y, distribution, p = c(0.25, 0.75), ...)
## {
##     y <- as.numeric(y)
##     stopifnot(length(p) == 2)
##     if (length(y) > 0) {
##         yy <- quantile(y, p)
##         xx <- distribution(p)
##         r <- diff(yy)/diff(xx)
##         panel.abline(c(yy[1] - xx[1] * r, r), ...)
##     }
## }



## prepanel.qqmathline.old <-
##     function(y, distribution, f.value = ppoints, p = c(0.25, 0.75), ...)
## {
##     ##if (!is.numeric(y)) 
##     y <- as.numeric(y)
##     stopifnot(length(p) == 2)
##     n <- length(y)

##     if (n > 0)
##     {
##         yy <- quantile(y, p)
##         xx <- distribution(p)
##         list(xlim = range(distribution(f.value(n))),
##              ylim = range(y),
##              dx = diff(xx),
##              dy = diff(yy))
##     }
##     else
##     {
##         list(xlim = c(NA, NA), ylim = c(NA, NA), dx = 1, dy = 1)
##     }
## }


## prepanel.default.qqmath.old <-
##     function(...)
##     prepanel.default.xyplot(...)


## panel.qqmath.old <-
##     function(...) panel.xyplot(...)


## qqmath.old <-
##     function(formula,
##              data = parent.frame(),
##              allow.multiple = FALSE,
##              outer = TRUE,
##              auto.key = FALSE,
##              aspect = "fill",
##              panel = "panel.qqmath",
##              prepanel = NULL,
##              scales = list(),
##              strip = TRUE,
##              groups = NULL,
##              xlab,
##              xlim,
##              ylab,
##              ylim,
## ###          f.value = ppoints,
##              f.value = NULL,
##              distribution = qnorm,
##              drop.unused.levels = lattice.getOption("drop.unused.levels"),
##              ...,
##              default.scales = list(),
##              subscripts = !is.null(groups),
##              subset = TRUE)
## {

##     ## dots <- eval(substitute(list(...)), data, parent.frame())
##     dots <- list(...)

##     groups <- eval(substitute(groups), data, parent.frame())
##     subset <- eval(substitute(subset), data, parent.frame())

##     ## Step 1: Evaluate x, y, etc. and do some preprocessing

##     form <-
##         latticeParseFormula(formula, data, subset = subset,
##                             groups = groups, multiple = allow.multiple,
##                             outer = outer, subscripts = TRUE,
##                             drop = drop.unused.levels)

##     groups <- form$groups

##     if (!is.function(panel)) panel <- eval(panel)
##     if (!is.function(strip)) strip <- eval(strip)
    
##     if ("subscripts" %in% names(formals(panel))) subscripts <- TRUE
##     if (subscripts) subscr <- form$subscr

##     prepanel <-
##         if (is.function(prepanel)) prepanel
##         else if (is.character(prepanel)) get(prepanel)
##         else eval(prepanel)

##     distribution.name <- deparse(substitute(distribution))
##     distribution <-
##         if (is.function(distribution)) distribution 
##         else if (is.character(distribution)) get(distribution)
##         else eval(distribution)

##     cond <- form$condition
##     number.of.cond <- length(cond)
##     x <- form$right

##     if (number.of.cond == 0) {
##         strip <- FALSE
##         cond <- list(as.factor(rep(1, length(x))))
##         number.of.cond <- 1
##     }



    



##     if(missing(ylab)) ylab <- form$right.name
##     if(missing(xlab)) xlab <- distribution.name
##     if (is.shingle(x)) stop("x cannot be a shingle")
##     ##x <- as.numeric(x)

##     ## create a skeleton trellis object with the
##     ## less complicated components:

##     foo <- do.call("trellis.skeleton",
##                    c(list(cond = cond,
##                           aspect = aspect,
##                           strip = strip,
##                           panel = panel,
##                           xlab = xlab,
##                           ylab = ylab,
##                           xlab.default = distribution.name,
##                           ylab.default = form$right.name,
##                           distribution = distribution),
##                      dots))

##     dots <- foo$dots # arguments not processed by trellis.skeleton
##     foo <- foo$foo
##     foo$call <- match.call()

##     ## Step 2: Compute scales.common (leaving out limits for now)

##     ## scales <- eval(substitute(scales), data, parent.frame())
##     if (is.character(scales)) scales <- list(relation = scales)
##     scales <- updateList(default.scales, scales)
##     foo <- c(foo, 
##              do.call("construct.scales", scales))


##     ## Step 3: Decide if limits were specified in call:

##     have.xlim <- !missing(xlim)
##     if (!is.null(foo$x.scales$limit)) {
##         have.xlim <- TRUE
##         xlim <- foo$x.scales$limit
##     }
##     have.ylim <- !missing(ylim)
##     if (!is.null(foo$y.scales$limit)) {
##         have.ylim <- TRUE
##         ylim <- foo$y.scales$limit
##     }

##     ## Step 4: Decide if log scales are being used:

##     have.xlog <- !is.logical(foo$x.scales$log) || foo$x.scales$log
##     have.ylog <- !is.logical(foo$y.scales$log) || foo$y.scales$log
##     if (have.xlog)
##     {
##         xlog <- foo$x.scales$log
##         xbase <-
##             if (is.logical(xlog)) 10
##             else if (is.numeric(xlog)) xlog
##             else if (xlog == "e") exp(1)

##         x <- log(x, xbase)
##         if (have.xlim) xlim <- log(xlim, xbase)
##     }
##     if (have.ylog) {
##         warning("cannot use log scale for y, use different distribution")
##         foo$y.scales$log <- FALSE
##     }
    
##     ## Step 5: Process cond

##     cond.max.level <- unlist(lapply(cond, nlevels))


##     id.na <- is.na(x)
##     for (var in cond)
##         id.na <- id.na | is.na(var)
##     if (!any(!id.na)) stop("nothing to draw")
##     ## Nothing simpler ?


##     ## Step 6: Evaluate layout, panel.args.common and panel.args

##     foo$panel.args.common <- dots
##     if (subscripts) foo$panel.args.common$groups <- groups

##     nplots <- prod(cond.max.level)
##     if (nplots != prod(sapply(foo$condlevels, length))) stop("mismatch")
##     foo$panel.args <- vector(mode = "list", length = nplots)


##     cond.current.level <- rep(1, number.of.cond)


##     for (panel.number in seq(length = nplots))
##     {

##         id <- !id.na
##         for(i in 1:number.of.cond)
##         {
##             var <- cond[[i]]
##             id <- id &
##             if (is.shingle(var))
##                 ((var >=
##                   levels(var)[[cond.current.level[i]]][1])
##                  & (var <=
##                     levels(var)[[cond.current.level[i]]][2]))
##             else (as.numeric(var) == cond.current.level[i])
##         }
##         if (any(id))
##         {
##             foo$panel.args[[panel.number]] <-
##                 if (is.null(f.value)) # exact data instead of quantiles
##                     list(x = distribution(ppoints(length(x[id]))), 
##                          y = sort(x[id]))
##                 else
##                     list(x = distribution(f.value(length(x[id]))), 
##                          y = quantile(x[id], f.value(length(x[id]))))
##         }
##         else
##             foo$panel.args[[panel.number]] <-
##                 list(x = numeric(0), y = numeric(0))

##         if (subscripts)
##             foo$panel.args[[panel.number]]$subscripts <-
##                 subscr[id]

##         cond.current.level <-
##             cupdate(cond.current.level,
##                     cond.max.level)
##     }


##     more.comp <- c(limits.and.aspect(prepanel.default.qqmath,
##                                      prepanel = prepanel, 
##                                      have.xlim = have.xlim, xlim = xlim, 
##                                      have.ylim = have.ylim, ylim = ylim, 
##                                      x.relation = foo$x.scales$relation,
##                                      y.relation = foo$y.scales$relation,
##                                      panel.args.common = foo$panel.args.common,
##                                      panel.args = foo$panel.args,
##                                      aspect = aspect,
##                                      nplots = nplots,
##                                      x.axs = foo$x.scales$axs,
##                                      y.axs = foo$y.scales$axs),
##                    cond.orders(foo))
##     foo[names(more.comp)] <- more.comp

##     if (is.null(foo$legend) && !is.null(groups) &&
##         (is.list(auto.key) || (is.logical(auto.key) && auto.key)))
##     {
##         foo$legend <-
##             list(list(fun = "drawSimpleKey",
##                       args =
##                       updateList(list(text = levels(as.factor(groups)),
##                                       points = TRUE,
##                                       rectangles = FALSE,
##                                       lines = FALSE), 
##                                  if (is.list(auto.key)) auto.key else list())))
##         foo$legend[[1]]$x <- foo$legend[[1]]$args$x
##         foo$legend[[1]]$y <- foo$legend[[1]]$args$y
##         foo$legend[[1]]$corner <- foo$legend[[1]]$args$corner

##         names(foo$legend) <- 
##             if (any(c("x", "y", "corner") %in% names(foo$legend[[1]]$args)))
##                 "inside"
##             else
##                 "top"
##         if (!is.null(foo$legend[[1]]$args$space))
##             names(foo$legend) <- foo$legend[[1]]$args$space
##     }

##     class(foo) <- "trellis"
##     foo
## }





back to top