#! /usr/local/bin/R #sink(paste("/home/xychris0/R/CGIwithR-log/RCSC1.R.",as.character(now),sep="")) #cat("program = RCSC1.R ; host = ",host, "; ", now, "; grid.title = ",name,"\n") sink(file="/dev/null") # to stop getting the Hmisc announcement text library(xtable) library(R2HTML) library(Hmisc) HTML <- TRUE graphDir <- "/var/psyctc/psyctc.org/stats/COREtools/scratch/" graphURLroot <- "/stats/COREtools/scratch/" if(length(system(paste("ls ",graphDir,"*.png",sep=""), intern=TRUE)) > 0 ) system(paste("rm ",graphDir,"*.png",sep="")) sink() # switch output back to stdout #zz <-file("/var/psyctc/psyctc.org/stats/COREtools/scratch/Rmess.all",open="wt") #sink(zz,type="message") #cat("\n\n") #cat("got to here (1): start of function declarations\n\n") ## functions Jacobson.plot <- function(vecdata1,vecdata2,varname,gendata,male,female,rc.crit,malecrit,femcrit,title,outdir,File,HTML=TRUE) { ## function which takes vectors of: ## vecdata1: initial scores ## vecdata2: second scores ## gendata: gender ## and scalars: ## male: value of gendata for the men ## female: value of gendata for the women ## malecrit: CSC criterion for the men ## femcrit: CSC criterion for the women ## returns vector same length as input vectors with CSC catetgories if (!is.numeric(vecdata1) | !is.numeric(vecdata2)) { stop("Scores must be numeric\n") } if (sum(is.na(vecdata1)) > 0) { stop("Missing value(s) in initial scores. Must be complete!\n") } if (sum(is.na(vecdata2)) > 0) { stop("Missing value(s) in second scores. Must be complete!\n") } if (length(vecdata1) != length(vecdata2)) { stop("Initial and second scores must be equal length!\n") } if (length(gendata) != length(vecdata1)) { stop("Length of gender vector must equal that of scores!\n") } if (!is.factor(gendata) & !is.numeric(gendata) & !is.character(gendata)) { stop("Gender vector must be factor, character or numeric!\n") } if (class(male) != class(female)) { stop("Class of male indicator must be same as that of female indicator!\n") } if (!is.factor(gendata)) { if (class(male) != class(gendata)) { stop("Class of male/female indicators must be same as that of the gender vector!\n") } } if (!is.numeric(malecrit) | !is.numeric(femcrit)) { stop("Male and female criterion scores must be numeric!\n") } ## this next one could actually be tweaked to allow lists or vectors of indicators of male or female but ... if (any(c(length(male),length(female),length(malecrit),length(femcrit)) != 1)) { stop("For now, only allow single criterion for each of gender, and gendered cut-offs!\n") } ## end of input tests n.all <- length(gendata) idx.men <- gendata==male n.male <- sum(idx.men) idx.women <- gendata==female n.female <- sum(idx.women) maxplot <- max(c(vecdata1,vecdata2)) minplot <- min(c(0,vecdata1,vecdata2)) offset <- (maxplot - minplot)/30 ##### all the data, all data, coded by gender if (HTML) { if ((n.male > 0) & (n.female) > 0) { File <- "allplot1.png" } if (n.male == 0) { File <- "maleplot.png" } if (n.female == 0) { File <- "femaleplot.png" } webPNG(file=File,width=10,height=8,res=144) par(cex=1.5) } plot(vecdata1,vecdata2,xlim=c(minplot,maxplot),ylim=c(minplot,maxplot),xlab="Before",ylab="After",type="n") if (varname !="") title(paste("Jacobson plot for \"",varname,"\"",sep="")) # reliable change ablines abline(0,1) abline(rc.crit,1) abline(-rc.crit,1) # men's data and CSC ablines par(pch=3,col="blue") points(vecdata1[idx.men],vecdata2[idx.men]) if (n.male > 0) { abline(v=malecrit) abline(h=malecrit) } # women's data and CSC ablines par(pch=1,col="red") points(vecdata1[idx.women],vecdata2[idx.women]) if (n.female > 0) { abline(v=femcrit) abline(h=femcrit) } par(pch=1,col=1) #GraphName <- paste(data.name,".",varname,".Jacobson",sep="") if (HTML) { graphics.off() cat("

