https://github.com/cran/meta
Raw File
Tip revision: cfb0abfe3d1ecc26d4bdfa13c45c68fa877bdd51 authored by Guido Schwarzer on 29 November 2012, 00:00:00 UTC
version 2.1-4
Tip revision: cfb0abf
funnel.meta.R
funnel.meta <- function(x,
                        xlim=NULL, ylim=NULL, xlab=NULL, ylab=NULL,
                        comb.fixed=x$comb.fixed, comb.random=x$comb.random,
                        axes=TRUE,
                        pch=if (!inherits(x, "trimfill")) 21 else ifelse(x$trimfill, 1, 21),
                        text=NULL, cex=1,
                        lty.fixed=2, lty.random=9,
                        lwd=1, lwd.fixed=lwd, lwd.random=lwd,
                        col="black", bg="darkgray",
                        col.fixed="black", col.random="black",
                        log="", yaxis="se",
                        contour.levels=NULL, col.contour,
                        ref=ifelse(x$sm %in% c("RR", "OR", "HR"), 1, 0),
                        level=x$level,
                        studlab=FALSE, cex.studlab=0.8,
                        ...){
  
  if (!inherits(x, "meta"))
    stop("Argument 'x' must be an object of class \"meta\"")
  
  if (inherits(x, "metacum"))
    stop("Funnel plot not meaningful for object of class \"metacum\"")
  ##
  if (inherits(x, "metainf"))
    stop("Funnel plot not meaningful for object of class \"metainf\"")
  
  TE <- x$TE
  seTE <- x$seTE
  TE.fixed <- x$TE.fixed
  TE.random <- x$TE.random
  sm <- x$sm
  if (is.logical(studlab) && studlab)
    studlab <- x$studlab
  
  if (length(comb.fixed)==0){
    comb.fixed <- FALSE
  }
  ##
  if (length(comb.random)==0){
    comb.random <- FALSE
  }
  ##
  if (length(level)==0){
    level <- NULL
  }
  
  
  if(length(TE) != length(seTE))
    stop("length of argument TE and seTE must be equal")
  
  if (!is.null(level) && (level<=0|level>=1))
    stop("no valid level for confidence interval")
  
  if (!is.null(contour.levels) &&
      any(contour.levels<=0|contour.levels>=1))
    stop("contour.levels must be between 0 and 1")
  
  iyaxis <- charmatch(yaxis,
                     c("se", "size", "invvar", "invse"),
                     nomatch = NA)
  if(is.na(iyaxis) | iyaxis==0)
    stop("yaxis should be \"se\", \"size\", \"invvar\", or \"invse\"")
  ##
  yaxis <- c("se", "size", "invvar", "invse")[iyaxis]
  
  seTE[is.infinite(seTE)] <- NA
  
  if ( yaxis == "se" )
    seTE.min <- 0
  else
    seTE.min <- min(seTE, na.rm=TRUE)
  ##
  seTE.max <- max(seTE, na.rm=TRUE)
  ##
  if (!is.null(level)){
    ##
    seTE.seq <- seq(seTE.min, seTE.max, length.out=500)
    ##
    ciTE <- ci(TE.fixed, seTE.seq, level)
    ##
    TE.xlim <- 1.025*c(min(c(TE, ciTE$lower), na.rm=TRUE),
                       max(c(TE, ciTE$upper), na.rm=TRUE))
  }
  ##
  if (match(sm, c("OR", "RR", "HR"), nomatch=0)>0){
    TE <- exp(TE)
    TE.fixed <- exp(TE.fixed)
    TE.random <- exp(TE.random)
    if (!is.null(level)){
      ciTE$lower <- exp(ciTE$lower)
      ciTE$upper <- exp(ciTE$upper)
      TE.xlim <- exp(TE.xlim)
    }
    ##
    if (log=="") log <- "x"
  }
  
  
  ##
  ## y-value: weight
  ##
  if (yaxis=="invvar") weight <- 1/seTE^2
  if (yaxis=="invse")  weight <- 1/seTE
  if (yaxis=="se") weight <- seTE
  if (yaxis=="size")
    if (inherits(x, "metabin") || inherits(x, "metacont"))
      weight <- floor(x$n.e)+floor(x$n.c)
    else if (length(x$n.e)>0 & length(x$n.c)>0)
      weight <- floor(x$n.e)+floor(x$n.c)
    else if (inherits(x, "metaprop"))
      weight <- floor(x$n)
    else if (length(x$n)>0)
      weight <- floor(x$n)
    else
      stop("no information on sample size available in object '",
           deparse(substitute(x)), "'")
  
  
  ##
  ## x-axis: labels / xlim
  ##
  if (is.null(xlab)){
    if      (sm=="OR" ) xlab <- "Odds Ratio"
    else if (sm=="RD" ) xlab <- "Risk Difference"
    else if (sm=="RR" ) xlab <- "Relative Risk"
    else if (sm=="SMD") xlab <- "Standardised mean difference"
    else if (sm=="WMD"|sm=="MD") xlab <- "Mean difference"
    else if (sm=="HR" ) xlab <- "Hazard Ratio"
    else if (sm=="AS" ) xlab <- "Arcus Sinus Transformation"
    else if (sm=="proportion" ){
      if (inherits(x, "metaprop"))
        if (!x$freeman.tukey)
          xlab <- "Proportion (arcsine transformation)"
        else
          xlab <- "Proportion (Freeman-Tukey double arcsine transformation)"
    }
    else xlab <- sm
  }
  ##
  if (is.null(xlim) & !is.null(level) &
      (yaxis == "se" |
       yaxis == "invse" |
       yaxis == "invvar"))
    xlim <- TE.xlim
  else if (is.null(xlim))
    xlim <- range(TE, na.rm=TRUE)
  
  
  ##
  ## y-axis: labels / ylim
  ##
  if (yaxis=="se"   & is.null(ylab)) ylab <- "Standard error"
  if (yaxis=="size" & is.null(ylab)) ylab <- "Study size"
  if (yaxis=="invvar" & is.null(ylab)) ylab <- "Inverse of variance"
  if (yaxis=="invse" & is.null(ylab)) ylab <- "Inverse of standard error"
  ##
  if (is.null(ylim) & yaxis=="se") ylim <- c(max(weight, na.rm=TRUE), 0)
  if (is.null(ylim)              ) ylim <- range(weight, na.rm=TRUE)
  
  ##
  ## plot
  ##
  plot(TE, weight, type="n",
       xlim=xlim, ylim=ylim, xlab=xlab, ylab=ylab,
       axes=axes, log=log, ...)
  
  if (!is.null(contour.levels) & yaxis!="size"){
    ##
    if (missing(col.contour))
      if (length(contour.levels)<2)
        col.contour <- "gray50"
      else
        col.contour <- gray(seq(0.5, 0.9, len=length(contour.levels)))
    ##
    if (length(contour.levels)!=length(col.contour))
      stop("arguments 'contour.levels' and 'col.contour' must be of the same length")
    ##
    seTE.cont <- seq(seTE.max, seTE.min, length.out=500)
    ##
    if (match(sm, c("OR", "RR", "HR"), nomatch=0)>0)
      ref <- log(ref)
    ##
    j <- 0
    ##
    for (i in contour.levels){
      ##
      j <- j+1
      ##
      ciContour <- ci(ref, seTE.cont, i)
      ##
      if (match(sm, c("OR", "RR", "HR"), nomatch=0)>0){
        ciContour$TE    <- exp(ciContour$TE)
        ciContour$lower <- exp(ciContour$lower)
        ciContour$upper <- exp(ciContour$upper)
      }
      sel.l <- ciContour$lower>min(xlim) & ciContour$lower<max(xlim)
      sel.u <- ciContour$upper>min(xlim) & ciContour$upper<max(xlim)
      ##
      min.l <- min(ciContour$lower)
      max.l <- max(ciContour$lower)
      min.u <- min(ciContour$upper)
      max.u <- max(ciContour$upper)
      ##
      if (yaxis=="se"){
        if (max.u<min(xlim) | min.l > max(xlim)){
          contour.u.x <- c(min(xlim), min(xlim), max(xlim), max(xlim))
          contour.u.y <- c(min(ylim), max(ylim), max(ylim), min(ylim))
          contour.l.x <- NA
          contour.l.y <- NA
        }
        else {
          contour.l.x <- c(min(xlim), min(xlim),
                           ciContour$lower[sel.l],
                           if (any(sel.l)) max(ciContour$lower[sel.l]) else NA)
          contour.l.y <- c(min(ylim), max(ylim), seTE.cont[sel.l],
                           min(ylim))
          ##
          contour.u.x <- c(max(xlim), max(xlim),
                           ciContour$upper[sel.u],
                           if (any(sel.u)) min(ciContour$upper[sel.u]) else NA)
          contour.u.y <- c(min(ylim), max(ylim), seTE.cont[sel.u],
                           min(ylim))
        }
      }
      ##
      if (yaxis=="invvar"){
        if (max.u<min(xlim) | min.l > max(xlim)){
          contour.u.x <- c(min(xlim), min(xlim), max(xlim), max(xlim))
          contour.u.y <- c(max(ylim), min(ylim), min(ylim), max(ylim))
          contour.l.x <- NA
          contour.l.y <- NA
        }
        else {
          contour.l.x <- c(min(xlim), min(xlim),
                           ciContour$lower[sel.l],
                           if (any(sel.l)) max(ciContour$lower[sel.l]) else NA)
          contour.l.y <- c(max(ylim), min(ylim), 1/seTE.cont[sel.l]^2,
                           max(ylim))
          ##
          contour.u.x <- c(max(xlim), max(xlim),
                           ciContour$upper[sel.u],
                           if (any(sel.u)) min(ciContour$upper[sel.u]) else NA)
          contour.u.y <- c(max(ylim), min(ylim), 1/seTE.cont[sel.u]^2,
                           max(ylim))
        }
      }
      ##
      if (yaxis=="invse"){
        if (max.u<min(xlim) | min.l > max(xlim)){
          contour.u.x <- c(min(xlim), min(xlim), max(xlim), max(xlim))
          contour.u.y <- c(max(ylim), min(ylim), min(ylim), max(ylim))
          contour.l.x <- NA
          contour.l.y <- NA
        }
        else {
          contour.l.x <- c(min(xlim), min(xlim),
                           ciContour$lower[sel.l],
                           if (any(sel.l)) max(ciContour$lower[sel.l]) else NA)
          contour.l.y <- c(max(ylim), min(ylim), 1/seTE.cont[sel.l],
                           max(ylim))
          ##
          contour.u.x <- c(max(xlim), max(xlim),
                           ciContour$upper[sel.u],
                           if (any(sel.u)) min(ciContour$upper[sel.u]) else NA)
          contour.u.y <- c(max(ylim), min(ylim), 1/seTE.cont[sel.u],
                           max(ylim))
        }
      }
      ##
      polygon(contour.l.x, contour.l.y,
              col=col.contour[j], border=FALSE)
      ##
      polygon(contour.u.x, contour.u.y,
              col=col.contour[j], border=FALSE)
    }
  }
  
  if (is.null(text))
    points(TE, weight, pch=pch, cex=cex, col=col, bg=bg)
  else
    text(TE, weight, labels=text, cex=cex, col=col)
  
  if (comb.fixed)
    lines(c(TE.fixed, TE.fixed), range(ylim), lty=lty.fixed, lwd=lwd.fixed, col=col.fixed)
  
  if (comb.random)
    lines(c(TE.random, TE.random), range(ylim), lty=lty.random, lwd=lwd.random, col=col.random)
  
  if (!is.null(level) & yaxis=="se"){
    points(ciTE$lower, seTE.seq, type="l", lty=lty.fixed, lwd=lwd.fixed)
    points(ciTE$upper, seTE.seq, type="l", lty=lty.fixed, lwd=lwd.fixed)
  }
  
  if (!is.null(level) & yaxis=="invvar"){
    points(ciTE$lower, 1/seTE.seq^2, type="l", lty=lty.fixed, lwd=lwd.fixed)
    points(ciTE$upper, 1/seTE.seq^2, type="l", lty=lty.fixed, lwd=lwd.fixed)
  }
  
  if (!is.null(level) & yaxis=="invse"){
    points(ciTE$lower, 1/seTE.seq, type="l", lty=lty.fixed, lwd=lwd.fixed)
    points(ciTE$upper, 1/seTE.seq, type="l", lty=lty.fixed, lwd=lwd.fixed)
  }

  if (!is.null(contour.levels) & yaxis!="size")
    res <- list(col.contour=col.contour)
  else
    res <- NULL

  if (!is.logical(studlab) && length(studlab)>0)
    text(TE, weight, labels=studlab, pos=2, cex=cex.studlab)  
  
  invisible(res)
}
back to top