File: plot.cox.zph.R

package info (click to toggle)
survival 3.8-6-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 15,496 kB
  • sloc: ansic: 8,088; makefile: 77
file content (139 lines) | stat: -rw-r--r-- 5,190 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
plot.cox.zph <- function(x, resid=TRUE, se=TRUE, df=4, nsmo=40, 
                         var, xlab="Time", ylab="", lty=1:2, col=1, lwd=1,
                         pch= 1, cex=1,
                         hr = FALSE, plot=TRUE, ...) {
    xx <- x$x
    yy <- x$y
    df <- max(df)     # in case df is a vector
    nvar <- ncol(yy)
    pred.x <- seq(from=min(xx), to=max(xx), length=nsmo)
    temp <- c(pred.x, xx)
    lmat <- ns(temp, df=df, intercept=TRUE)
    pmat <- lmat[1:nsmo,]       # for prediction
    xmat <- lmat[-(1:nsmo),]
    if (!is.logical(hr)) stop("hr parameter must be TRUE/FALSE")

    if (missing(ylab)) {
        if (hr)  ylab <- paste("HR(t) for", dimnames(yy)[[2]])
            else ylab <- paste("Beta(t) for", dimnames(yy)[[2]])
    }       
    if (missing(var)) var <- 1:nvar
    else {
	if (is.character(var)) var <- match(var, dimnames(yy)[[2]])
	if  (any(is.na(var)) || max(var)>nvar || min(var) <1)
	    stop("Invalid variable requested")
    }
    if (!plot) resid <- FALSE   # only return the curve
    
    # xaxt might be in ...
    if (!is.na(match("xaxt", ...names()))) doxaxis <- FALSE
    else doxaxis <- TRUE

    #
    # Figure out a 'good' set of x-axis labels.  Find 8 equally spaced
    #    values on the 'transformed' axis.  Then adjust until they correspond
    #    to rounded 'true time' values.  Avoid the edges of the x axis, or
    #    approx() may give a missing value
    if (x$transform == 'log') {
	xx <- exp(xx)
	pred.x <- exp(pred.x)
	}
    else if (x$transform != 'identity') {
	xtime <- x$time
        indx <- !duplicated(xx)  #avoid a warning message in R
	apr1  <- approx(xx[indx], xtime[indx], 
                        seq(min(xx), max(xx), length=17)[2*(1:8)])
	temp <- signif(apr1$y,2)
	apr2  <- approx(xtime[indx], xx[indx], temp)
	xaxisval <- apr2$y
	xaxislab <- rep("",8)
	for (i in 1:8) xaxislab[i] <- format(temp[i])
	}
    col <- rep(col, length=2)
    lwd <- rep(lwd, length=2)
    lty <- rep(lty, length=2)

    # Now, finally do the work
    for (i in var) {
        #   Since release 3.1-6, yy can have missing values.  If a covariate is
        # constant within a stratum then it's Shoenfeld residual is identially
        # zero for all observations in that stratum.  These "structural zeros"
        # are marked with an NA.  They contain no information and should not
        # by plotted.  Thus we need to do the spline fit one stratum at a time.
	y <- yy[,i]
        keep <- !is.na(y)
        if (!all(keep)) y <- y[keep]
        
        qmat <- qr(xmat[keep,])
        if (qmat$rank < df) {
            warning("spline fit is singular, variable ", i, " skipped")
            next
        } 

	yhat <- pmat %*% qr.coef(qmat, y)
	if (resid) yr <-range(yhat, y)
	else       yr <-range(yhat)

	if (se) {
            bk <- backsolve(qmat$qr[1:df, 1:df], diag(df))
            xtx <- bk %*% t(bk)
            seval <- ((pmat%*% xtx) *pmat) %*% rep(1, df)
    
	    temp <- 2* sqrt(x$var[i,i]*seval)
	    yup <- yhat + temp
	    ylow<- yhat - temp
	    yr <- range(yr, yup, ylow)
	    }


        if (!plot)  # return the curve
            return(list(x=pred.x, y=cbind(yhat, yup, ylow)))

        if (!hr) {
            if (x$transform=='identity')
                plot(range(xx), yr, type='n', xlab=xlab, ylab=ylab[i], ...)
            else if (x$transform=='log')
                plot(range(xx[keep]), yr, type='n', xlab=xlab, ylab=ylab[i], 
                     log='x', ...)
            else {
                if (doxaxis) {
                    plot(range(xx[keep]), yr, type='n', xlab=xlab, 
                         ylab=ylab[i], xaxt = 'n', ...)
                    axis(1, xaxisval, xaxislab)
                }
                else plot(range(xx[keep]), yr, type='n', xlab=xlab,
                          ylab=ylab[i], ...)
            }
            if (resid) points(xx[keep], y, pch=pch, cex=cex)

            lines(pred.x, yhat, lty=lty[1], col=col[1], lwd=lwd[1])
            if (se) {
                lines(pred.x, yup,  col=col[2], lty=lty[2], lwd=lwd[2])
                lines(pred.x, ylow, col=col[2], lty=lty[2], lwd=lwd[2])
	    }
        } else {    
            if (x$transform=='identity')
                plot(range(xx), exp(yr), type='n', xlab=xlab, ylab=ylab[i],
                     log='y', ...)
            else if (x$transform=='log')
                plot(range(xx[keep]), exp(yr), type='n', xlab=xlab, 
                     ylab=ylab[i], log='xy', ...)
            else {
                if (doxaxis) {
                    plot(range(xx[keep]), exp(yr), type='n', xlab=xlab, 
                         ylab=ylab[i], log='y', xaxt= 'n',...)
                    axis(1, xaxisval, xaxislab)
                }
                else  plot(range(xx[keep]), exp(yr), type='n', xlab=xlab, 
                         ylab=ylab[i], log='y', ...)
	    }
            if (resid) points(xx[keep], exp(y), pch=pch, cex=cex)

            lines(pred.x, exp(yhat), lty=lty[1], col=col[1], lwd=lwd[1])
            if (se) {
                lines(pred.x, exp(yup),  col=col[2], lty=lty[2], lwd=lwd[2])
                lines(pred.x, exp(ylow), col=col[2], lty=lty[2], lwd=lwd[2])
	    }
        }
    }
}