") cat(title) cat("

") img(src=File) } else { cat(title) } } #cat("got to here (2): end of function declaration Jacobson.plot\n\n") print.CSC.by.RC <- function(csc,rc.chge,title,HTML=TRUE,File) { ##### crosstabulate RC cf CSC if (!is.numeric(csc) & !is.factor(csc)) { stop("CSC must be supplied as factor or numeric!\n") } if (!is.numeric(rc.chge) & !is.factor(rc.chge)) { stop("RC must be supplied as factor or numeric!\n") } if (length(csc) != length(rc.chge)) { stop("CSC and RC must be of equal lenght!\n") } if (sum(is.na(csc)) > 0) { stop("CSC must be non-missing!\n") } if (sum(is.na(rc.chge)) > 0) { stop("RC must be non-missing!\n") } require(Hmisc) n.all <- length(csc) tmp.res <- table(rc.chge,csc) newtitle <- paste("Breakdown of RC by CSC: n",title) if(HTML) { newtitle <- paste("

",newtitle,"

") cat(newtitle) nc <- dim(tmp.res)[2] tmp.res2 <- matrix(tmp.res,ncol=nc) dimnames(tmp.res2) <- list(levels(rc.chge),levels(csc)) x <- xtable(tmp.res2,display=rep("d",nc+1),caption="numbers") print(x,type="html") } else { cat(newtitle) cat(tmp.res) } did.well.n <- sum(tmp.res[1,])+tmp.res[2,1] tmp.ci1 <- binconf(did.well.n,n.all) tmp.ci1b <- paste(round(100*tmp.ci1[2],1),"% to ",round(100*tmp.ci1[3],1),"%",sep="") tmp.res <- round(100*tmp.res/n.all,2) tmp.res2 <- matrix(tmp.res,ncol=nc) dimnames(tmp.res2) <- list(levels(rc.chge),levels(csc)) did.well.perc <- round(sum(tmp.res[1,])+tmp.res[2,1],1) newtitle <- paste("Breakdown of RC by CSC: %",title) if(HTML) { newtitle <- paste("

",newtitle,"

