R/toxFigures.R

Defines functions toxFigures

Documented in toxFigures

#' Create PRO-CTCAE severity frequency distribution figures for individual
#' survey items and composite scores
#'
#'
#' 	  Data format should be in 'long' format, where each PRO-CTCAE item is a
#' 	  variable/column.
#'
#' @param dsn A data.frame object with PRO-CTCAE data
#' @param id_var A character string.Name of ID variable differentiating each
#'   PRO-CTCAE survey/participant entered as a quoted string.
#' @param cycle_var A character string. Name of variable differentiating one
#'   longitudinal/repeated. PRO-CTCAE survey from another, within an individual
#'   ID.
#' @param baseline_val A number indicating the expected baseline cycle/time
#'   point.
#' @param arm_var A character string. Name of arm variable differentiating
#'   treatment groups. Must be character or factor class. Overall AUC
#'   will be reported if no arm/grouping variable is provided. Defaults to
#'   \code{NA}.
#' @param plot_limit A number. Limit the number of cycles to be plotted up to
#'   and including a given cycle number. All available cycle time points are
#'   plotted if no cycle number is provided. Defaults to \code{NA}.
#' @param colors A number. Specify the coloring scheme of symptom grades within
#'   frequency bars. Options include: 1 = Blue and red color shading, 2 =
#'   qualitative color shades (color blind friendly), 3 = black and white.
#'   Defaults to 1.
#' @param label A number. Label frequency bars with sample size (n) or percent
#'   shown on the y-axis. Label options include: \code{1} = sample size (n)
#'   within each cycle (symptom grade 0 or higher), \code{2} = sample size (n)
#'   within each cycle with present symptoms (symptom grade > 0), \code{3} =
#'   sample size (n) within each cycle with severe symptoms (symptom grade >=
#'   3), \code{4} = percent of subjects within each cycle with present
#'   symptoms (symptom grade > 0), \code{5} = percent of subjects within each
#'   cycle with severe symptoms (symptom grade >= 3). No labels will be applied
#'   if not specified. Defaults to \code{NA}.
#' @param summary_only Logical. Only display the summary measures in figures /
#'   Suppress the individual time points from plotting. Defaults to
#'   \code{FALSE}.
#' @param cycles_only Logical. Only display the longitudinal time points in
#'   figures / Suppress the summary measures from plotting. Defaults to
#'   \code{FALSE}.
#' @param x_label A character string. Label for the x axis of the plot. Defaults
#'   to \code{"Randomized Treatment Assignment"} if \code{arm_var} is specified,
#'   defaults to \code{"Overall"} if not \code{arm_var} is specified.
#' @param x_lab_angle A integer between 0 and 360. Allows the user to rotate the
#'   x axis labels in order to fit long arm names (0 or 45 recommended).
#'   Defaults to \code{0}.
#' @param x_lab_vjust A number. A ggplot2 object option. Allows the user to
#'   vertically adjusts the x axis labels in order to fit arm names. Defaults to
#'   \code{1}.
#' @param x_lab_hjust A number. A ggplot2 object option. Allows the user to
#'   horizontally adjusts the x axis labels in order to fit arm names. Defaults
#'   to \code{0}.
#' @param plot_data Logical. Return the data used to construct plots as element
#'   of the returned object. Defaults to \code{FALSE}.
#' @return A list object. The returned object is a (k X 2) or (k x 3) nested
#'   list. Where k is the number of PRO-CTCAE item groups (e.g. pain, fatigue,
#'   nausea); list[[1 ... i ... k]]. For each list item there are 2 or 3
#'   elements. The 1st element of each list item is the name of the PRO-CTCAE
#'   item group returned as a string. The 2nd element is the PRO-CTCAE figure as
#'   a ggplot object. The 3rd (and optional) element is the data used to
#'   construct the ggplot figure, available via \code{plot_data}.
#' @importFrom magrittr %>%
#' @examples
#' fig_acute = toxFigures(dsn = ProAE::tox_acute[c(1:300, 1101:1400),],
#'  cycle_var = "Cycle",
#'  baseline_val = 1,
#'  arm_var = "arm",
#'  id_var = "id",
#'  label = 0,
#'  x_lab_angle = -45,
#'  x_lab_vjust =  .3,
#'  x_lab_hjust = .2,
#'  colors = 2)
#' fig_acute[[1]]
#' @export


