require(hreport) # add to above: results='hide' knitrSet(lang='markdown', fig.path='figure/') options(prType='html') mu <- markupSpecs$html # in Hmisc - HTML markups frac <- mu$frac
mu$styles() # define HTML styles, functions
# Function to generate data for one study gendat <- function(study, n) { f <- function(p) rbinom(n, 1, p) d <- data.frame(study=study, subjid=1:n, site=sample(1:10, n, TRUE), tx=sample(c('A','B'), n, TRUE), age=rnorm(n, 50, 10), sex=sample(c('female', 'male'), n, TRUE), edate=as.Date('2019-10-01') + round(runif(n, 0, 100)), sbp=rnorm(n, 120, 7), dbp=rnorm(n, 80, 6), race=sample(c('Asian', 'Black/AA', 'White'), n, TRUE), meda=f(0.3), medb=f(0.2), td=round(runif(n, 0, 30)), death=rbinom(n, 1, 0.4), e1 = f(.03), e2 = f(.03), e3 = f(.03), e4 = f(0.05), tested = rbinom(n, 1, .75), e6 = f(.03), e7 = f(0.04) ) d <- upData(d, e5 = ifelse(tested, f(.06), NA), # don't randomize if exclusion present: rdate = ifelse(e1|e2|e3|e4|ifelse(is.na(e5), 0, e5)|e6|e7, NA, edate + round(runif(n, 0, 30))), rdate = as.Date(rdate, origin='1970-01-01'), # ifelse loses Date class tx = ifelse(is.na(rdate), NA, tx), labels=c(age='Age', rdate='Randomization Date', edate='Enrollment Date', e1='Prior MI', e2='History of Asthma', e3='History of Upper GI Bleeding', e4='No Significant CAD', e5='Inadequate Renal Function', e6='Pneumonia within 6 weeks', e7='Hostile', race='Race', sex='Sex', tx='treatment', sbp='Systolic BP', dbp='Diastolic BP', meda='Comcomitant medication A', medb='Concomitant medication B', td='Follow-up Time', death='Death'), units=c(sbp='mmHg', dbp='mmHg', age='years', td='day'), print=FALSE) denom <- c(enrolled=nrow(d), randomized=sum(! is.na(d$rdate)), table(subset(d, ! is.na(rdate))$tx)) sethreportOption(tx.var='tx', denom=denom, study=study) d } set.seed(1) d1 <- gendat('Study 1', 500) d2 <- gendat('Study 2', 250) d3 <- rbind(d1, d2) denom <- c(enrolled=nrow(d3), randomized=sum(! is.na(d3$rdate)), table(subset(d3, ! is.na(rdate))$tx)) sethreportOption(tx.var='tx', denom=denom, study='Study 1+2')
This is an example report using simulated data. Two studies are simulated. Variable names in the two datasets are the same here, though they needn't be. The study IDs are Study 1
and Study 2
. These IDs are used to label the tabs that can be clicked to allow the alternate study result to be viewed.
Since the variable names are the same, the two studies have also been combined to produce a third "study" called e.g. Study 1+2
. For certain results, study
is used as a stratification variable for the Study 1+2
tab. Since patient accrual is unique to each study, a combined accrual report is not presented. The exclusion criteria report is also not included for the combined trials.
For accrual and exclusion reports, the entire database is used. After that point, datasets are subsetted to include only randomized participants.
Most of the graphs produced here are semi-interactive. One can hover over elements of graphs with the mouse to have detailed information pop up.
Needles represent the fraction of observations used in the current
analysis. The first needle (red) shows the fraction of enrolled
patients used. If randomization was taken into account, a second
needle (green) represents the fraction of randomized subjects included
in the analysis. When the analyses consider treatment assignment, two
more needles may be added to the display, showing, respectively, the
fraction of subjects randomized to treatment A used in the analysis
and the fraction of subjects on treatment B who were analyzed. The
colors of these last two needles are the colors used for the two
treatments throughout the report. The following table shows some
examples. dNeedle
uses colors in sethreportOption(tx.col=, er.col=)
.
# Store using short variable names so Rmarkdown table column # width will not be wider than actually needed dned <- function(x) dNeedle(x, study='Study 1') n1 <- dned(1) n2 <- dned((3:4)/4) n3 <- dned((1:2)/4) n4 <- dned(c(1,2,3,1)/4)
|Signpost | Interpretation |
|------- | -------------------------------------------------|
| r n1
| All enrolled subjects analyzed, randomization not considered|
| r n2
| Analysis uses r frac(3,4)
of enrolled subjects, and all randomized subjects|
| r n3
| Analysis uses r frac(1,4)
of enrolled subjects, and r frac(1,2)
of randomized subjects|
| r n4
| Same as previous example, and in addition the analysis utilized treatment assignment, analyzing r frac(3,4)
of those randomized to A and r frac(1,4)
of those randomized to B|
Graphs containing pairs of Kaplan-Meier survival curves show a shaded region centered at the midpoint of the two survival estimates and having a height equal to the half-width of the approximate 0.95 pointwise confidence interval for the difference of the two survival probabilities. Time points at which the two survival estimates do not touch the shaded region denote approximately significantly different survival estimates, without any multiplicity correction.
accrualReport(enroll(edate) + randomize(rdate) ~ site(site), data=d1, dateRange=c('2019-10-01', '2020-03-01'), targetN= data.frame(edate=c(250, 500), rdate=c(125, 250)), targetDate=c('2020-01-15', '2020-03-01'), closeDate='2020-06-01', study='Study 1')
accrualReport(enroll(edate) + randomize(rdate) ~ site(site), data=d2, dateRange=c('2019-10-01', '2020-03-01'), targetN= data.frame(edate=c(125, 250), rdate=c(75, 125)), targetDate=c('2020-01-15', '2020-03-01'), closeDate='2020-06-01', study='Study 2')
exReport(~ e1 + e2 + e3 + e4 + e5 + e6 + e7 + id(subjid) + cond(e5, 'Tested', tested), whenapp= c(e4='CCTA done'), study='Study 1', data=d1)
exReport(~ e1 + e2 + e3 + e4 + e5 + e6 + e7 + id(subjid) + cond(e5, 'Tested', tested), whenapp= c(e4='CCTA done'), study='Study 2', data=d2)
# From here on, only randomized participants will be considered d1 <- subset(d1, ! is.na(rdate)) d2 <- subset(d2, ! is.na(rdate)) d3 <- subset(d3, ! is.na(rdate)) dReport(race + sex ~ 1, head='Overall frequencies of categorical demographic variables', data=d1, study='Study 1') # Show continuous variables stratified by treatment dReport(dbp + sbp + age ~ tx, data=d1, study='Study 1', sopts=list(width=800))
dReport(race + sex ~ 1, head='Overall frequencies of categorical demographic variables', data=d2, study='Study 2') dReport(dbp + sbp + age ~ tx, data=d2, study='Study 2', sopts=list(width=800))
When combining studies we don't need to examine baseline variables stratified by treatment but rather stratified by study.
dReport(race + sex ~ study, head='Overall frequencies of categorical demographic variables', data=addMarginal(d3, study), study='Study 1+2') dReport(dbp + sbp + age ~ study, data=addMarginal(d3, study), study='Study 1+2', sopts=list(width=800, ncols=2))
survReport(Surv(td, death) ~ tx, data=d1, study='Study 1')
survReport(Surv(td, death) ~ tx, data=d2, study='Study 2')
survReport(Surv(td, death) ~ tx, data=d3, study='Study 1+2')
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.