") HTML(newtitle,File=File,Align="left") x <- xtable(tmp.res2,display=rep("d",nc+1),caption="percentages") print(x,type="html") #HTML(tmp.res,File=File) } else { cat(newtitle) cat(tmp.res) } } #cat("got to here (3): end of function declaration print.CSC.by.RC\n\n") CSC.categories <- function(vecdata1,vecdata2,gendata,male,female,malecrit,femcrit) { ## function which takes vectors of: ## vecdata1: initial scores ## vecdata2: second scores ## gendata: gender ## and scalars: ## male: value of gendata for the men ## female: value of gendata for the women ## malecrit: CSC criterion for the men ## femcrit: CSC criterion for the women ## returns vector same length as input vectors with CSC catetgories if (!is.numeric(vecdata1) | !is.numeric(vecdata2)) { stop("Scores must be numeric\n") } if (sum(is.na(vecdata1)) > 0) { stop("Missing value(s) in initial scores. Must be complete!\n") } if (sum(is.na(vecdata2)) > 0) { stop("Missing value(s) in second scores. Must be complete!\n") } if (length(vecdata1) != length(vecdata2)) { stop("Initial and second scores must be equal length!\n") } if (length(gendata) != length(vecdata1)) { stop("Length of gender vector must equal that of scores!\n") } if (!is.factor(gendata) & !is.numeric(gendata) & !is.character(gendata)) { stop("Gender vector must be factor, character or numeric!\n") } if (class(male) != class(female)) { stop("Class of male indicator must be same as that of female indicator!\n") } if (!is.factor(gendata)) { if (class(male) != class(gendata)) { stop("Class of male/female indicators must be same as that of the gender vector!\n") } } if (!is.numeric(malecrit) | !is.numeric(femcrit)) { stop("Male and female criterion scores must be numeric!\n") } ## this next one could actually be tweaked to allow lists or vectors of indicators of male or female but ... if (any(c(length(male),length(female),length(malecrit),length(femcrit)) != 1)) { stop("For now, only allow single criterion for each of gender, and gendered cut-offs!\n") } ## end of input tests n.all <- length(vecdata1) criteria <- rep(NA,n.all) men <- gendata==male women <- gendata==female criteria[men] <- malecrit criteria[women] <- femcrit starthigh <- ifelse(vecdata1 >= criteria,1,0) endhigh <- ifelse(vecdata2 >= criteria,1,0) csc <- starthigh + endhigh csc[starthigh==1 & endhigh==0] <- -1 csc[starthigh==0 & endhigh==1] <- 5 CSC <- factor(csc) levels(CSC) <- c("CS Improved","Stayed low","Stayed high","Low to high") return(CSC) } #cat("got to here (3): end of function declaration CSC.categories\n\n") print.CSC <- function(csc,title,HTML=TRUE,File) { # print those results # men and women require(Hmisc) n.all <- length(csc) tmp.res <- table(csc) if (length(tmp.res) < 4) { tmp.csc.table.tmp <- tmp.csc.table.fixed tmp.csc.table.tmp <- pad.up(tmp.res,tmp.csc) tmp.res <- tmp.csc.table.tmp } tmp.perc <- round(100*tmp.res[1:4]/n.all,1) tmp.res2 <- rbind(tmp.res[1:4],tmp.perc) tmp.res2 <- cbind(tmp.res2,c(sum(tmp.res2[1,]),sum(tmp.res2[2,]))) tmp.ci1 <- binconf(tmp.res[1],n.all) tmp.ci2 <- binconf(tmp.res[2],n.all) tmp.ci3 <- binconf(tmp.res[3],n.all) tmp.ci4 <- binconf(tmp.res[4],n.all) tmp.ci1b <- paste(round(100*tmp.ci1[2],1),"to",round(100*tmp.ci1[3],1)) tmp.ci2b <- paste(round(100*tmp.ci2[2],1),"to",round(100*tmp.ci2[3],1)) tmp.ci3b <- paste(round(100*tmp.ci3[2],1),"to",round(100*tmp.ci3[3],1)) tmp.ci4b <- paste(round(100*tmp.ci4[2],1),"to",round(100*tmp.ci4[3],1)) tmp.res3 <- rbind(tmp.res2,c(tmp.ci1b,tmp.ci2b,tmp.ci3b,tmp.ci4b,"")) dimnames(tmp.res3) <- list(c("n","%","CI"),c(names(tmp.res[1:4]),"Total")) newtitle <- paste("Breakdown of clinically significant change:",title) if(HTML) { newtitle <- paste("

",newtitle,"

") HTML(newtitle,File=File,Align="left") x <- xtable(tmp.res3,caption=newtitle) print(x,type="html") cat("

") #HTML(tmp.res3,File=File) } else { cat(newtitle) cat(tmp.res3) } } #cat("got to here (4): end of function declaration print.CSC\n\n") print.RC.change <- function(rc.chge,title,HTML=TRUE,File) { if (!is.factor(rc.chge)) { stop("RC change data must be factor\n") } if (sum(is.na(rc.chge))) { stop("RC change data must be complete\n") } require(Hmisc) # requires binconf() ###### tabular summary of reliable change n.all <- length(rc.chge) tmp.res <- table(rc.chge) tmp.perc <- round(100*tmp.res[1:3]/n.all,1) tmp.res2 <- rbind(tmp.res[1:3],tmp.perc) tmp.res2 <- cbind(tmp.res2,c(sum(tmp.res2[1,]),sum(tmp.res2[2,]))) tmp.ci1 <- binconf(tmp.res[1],n.all) tmp.ci2 <- binconf(tmp.res[2],n.all) tmp.ci3 <- binconf(tmp.res[3],n.all) tmp.ci1b <- paste(round(100*tmp.ci1[2],1),"to",round(100*tmp.ci1[3],1)) tmp.ci2b <- paste(round(100*tmp.ci2[2],1),"to",round(100*tmp.ci2[3],1)) tmp.ci3b <- paste(round(100*tmp.ci3[2],1),"to",round(100*tmp.ci3[3],1)) tmp.res3 <- rbind(tmp.res2,c(tmp.ci1b,tmp.ci2b,tmp.ci3b,"")) dimnames(tmp.res3) <- list(c("n","%","CI"),c(names(tmp.res[1:3]),"Total")) newtitle <- paste("Breakdown of reliable change",title) if (HTML) { newtitle <- paste("

