patientProfilesVis
packageThis package patientProfilesVis
enables to create subject profile reports of patients/subjects in a clinical trial.
Such visualization can be used to obtain a global view of the subject metadata information, combined with its treatment exposure and concomitant medications, in relation with the adverse events occurring during the trial, and any measurements conducted during a clinical trial (e.g. laboratory, vital signs or ECG).
library(patientProfilesVis)
library(pander)
The input dataset for the creation of patient profiles should be a data.frame, typically CDISC ‘Study Data Tabulation Model’ (a.k.a SDTM) or ‘Analysis Data Model’ (a.k.a. ADaM) datasets.
The package also support tibble datasets as imported by the read_sas
/read_xpt
functions from the haven
.
Alternatively, datasets can be imported at once with the loadDataADaMSDTM
function from the clinUtils
package.
Furthermore, the input dataset should contain a variable containing subject identifier. This variable is set to USUBJID
by default, but can be overwritten via the subjectVar
parameter.
The package is demonstrated with a subset of the SDTM datasets from the CDISC Pilot 01 dataset, available in the clinUtils
package.
library(clinUtils)
# import example data:
data(dataSDTMCDISCP01)
# formatted as a list of data.frame (one per domain)
dataSDTM <- dataSDTMCDISCP01
names(dataSDTM)
## [1] "AE" "CM" "DM" "DS" "EX" "LB" "MH" "QS"
## [9] "SUPPDM" "SV" "VS"
# and corresponding labels
labelVarsSDTM <- attr(dataSDTM, "labelVars")
head(labelVarsSDTM)
## STUDYID DOMAIN
## "Study Identifier" "Domain Abbreviation"
## USUBJID AESEQ
## "Unique Subject Identifier" "Sequence Number"
## AESPID AETERM
## "Sponsor-Defined Identifier" "Reported Term for the Adverse Event"
A subset of the ADaM datasets from the CDISC Pilot 01 dataset, available in the clinUtils
package, is also imported for the example in section ADaM dataset.
# import example data:
data(dataADaMCDISCP01)
# formatted as a list of data.frame (one per domain)
dataADaM <- dataADaMCDISCP01
names(dataADaM)
## [1] "ADAE" "ADCM" "ADLBC" "ADPP" "ADQSADAS" "ADQSCIBC" "ADQSNPIX"
## [8] "ADSL" "ADVS"
# and corresponding labels
labelVarsADaM <- attr(dataADaM, "labelVars")
head(labelVarsADaM)
## STUDYID SITEID
## "Study Identifier" "Study Site Identifier"
## USUBJID TRTA
## "Unique Subject Identifier" "Actual Treatment"
## TRTAN AGE
## "Actual Treatment (N)" "Age"
# example subjects for the vignette:
subjectAE <- "01-718-1427"
subjectMH <- "01-718-1371"
subjectCM <- "01-701-1148"
subjectLB <- "01-704-1445"
Different types of visualization (a.k.a ‘modules’) are available via dedicated R function. Each function creates a separate visualization for each subject available in the dataset.
Four plot types/modules are currently available in the package:
subjectProfileTextPlot
functionsubjectProfileIntervalPlot
functionsubjectProfileEventPlot
functionsubjectProfileLinePlot
functionEach of this function returns a nested list of plots (ggplot
object).
Each element of the list contains the plots for a specific subject. The subject profile plot for a specific subject/module is possibly split into multiple plots to fit in the final report (formatReport
parameter).
The ‘text’ module enables to specify meta-information for each subject. There are two ways to specify such information, either by specifying a set of variables/columns of the data (paramValueVar
only), or by a variable/column containing the parameter name (paramNameVar
) and variable(s)/column(s) containing the parameter value (paramValueVar
).
# annotate subject demographics meta-data
# by specifying a set of variables to include
dmPlots <- subjectProfileTextPlot(
data = dataSDTM$DM,
paramValueVar = c("SEX|AGE", "RACE|COUNTRY", "ARM"),
labelVars = labelVarsSDTM
)
It is possible to specify multiple variable to represent in the plot for a certain variable name.
# annotate subject medical history
# by specifying a combination of parameter value/name
mhPlots <- subjectProfileTextPlot(
data = dataSDTM$MH,
paramNameVar = c("MHDECOD"),
paramValueVar = c("MHSTDTC", "MHSEV"),
paramGroupVar = "MHCAT",
title = "Medical History: status",
labelVars = labelVarsSDTM
)
Information is displayed as a listing, by setting the table
parameter to TRUE.
aeListingPlots <- subjectProfileTextPlot(
data = dataSDTM$AE,
paramValueVar = c(
"AEBODSYS", "AESOC", "AEHLT",
"AELLT", "AEDECOD", "AESTDTC",
"AEENDTC", "AESER", "AEACN"
),
paramGroupVar = "AESTDTC",
labelVars = labelVarsSDTM,
table = TRUE
)
By default, the widths of the columns of the table are optimized based on the column content, but custom widths can be specified via the colWidth
parameter.
For example, the column for the system organ class is enlarged.
aeListingPlots <- subjectProfileTextPlot(
data = dataSDTM$AE,
paramValueVar = c(
"AEBODSYS", "AESOC", "AEHLT",
"AELLT", "AEDECOD", "AESTDTC",
"AEENDTC", "AESER", "AEACN"
),
paramGroupVar = "AESTDTC",
labelVars = labelVarsSDTM,
table = TRUE,
colWidth = c(
0.2, 0.2, 0.05,
0.1, 0.1, 0.05,
0.05, 0.05, 0.05
)
)
In case multiple variable are used as paramValueVar
and they should be concatenated with a specific format, a function can be specified via the parameter: paramValueVar
.
# annotate subject medical history
# by specifying a combination of parameter value/name
paramValueVarFct <- function(data)
with(data, paste0(
ifelse(MHSEV != "", paste("severity:", MHSEV, ""), ""),
"(start = ", ifelse(MHSTDTC != "", MHSTDTC, "undefined"), ")"
))
mhPlotsMultipleVars <- subjectProfileTextPlot(
data = dataSDTM$MH,
paramNameVar = "MHDECOD",
paramValueVar = paramValueVarFct,
title = "Medical History: status with dates",
labelVars = labelVarsSDTM
)
# annotate subject medical history
# by specifying a combination of parameter value/name
mhPlotsGroup <- subjectProfileTextPlot(
data = dataSDTM$MH,
paramNameVar = "MHDECOD",
paramValueVar = c("MHDECOD", "MHSTDTC"),
paramGroupVar = "MHCAT",
title = "Medical History: grouped by category",
labelVars = labelVarsSDTM
)
Event with a fixed start/end time are displayed as time interval via the ‘interval’ module.
This module is used to represent the start/end date of the adverse events.
Please check section Missing starting/end time for further information on how records with missing start/end date are represented.
dataAE <- dataSDTM$AE
# sort severities
dataAE[, "AESEV"] <- factor(dataAE[, "AESEV"], levels = c("MILD", "MODERATE", "SEVERE"))
aePlots <- subjectProfileIntervalPlot(
data = dataAE,
paramVar = "AETERM",
timeStartVar = "AESTDY",
timeEndVar = "AEENDY",
colorVar = "AESEV",
labelVars = labelVarsSDTM,
title = "Adverse events"
)
## 3 record(s) with missing Study Day of Start of Adverse Event and 19 record(s) with missing Study Day of End of Adverse Event are imputed with minimal imputation.
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_point()`).
The exposure of the patients to certain treatment(s) is also represented in this time interval visualization
exPlots <- subjectProfileIntervalPlot(
data = dataSDTM$EX,
paramVar = c("EXTRT", "EXDOSE", "EXDOSU"),
timeStartVar = "EXSTDY",
timeEndVar = "EXENDY",
colorVar = "EXDOSFRM",
labelVars = labelVarsSDTM,
title = "Treatment exposure"
)
cmPlots <- subjectProfileIntervalPlot(
data = dataSDTM$CM,
paramVar = c(
"CMTRT",
"CMDOSE", "CMDOSU", "CMROUTE",
"CMDOSFRQ"
),
timeStartVar = "CMSTDY",
timeEndVar = "CMENDY",
paramGroupVar = "CMCLAS",
colorVar = "CMCLAS",
labelVars = labelVarsSDTM,
title = "Concomitant medications"
)
## 171 record(s) with missing Study Day of Start of Medication and 208 record(s) with missing Study Day of End of Medication are imputed with minimal imputation.
## Warning: Removed 26 rows containing missing values or values outside the scale range
## (`geom_segment()`).
## Warning: Removed 31 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 26 rows containing missing values or values outside the scale range
## (`geom_point()`).
The interval visualization requires specified start/end time for each record.
However, it is frequent that the start or the end time of an event/record is missing in clinical data, especially if the data is being collected.
Different types of missing values can occur during a clinical study:
It might be important to still display these records in the visualization, so different types of imputation for missing start/end date for the interval visualization are available in the package.
Please have a look at the section ‘Details’ of the documentation of the subjectProfileIntervalPlot
function for the most up-to-date information on this imputation.
By default, minimal imputation is used (specified via the parameter timeImpType
). Specific symbols are used to represent missing starting/end time.
Records with:
aePlots <- subjectProfileIntervalPlot(
data = dataAE,
paramVar = "AETERM",
timeStartVar = "AESTDY",
timeEndVar = "AEENDY",
colorVar = "AESEV",
labelVars = labelVarsSDTM,
title = "Adverse events"
)
## 3 record(s) with missing Study Day of Start of Adverse Event and 19 record(s) with missing Study Day of End of Adverse Event are imputed with minimal imputation.
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_point()`).
To set the values represented for records with missing start/end dates, the time limits can be extracted from a specified dataset containing the start/end date for each subject via the timeLimData
/timeLimStartVar
/timeLimEndVar
parameters.
This option is used below to impute missing starting/end time with the first/last visit for each subject based on the ‘Subject Visit’ dataset.
As the start and end of the subject visit dates are not available as relative day in the example data, these are first computed based on the subject reference start date/time available in the demography dataset.
dataSV <- dataSDTM$SV
dataSV$RFSTDTC <- dataSDTM$DM[match(dataSV$USUBJID, dataSDTM$DM$USUBJID), "RFSTDTC"]
dataSV$SVSTDY <- with(dataSV, as.numeric(as.Date(SVSTDTC)-as.Date(RFSTDTC)+1))
dataSV$SVENDY <- with(dataSV, as.numeric(as.Date(SVENDTC)-as.Date(RFSTDTC)+1))
aePlotsTimLimFromSV <- subjectProfileIntervalPlot(
data = dataAE,
paramVar = "AETERM",
timeStartVar = "AESTDY",
timeEndVar = "AEENDY",
colorVar = "AESEV",
labelVars = labelVarsSDTM,
title = "Adverse events",
timeLimData = dataSV,
timeLimStartVar = "SVSTDY", timeLimStartLab = "First subject visit",
timeLimEndVar = "SVENDY", timeLimEndLab = "Last subject visit",
)
## 3 record(s) with missing Study Day of Start of Adverse Event and 19 record(s) with missing Study Day of End of Adverse Event are imputed with First subject visit/Last subject visit or minimal imputation.
svSubjectAE <- subset(dataSV, USUBJID == subjectAE)[, c("VISIT", "SVSTDY", "SVENDY")]
pander(svSubjectAE)
VISIT | SVSTDY | SVENDY | |
---|---|---|---|
82 | SCREENING 1 | -3 | -3 |
83 | SCREENING 2 | -1 | -1 |
84 | BASELINE | 1 | 1 |
85 | AMBUL ECG PLACEMENT | 14 | 14 |
86 | WEEK 2 | 15 | 15 |
87 | WEEK 4 | 32 | 32 |
88 | AMBUL ECG REMOVAL | 34 | 34 |
89 | WEEK 6 | 43 | 43 |
90 | WEEK 8 | 64 | 64 |
91 | UNSCHEDULED 8.2 | 64 | 64 |
92 | RETRIEVAL | 169 | 169 |
This is also used to restrict the time limits of the plots.
As the modules will be combined with the same time limits, it might be advisable to restrict the time limits for this module via the timeLimData
, timeLimStartVar
and timeLimEndVar
parameter.
In this example the time limits are restricted to the minimum/maximum time range of the subject visits.
cmPlotsTimeSV <- subjectProfileIntervalPlot(
data = dataSDTM$CM,
paramVar = c(
"CMTRT",
"CMDOSE", "CMDOSU", "CMROUTE",
"CMDOSFRQ"
),
timeStartVar = "CMSTDY",
timeEndVar = "CMENDY",
paramGroupVar = "CMCLAS",
colorVar = "CMCLAS",
labelVars = labelVarsSDTM,
title = "Concomitant medications",
timeLimData = dataSV,
timeLimStartVar = "SVSTDY",
timeLimEndVar = "SVENDY",
timeAlign = FALSE
)
## 171 record(s) with missing Study Day of Start of Medication and 208 record(s) with missing Study Day of End of Medication are imputed with SVSTDY/SVENDY or minimal imputation.
Missing start/end dates, partial dates or custom date status can be specified by creating two extra variables in the input data containing the status of the start/end time (timeStartShapeVar
/timeEndShapeVar
).
This status is represented as different symbols in the plot.
Please note that because the default ggplot2
symbol palette doesn’t contain the left and right triangle symbols; these are specified in Unicode format in hexadecimal (see List of unicode symbols).
# add status for dates:
dataAE$AESTDYST <- with(dataAE,
ifelse(is.na(AESTDY) & !is.na(AESTDY), "Missing start", "")
)
shapePalette <- c(
`Missing start`= "\u25C4", # left-pointing arrow
'NOT RECOVERED/NOT RESOLVED' = "\u25BA", # right-pointing arrow
'RECOVERED/RESOLVED' = "\u25A0", # small square
'FATAL' = "\u2666", # diamond
UNKNOWN = "+"
)
aePlotsShape <- subjectProfileIntervalPlot(
data = dataAE,
paramVar = "AETERM",
timeStartVar = "AESTDY", timeEndVar = "AEENDY",
timeStartShapeVar = "AESTDYST", timeEndShapeVar = "AEOUT",
shapePalette = shapePalette,
shapeLab = "Study date status",
colorVar = "AESEV",
labelVars = labelVarsSDTM,
title = "Adverse events"
)
## 3 record(s) with missing Study Day of Start of Adverse Event and 19 record(s) with missing Study Day of End of Adverse Event are imputed with minimal imputation.
## Empty records in the: 'AESTDYST' variable are converted to NA.
## Warning: Removed 16 rows containing missing values or values outside the scale range
## (`geom_point()`).
To restrict the time range in the visualization, the time limits can be set via the timeLim
parameter.
The visualization are restricted to the timr range from baseline to the last visit (Week 26).
timeLim <- c(0, 182)
cmPlotsTimeSpec <- subjectProfileIntervalPlot(
data = dataSDTM$CM,
paramVar = c(
"CMTRT",
"CMDOSE", "CMDOSU", "CMROUTE",
"CMDOSFRQ"
),
timeStartVar = "CMSTDY",
timeEndVar = "CMENDY",
paramGroupVar = "CMCLAS",
colorVar = "CMCLAS",
labelVars = labelVarsSDTM,
title = "Concomitant medications",
timeLim = timeLim
)
## 171 record(s) with missing Study Day of Start of Medication and 208 record(s) with missing Study Day of End of Medication are imputed with minimal imputation.
## Warning: Removed 26 rows containing missing values or values outside the scale range
## (`geom_segment()`).
## Warning: Removed 31 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 26 rows containing missing values or values outside the scale range
## (`geom_point()`).
By default, the visualizations created with the subjectProfileIntervalPlot
are aligned in the time-axis across subjects.
To obtain visualization which don’t align, the parameter: timeAlign
is set to FALSE.
cmPlotsNotAligned <- subjectProfileIntervalPlot(
data = dataSDTM$CM,
paramVar = c(
"CMTRT",
"CMDOSE", "CMDOSU", "CMROUTE",
"CMDOSFRQ"
),
timeStartVar = "CMSTDY",
timeEndVar = "CMENDY",
paramGroupVar = "CMCLAS",
colorVar = "CMCLAS",
labelVars = labelVarsSDTM,
title = "Concomitant medications",
timeAlign = FALSE
)
## 171 record(s) with missing Study Day of Start of Medication and 208 record(s) with missing Study Day of End of Medication are imputed with minimal imputation.
In this case, each visualization contains specific time-limits.
## Warning: Removed 26 rows containing missing values or values outside the scale range
## (`geom_segment()`).
## Warning: Removed 31 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 26 rows containing missing values or values outside the scale range
## (`geom_point()`).
When building the report, the same parameter should be used (see section Report creation).
The ‘event’ module enables to represent event data.
This is used to represent the presence/absence of a certain laboratory measurement (and corresponding time).
# consider a subset of the laboratory data for example:
lbTests <- c("CHOL", "PHOS", "ANISO", "MCHC", "PLAT", "KETONES")
dataLB <- subset(dataSDTM$LB, LBTESTCD %in% lbTests)
# sort the categories (empty values '', if any, becomes NA)
dataLB$LBNRIND <- factor(dataLB$LBNRIND, levels = c("LOW", "NORMAL", "HIGH", "ABNORMAL"))
# create plot
lbPlots <- subjectProfileEventPlot(
data = dataLB,
paramVar = c("LBCAT", "LBTEST"),
paramGroupVar = "LBCAT",
timeVar = "LBDY",
labelVars = labelVarsSDTM,
title = "Laboratory test measurements"
)
The laboratory events are colored based on the category of the laboratory parameter, with the colorVar
parameter.
The reference range indicator is used to set different symbols via the shapeVar
. Symbols specific of this categorization are used via the shapePalette
parameter: bottom/top arrow for low/high measurements, dot for measurements in normal range and star for abnormal measurements.
# create plot
lbPlotsColorShape <- subjectProfileEventPlot(
data = dataLB,
paramVar = "LBTEST",
paramGroupVar = "LBCAT",
timeVar = "LBDY",
colorVar = "LBCAT",
labelVars = labelVarsSDTM,
shapeVar = "LBNRIND",
shapePalette = c(
'LOW' = 25, 'NORMAL' = 19, 'HIGH' = 24,
'ABNORMAL' = 11
),
title = "Laboratory test measurements: reference range indicator"
)
The ‘line’ module enables to represent value of a variable across time.
This is used to represent the evolution of the lab parameters.
# create plot
lbLinePlots <- subjectProfileLinePlot(
data = dataLB,
paramNameVar = "LBTEST",
paramValueVar = "LBSTRESN",
paramGroupVar = "LBCAT",
timeVar = "LBDY",
title = "Laboratory test measurements: actual value",
labelVars = labelVarsSDTM
)
The color and the shape of the points can be specified via the colorVar
and shapeVar
parameters, similarly as for the subjectProfileEventPlot
function. The reference range measurement is represented via these parameters.
# create plot
lbLinePlotsColorShape <- subjectProfileLinePlot(
data = dataLB,
paramNameVar = "LBTEST",
paramValueVar = "LBSTRESN",
colorVar = "LBCAT",
shapeVar = "LBNRIND",
shapePalette = c(
'LOW' = 25, 'NORMAL' = 19, 'HIGH' = 24,
'ABNORMAL' = 11
),
paramGroupVar = "LBCAT",
timeVar = "LBDY",
title = "Laboratory test measurements: actual value",
labelVars = labelVarsSDTM
)
A reference range for each parameter can be visualized if the variables containing the low and upper limit of the range are specified via paramValueRangeVar
:
# create plot
lbLineRefRangePlots <- subjectProfileLinePlot(
data = dataLB,
paramNameVar = "LBTEST",
paramValueVar = "LBSTRESN",
paramGroupVar = "LBCAT",
paramValueRangeVar = c("LBSTNRLO", "LBSTNRHI"),
shapeVar = "LBNRIND",
shapePalette = c(
'LOW' = 25, 'NORMAL' = 19, 'HIGH' = 24,
'ABNORMAL' = 11
),
timeVar = "LBDY",
title = "Laboratory test measurements: actual value",
labelVars = labelVarsSDTM
)
By default, for each parameter, the range of the y-axis is extended to the reference range in case the range of the associated observations is smaller than the specified reference range.
If the range of the y-axis should only contain the range of the actual measurements, (so shouldn’t be extended to cover the reference range), the yLimFrom
parameter should be set on: ‘value’.
# create plot
lbLineYLimFromValuePlots <- subjectProfileLinePlot(
data = dataLB,
paramNameVar = "LBTEST",
paramValueVar = "LBSTRESN",
paramGroupVar = "LBCAT",
paramValueRangeVar = c("LBSTNRLO", "LBSTNRHI"),
shapeVar = "LBNRIND",
shapePalette = c(
'LOW' = 25, 'NORMAL' = 19, 'HIGH' = 24,
'ABNORMAL' = 11
),
yLimFrom = "value",
timeVar = "LBDY",
title = "Laboratory test measurements: actual value",
labelVars = labelVarsSDTM
)
A subset of interest can be specified via:
These parameters are also available for all other module types.
If only a subset of parameters are of interest subsetVar
and subsetValue
can be used.
By default, the subset is extracted from the current data
, but can also be extracted from a different dataset specified via subsetData
.
The patient laboratory profile is only created for the patients with severe adverse events:
# create plot
lbPlotsSubset <- subjectProfileEventPlot(
data = dataLB,
paramVar = "LBTEST",
# select subjects of interest:
subsetData = dataSDTM$AE,
subsetVar = "AESEV", subsetValue = "SEVERE",
timeVar = "LBDY",
colorVar = "LBNRIND",
shapeVar = "LBNRIND",
shapePalette = c(
'LOW' = 25, 'NORMAL' = 19, 'HIGH' = 24,
'ABNORMAL' = 11
),
title = "Hematology test measurements",
labelVars = labelVarsSDTM
)
cat("Only the", length(lbPlotsSubset), "patients with severe adverse events:", toString(names(lbPlotsSubset)), "are considered.\n")
## Only the 5 patients with severe adverse events: 01-701-1211, 01-704-1445, 01-710-1083, 01-718-1371, 01-718-1427 are considered.
A set of subjects of interest from the input data
can be specified via the subjectSubset
parameter (by default extracted from the subjectVar
parameter):
# create plot
lbPlotsSubjectSubset <- subjectProfileEventPlot(
data = dataLB,
paramVar = "LBTEST",
subsetVar = "LBCAT", subsetValue = "HEMATOLOGY",
subjectSubset = subjectLB,
timeVar = "LBDY",
colorVar = "LBNRIND",
shapeVar = "LBNRIND",
shapePalette = c(
'LOW' = 25, 'NORMAL' = 19, 'HIGH' = 24,
'ABNORMAL' = 11
),
title = "Laboratory test measurements for subject of interest",
labelVars = labelVarsSDTM
)
cat("Only the patient:", toString(names(lbPlotsSubjectSubset)), "is considered.\n")
## Only the patient: 01-704-1445 is considered.
Missing values in the specified color/shape variables are always displayed in the legend and associated palette.
If the variable is specified as character (by default when the dataset is loaded into R), the variable is converted to a factor and empty values (’’, if any) in the variable are converted to missing (NA).
If the variable is specified as factor, the missing values are included in the levels of the factor (via exclude = NULL
in factor
).
By default, if a character vector is specified, the categories are sorted in alphabetical order when the variable is converted to a factor in R.
dataLB <- subset(dataSDTM$LB, LBTESTCD %in% lbTests)
# LBRIND is a character: elements sorted in alphabetical order
lbPlotsColor <- subjectProfileEventPlot(
data = dataLB,
paramVar = "LBTEST",
paramGroupVar = "LBCAT",
timeVar = "LBDY",
colorVar = "LBNRIND",
title = "Laboratory test measurements: actual value",
labelVars = labelVarsSDTM
)
To specify the elements of the variable in a specific order (e.g. ordered categories), the variable should be converted to a factor with its levels sorted in the order of interest (as by default in ggplot2
).
For example, the reference ranges for the laboratory measurements are sorted from low to high in the legend:
dataLB <- subset(dataSDTM$LB, LBTESTCD %in% lbTests)
# sort LBRIND
dataLB$LBNRIND <- with(dataLB,
factor(LBNRIND, levels = c("LOW", "NORMAL", "HIGH", "ABNORMAL"))
)
# create plot
lbPlotsColor <- subjectProfileEventPlot(
data = dataLB,
paramVar = "LBTEST",
paramGroupVar = "LBCAT",
timeVar = "LBDY",
colorVar = "LBNRIND",
title = "Laboratory test measurements: actual value",
labelVars = labelVarsSDTM
)
Sometimes, the variable are also available their numeric form in the CDISC datasets.
In this case, corresponding numeric variable can be used for sorting:
dataLB <- subset(dataSDTM$LB, LBTESTCD %in% lbTests)
# for the demo, creates numeric variable associated to reference range
# (often already available)
dataLB$LBNRINDN <- c(LOW = 1, NORMAL = 2, HIGH = 3, ABNORMAL = 10)[dataLB$LBNRIND]
dataLB$LBNRIND <- with(dataLB, reorder(LBNRIND, LBNRINDN))
lbPlotsColor <- subjectProfileEventPlot(
data = dataLB,
paramVar = "LBTEST",
paramGroupVar = "LBCAT",
timeVar = "LBDY",
colorVar = "LBNRIND", shapeVar = "LBNRIND",
title = "Laboratory test measurements: actual value",
labelVars = labelVarsSDTM
)
Palette for the colors and shapes associated with specific variables can be set for all patient profile visualizations at once by setting the patientProfilesVis.colors
and patientProfilesVis.shapes
options at the start of the R session.
The default palette for colors is the viridis
colorblind palette and a custom palette for shapes has been created in the package.
# display default palettes
colorsDefault <- getOption("patientProfilesVis.colors")
str(colorsDefault)
## function (n, alpha = 1, begin = 0, end = 1, direction = 1, option = "D")
shapesDefault <- getOption("patientProfilesVis.shapes")
shapesDefault
## [1] "circle filled" "square filled" "diamond filled"
## [4] "triangle filled" "triangle down filled" "square open"
## [7] "circle open" "triangle open" "plus"
## [10] "cross" "diamond open" "triangle down open"
## [13] "square cross" "asterisk" "diamond plus"
## [16] "circle plus" "star" "square plus"
## [19] "circle cross" "square triangle" "square"
## [22] "triangle" "diamond" "circle"
# create plot
lbPlots <- subjectProfileEventPlot(
data = dataLB,
paramVar = "LBTEST",
paramGroupVar = "LBCAT",
timeVar = "LBDY",
colorVar = "LBNRIND",
shapeVar = "LBNRIND",
title = "Laboratory test measurements: actual value",
labelVars = labelVarsSDTM
)
The palettes can be set for all patient profile visualization, e.g. at the start of the R session, with:
# change palettes for the entire R session
options(patientProfilesVis.colors = c("gold", "pink", "cyan"))
options(patientProfilesVis.shapes = c("cross", "diamond", "circle", "square"))
In case the palette contains less elements than available in the data, these are replicated.
# create plot
lbPlots <- subjectProfileEventPlot(
data = dataLB,
paramVar = "LBTEST",
paramGroupVar = "LBCAT",
timeVar = "LBDY",
colorVar = "LBNRIND",
shapeVar = "LBNRIND",
title = "Laboratory test measurements: actual value",
labelVars = labelVarsSDTM
)
Palettes are reset to the default patient profiles palettes at the start of a new R session, or by setting:
# change palettes for the entire R session
options(patientProfilesVis.colors = colorsDefault)
options(patientProfilesVis.shapes = shapesDefault)
Custom palettes for standard reference indicator variable are available in the clinUtils
package, via the function getPaletteCDISC
.
# sort LBNRIND
dataLB$LBNRIND <- with(dataLB,
factor(LBNRIND, levels = c("LOW", "NORMAL", "HIGH", "ABNORMAL"))
)
colorPaletteLBNRIND <- getPaletteCDISC(dataLB$LBNRIND, var = "NRIND", type = "color")
print(colorPaletteLBNRIND)
## LOW NORMAL HIGH ABNORMAL
## "orange" "green4" "orange" "red"
shapePaletteLBNRIND <- getPaletteCDISC(dataLB$LBNRIND, var = "NRIND", type = "shape")
print(shapePaletteLBNRIND)
## LOW NORMAL HIGH ABNORMAL
## 25 21 24 18
# create plot
lbPlots <- subjectProfileEventPlot(
data = dataLB,
paramVar = "LBTEST",
paramGroupVar = "LBCAT",
timeVar = "LBDY",
colorVar = "LBNRIND", colorPalette = colorPaletteLBNRIND,
shapeVar = "LBNRIND", shapePalette = shapePaletteLBNRIND,
title = "Laboratory test measurements: actual value",
labelVars = labelVarsSDTM
)
For certain module, it might be of interest to transform the time axis to e.g. ‘zoom’ in one part of the the study timeframe. The timeTrans
parameter is used to specify a custom transformation of the time-axis.
The getTimeTrans
provides convenient transformations:
This is typically of interest for domains including events occurring/recorded long before the start of the study (e.g. concomitant medications).
For example, the following subject has a concomitant medication starting long before the start of the study. This results into the positive part of the time axis being ‘squeezed’.
cmPlots <- subjectProfileIntervalPlot(
data = dataSDTM$CM,
paramVar = c(
"CMTRT",
"CMDOSE", "CMDOSU", "CMROUTE",
"CMDOSFRQ"
),
timeStartVar = "CMSTDY",
timeEndVar = "CMENDY",
paramGroupVar = "CMCLAS",
colorVar = "CMCLAS",
title = "Concomitant medications",
labelVars = labelVarsSDTM
)
## 171 record(s) with missing Study Day of Start of Medication and 208 record(s) with missing Study Day of End of Medication are imputed with minimal imputation.
subjectCMTimeTrans <- "01-701-1192"
## Warning: Removed 13 rows containing missing values or values outside the scale range
## (`geom_segment()`).
## Warning: Removed 32 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 13 rows containing missing values or values outside the scale range
## (`geom_point()`).
A hyperbolic arc-sine transformation is applied on the time axis, only for the negative times, to focus mainly on the medications taken after the start of the treatment exposure (after time 0).
timeTrans <- getTimeTrans("asinh-neg")
cmPlotsTimeTrans <- subjectProfileIntervalPlot(
data = dataSDTM$CM,
paramVar = c(
"CMTRT",
"CMDOSE", "CMDOSU", "CMROUTE",
"CMDOSFRQ"
),
timeStartVar = "CMSTDY",
timeEndVar = "CMENDY",
paramGroupVar = "CMCLAS",
colorVar = "CMCLAS",
timeTrans = timeTrans,
title = "Concomitant medications",
labelVars = labelVarsSDTM
)
## 171 record(s) with missing Study Day of Start of Medication and 208 record(s) with missing Study Day of End of Medication are imputed with minimal imputation.
## Warning: Removed 13 rows containing missing values or values outside the scale range
## (`geom_segment()`).
## Warning: Removed 32 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 13 rows containing missing values or values outside the scale range
## (`geom_point()`).
A report, combining all subject profile visualizations is created via the function createSubjectProfileReport
.
The function:
subjectProfileCombine
function)Please note that the example report(s) in the section are not created by default in the vignette, for time constraints.
Feel free to run yourself the code, and check the resulting pdf report!
Example code to create patient profiles for SDTM or ADaM datasets is described below.
# demography
dmPlots <- subjectProfileTextPlot(
data = dataSDTM$DM,
paramValueVar = c("SEX|AGE", "RACE|COUNTRY", "ARM"),
labelVars = labelVarsSDTM
)
# medical history
mhPlots <- subjectProfileTextPlot(
data = dataSDTM$MH,
paramNameVar = c("MHDECOD"),
paramValueVar = c("MHCAT", "MHTERM", "MHSTDTC"),
title = "Medical History: status",
labelVars = labelVarsSDTM
)
# concomitant medications
cmPlots <- subjectProfileIntervalPlot(
data = dataSDTM$CM,
paramVar = c(
"CMTRT",
"CMDOSE", "CMDOSU", "CMROUTE",
"CMDOSFRQ"
),
timeStartVar = "CMSTDY",
timeEndVar = "CMENDY",
paramGroupVar = "CMCLAS",
colorVar = "CMCLAS",
timeTrans = timeTrans,
title = "Concomitant medications",
labelVars = labelVarsSDTM
)
# treatment exposure
exPlots <- subjectProfileIntervalPlot(
data = dataSDTM$EX,
paramVar = c("EXTRT", "EXDOSE", "EXDOSU"),
timeStartVar = "EXSTDY",
timeEndVar = "EXENDY",
colorVar = "EXDOSFRM",
labelVars = labelVarsSDTM,
title = "Treatment exposure"
)
# adverse events:
dataAE <- dataSDTM$AE
# sort severities
dataAE[, "AESEV"] <- factor(dataAE[, "AESEV"], levels = c("MILD", "MODERATE", "SEVERE"))
aePlots <- subjectProfileIntervalPlot(
data = dataAE,
paramVar = "AETERM",
timeStartVar = "AESTDY",
timeEndVar = "AEENDY",
colorVar = "AESEV",
labelVars = labelVarsSDTM,
title = "Adverse events"
)
# laboratory parameter
lbLinePlots <- subjectProfileLinePlot(
data = dataSDTM$LB,
paramNameVar = "LBTEST",
paramValueVar = "LBSTRESN",
paramValueRangeVar = c("LBSTNRLO", "LBSTNRHI"),
paramGroupVar = "LBCAT",
timeVar = "LBDY",
title = "Laboratory test measurements: actual value",
labelVars = labelVarsSDTM
)
# create report
pathReport <- "subjectProfile_SDTM.pdf"
createSubjectProfileReport(
listPlots = list(
dmPlots,
mhPlots,
cmPlots,
exPlots,
aePlots,
lbLinePlots
),
outputFile = pathReport
)
# demography
adslPlots <- subjectProfileTextPlot(
data = dataADaM$ADSL,
paramValueVar = c("SEX|AGE", "RACE", "TRT01P"),
labelVars = labelVarsADaM
)
# adverse events:
dataADAE <- dataADaM$ADAE
# sort severities
dataADAE[, "AESEV"] <- factor(dataAE[, "AESEV"], levels = c("MILD", "MODERATE", "SEVERE"))
adaePlots <- subjectProfileIntervalPlot(
data = dataADAE,
paramVar = "AEDECOD",
timeStartVar = "ASTDY",
timeEndVar = "AENDY",
colorVar = "AESEV",
labelVars = labelVarsADaM,
timeTrans = getTimeTrans("asinh-neg"),
title = "Adverse events"
)
# laboratory parameter
adlbcPlots <- subjectProfileLinePlot(
data = dataADaM$ADLBC,
paramNameVar = "PARAM",
paramValueVar = "AVAL",
paramValueRangeVar = c("A1LO", "A1HI"),
paramGroupVar = "PARCAT1",
timeVar = "ADY",
title = "Laboratory test measurements: actual value",
labelVars = labelVarsADaM
)
# create report
pathReport <- "subjectProfile_ADaM.pdf"
createSubjectProfileReport(
listPlots = list(
adslPlots,
adaePlots,
adlbcPlots
),
outputFile = pathReport
)
Reference lines can be displayed as vertical lines spanning all visualizations.
Custom reference lines to indicated the two screening visits and the baseline are displayed for a example subject:
# reference lines input parameter
refLinesParam <- list(
list(
time = -7,
label = "Screening 1",
color = "purple"
),
list(
time = -7,
label = "Screening 2",
color = "purple"
),
list(
time = 1,
label = "Baseline",
color = "darkblue"
)
)
# create report
pathReport <- "subjectProfile_SDTM_referenceLines_custom.pdf"
createSubjectProfileReport(
listPlots = list(
dmPlots,
mhPlots,
cmPlots,
exPlots,
aePlots,
lbLinePlots
),
refLines = refLinesParam,
outputFile = pathReport
)
In the following example: the reference lines are extracted from the subject visits: SV
dataset.
# create report
pathReport <- "subjectProfile_SDTM_referenceLines_subjectVisit.pdf"
# only retain screening, baseline and planned visits
dataSV <- subset(dataSDTM$SV, grepl("SCREENING|WEEK|BASELINE", VISIT))
createSubjectProfileReport(
listPlots = list(
dmPlots,
mhPlots,
cmPlots,
exPlots,
aePlots,
lbLinePlots
),
# reference line(s)
refLinesData = dataSV,
refLinesTimeVar = "VISITDY",
refLinesLabelVar = "VISIT",
outputFile = pathReport
)
A simple index by sex and arm of each subject is created via the bookmark parameter.
# create report
pathReport <- "subjectProfile_SDTM_bookmarks.pdf"
dataDM <- dataSDTM$DM
# sort arm categories
dataDM$ARM <- factor(dataDM$ARM,
levels = c("Placebo", "Xanomeline Low Dose", "Xanomeline High Dose"))
createSubjectProfileReport(
listPlots = list(
dmPlots,
mhPlots,
cmPlots,
exPlots,
aePlots,
lbLinePlots
),
subset = c("01-718-1427", "01-704-1445", "01-701-1211"),
# bookmark(s)
bookmarkData = dataDM,
bookmarkVar = c("SEX", "ARM"),
# sort subjects in the report based on:
subjectSortData = dataDM,
subjectSortVar = "ARM",
outputFile = pathReport
)
In order that the different visualizations are not aligned in the time axis, the modules to be aligned can be specified to the timeAlign
parameter.
This can be of interest when combining a visualization displaying concomitant medications with historical data with a high time range and visualization of events occuring only during the study timeframe; or for modules with different time units.
Please note that the corresponding interval module(s) should also be created with the parameter: timeAlign = FALSE
in the function subjectProfileIntervalPlot
call (see section Interval module).
Please find an example below of subject profiles displaying the adverse events occurring from baseline associated with the laboratory measurements before and after baseline.
# create the list of visualizations
# The list is named in order that the names are used
# to reference the module for the alignment parameters
listPlots <- list(AE = aePlots, LB = lbLinePlots)
subsetPatients <- c(subjectAE, subjectLB)
By default, the visualizations are aligned across domains (timeAlign
is ‘all’) and subjects (timeAlignPerSubject
is “none”).
Please note that because all domains are aligned, the adverse event domain is extended to also contain the times for laboratory measurements (and not only from baseline on as specified during the creation of the AE visualizations).
pathReport <- "subjectProfile_timeAlign-all_timeAlignPerSubject-none.pdf"
createSubjectProfileReport(
listPlots = listPlots,
outputFile = pathReport,
subset = subsetPatients
)
The visualizations are aligned only for the adverse events domain (timeAlign
set to: ‘AE’) and across subjects (timeAlignPerSubject
is “none”).
pathReport <- "subjectProfile_timeAlign-AE_timeAlignPerSubject-none.pdf"
createSubjectProfileReport(
listPlots = listPlots,
outputFile = pathReport,
subset = subsetPatients,
timeAlign = "AE"
)
The visualizations are not aligned across domain (timeAlign
set to: ‘none’) neither subjects (timeAlignPerSubject
is “none”).
pathReport <- "subjectProfile_timeAlign-none_timeAlignPerSubject-none.pdf"
createSubjectProfileReport(
listPlots = listPlots,
outputFile = pathReport,
subset = subsetPatients,
timeAlign = "none"
)
The visualizations are aligned (timeAlign
set to: ‘all’) per subject (timeAlignPerSubject
is “all”).
pathReport <- "subjectProfile_timeAlign-all_timeAlignPerSubject-all.pdf"
createSubjectProfileReport(
listPlots = listPlots,
outputFile = pathReport,
subset = subsetPatients,
timeAlignPerSubject = "all"
)
For clinical trial with high number of patients (e.g. phase 3), the creation of the subject profile report can be time-consuming.
Please find below a few advices:
subjectSubset
or subsetData
/subsetVar
/subsetValue
parameterssubjectSortData
/subjectSortVar
)exportBatchSize
parameter. Exporting the patient profiles by batch of 10 subjects can be a good idea for a for study with a high number of patients.nCores
of the createSubjectProfileReport
function. In this case, the package parallel
is required.parallel::detectCores()
.R version 4.4.0 (2024-04-24)
Platform: x86_64-pc-linux-gnu
locale: C
attached base packages: stats, graphics, grDevices, utils, datasets, methods and base
other attached packages: pander(v.0.6.5), clinUtils(v.0.2.0), patientProfilesVis(v.2.0.9) and knitr(v.1.47)
loaded via a namespace (and not attached): gtable(v.0.3.5), jsonlite(v.1.8.8), highr(v.0.11), compiler(v.4.4.0), Rcpp(v.1.0.12), stringr(v.1.5.1), parallel(v.4.4.0), gridExtra(v.2.3), jquerylib(v.0.1.4), scales(v.1.3.0), yaml(v.2.3.8), fastmap(v.1.2.0), ggplot2(v.3.5.1), R6(v.2.5.1), plyr(v.1.8.9), labeling(v.0.4.3), htmlwidgets(v.1.6.4), forcats(v.1.0.0), tibble(v.3.2.1), munsell(v.0.5.1), bslib(v.0.7.0), pillar(v.1.9.0), rlang(v.1.1.4), utf8(v.1.2.4), DT(v.0.33), stringi(v.1.8.4), cachem(v.1.1.0), xfun(v.0.44), sass(v.0.4.9), viridisLite(v.0.4.2), cli(v.3.6.2), withr(v.3.0.0), magrittr(v.2.0.3), crosstalk(v.1.2.1), digest(v.0.6.35), grid(v.4.4.0), haven(v.2.5.4), hms(v.1.1.3), cowplot(v.1.1.3), lifecycle(v.1.0.4), vctrs(v.0.6.5), evaluate(v.0.24.0), glue(v.1.7.0), data.table(v.1.15.4), farver(v.2.1.2), fansi(v.1.0.6), colorspace(v.2.1-0), reshape2(v.1.4.4), rmarkdown(v.2.27), tools(v.4.4.0), pkgconfig(v.2.0.3) and htmltools(v.0.5.8.1)