toxFigures = function(dsn,
                     id_var,
                     cycle_var,
                     baseline_val,
                     arm_var=NA,
                     plot_limit=NA,
                     colors=1,
                     label=0,
                     summary_only=FALSE,
                     cycles_only=FALSE,
                     x_lab_angle=0,
                     x_lab_vjust=1,
                     x_lab_hjust=0,
                     x_label = "Randomized Treatment Assignment",
                     plot_data=FALSE){

  # ----------------------------------------------------------------
  # -- Checks 1/2
  # ----------------------------------------------------------------

  ## -- Assign binding for data.frame variables used within ggplot2 objects as global variables

  grade_comp = NULL
  grade_item = NULL
  arm = NULL
  bar_lab_opt = NULL

  ## -- Required parameters

  if(exists("dsn")){
    if(!is.data.frame(dsn)){
      stop("param dsn must be provided as a data.frame object")
    }
  } else {stop("param dsn not provided")}

  if(exists("id_var")){
    if(!is.character(id_var)){
      stop("param id_var must be provided as a character string")
    } else if (!(id_var %in% colnames(dsn))){
      stop(paste0("param id_var (", id_var, ") not found as a variable in dsn (", deparse(substitute(dsn)), ")"))
    }
  } else {stop("param id_var not provided")}

  if(exists("cycle_var")){
    if(!is.character(cycle_var)){
      stop("param cycle_var must be provided as a character string")
    } else if (!(cycle_var %in% colnames(dsn))){
      stop(paste0("param cycle_var (", cycle_var, ") not found as a variable in dsn (", deparse(substitute(dsn)), ")"))
    }
  } else {stop("param cycle_var not provided")}

  if(exists("baseline_val")){
    if(!(is.numeric(baseline_val) | is.integer(baseline_val) | length(baseline_val)==1)){
      stop("param baseline_val must be provided as a single number, of class numeric or integer")
    }
  } else {stop("param baseline_val not provided")}

  ## -- Check for any duplicate individuals within cycles

  if(any(duplicated(dsn[,c(id_var, cycle_var)]))){
    stop(paste0("Duplicate observations were found within id_var and cycle_var combinations (", id_var, " and ", cycle_var, ")"))
  }


  # ----------------------------------------------------------------
  # -- Defaults
  # ----------------------------------------------------------------

  if(is.na(arm_var)){
    arm_var = "overall_"
    if(x_label=="Randomized Treatment Assignment"){
      x_label = "Overall"
    }
  }

  if(summary_only==TRUE & cycles_only==TRUE){
    summary_only = TRUE
  }

  ## -------------------------------------------------------------
  ## --- Reference data sets
  ## -------------------------------------------------------------

  proctcae_vars[, ] = lapply(proctcae_vars[, ], as.character)

  # ================================================================
  # ==== ACCOMMODATION FOR 27A HAIR LOSS AMOUNT ====================
  # ================================================================
  ## -- Item 27 asks about hair loss and is referenced as an 'amount'
  ## -- However this item utilizes the Interference response bank.
  ## -- This is accommodated here by treating it as Interference then
  ## -- resulting plot is manually labeled 'Amount' BTL - 20AUG2020

  proctcae_vars[proctcae_vars$name=="PROCTCAE_27A_SCL",]$short_label = "Hair Loss Interference"

  # ================================================================
  # ================================================================
  # ================================================================


  # ----------------------------------------------------------------
  # -- Get existing PROCTCAE variables in dsn
  # ----------------------------------------------------------------

  ## - Individual items
  dsn_items0 = toupper(names(dsn)[toupper(names(dsn)) %in% proctcae_vars$name])
  dsn_items = dsn_items0[! dsn_items0 %in% as.character(proctcae_vars$name[proctcae_vars$fmt %in% c("yn_2_fmt", "yn_3_fmt", "yn_4_fmt")])]

  ## - Composites
  proctcae_vars_comp0 = proctcae_vars[,-1] %>% dplyr::mutate_if(is.factor, as.character)
  # proctcae_vars_comp0 = proctcae_vars[,-1]
  proctcae_vars_comp0 = proctcae_vars_comp0[!proctcae_vars_comp0$name %in% as.character(proctcae_vars_comp0$name[proctcae_vars_comp0$fmt %in% c("yn_2_fmt",
                                                                                                                                                "yn_3_fmt",
                                                                                                                                                "yn_4_fmt")]),]
  proctcae_vars_comp = c()
  proctcae_vars_comp$name = paste0(substr(proctcae_vars_comp0$name, 1, nchar(proctcae_vars_comp0$name)-5), "_COMP")
  proctcae_vars_comp$short_label = sub(proctcae_vars_comp0$short_label, pattern = " [[:alpha:]]*$", replacement = "")
  proctcae_vars_comp = unique(data.frame(proctcae_vars_comp, stringsAsFactors=FALSE))
  dsn_comps = toupper(names(dsn)[toupper(names(dsn)) %in% proctcae_vars_comp$name])

  # ----------------------------------------------------------------
  # -- Checks 2/2
  # ----------------------------------------------------------------

  ## -- Confirm there are available PRO-CTCAE variables within dsn with expected naming convention
  if(identical(dsn_items, character(0)) & identical(dsn_comps, character(0))){
    stop(paste0("No PRO-CTCAE variables found within dsn (", deparse(substitute(dsn)), ") meeting the expected naming convention"))
  }

  # ----------------------------------------------------------------
  # -- Cluster available items and composites together
  # ----------------------------------------------------------------

  ## -- Available PRO-CTCAE items and composites available in dsn
  refset = data.frame(name = c(dsn_items, dsn_comps))
  refset$number = as.integer(gsub("[^0-9]", "", refset$name))
  refset$rank = ifelse(grepl("COMP", refset$name), 4,
                       ifelse(grepl("A_", refset$name), 1,
                              ifelse(grepl("B_", refset$name), 2, 3)))

  refset = refset[order(refset$number,refset$rank),]
  refset = merge(x=refset,
                 y= data.frame(number = unique(refset$number),
                               group_rank = 1:length(unique(refset$number)),
                               stringsAsFactors=FALSE),
                 by="number", all.x=TRUE)

  ## -- All non-indicator PRO-CTCAE with possible composites

  reflabs0 = data.frame(name=proctcae_vars$name,
                        short_label = proctcae_vars$short_label,
                        lab = unlist(lapply(strsplit(proctcae_vars$short_label, split=" "), 1, FUN=utils::tail)),
                        stringsAsFactors=FALSE)

  reflabs0$group_lab = ifelse(reflabs0$lab=="Severity", trimws(gsub("Severity","", reflabs0$short_label)),
                              ifelse(reflabs0$lab=="Frequency", trimws(gsub("Frequency","", reflabs0$short_label)),
                                     trimws(gsub("Interference","", reflabs0$short_label))))
  reflabs0 = reflabs0[!grepl("_IND", reflabs0$name),]
  reflabs0$comp_name = paste0(substr(reflabs0$name,1,nchar(reflabs0$name)-5),"_COMP")
  reflabs1 = unique(reflabs0[c("group_lab", 'comp_name')])
  names(reflabs1) = c("group_lab","name")
  reflabs1$lab = "Composite"
  reflabs = rbind.data.frame(reflabs0[c("name", "group_lab", "lab")],
                             reflabs1[c("name", "group_lab", "lab")],
                             stringsAsFactors=FALSE)

  refset = merge(x=refset,
                 y=reflabs,
                 by= "name", all.x=TRUE)
  refset = refset[order(refset$number,refset$rank),]


  # ----------------------------------------------------------------
  # -- For each available PRO-CTCAE item grouping [i], process
  # ----------------------------------------------------------------

  for (i in 1:max(refset$group_rank)){

    if(i==1){list_out = vector(mode='list', max(refset$group_rank))}

    # ----------------------------------------------------------------
    # -- For each PRO-CTCAE item within the grouping [j], process
    # ----------------------------------------------------------------
    group_i = refset[refset$group_rank==i,]
    plot_combined0 = data.frame()
    for (j in 1:NROW(group_i)){
      item = as.character(group_i$name[j])

      if(arm_var != "overall_"){
        dsn0 = stats::na.omit(dsn[,c(id_var, cycle_var, arm_var, item)])
      } else if (arm_var == "overall_"){
        dsn0 = stats::na.omit(dsn[,c(id_var, cycle_var, item)])
        dsn0$overall_ = "Overall"
      }


      # ----------------------------------------------------------------
      # -- Construct summary measures
      # ----------------------------------------------------------------
      ## -- Maximum grade post baseline
      max_post0 = stats::aggregate(dsn0[dsn0[,cycle_var]>baseline_val, item],
                                   by = list(dsn0[dsn0[,cycle_var]>baseline_val,id_var]),
                                   FUN=max)
      colnames(max_post0) = c(id_var, item)
      max_post0[,cycle_var] = "Maximum*"
      max_post1 = unique(merge(x=max_post0, y=dsn0[,c(id_var, arm_var)], by=id_var, all.x = TRUE))

      ## -- Baseline adjusted
      base_adj0 = dsn0[dsn0[,cycle_var]==baseline_val, c(id_var, item)]
      colnames(base_adj0)[2] = "base_val"

      base_adj1 = merge(x=dsn0, y=base_adj0, by=id_var, all.x=TRUE)
      base_adj2 = stats::aggregate(base_adj1[base_adj1[,cycle_var]>baseline_val, item],
                                   by = list(base_adj1[base_adj1[,cycle_var]>baseline_val,id_var]),
                                   FUN=max)
      colnames(base_adj2) = c(id_var, "max_post_bl")
      base_adj2 = merge(x=base_adj1, y=unique(base_adj2), by=id_var, all.x=TRUE)
      base_adj2$bl_adjusted = ifelse(!is.na(base_adj2$max_post_bl) & base_adj2$base_val >= base_adj2$max_post_bl,
                                     0, base_adj2$max_post_bl)
      base_adj3 = unique(base_adj2[!is.na(base_adj2$bl_adjusted),c(id_var, arm_var, "bl_adjusted")])
      base_adj3[,cycle_var] = "Adjusted**"
      colnames(base_adj3)[colnames(base_adj3) == "bl_adjusted"] = item


      dsn1 = rbind.data.frame(dsn0, max_post1, base_adj3)

      # ----------------------------------------------------------------
      # -- Create labels for the bars
      # ----------------------------------------------------------------

      if(label==0){
        labs = dsn1[,c(cycle_var, arm_var)]
        labs$bar_lab_opt = NA
      } else if(label==1){
        labs = stats::aggregate(dsn1[dsn1[,item]>=0,item],
                                by=list(dsn1[dsn1[,item]>=0,cycle_var],
                                        dsn1[dsn1[,item]>=0,arm_var]),
                                FUN=length)
      } else if(label %in% c(2,4)){
        labs = stats::aggregate(dsn1[dsn1[,item]>0,item],
                                by=list(dsn1[dsn1[,item]>0,cycle_var],
                                        dsn1[dsn1[,item]>0,arm_var]),
                                FUN=length)
      } else if(label %in% c(3,5)){
        labs = stats::aggregate(dsn1[dsn1[,item]>=3,item],
                                by=list(dsn1[dsn1[,item]>=3,cycle_var],
                                        dsn1[dsn1[,item]>=3,arm_var]),
                                FUN=length)
      }
      names(labs) = c(cycle_var, arm_var, "bar_lab_opt")

      # -- Force zero counts
      combo_counts = data.frame(table(dsn1[,cycle_var], dsn1[,arm_var]), stringsAsFactors=FALSE)
      names(combo_counts) = c(cycle_var, arm_var, "total")
      combo_counts$flag = 1

      labs2 = merge(x=labs, y=combo_counts, by=c(cycle_var, arm_var), all.y = TRUE)

      if(any(is.na(labs2$bar_lab_opt))){
        labs2[is.na(labs2$bar_lab_opt),]$bar_lab_opt = 0
      }

      if(label %in% c(4,5)){
        labs2[labs2$bar_lab_opt!=0,]$bar_lab_opt=round(labs2[labs2$bar_lab_opt!=0,]$bar_lab_opt/labs2[labs2$bar_lab_opt!=0,]$total,digits=2)*100
      }

      dsn2 = merge(dsn1, labs2, by = c(cycle_var, arm_var))

      # -- Only one label per cycle/arm combination
      high = by(dsn2, INDICES = list(dsn2[,cycle_var], dsn2[,arm_var]), FUN = utils::tail, n=1)
      high2 = do.call("rbind", as.list(high))
      row_keeps = as.integer(rownames(high2))
      dsn2[!(1:NROW(dsn2) %in% row_keeps),]$bar_lab_opt = NA

      # ----------------------------------------------------------------
      # -- Create labels for the cycle_var facets
      # ----------------------------------------------------------------
      dsn2$cycle_var_v_plot=factor(ifelse(dsn2[,cycle_var]=="Maximum*",
                                          "Maximum*",
                                          ifelse(dsn2[,cycle_var]=="Adjusted**", "Adjusted**",
                                                 paste0(cycle_var," ", dsn2[,cycle_var]))),
                                   levels=c(paste0(cycle_var," ", min(dsn0[,cycle_var]):max(dsn0[,cycle_var])),
                                            "Maximum*",
                                            "Adjusted**"))
      dsn2$lab = group_i$lab[j]
      dsn2$item = item
      colnames(dsn2)[4] = "grade"

      # -- Append
      plot_combined0 = rbind.data.frame(plot_combined0, dsn2, stringsAsFactors=FALSE)
    }

    plot_combined0$grade_item = ifelse(plot_combined0$lab!="Composite", plot_combined0$grade, NA)
    plot_combined0$grade_comp = ifelse(plot_combined0$lab=="Composite", plot_combined0$grade, NA)
    plot_combined0$item_lab = factor(plot_combined0$lab, levels=unique(plot_combined0$lab))

    # ----------------------------------------------------------------
    # -- Color palette options
    # ----------------------------------------------------------------

    if(colors==1){
      # -- Default
      item_col0 = "white"
      item_col1 = "#90B0D9"
      item_col2 = "#4D7EBF"
      item_col3 = "#13478C"
      item_col4 = "#142233"

      comp_col0 = "white"
      comp_col1 = "#E5BFC6"
      comp_col2 = "#D9576E"
      comp_col3 = "#99293D"

      colset1 = c(
        "0" = item_col0,
        "1" = item_col1,
        "2" = item_col2,
        "3" = item_col3,
        "4" = item_col4
      )
      colset2 = c(
        "0" = comp_col0,
        "1" = comp_col1,
        "2" = comp_col2,
        "3" = comp_col3
      )
    } else if(colors==2){
      # -- Qualitative (color-blind friendly)
      item_col0 = "white"
      item_col1 = "#0571B0"
      item_col2 = "#92C5DE"
      item_col3 = "#F4A582"
      item_col4 = "#CA0020"

      comp_col0 = "white"
      comp_col1 = "#A6DBA0"
      comp_col2 = "#C2A5CF"
      comp_col3 = "#7B3294"

      colset1 = c(
        "0" = item_col0,
        "1" = item_col1,
        "2" = item_col2,
        "3" = item_col3,
        "4" = item_col4
      )
      colset2 = c(
        "0" = comp_col0,
        "1" = comp_col1,
        "2" = comp_col2,
        "3" = comp_col3
      )
    } else if(colors==3){
      # -- Black and white
      item_col0 = "white"
      item_col1 = "#E6E6E6"
      item_col2 = "#BDBDBD"
      item_col3 = "#636363"
      item_col4 = "#000000"

      comp_col0 = "white"
      comp_col1 = "#BDBDBD"
      comp_col2 = "#636363"
      comp_col3 = "#000000"

      colset1 = c(
        "0" = item_col0,
        "1" = item_col1,
        "2" = item_col2,
        "3" = item_col3,
        "4" = item_col4
      )
      colset2 = c(
        "0" = comp_col0,
        "1" = comp_col1,
        "2" = comp_col2,
        "3" = comp_col3
      )
    }

    ## -- Line color adjustments
    colset1_line = colset1
    colset1_line[1] = "grey"

    colset2_line = colset2
    colset2_line[1] = "grey"

    ## -- Optional title
    title_i = refset[refset$group_rank==i,]$group_lab[1]

    plot_combined0$grade_item = ifelse(plot_combined0$lab!="Composite", plot_combined0$grade, NA)
    plot_combined0$grade_comp = ifelse(plot_combined0$lab=="Composite", plot_combined0$grade, NA)
    plot_combined0$item_lab = factor(plot_combined0$lab, levels=unique(plot_combined0$lab))

    # -- Legend components
    facets = factor(unique(plot_combined0$lab), levels = c("Frequency", "Severity", "Interference", "Composite"))

    foot_note = ""
    ptsize1="15pt"
    ptsize2="10pt"

    for (k in facets){
      if(k=="Frequency"){
        freq0 = paste0("<span style='font-size:",ptsize1,"'>\U23CD </span>Never /   ")
        freq1 = paste0("<span style='font-size:",ptsize2,";color:", item_col1, ";'>\U25A0</span> Rarely   /   ")
        freq2 = paste0("<span style='font-size:",ptsize2,";color:", item_col2, ";'>\U25A0</span> Occasionally   /   ")
        freq3 = paste0("<span style='font-size:",ptsize2,";color:", item_col3, ";'>\U25A0</span> Frequently   /   ")
        freq4 = paste0("<span style='font-size:",ptsize2,";color:", item_col4, ";'>\U25A0</span> Almost constantly")
        foot_note = paste0(foot_note, "**Frequency:** ", freq0, freq1, freq2, freq3, freq4, "<br>")
      } else if(k=="Severity"){
        sev0 = paste0("<span style='font-size:",ptsize1,";'>\U23CD </span>None  /  ")
        sev1 = paste0("<span style='font-size:",ptsize2,";color:", item_col1, "'>\U25A0</span>  Mild   /   ")
        sev2 = paste0("<span style='font-size:",ptsize2,";color:", item_col2, ";'>\U25A0</span> Moderate   /   ")
        sev3 = paste0("<span style='font-size:",ptsize2,";color:", item_col3, ";'>\U25A0</span> Severe   /   ")
        sev4 = paste0("<span style='font-size:",ptsize2,";color:", item_col4, ";'>\U25A0</span> Very severe")
        foot_note = paste0(foot_note, "**Severity:** ", sev0, sev1, sev2, sev3, sev4, "<br>")
      } else if(k=="Interference"){
        int0 = paste0("<span style='font-size:",ptsize1,";'>\U23CD </span>Not at all  /  ")
        int1 = paste0("<span style='font-size:",ptsize2,";color:", item_col1, ";'>\U25A0</span> A little bit   /   ")
        int2 = paste0("<span style='font-size:",ptsize2,";color:", item_col2, ";'>\U25A0</span> Somewhat   /   ")
        int3 = paste0("<span style='font-size:",ptsize2,";color:", item_col3, ";'>\U25A0</span> Quite a bit   /   ")
        int4 = paste0("<span style='font-size:",ptsize2,";color:", item_col4, ";'>\U25A0</span> Very much")

        # ================================================================
        # ==== ACCOMMODATION FOR 27A HAIR LOSs AMOUNT =====================
        # ================================================================
        if(refset[refset$group_rank==i,]$group_lab[1]=="Hair Loss"){
          foot_note = paste0(foot_note, "**Amount:** ", int0, int1, int2, int3, int4, "<br>")
        } else {
          foot_note = paste0(foot_note, "**Interference:** ", int0, int1, int2, int3, int4, "<br>")
        }
        # ================================================================
        # ================================================================
        # ================================================================

      } else if(k=="Composite"){
        comp0 = paste0("<span style='font-size:",ptsize1,";'>\U23CD </span>0  /  ")
        comp1 = paste0("<span style='font-size:",ptsize2,";color:", comp_col1 ,";'>\U25A0</span> 1  /  ")
        comp2 = paste0("<span style='font-size:",ptsize2,";color:", comp_col2 ,";'>\U25A0</span> 2  /  ")
        comp3 = paste0("<span style='font-size:",ptsize2,";color:", comp_col3 ,";'>\U25A0</span> 3 ")
        foot_note = paste0(foot_note, "**Composite Grade:** ", comp0, comp1, comp2, comp3, "<br>")
      }
    }

    foot1 = "\\*Maximum score or grade reported post-baseline per patient.<br>"
    foot2a = "\\*\\*Maximum score or grade reported post-baseline per patient when"
    if(summary_only == TRUE){
      foot2b = " including only scores<br> that were worse than the patient's baseline score."
    } else {
      foot2b = " including only scores that were worse than the patient's baseline score."
    }

    # -- Label footnote addition
    label_foot = ""
    if(label %in% c(2,4)){
      foot_grade = 1
    }
    if(label %in% c(3,5)){
      foot_grade = 3
    }
    if(label %in% c(2,3)){
      foot_symbol = "(n)"
      foot_type = "number"
      y_scale_lab = c("0","25","50","75","100", "n ")
    }
    if(label %in% c(4,5)){
      foot_symbol = "(%)"
      foot_type = "percent"
      y_scale_lab = c("0","25","50","75","100", "% ")
    }

    if(label==1){
      label_foot = "Column labels (n) show the number of subjects with an observed symptom score or grade.<br>"
      y_scale_lab = c("0","25","50","75","100", "n ")
    } else if (label %in% c(2, 3, 4, 5)){
      label_foot = paste0("Column labels ", foot_symbol, " show the ", foot_type,
                          " of subjects with symptom score or grade ",
                          foot_grade," or greater.<br>")
    }

    if(cycles_only==TRUE){
      foot_note = paste0(foot_note, label_foot)
    } else if(cycles_only==FALSE){
      foot_note = paste0(foot_note, label_foot, foot1, foot2a, foot2b)
    }

    ## ----------------------------------------------------------------
    ## -- Conditional ggplot object combinations
    ## ----------------------------------------------------------------

    # -- Restrict the cycles to be plotted
    if(!is.na(plot_limit)){
      plot_combined0$cycle_plot_lim = as.integer(gsub("[^0-9]", "", plot_combined0[,cycle_var]))
      plot_combined0=plot_combined0[(!is.na(plot_combined0$cycle_plot_lim)&plot_combined0$cycle_plot_lim<=plot_limit)|plot_combined0[,cycle_var] %in% c("Adjusted**","Maximum*"),]
    }

    # -- Only show summary measures
    if(summary_only==TRUE){
      plot_combined0 = plot_combined0[plot_combined0[,cycle_var] %in% c("Adjusted**", "Maximum*"),]
    }

    # -- Do not show summary measures
    if(cycles_only==TRUE){
      plot_combined0 = plot_combined0[!(plot_combined0[,cycle_var] %in% c("Adjusted**", "Maximum*")),]
    }

    names(plot_combined0)[names(plot_combined0) == arm_var] = "arm"
    if(arm_var=="overall_"){plot_combined0$arm=""}

    # ================================================================
    # ==== ACCOMMODATION FOR 27A HAIR LOSs AMOUNT ====================
    # ================================================================
    if(refset[refset$group_rank==i,]$group_lab[1]=="Hair Loss"){
      levels(plot_combined0$item_lab) = c("Amount", "Composite", "Interference")
      plot_combined0[plot_combined0$lab=="Interference",]$item_lab = "Amount"
    }
    # ================================================================
    # ================================================================
    # ================================================================

    # ----------------------------------------------------------------
    # -- No labels requested
    # ----------------------------------------------------------------
    if(label==0){

      # ----------------------------------------------------------------
      # --
      # ----------------------------------------------------------------
      if("Composite" %in% unique(plot_combined0$lab) &
         sum(c("Frequency", "Severity", "Interference", "Amount") %in% unique(plot_combined0$lab))>0){

        figure_i = ggplot2::ggplot(plot_combined0, ggplot2::aes(arm)) +

          ## -- Individual items
          ggplot2::scale_fill_manual(values = colset1,
                                     limits = names(colset1),
                                     guide = ggplot2::guide_legend(order = 2)) +
          ggplot2::scale_color_manual(values = colset1_line) +
          ggplot2::geom_bar(data = plot_combined0[!is.na(plot_combined0$grade_item),],
                            ggplot2::aes(fill = as.factor(grade_item), color=as.factor(grade_item)), position = "fill", width = .8) +

          ggnewscale::new_scale(new_aes = "fill") +
          ggnewscale::new_scale(new_aes = "color") +

          # ## -- Composite items
          ggplot2::scale_fill_manual(values = colset2,
                                     limits = names(colset2),
                                     guide = ggplot2::guide_legend(order = 3)) +
          ggplot2::scale_color_manual(values = colset2_line) +
          ggplot2::geom_bar(data = plot_combined0[!is.na(plot_combined0$grade_comp),],
                            ggplot2::aes(fill = as.factor(grade_comp), color=as.factor(grade_comp)), position = "fill", width = .8) +

          ggplot2:: scale_y_continuous(labels = c("0","25","50","75","100"),
                                       breaks = c(0, .25, .5, .75, 1),
                                       limits = c(0, 1.01)) +

          ggplot2::facet_grid(item_lab~cycle_var_v_plot) +
          ggplot2::xlab(x_label) +
          ggplot2::ylab("Percent of Total Frequency") +

          ggplot2::labs(caption = foot_note) +

          ggplot2::theme(
            plot.caption = ggtext::element_markdown(hjust=0, lineheight = -20),
            plot.title.position = "plot",
            plot.caption.position =  "plot",
            axis.title.y = ggplot2::element_text(margin = ggplot2::margin(t = 0, r = 10, b = 0, l = 0)),
            axis.title.x = ggplot2::element_text(margin = ggplot2::margin(t = 10, r = 0, b = 0, l = 0)),
            axis.text.x = ggplot2::element_text(angle = x_lab_angle, vjust=x_lab_vjust, hjust=x_lab_hjust),
            legend.position="none",
            legend.box = "vertical",
            legend.direction = "horizontal",
            legend.box.just = "left",
            panel.grid.major = ggplot2::element_blank(),
            panel.grid.minor = ggplot2::element_blank(),
            panel.background = ggplot2::element_rect(color="grey", fill="white"),
            strip.background = ggplot2::element_rect(colour="grey", fill="#ededed"),
            strip.text.y = ggplot2::element_text(angle=90))
      }

      # ----------------------------------------------------------------
      # -- Individual items only
      # ----------------------------------------------------------------
      else if(!("Composite" %in% unique(plot_combined0$lab))){

        figure_i = ggplot2::ggplot(plot_combined0, ggplot2::aes(arm)) +

          ## -- Individual items
          ggplot2::scale_fill_manual(values = colset1,
                                     limits = names(colset1),
                                     guide = ggplot2::guide_legend(order = 2)) +
          ggplot2::scale_color_manual(values = colset1_line) +
          ggplot2::geom_bar(ggplot2::aes(fill = as.factor(grade_item), color=as.factor(grade_item)), position = "fill", width = .8) +

          ggplot2::scale_y_continuous(labels = c("0","25","50","75","100"),
                             breaks = c(0, .25, .5, .75, 1),
                             limits = c(0, 1.01)) +

          ggplot2::facet_grid(item_lab~cycle_var_v_plot) +
          ggplot2::xlab(x_label) +
          ggplot2::ylab("Percent of Total Frequency") +

          ggplot2::labs(caption = foot_note) +

          ggplot2::theme(
            plot.caption = ggtext::element_markdown(hjust=0, lineheight = -20),
            plot.title.position = "plot",
            plot.caption.position =  "plot",
            axis.title.y = ggplot2::element_text(margin = ggplot2::margin(t = 0, r = 10, b = 0, l = 0)),
            axis.title.x = ggplot2::element_text(margin = ggplot2::margin(t = 10, r = 0, b = 0, l = 0)),
            axis.text.x = ggplot2::element_text(angle = x_lab_angle, vjust=x_lab_vjust, hjust=x_lab_hjust),
            legend.position="none",
            legend.box = "vertical",
            legend.direction = "horizontal",
            legend.box.just = "left",
            panel.grid.major = ggplot2::element_blank(),
            panel.grid.minor = ggplot2::element_blank(),
            panel.background = ggplot2::element_rect(color="grey", fill="white"),
            strip.background = ggplot2::element_rect(colour="grey", fill="#ededed"),
            strip.text.y = ggplot2::element_text(angle=90))

      }

      # ----------------------------------------------------------------
      # -- Composite items only
      # ----------------------------------------------------------------
      else if("Composite" %in% unique(plot_combined0$lab)&
              sum(c("Frequency", "Severity", "Interference", "Amount") %in% unique(plot_combined0$lab))==0){

        figure_i = ggplot2::ggplot(plot_combined0, ggplot2::aes(x=arm)) +

          ## -- Composite items
          ggplot2::scale_fill_manual(values = colset2,
                                     limits = names(colset2),
                                     guide = ggplot2::guide_legend(order = 3)) +
          ggplot2::scale_color_manual(values = colset2_line) +
          ggplot2::geom_bar(ggplot2::aes(fill = as.factor(grade_comp), color=as.factor(grade_comp)), position = "fill", width = .8) +

          ggplot2::scale_y_continuous(labels = c("0","25","50","75","100"),
                             breaks = c(0, .25, .5, .75, 1),
                             limits = c(0, 1.01)) +

          ggplot2::facet_grid(item_lab~cycle_var_v_plot) +
          ggplot2::xlab(x_label) +
          ggplot2::ylab("Percent of Total Frequency") +

          ggplot2::labs(caption = foot_note) +

          ggplot2::theme(
            plot.caption = ggtext::element_markdown(hjust=0, lineheight = -20),
            plot.title.position = "plot",
            plot.caption.position =  "plot",
            axis.title.y = ggplot2::element_text(margin = ggplot2::margin(t = 0, r = 10, b = 0, l = 0)),
            axis.title.x = ggplot2::element_text(margin = ggplot2::margin(t = 10, r = 0, b = 0, l = 0)),
            axis.text.x = ggplot2::element_text(angle = x_lab_angle, vjust=x_lab_vjust, hjust=x_lab_hjust),
            legend.position="none",
            legend.box = "vertical",
            legend.direction = "horizontal",
            legend.box.just = "left",
            panel.grid.major = ggplot2::element_blank(),
            panel.grid.minor = ggplot2::element_blank(),
            panel.background = ggplot2::element_rect(color="grey", fill="white"),
            strip.background = ggplot2::element_rect(colour="grey", fill="#ededed"),
            strip.text.y = ggplot2::element_text(angle=90))

      }
    }

    # ----------------------------------------------------------------
    # -- Labels requested
    # ----------------------------------------------------------------
    else if(label!=0){

      # ----------------------------------------------------------------
      # -- Individual and composite items
      # ----------------------------------------------------------------
      if("Composite" %in% unique(plot_combined0$lab) &
         sum(c("Frequency", "Severity", "Interference", "Amount") %in% unique(plot_combined0$lab))>0){


        figure_i = ggplot2::ggplot(plot_combined0, ggplot2::aes(x=arm)) +

          ## -- Individual items
          ggplot2::scale_fill_manual(values = colset1,
                                     limits = names(colset1),
                                     guide = ggplot2::guide_legend(order = 2)) +
          ggplot2::scale_color_manual(values = colset1_line) +
          ggplot2::geom_bar(data = plot_combined0[!is.na(plot_combined0$grade_item),],
                            ggplot2::aes(fill = as.factor(grade_item), color=as.factor(grade_item)), position = "fill", width = .8) +
          ggnewscale::new_scale(new_aes = "fill") +
          ggnewscale::new_scale(new_aes = "color") +


          ## -- Composite items
          ggplot2::scale_fill_manual(values = colset2,
                                     limits = names(colset2),
                                     guide = ggplot2::guide_legend(order = 3)) +
          ggplot2::scale_color_manual(values = colset2_line) +
          ggplot2::geom_bar(data = plot_combined0[!is.na(plot_combined0$grade_comp),],
                            ggplot2::aes(fill = as.factor(grade_comp), color=as.factor(grade_comp)), position = "fill", width = .8) +

          ## -- Customize
          ggplot2::geom_hline(yintercept=1.04, linetype="solid", color = "darkgrey") +


          ggplot2::geom_text(ggplot2::aes(y= 1.13, label=bar_lab_opt), size=3, na.rm=TRUE) +
          ggplot2::scale_y_continuous(labels = y_scale_lab,
                                      breaks = c(0, .25, .5, .75, 1, 1.13),
                                      limits = c(0, 1.14)) +

          ggplot2::facet_grid(item_lab~cycle_var_v_plot) +
          ggplot2::xlab(x_label) +
          ggplot2::ylab("Percent of Total Frequency") +

          ggplot2::labs(caption = foot_note) +

          ggplot2::theme(
            plot.caption = ggtext::element_markdown(hjust=0, lineheight = -20),
            plot.title.position = "plot",
            plot.caption.position =  "plot",
            axis.title.y = ggplot2::element_text(margin = ggplot2::margin(t = 0, r = 10, b = 0, l = 0)),
            axis.title.x = ggplot2::element_text(margin = ggplot2::margin(t = 10, r = 0, b = 0, l = 0)),
            axis.text.x = ggplot2::element_text(angle = x_lab_angle, vjust=x_lab_vjust, hjust=x_lab_hjust),
            legend.position="none",
            legend.box = "vertical",
            legend.direction = "horizontal",
            legend.box.just = "left",
            panel.grid.major = ggplot2::element_blank(),
            panel.grid.minor = ggplot2::element_blank(),
            panel.background = ggplot2::element_rect(color="grey", fill="white"),
            strip.background = ggplot2::element_rect(colour="grey", fill="#ededed"),
            strip.text.y = ggplot2::element_text(angle=90))
      }

      # ----------------------------------------------------------------
      # -- Individual items only
      # ----------------------------------------------------------------
      else if(!("Composite" %in% unique(plot_combined0$lab))){

        figure_i = ggplot2::ggplot(plot_combined0, ggplot2::aes(x=arm)) +

          ## -- Individual items
          ggplot2::scale_fill_manual(values = colset1,
                                     limits = names(colset1),
                                     guide = ggplot2::guide_legend(order = 2)) +
          ggplot2::scale_color_manual(values = colset1_line) +
          ggplot2::geom_bar(ggplot2::aes(fill = as.factor(grade_item), color=as.factor(grade_item)), position = "fill", width = .8) +

          ## -- Customize
          ggplot2::geom_hline(yintercept=1.04, linetype="solid", color = "darkgrey") +

          ggplot2::geom_text(ggplot2::aes(y= 1.13, label=bar_lab_opt), size=3, na.rm=TRUE) +
          ggplot2::scale_y_continuous(labels = y_scale_lab,
                                      breaks = c(0, .25, .5, .75, 1, 1.13),
                                      limits = c(0, 1.14)) +

          ggplot2::facet_grid(item_lab~cycle_var_v_plot) +
          ggplot2::xlab(x_label) +
          ggplot2::ylab("Percent of Total Frequency") +

          ggplot2::labs(caption = foot_note) +

          ggplot2::theme(
            plot.caption = ggtext::element_markdown(hjust=0, lineheight = -20),
            plot.title.position = "plot",
            plot.caption.position =  "plot",
            axis.title.y = ggplot2::element_text(margin = ggplot2::margin(t = 0, r = 10, b = 0, l = 0)),
            axis.title.x = ggplot2::element_text(margin = ggplot2::margin(t = 10, r = 0, b = 0, l = 0)),
            axis.text.x = ggplot2::element_text(angle = x_lab_angle, vjust=x_lab_vjust, hjust=x_lab_hjust),
            legend.position="none",
            legend.box = "vertical",
            legend.direction = "horizontal",
            legend.box.just = "left",
            panel.grid.major = ggplot2::element_blank(),
            panel.grid.minor = ggplot2::element_blank(),
            panel.background = ggplot2::element_rect(color="grey", fill="white"),
            strip.background = ggplot2::element_rect(colour="grey", fill="#ededed"),
            strip.text.y = ggplot2::element_text(angle=90))
      }

      # ----------------------------------------------------------------
      # -- Composite items only
      # ----------------------------------------------------------------
      else if("Composite" %in% unique(plot_combined0$lab)&
              sum(c("Frequency", "Severity", "Interference", "Amount") %in% unique(plot_combined0$lab))==0){

        figure_i = ggplot2::ggplot(plot_combined0, ggplot2::aes(x=arm)) +

          ## -- Composite items
          ggplot2::scale_fill_manual(values = colset2,
                                     limits = names(colset2),
                                     guide = ggplot2::guide_legend(order = 3)) +
          ggplot2::scale_color_manual(values = colset2_line) +
          ggplot2::geom_bar(ggplot2::aes(fill = as.factor(grade_comp), color=as.factor(grade_comp)), position = "fill", width = .8) +

          ## -- Customize
          ggplot2::geom_hline(yintercept=1.04, linetype="solid", color = "darkgrey") +

          ggplot2::geom_text(ggplot2::aes(y= 1.13, label=bar_lab_opt), size=3, na.rm=TRUE) +
          ggplot2::scale_y_continuous(labels = y_scale_lab,
                                      breaks = c(0, .25, .5, .75, 1, 1.13),
                                      limits = c(0, 1.14)) +

          ggplot2::facet_grid(item_lab~cycle_var_v_plot) +
          ggplot2::xlab(x_label) +
          ggplot2::ylab("Percent of Total Frequency") +

          ggplot2::labs(caption = foot_note) +

          ggplot2::theme(
            plot.caption = ggtext::element_markdown(hjust=0, lineheight = -20),
            plot.title.position = "plot",
            plot.caption.position =  "plot",
            axis.title.y = ggplot2::element_text(margin = ggplot2::margin(t = 0, r = 10, b = 0, l = 0)),
            axis.title.x = ggplot2::element_text(margin = ggplot2::margin(t = 10, r = 0, b = 0, l = 0)),
            axis.text.x = ggplot2::element_text(angle = x_lab_angle, vjust=x_lab_vjust, hjust=x_lab_hjust),
            legend.position="none",
            legend.box = "vertical",
            legend.direction = "horizontal",
            legend.box.just = "left",
            panel.grid.major = ggplot2::element_blank(),
            panel.grid.minor = ggplot2::element_blank(),
            panel.background = ggplot2::element_rect(color="grey", fill="white"),
            strip.background = ggplot2::element_rect(colour="grey", fill="#ededed"),
            strip.text.y = ggplot2::element_text(angle=90))
      }
    }

    list_out[[i]] = list()
    list_out[[i]][[1]] = refset[refset$group_rank==i,]$group_lab[1]
    list_out[[i]][[2]] = figure_i
    if(plot_data == TRUE){
      list_out[[i]][[3]] = plot_combined0[, !(names(plot_combined0) %in% "null")]
    }
  }

  ## -- Reference table for user to view the indexing of PRO-CTCAE item groups withing the list output
  for (i in 1:length(list_out)){
    if (i==1) {fig_tab = data.frame()}
    list_deat = data.frame(PRO_AE = list_out[[i]][[1]], item_index=i)
    fig_tab = rbind(fig_tab, list_deat)
  }

  ## -- Reference table
  print(fig_tab)

  ## -- Object return
  invisible(list_out)
}
blakelanglais/ProAE documentation built on Dec. 19, 2021, 9:52 a.m.