",newtitle,"

") #cat(newtitle) x <- xtable(tmp.res3,caption=newtitle) print(x,type="html") #HTML(tmp.res3,File=File) } else { cat(newtitle) cat(tmp.res3) } cat("

") } #cat("got to here (5): end of function declaration print.RC.change\n\n") RC.change <- function(diffs,rc.crit) { ## little function that returns a vector of reliable change ## given the differences and the criterion if (!is.numeric(diffs)) { stop("Diffs must be numeric\n") } if (sum(is.na(diffs)>0)) { stop("Missing values in diffs\n") } if (!is.numeric(rc.crit)) { stop("RC criterion must be numeric\n") } sign <- sign(diffs) rc.chge <- abs(diffs) rc.chge <- ifelse(rc.chge 1) {stop("Alpha must be numeric, positive and <= 1.0") } return(sqrt(2)*1.96*sqrt(1-alpha)*sd1) } #cat("got to here (8): end of function declaration RC.crit\n\n") RC.crit.scores <- function(scores,alpha) { if (!is.numeric(scores)) {stop("Scores must be numeric") } if (length(scores) < 11) {stop("Need more than ten scores to make any sense of calculating RC criterion") } if (!is.numeric(alpha) | alpha < 0 | alpha > 1) {stop("Alpha must be numeric, positive and <= 1.0") } if (sum(is.na(scores)) > 0) {warning("Missing values in scores, they have been ignored\n") } sd1 <- sqrt(var(na.omit(scores))) return(sqrt(2)*1.96*sqrt(1-alpha)*sd1) } #cat("got to here (9): end of function declaration RC.crit.scores\n\n") RCSC.from.datasheet <- function(data,var1,var2,alpha,varname="",gender,male,female,malecrit,femcrit,alldata=0,ID=NA,group=NA,HTML=FALSE,outdir=".",extension="html",printdata=FALSE){ if (HTML) { require(R2HTML) } require(Hmisc) # looks at RC of RCSC paradigm for data from datasheet (data) with columns as variables # cat("

got inside to here (1)

\n") # and rows as individuals' data # var1,var2 are column numbers of variables in the dataset to analyse: initial, later # varname is the name of measure (used for the output filename) # gender is column number of the gender variable # male is value indicating male # female is value indicating female # malecrit is male CSC criterion # femcrit is female CSC criterion call <- match.call() # allows you to get at the dataset name as text you can use as a label data.name <- as.vector(as.character(call[[2]])) # it's the 2nd in that list if (HTML) { filename <- paste(data.name,".",varname,sep="") File <- HTMLInitFile(filename=filename,outdir=outdir) } ## this just produces a data.frame of the data with ID and group markers if they exist cleandata <- cleandata(data,var1,var2,gender,ID=ID,group=group) vecdata1 <- cleandata$"First.score" vecdata2<- cleandata$"Second.score" gendata <- cleandata$Gender ## OK now do more with what we've selected n.all <- length(vecdata1) idx.men <- (1:n.all)[gendata==male] idx.women <- (1:n.all)[gendata==female] n.women <- length(gendata[idx.women]) n.men <- length(gendata[idx.men]) # # now get the parameters you need for RC rc.crit <- RC.crit.scores(vecdata1,alpha) ## now do some work with that diffs <- vecdata2 - vecdata1 rc.chge <- RC.change(diffs,rc.crit) idx.rel.worse <- (1:n.all)[rc.chge==1] # index of who got reliably worse idx.rel.unchg <- (1:n.all)[rc.chge==0] # unchanged idx.rel.better <- (1:n.all)[rc.chge==-1] # reliably better # get things right for outputting rc.crit <- round(rc.crit,3) param <- rbind(data.name,var1,var2,alpha,varname,gender,male,female,malecrit,femcrit,n.all,n.women,n.men,rc.crit) if (HTML) { cat("

 


 ") cat("

Checking on the input

