# This file contains the public functions associated
# with the results of the predict from data simulations
##' @include eventData.R accrual.R longlagSettings.R simQOutput.R singleSimDetails.R eventPrediction_package.R
NULL
##' Class that contains results from the simulating event predictions
##' from Data
##' @slot limit The confidence interval width used by recQuantiles, eventQuantiles and dropoutQuantiles
##' If limit = 0.05 then the CI is the 5th - 95th percentile
##' @slot eventQuantiles The dates on which the median and CI of each event is expected to occur
##' @slot event.data The EventData object used when simulating events
##' @slot accrualGenerator The AccrualGenerator object used to recruit new subjects
##' @slot Naccrual The number of additional subjects recruited for each simulation
##' @slot time.pred.data A data frame giving the expected number of events (and CI intervals) for
##' given target dates. See vignette for further details
##' @slot event.pred.data A data frame giving the expected date (and CI intervals) for given
##' target numbers of events occurring. See vignette for further details
##' @slot recQuantiles The dates on which the median and CI of each recruitment is expected to occur
##' @slot dropoutQuantiles The dates on which the median and CI of each event is expected to occur
##' @slot singleSimDetails A SingleSimDetails object containing the subject level details of the simulation
##' see SingleSimDetails class documentaion for further details.
##' @slot dropout.shape The Weibull shape parameter of the dropout risk used for the simulations
##' @slot dropout.rate The Weibull rate parameter of the dropout risk used for the simulations (in units of day^{-1}).
##' If no dropout then this is 0
##' @slot simParams The \code{FromDataSimParam} object which contains the information
##' used to generate the survial times
##' @seealso \code{\link{show,FromDataResults-method}}, \code{\link{predict,FromDataResults-method}},
##' \code{\link{summary,FromDataResults-method}}
##' @export
setClass("FromDataResults",
slots=list(limit = "numeric",
eventQuantiles="SimQOutput",
event.data = "EventData",
accrualGenerator="AccrualGenerator",
Naccrual="numeric",
time.pred.data="data.frame",
event.pred.data="data.frame",
recQuantiles = "SimQOutput",
dropoutQuantiles="SimQOutput",
singleSimDetails="SingleSimDetails",
dropout.shape="numeric",
dropout.rate="numeric",
simParams="FromDataSimParam")
)
##' @name show
##' @rdname show-methods
##' @aliases show,FromDataResults-method
##' @export
setMethod( "show",
"FromDataResults",
function(object) {
cat("FromDataResults object, use object@param to access individual columns:\n")
cat("limit: ")
cat(object@limit)
cat("\nEvent Times\n")
show(object@eventQuantiles)
cat(".. use object@EventData@param to access individual columns:\n")
cat(str( object@event.data@subject.data))
})
##' @name predict
##' @rdname predict-methods
##' @aliases predict,FromDataResults-method
##' @export
setMethod("predict","FromDataResults",
function(object,time.pred=NULL,event.pred=NULL){
if(is.null(time.pred) && is.null(event.pred)){
stop("No predictions requested! Please enter either an event.pred or time.pred argument")
}
max.num.events <- length(object@eventQuantiles@median)
if(any(event.pred <= 0) || any(event.pred > max.num.events)){
stop(paste("Invalid event.pred must be positive and < ",max.num.events+1,
". Fewer than ", 100*object@limit ,"% of the simulations had at least " ,max.num.events+1, " events.",sep=""))
}
if(!is.null(time.pred)){
time.pred <- FixDates(time.pred)
new.details <- PredictGivenDates(time.pred,object@eventQuantiles)
new.details$daysatrisk <- CalculateDaysAtRisk(object@singleSimDetails,new.details$time)
object@time.pred.data <- rbind(object@time.pred.data,new.details)
rownames(object@time.pred.data) <- NULL
}
if(!is.null(event.pred)){
new.details <- PredictGivenTargetEvents(event.pred,object@eventQuantiles)
new.details$daysatrisk <- CalculateDaysAtRisk(object@singleSimDetails,new.details$time)
object@event.pred.data <- rbind(object@event.pred.data,new.details)
rownames(object@event.pred.data) <- NULL
}
return(object)
})
##' @param round.method If the string "toMonths" then dates are rounded
##' to the nearest month. For the lower confidence interval value the month of
##' the date 15 days earlier than the given value is used
##' and for the upper confidence interval value the month of the
##' date 15 days later is used. For the median, the month is used.
##' @param text.width The width of the summary text
##' @param show.predictions Logical if TRUE then include the time.pred.data and
##' event.pred.data information in the text
##' @param show.at.risk Output the median number of at risk years
##' @rdname summary-methods
##' @name summary
##' @rdname summary-methods
##' @aliases summary,FromDataResults-method
##' @export
setMethod("summary","FromDataResults",
function(object,round.method="None",text.width=60,show.predictions=TRUE,show.at.risk=TRUE){
cat(getFromDataResultsSummaryText(object,round.method,text.width,show.predictions,show.at.risk))
})
##' @param title The title text, by default it is \code{summary(x)}
##' @param text.width Number of characters to wrap title text by.
##' @param show.obs If TRUE, add a line and points displaying the observed events.
##' @param round.method If the string "toMonths" then dates are rounded
##' to the nearest month. For the lower confidence interval value
##' the date 15 days earlier than the given value is rounded to the nearest
##' month and for the upper confidence intervalvalue the
##' date 15 dats later than the given value is rounded to the nearest month
##' @param show.predictions If TRUE show brown dashed lines at the user specified prediction
##' times/number of events.
##' @param pred.to.present If TRUE, move all predictions from past to present. Beware.
##' @param include.dropouts Include the cumulative dropouts on the graph (logical)
##' @param legend.position The position of the graph legend
##' @param custom.dates A vector of dates (in string or Date format) to be output on the x-axis
##' if NULL then default dates will be used
##' @rdname plot-methods
##' @name plot
##' @aliases plot,FromDataResults,missing-method
##' @export
setMethod( "plot",
signature( x="FromDataResults", y="missing" ),
function( x, title=getFromDataResultsSummaryText(x,round.method=round.method,text.width=text.width,
show.predictions=show.predictions),
show.title=FALSE, text.width=80, show.obs=FALSE,round.method="None",show.predictions=TRUE,
pred.to.present = FALSE, xlim = c(0,-1), ylim=NULL,include.dropouts=TRUE,
legend.position="bottomright",custom.dates=NULL) {
daysinyear <- standarddaysinyear()
#Note this function is due a refactoring
#as the rec, event and dropout lines could all call
#the same function and the
#event and dropout data could call the same function
if(pred.to.present){
warning("Using pred.to.present may mask problems with the data. This option is not recommended")
}
#First deal with margins
oldmar <- par()$mar
mar_val <- 0.5
if(show.title){
chr.pos <- which(unlist(strsplit(title,NULL)) == '\n')
chr.count <- length(chr.pos)
mar_val <- 1.5+chr.count
}
par(mar=c(5.1,4.1,mar_val,2.1))
#real data for past events
indat <- x@event.data@subject.data
indat$last.date <- LastDate(indat)
eventdata <- indat[indat$has.event==1, ]
eventdata <- eventdata[order(eventdata$last.date),]
dropoutdata <- indat[indat$withdrawn==1,]
dropoutdata <- dropoutdata[order(dropoutdata$last.date),]
inf.date <- as.Date(Inf,origin="1970-01-01")
q.median <- x@eventQuantiles@median[x@eventQuantiles@median!=inf.date]
q.upper <- x@eventQuantiles@upper[x@eventQuantiles@upper!=inf.date]
q.lower <- x@eventQuantiles@lower[x@eventQuantiles@lower!=inf.date]
#Sort out ranges
x_min <- min(x@recQuantiles@median) + xlim[1]*daysinyear/12
x_max <- if(xlim[2]>0) min(x@recQuantiles@median) + xlim[2]*daysinyear/12 else max(q.upper,q.median,q.lower)
r <- c(x_min,x_max)
N.subjects <- length(indat$rand.date)
if(pred.to.present && N.subjects > 0 && nrow(eventdata) > 0){
idx <- which(q.median < max(indat$last.date))
q.median[nrow(eventdata):max(idx)] <- as.Date(max(indat$last.date),origin="1970-01-01")
q.lower[idx] <- q.median[idx]
q.upper[idx] <- q.median[idx]
}
if(is.null(ylim)) ylim <- c(0, N.subjects + x@Naccrual)
plot(q.median, seq_along(q.median), type='l',
xlim=r,
ylim=ylim,
xlab="",
ylab="",
col="blue",
lwd = 2,
xaxt = "n",
las = 1
)
if(nrow(eventdata)> 0){
lines(eventdata$last.date, 1:nrow(eventdata), col="purple", lwd=2)
lines(c(tail(eventdata$last.date,1),max(indat$last.date)),rep(nrow(eventdata),2),col="purple",lwd=1,lty=1)
}
if(nrow(dropoutdata)>0 && include.dropouts){
lines(dropoutdata$last.date, 1:nrow(dropoutdata), col="tan", lwd=2 )
lines(c(tail(dropoutdata$last.date,1),max(indat$last.date)),rep(nrow(dropoutdata),2),col="tan",lwd=1,lty=1)
}
if(show.obs == TRUE){
if(nrow(eventdata) > 0) points( eventdata$last.date, 1:nrow(eventdata), col="purple", pch=20 )
if(nrow(dropoutdata)>0 && include.dropouts) points( dropoutdata$last.date, 1:nrow(dropoutdata), col="tan", pch=20 )
}
qs.mod <- if(is.null(custom.dates))
seq(from=r[1], to=r[2], by=(r[2]-r[1])/25 )
else
FixDates(custom.dates)
axis(1, qs.mod, format(qs.mod, "%d %b %Y"), cex.axis = .7, las=3)
mtext('N',side=2,at=median(seq_along(q.lower)),line=3, las=1)
lines(q.lower, seq_along(q.lower), type='l', lty='dashed', col="red", lwd = 2)
lines(q.upper, seq_along(q.upper), type='l', lty='dashed', col="red", lwd = 2)
lines(x@recQuantiles@median, 1:length( x@recQuantiles@median), lwd=2 )
lines(c(tail(x@recQuantiles@median,n=1),max(tail(x@recQuantiles@median,n=1),r[2])),rep(N.subjects+x@Naccrual,2),lwd=2)
lines(x@recQuantiles@lower, 1:length(x@recQuantiles@lower), lwd=1,lty="dashed")
lines(x@recQuantiles@upper, 1:length(x@recQuantiles@upper), lwd=1,lty="dashed")
if(include.dropouts && x@dropout.rate!=0){
lines(x@dropoutQuantiles@median,seq_along(x@dropoutQuantiles@median),type='l',col="aquamarine4",lwd=2)
lines(x@dropoutQuantiles@lower, 1:length(x@dropoutQuantiles@lower), lwd=1,lty="dashed",col="aquamarine3")
lines(x@dropoutQuantiles@upper, 1:length(x@dropoutQuantiles@upper), lwd=1,lty="dashed",col="aquamarine3")
}
if(nrow(eventdata)>0){
points(max(indat$last.date, na.rm=TRUE), nrow(eventdata), cex=1.5, pch=21, col="red", bg="yellow")
abline(h=nrow(eventdata), lty="dashed", col="blue")
}
abline(v=max(indat$last.date, na.rm=TRUE), lty="dashed", col="blue")
if(nrow(dropoutdata)>0){
points(max(indat$last.date, na.rm=TRUE), nrow(dropoutdata), cex=1.0, pch=21, col="tan", bg="darkslategray")
}
if(show.title==TRUE){
mtext(title,side=3,cex=0.9,adj=0)
}
if(nrow(x@event.pred.data)!=0 && show.predictions){
abline(v=x@event.pred.data$time, lty="dashed", col="brown")
abline(h=x@event.pred.data$event, lty="dashed", col="brown")
points(x@event.pred.data$time, x@event.pred.data$event, cex=1.5, pch=21, col="red", bg="yellow")
}
if(nrow(x@time.pred.data)!=0 && show.predictions){
abline(v=x@time.pred.data$time, lty="dashed", col="brown")
abline(h=x@time.pred.data$event, lty="dashed", col="brown")
points(x@time.pred.data$time, x@time.pred.data$event, cex=1.5, pch=21, col="red", bg="yellow")
}
#legend
CItext <- paste("CI [",x@limit,",",1-x@limit,"]",sep="")
leg.text <- c("Recruitment", "Predicted Events",CItext)
leg.col <- c("black","blue","red")
leg.lty <- c(1,1,8)
if(nrow(eventdata)>0){
leg.text <- c(leg.text,"Analysis Date")
leg.lty <- c(leg.lty,3)
leg.col <- c(leg.col,"blue")
}
if(show.predictions && (nrow(x@event.pred.data) > 0 || nrow(x@time.pred.data)>0) ){
leg.text <- c(leg.text,"Predictions")
leg.lty <- c(leg.lty,3)
leg.col <- c(leg.col,"brown")
}
if(include.dropouts && x@dropout.rate!=0){
leg.text <- c(leg.text,"Predicted Dropouts")
leg.lty <- c(leg.lty,1)
leg.col <- c(leg.col,"aquamarine4")
}
if(include.dropouts && x@dropout.rate==0 && sum(x@event.data@subject.data$withdrawn)!=0 ){
leg.text <- c(leg.text,"Dropouts")
leg.lty <- c(leg.lty,1)
leg.col <- c(leg.col,"tan")
}
legend(legend.position,
leg.text,col=leg.col,lty=leg.lty,text.col=leg.col,
lwd=rep(2,length(leg.text)),bty="n")
par(mar=oldmar)
})