") x <- xtable(param,caption="Values") print(x,type="html") } else { cat(param) } cat("

 


 ") cat("

Analyses of whether or how often reliable change or deterioration seen

") print.RC.change(rc.chge,"Men and Women",HTML=HTML,File=File) print.RC.change(rc.chge[idx.men],"Men only",HTML=HTML,File=File) print.RC.change(rc.chge[idx.women],"Women only",HTML=HTML,File=File) cat("

 

") csc <- CSC.categories(vecdata1,vecdata2,gendata,male,female,malecrit,femcrit) cat("

 


 ") cat("

Analyses of whether or how often clinically significant change was seen

") print.CSC(csc,"Men and Women",HTML=HTML,File=File) print.CSC(csc[idx.men],"Men only",HTML=HTML,File=File) print.CSC(csc[idx.women],"Women only",HTML=HTML,File=File) cat("

 


 ") cat("

Analyses of reliable change against clinically significant change

") print.CSC.by.RC(csc,rc.chge,"Men and Women",HTML=HTML,File=File) print.CSC.by.RC(csc[idx.men],rc.chge[idx.men],"Men only",HTML=HTML,File=File) print.CSC.by.RC(csc[idx.women],rc.chge[idx.women],"Women only",HTML=HTML,File=File) cat("

 


 ") cat("

Jacobson plots

") Jacobson.plot(vecdata1,vecdata2,"CORE-OM",gendata,male,female,rc.crit,malecrit,femcrit,title="Men and Women",outdir,File,HTML=HTML) Jacobson.plot(vecdata1[idx.men],vecdata2[idx.men],"CORE-OM",gendata[idx.men],male,female,rc.crit,malecrit,femcrit,title="Men only",outdir,File,HTML=HTML) Jacobson.plot(vecdata1[idx.women],vecdata2[idx.women],"CORE-OM",gendata[idx.women],male,female,rc.crit,malecrit,femcrit,title="Women only",outdir,File,HTML=HTML) ##### tabulation of who did what results <- cbind(cleandata,diffs,rc.chge,csc) if (printdata) { if (HTML) { cat("

 


 ") cat("

Listing of the data

") x <- xtable(results,caption="Original data with change, RC and CSC") print(x,type="html") #HTML(results,File=File) } else { cat("Listing of data") cat(results) } } #return(results) } ## end of functions #cat("got to here (10): end of function declarations\n\n") tag(HTML) tag(HEAD) tag(TITLE) cat("RCSC analysis") untag(TITLE) untag(HEAD) lf(2) tag(BODY, bgcolor = "lime") lf(2) tag(center) prob <- 0 comments("Get the data") #cat("

") #cat(names(formData)) #cat("

") # cat(unlist(formData)) #cat("

") name <- formData$name #cat("

") #cat(name) title <- formData$title #cat("

") #cat(title) alpha <- as.numeric(scanText(formData$alpha)) #cat("

") #cat(alpha) what1 <- formData$what #cat("

what1:") #cat(what1) #cat("

is.character(what1):") #tmp <- is.character(what1) #cat(tmp) #tmp <- is.list(what1) #cat("

is.list(what1):") #cat(tmp) #tmp <- dim(what1) #cat("

dim(what1):") #cat(tmp) #tmp <- nchar(what1) #cat("

nchar(what1)") #cat(tmp) #cat("

what2:") what2 <- strsplit(what1," ",extended=FALSE) #tmp <- unlist(what2) #cat(tmp) nvars <- length(unlist(what2)) #cat("

nvars:") #cat(nvars) dat <- unlist(scanText(formData$data,what=what2[1])) #cat("

dat:") #cat(dat) #cat("

length") length.dat <- length(dat) nrows <- length.dat/nvars md <- matrix(dat,ncol=nvars,byrow=TRUE) #cat("

md:") #cat(md) #tmp <- dim(md) #cat("

dim(md):
") #cat(tmp) #cat("

length.dat:
") #cat(length.dat) #cat(" ") var1 <- as.numeric(formData$var1) #cat("

var1:
") #cat(var1) var2 <- as.numeric(formData$var2) #cat("

var2:
") #cat(var2) gender <- as.numeric(formData$gender) #cat("

gender:
") #cat(gender) ID <- as.numeric(formData$ID) #cat("

ID:
") #cat(ID) group <- as.numeric(formData$group) #cat("

group:
") #cat(group) male <- formData$male #cat("

male:
") #cat(male) female <- formData$female #cat("

female:
") #cat(female) femcrit <- as.numeric(formData$femcrit) #cat("

femcrit:
") #cat(femcrit) malecrit <- as.numeric(formData$malecrit) #cat("

malecrit:
") #cat(malecrit) #cat("

now:
") now <- system('date +%Y-%m-%d,%T', intern=TRUE) #cat(now) #cat("

host:
") host <- system("echo $REMOTE_ADDR", intern=TRUE) #cat(host) #cat("

class(md)") vecdat1 <- as.numeric(md[,var1]) #cat("

vecdat1:
") #cat(vecdat1) vecdat2 <- as.numeric(md[,var2]) #cat("

vecdat2:
") #cat(vecdat2) gendat <- md[,gender] #cat("

gendat:
") #cat(gendat) iddat <- md[,ID] #cat("

iddat:
") #cat(iddat) grpdat <- md[,group] #cat("

grpdat:
") #cat(grpdat) if (!is.na(ID) & !is.na(group)) { # cat("Both ID and group") newdat <- data.frame(I(vecdat1),I(vecdat2),I(gendat),I(iddat),I(grpdat)) colnames(newdat) <- c("Initial","Second","Gender","ID","Group") ID <- 4 group <- 5 } if (is.na(ID) & !is.na(group)) { # cat("group not ID") newdat <- data.frame(I(vecdat1),I(vecdat2),I(gendat),I(iddat),I(grpdat)) colnames(newdat) <- c("Initial","Second","Gender","Group") group <- 4 } if (!is.na(ID) & is.na(group)) { # cat("ID not group") newdat <- data.frame(I(vecdat1),I(vecdat2),I(gendat),I(iddat),I(grpdat)) colnames(newdat) <- c("Initial","Second","Gender","ID") ID <- 4 } if (is.na(ID) & is.na(group)) { # cat("neither ID nor group") newdat <- data.frame(I(vecdat1),I(vecdat2),I(gendat),I(iddat),I(grpdat)) colnames(newdat) <- c("Initial","Second","Gender") } class(newdat[,3]) <- "character" #cat("Got to making up data again\n") #cat("

newdat:
") #cat(newdat) #for (i in 1:nvars) { cat(class(newdat[,i])) } ##### start of testing of the input ##### #cat("Got to testing the input\n") prob <- 0 if (is.na(alpha) || (alpha < 0) || (alpha > 1.0)) { cat("

Alpha must be a positive number such that: 0 < alpha < 1, go back and try again!

") prob <- 1 } if (is.na(malecrit) || is.na(femcrit)) { cat("

CSC criteria for men and women must be given and be numbers, go back and try again!

") prob <- 1 } if (prob) { cat("

Go back and try again!

") cat("CGI script written by Chris Evans using David Firth's excellent GGIwithR package. ") linkto("Contact me if something isn't working right ...", "http://www.psyctc.org/cgi-bin/mailto.pl?webmaster") ; br() } lf(2) comments("end of testing") # should have valid data cat("

Reliable and clinically significant change analysis

") cat("

for submission name: ",name," on measure ",title,"

") cat("In the output that follows tables usually have captions immediately after them") cat("") cat("
") #for (i in 1:nvars) { # cat("

") # cat(i) # cat("
") # cat(newdat[,i]) # cat("

") # cat(class(newdat[,i])) # cat("

") #} #cat("entering main function call") RCSC.from.datasheet(newdat,1,2,alpha,varname=name,3,male,female,malecrit,femcrit,alldata=1,ID=ID,group=group,HTML=TRUE,outdir="//var//psyctc//psyctc.org//stats//COREtools//scratch//",extension="html",printdata=TRUE) untag(BODY) untag(HTML) lf() sink(paste("/home/xychris0/R/CGIwithR-log/RCSC1.R.",as.character(now),sep="")) cat("program = RCSC1.R ; host = ",host, "; ", now, "; grid.title = ",name,"\n") sink()