### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
#
# R script for study: 
#   Title: 'Evaluation of lexical clarification by patients reading their clinical notes: A quasi-experimental interview study'
#   Authors: Hugo J.T. van Mens, Mirte M. van Eysden, Remko Nienhuis, Johannes J.M. van Delden, Nicolette F. de Keizer, Ronald Cornet
#   Journal: BMC Medical informatics and decision making 
#
#   Script author: HJT van Mens
#   Date: May 26, 2020
#
#   Castor version: V2019.2.12 - v2019.3.9
#   R version: 3.6.1
#   RStudio version: 1.2.1335
#   Requirements:
#       Adapt settings below to local file paths and names
#       
### ### ### ### ### ### ### ### ### ### ### ### ### ### ###

#### Load libraries ####
library(openxlsx) # openxlsx_4.1.2
library(utils)
library(stats)
library(tidyverse) # tidyverse_1.3.0 ggplot2_3.2.1 
library(plyr) # plyr_1.8.4

#### Configure settings ####
# set working directory to local folder that contains Castor Data
setwd("")

now <- format(Sys.time(), "%Y%m%d%H%M%S")
# set filename of file that contains the Castor Data
castorXlsxFileName <- "Data/Influence_of_lexical_clarification_on_patient_understanding_excel_export_dc9f88cc3f86ae7c.xlsx"
settingXlsxFileName <- "Data/Analysis configuration.xlsx"
outputXlsxFileName <- paste("Output/", now, " Analysis output.xlsx", sep = "")

#### Functions ####
IsEmpty <- function(string) {
  return(string == "" | is.na(string))
}

LookupStudyVariableName <- function(variableName, value) {
  optionGroupName <- subset(studyVariables, Variable.name == variableName)$Optiongroup.name
  return(subset(englishFieldOptions, Option.group.name == optionGroupName & Option.value == value)$English.name[1])
}

LookupStudyVariableNames <- function(variableName, list) {
  varNames <- c()
  for(value in list) {
    varNames <- append(varNames, LookupStudyVariableName(variableName, value))
  }
  return(varNames)
} 

LookupReportVariableName <- function(variablename, value) {
  optionGroupName <- subset(reportVariables, Variable.name == variablename)$Optiongroup.name
  return(subset(englishFieldOptions, Option.group.name == optionGroupName & Option.value == value)$English.name)
}

WriteNumberAndPercentage <- function(number, total) {
  n = as.character(number)
  percentage = as.character(round(number / total * 100, digits = 0))
  return(paste(n, " (", percentage, ")", sep = ""))
}

WriteMedianAndIqr <- function(vector) {
  fiveNum <- fivenum(vector)
  q1 <- as.character(fiveNum[2])
  q2 <- as.character(fiveNum[3])
  q3 <- as.character(fiveNum[4])
  return(paste(q2, " (", q1, "-", q3, ")", sep = ""))
}

WriteMedianAndRange <- function(vector) {
  q0 <- as.character(quantile(vector, 0, na.rm = TRUE))
  q2 <- as.character(median(vector, na.rm = TRUE))
  q4 <- as.character(quantile(vector, 1, na.rm = TRUE))
  return(paste(q2, " (", q0, "-", q4, ")", sep = ""))
}

CategoricalDataToStatistics <- function(variableName, dataVector) {
  vectorLength <- length(dataVector)
  optionGroupName <- subset(studyVariables, Variable.name == variableName)$Optiongroup.name
  optionGroupSubset <- subset(englishFieldOptions, Option.group.name == optionGroupName)
  variableValues <- optionGroupSubset$Option.value
  frequencies <- c()
  for (variableValue in variableValues) {
    frequencies <- append(frequencies, WriteNumberAndPercentage(length(which(dataVector == variableValue)), vectorLength))
  }
  return(data.frame(statistic = rep(c(variableName, ""), c(1,length(variableValues) - 1)),
                    description = optionGroupSubset$English.name, 
                    value = frequencies,
                    unit = rep("n (%)", length(variableValues))))
}

LowerCIofProportion <- function(proportion, total) {
  lowerCI <- proportion - 1.96 * StandardErrorOfProportion(proportion, total)
  if (lowerCI < 0){
    return (0)
  } else {
    return (lowerCI)
  }
}

UpperCIofProportion <- function(proportion, total) {
  upperCI <- proportion + 1.96 * StandardErrorOfProportion(proportion, total)
  if (upperCI > 1) {
    return (1)
  } else {
    return (upperCI)
  }
}

StandardErrorOfProportion <- function(proportion, total) {
  return(sqrt(proportion*(1-proportion)/total))
}

statistics <- c()
AddStatistic <- function(statistic, description, value, unit) {
  statistics <- rbind(statistics, 
                      data.frame(statistic = c(statistic), 
                                 description = c(description), 
                                 value = c(as.character(value)), 
                                 unit = c(unit)))
  return(statistics)
}

AddStatistics <- function(dataFrame) {
  statistics <- rbind(statistics, dataFrame)
  return(statistics)
}

WriteAgeGroupStatistics <- function(dataVector, ranges) {
  ageGroupNames <- c()
  values <- c()
  dataVectorLength <- length(dataVector)
  rangeLength <- length(ranges[,1])
  for(i in 1:nrow(ranges))
  {
    min <- ranges[i, "min"]
    max <- ranges[i, "max"]
    number <- length(which(dataVector >= min & dataVector <= max))
    ageGroupNames <- append(ageGroupNames, paste(min, "-", max, "years"))
    values <- append(values, WriteNumberAndPercentage(number, dataVectorLength))
  }
  return(data.frame(statistic = rep(c("Age group", ""), c(1,rangeLength - 1)),
                    description = ageGroupNames, 
                    value = values,
                    unit = rep("n (%)", rangeLength)))
}

logs <- data.frame()
options(digits.secs = 3)
Log <- function(logs, category, messages) {
  newLogs <- LogLine(category, messages)
  return(rbind(logs, newLogs))
}

LogLine <- function(category, messages) {
  newLogs <- data.frame()
  for (message in messages) {
    dateTimeNow <- format(Sys.time(), "%Y-%m-%d %H:%M:%OS")
    newLogs <- rbind(newLogs, data.frame(datetime = dateTimeNow, category = category, message = message))
  }
  return(newLogs)
}

LogIfNotEmpty <- function(logs, category, message, dataFrame) {
  if (length(dataFrame[,1]) > 0)
  {
    newLogs <- LogLine(category, message)
    newLogs <- rbind(newLogs, LogLine(category, DataFrameToStrings(dataFrame)))
    return (rbind(logs, newLogs))
  }
  return(logs)
}

VectorToString <- function(vector) {
  string <- c()
  for (element in vector) {
    string <- paste(string, toString(element))
  }
  return(string)
}

DataFrameToStrings <- function(dataFrame) {
  if (length(dataFrame[,1]) > 0) {
    strings <- c(VectorToString(colnames(dataFrame)))
    for (row in 1:nrow(dataFrame)) {
      strings <- append(strings, VectorToString(dataFrame[row,]))
    }
    return(strings)
  }
}

logs <- Log(logs, "Information", "Loaded functions")


#### Read Excel document with Castor output ####

sheetNames <- getSheetNames(castorXlsxFileName)
englishFieldOptions <- read.xlsx(settingXlsxFileName, sheet = "Field options")
ageGroups <- read.xlsx(settingXlsxFileName, sheet = "Age groups")

studyResults <- read.xlsx(castorXlsxFileName, sheet = "Study results")
studyVariables <- read.xlsx(castorXlsxFileName, sheet = "Study variable list")
terms <- read.xlsx(castorXlsxFileName, sheet = "Term")
clarifications <- read.xlsx(castorXlsxFileName, sheet = "Clarification")
medicalLetters <- read.xlsx(castorXlsxFileName, sheet = "Medical_letter")
reportVariables <- read.xlsx(castorXlsxFileName, sheet = "Report variable list")
fieldOptions <- read.xlsx(castorXlsxFileName, sheet = "Field options")
comments <- read.xlsx(castorXlsxFileName, sheet = "Comments")
queries <- read.xlsx(castorXlsxFileName, sheet = "Queries")
verifications <- read.xlsx(castorXlsxFileName, sheet = "Verifications")

logs <- Log(logs, "Information", "Loaded data")

#### Swap difficulty and ease ####
studyResults$ToolDifficulty <- 100 - strtoi(studyResults$ToolDifficulty)
terms$TermDifficulty <- 100 - strtoi(terms$TermDifficulty)
clarifications$TermDifficultyAtClarification <- 100 - strtoi(clarifications$TermDifficultyAtClarification)
clarifications$ClarificationDifficulty <- 100 - strtoi(clarifications$ClarificationDifficulty)



#### Table 1 Participant characteristics ####
# generate Table 1 with study population characteristics
statistics <- c()
numberOfRecords = length(studyResults$Record.Id)

# Gender
participants <- data.frame(Record.Id = studyResults$Record.Id)
# removed identifying information by removing gender in participants table
# participants$Gender <- with(studyResults, LookupStudyVariableNames("Gender", Gender))

statistics <- AddStatistics(CategoricalDataToStatistics("Gender", studyResults$Gender))

# Age
participants$Age <- with(studyResults, 2019 - strtoi(BirthYear))
statistics <- AddStatistic("Age", "", WriteMedianAndRange(participants$Age), "median (range)")
# removed identifying information by converting ages to age groups in participants table
participants$Age <- with(participants, paste(substring(Age, 1, 1), "0-", substring(Age, 1, 1), "9", sep = "")) 

# Age groups
statistics <- AddStatistics(WriteAgeGroupStatistics(participants$Age, ageGroups))

# Education
participants$Education <- with(studyResults, LookupStudyVariableNames("Education", Education))
statistics <- AddStatistics(CategoricalDataToStatistics("Education", studyResults$Education))

# TreatmentDuration
participants$TreatmentDuration <- with(studyResults, LookupStudyVariableNames("TreatmentDuration", TreatmentDuration))
statistics <- AddStatistics(CategoricalDataToStatistics("TreatmentDuration", studyResults$TreatmentDuration))

# WorksInHealthCare
participants$WorksInHealthCare <- with(studyResults, LookupStudyVariableNames("WorksInHealthCare", WorksInHealthCare))
statistics <- AddStatistics(CategoricalDataToStatistics("WorksInHealthCare", studyResults$WorksInHealthCare))

# "HelpedByOthers"
participants$HelpedByOthers <- with(studyResults, LookupStudyVariableNames("HelpedByOthers", HelpedByOthers))

# "ConfidenceFillingForms"
participants$ConfidenceFillingForms <- with(studyResults, LookupStudyVariableNames("ConfidenceFillingForms", ConfidenceFillingForms))

# "UnderstandsWrittenInformation"
participants$UnderstandsWrittenInformation <- with(studyResults, LookupStudyVariableNames("UnderstandsWrittenInformation", UnderstandsWrittenInformation))

# Set of Brief Screening Questions Score
#   a score below 2 indicates an inadequate health literacy and a score above 2 and adequate health literacy
studyResults$SBSQ <- with(studyResults, 4 - (strtoi(HelpedByOthers) + strtoi(ConfidenceFillingForms) + strtoi(UnderstandsWrittenInformation)) / 3)
participants$SBSQ <- studyResults$SBSQ

statistics <- AddStatistic("Health literacy",
                           "Inadequate (SBSQ <= 2)",
                           WriteNumberAndPercentage(length(which(studyResults$SBSQ <= 2)), length(studyResults$SBSQ)),
                           "n (%)")
statistics <- AddStatistic("",
                           "Adequate (SBSQ > 2)",
                           WriteNumberAndPercentage(length(which(studyResults$SBSQ > 2)), length(studyResults$SBSQ)),
                           "n (%)")

table1 <- statistics



#### Medical letters ####
statistics <- data.frame()

# number of medical letters not empty
notEmptyLetters <- subset(medicalLetters, (!IsEmpty(LetterType)))
emptyLetterCount <- length(medicalLetters$Record.Id) - length(notEmptyLetters$Record.Id)

# filter out empty medical letters
medicalLetters <- notEmptyLetters
logs <- Log(logs, "Information", paste("Filtered out", emptyLetterCount, "empty letters based on having an empty MedicalLetter and empty LetterType field"))

# exclude letter that was only available in control environment and not in the intervention environment due to different version of data
medicalLetters <- subset(medicalLetters, Report.Name.Custom != 'Medical letter - 29-10-2019 11:45:59')
terms <- subset(terms, Report.Parent != 'Medical letter - 29-10-2019 11:45:59')
clarifications <- subset(clarifications, Report.Parent != 'Medical letter - 29-10-2019 11:45:59')

# exclude letter that was directed at the patient himself (with 'Patiëntgerichte brief') from letters, and from terms and clarifications
medicalLetters <- subset(medicalLetters, Report.Name.Custom != 'Medical letter - 31-10-2019 12:52:09')
terms <- subset(terms, Report.Parent != 'Medical letter - 31-10-2019 12:52:09')
clarifications <- subset(clarifications, Report.Parent != 'Medical letter - 31-10-2019 12:52:09')

logs <- Log(logs, "Information", "Excluded letter 'Medical letter - 31-10-2019 12:52:09' because it was directed at the patient himself.")

# number of letters per participant
participants$NumberOfLetters <- as.data.frame(table(medicalLetters$Record.Id))$Freq

# add columns with letter types per participant
letterTypePerParticipant <- reshape(as.data.frame(table(medicalLetters$Record.Id, medicalLetters$LetterType)), 
                                    idvar = "Var1", timevar = "Var2", direction = "wide")[,2:4]
participants <- cbind(participants, letterTypePerParticipant)

# add letter specialties per participant
participants$Specialties <- aggregate(Specialty ~ Record.Id, data = medicalLetters, c)$Specialty

# sort letters by LetterNumber and then by Record.Id
medicalLetters <- medicalLetters[order(medicalLetters$Record.Id, medicalLetters$LetterNumber),]

# add primary key to letters
medicalLetters$Letter.Id <- c(1:length(medicalLetters$Record.Id))

# select certain columns in another order
medicalLetters <- data.frame(Record.Id = medicalLetters$Record.Id, Letter.Id = medicalLetters$Letter.Id, LetterNumber = medicalLetters$LetterNumber,
                             Report.Name.Custom = medicalLetters$Report.Name.Custom, LetterType = medicalLetters$LetterType,
                             Specialty = medicalLetters$Specialty, KnowsLetter = medicalLetters$KnowsLetter,
                             KnowsLetterContent = medicalLetters$KnowsLetterContent)


### Data validation ###

# Do all letters have terms?
lettersWithoutTerms <- medicalLetters[which(medicalLetters$Report.Name.Custom %in% unique(terms$Report.Parent) == FALSE),]
logs <- LogIfNotEmpty(logs, "Warning", "Found letter(s) without any difficult terms:", lettersWithoutTerms)

# Do all letters have clarifications?
lettersWithoutClarifications <- medicalLetters[which(medicalLetters$Report.Name.Custom %in% unique(clarifications$Report.Parent) == FALSE),]
logs <- LogIfNotEmpty(logs, "Warning", "Found letter(s) without clarifications:", lettersWithoutClarifications)

# Order medical letters by id
medicalLetters <- medicalLetters[order(medicalLetters$Letter.Id),]


#### Difficult terms ####

notEmptyTerms <- subset(terms, !IsEmpty(Term))
emptyTermCount <- length(terms$Term) - length(notEmptyTerms$Term)

# filter out empty terms
terms <- notEmptyTerms
logs <- Log(logs, "Warning", paste("Filtered out", emptyTermCount, "empty terms based on having an empty Term field"))

# Difficult terms per record
participants$Terms <- as.data.frame(table(terms$Record.Id))$Freq

# Difficult terms per letter
freqs <- as.data.frame(table(terms$Report.Parent))
colnames(freqs) <- c("Report.Name.Custom", "Terms")
medicalLetters <- merge(medicalLetters, freqs, by = c("Report.Name.Custom"), all.x = TRUE)
# checked whether terms was 0, set terms to 0 if they are NA
medicalLetters[is.na(medicalLetters$Terms),]$Terms <- 0

# median and inter quartile range of term difficulty per record
summaryColnames <- c("Min", "First", "Median", "Mean", "Third", "Max")
termDifficultyPerRecord <- aggregate(strtoi(terms$TermDifficulty), list(terms$Record.Id), summary)

termDifficultyIqr <- data.frame(First = sapply(termDifficultyPerRecord$x, '[','1st Qu.'), Third = sapply(termDifficultyPerRecord$x, '[','3rd Qu.'))
termDifficultyPerRecord <- data.frame(Record.Id = termDifficultyPerRecord$Group.1,
                                      TermDifficultyMedian = sapply(termDifficultyPerRecord$x, '[', 'Median'),
                                      TermDifficultyIqr = with(termDifficultyIqr, paste(First, " - ", Third, sep = "")))
participants <- merge(participants, termDifficultyPerRecord, by = c("Record.Id"), all.x = TRUE)

# inter quartile ranges of term difficulty per letter
termDifficultyPerLetter <- aggregate(strtoi(terms$TermDifficulty), list(terms$Report.Parent), summary)

termDifficultyIqr <- data.frame(First = sapply(termDifficultyPerLetter$x, '[','1st Qu.'), Third = sapply(termDifficultyPerLetter$x, '[','3rd Qu.'))
termDifficultyPerLetter <- data.frame(Report.Name.Custom = termDifficultyPerLetter$Group.1,
                                      TermDifficultyMedian = sapply(termDifficultyPerLetter$x, '[', 'Median'),
                                      TermDifficultyIqr = with(termDifficultyIqr, paste(First, " - ", Third, sep = "")))
medicalLetters <- merge(medicalLetters, termDifficultyPerLetter, by = c("Report.Name.Custom"), all.x = TRUE)

#### Count number of words per letter ####

wordsPerFile <- c()
wordsPerParticipant <- c()
participantIds <- c()
# exclude 2.1 and 4.2
for (file in list.files("Texts")) {
  participantIds <- append(participantIds, strtoi(strsplit(file, split = "[.]")[[1]][1]))
  fileName <- paste("Texts/", file, sep = "")
  # split file by whitespace
  tokens <- strsplit(read_file(fileName), split = "\\s")
  # remove empty strings
  tokens <- tokens[tokens != ""]
  newTokens <- c()
  for (token in tokens) {
    if (grepl("\\w", token)) {
      newTokens <- append(newTokens, token)
    }
  }
  wordsPerFile <- append(wordsPerFile, length(newTokens))
}
fileFrame <- data.frame(participant = participantIds, file = list.files("Texts"), words = wordsPerFile)


#### Clarifications ####
notEmptyClarification <- subset(clarifications, !IsEmpty(ClarifiedTerm))
emptyClarificationCount <- length(clarifications$Record.Id) - length(subset(clarifications, !IsEmpty(ClarifiedTerm))$Record.Id)

# filter out clarifications that miss a clarified term
clarifications <- notEmptyClarification
logs <- Log(logs, "Warning", paste("Filtered out", emptyClarificationCount, "clarifications without a ClarifiedTerm"))

# empty synonym, for clarifications with clarified terms
clarificationWithoutSynonyms <- subset(clarifications, !IsEmpty(ClarifiedTerm) & IsEmpty(ClarificationSynonym))
logs <- LogIfNotEmpty(logs, "Warning", "Found clarifications that miss synonyms:", clarificationWithoutSynonyms)

# empty definition, for clarifications with clarified terms and synonyms
logs <- LogIfNotEmpty(logs, "Warning", "Found clarifications that miss definitions:", subset(clarifications, !IsEmpty(ClarifiedTerm) & !IsEmpty(ClarificationSynonym) & IsEmpty(ClarificationDefinition)))

# empty difficulty, usefulness not empty or other way around
clarificationsWithMissingRatings <- subset(clarifications, 
                                           !IsEmpty(ClarifiedTerm) & !IsEmpty(ClarificationSynonym) &
                                             (
                                               ( !IsEmpty(ClarificationDifficulty) & IsEmpty(ClarificationUsefulness)) |
                                                 ( IsEmpty(ClarificationDifficulty) & !IsEmpty(ClarificationUsefulness))
                                             )
                                          )

logs <- LogIfNotEmpty(logs, "Warning", "Found clarifications that miss either usefulness or difficulty rating but not the other", clarificationsWithMissingRatings)



#### Clarifications per clarification synonym and definition ####
clarifiedTerms <- as.data.frame(table(clarifications$ClarifiedTerm))
termsClarifiedOnce <- clarifiedTerms[clarifiedTerms$Freq == 1,]$Var1

# frequency of synonyms
synonyms <- as.data.frame(table(tolower(clarifications$ClarificationSynonym)))

# frequency of synonyms per record
synonymFrequency <- as.data.frame(table(tolower(clarifications$ClarificationSynonym), clarifications$Record.Id))
# set frequency of synonyms per record to 1 where frequency > 1
synonymFrequency[synonymFrequency$Freq > 1,]$Freq <- 1
# frequency per record as uniq column
synonyms$Uniq <- as.data.frame(table(synonymFrequency[synonymFrequency$Freq > 0,]$Var1))$Freq

definitions <- c()
for (i in 1:length(synonyms$Var1)) {
  synonym <- synonyms$Var1[i]
  definition <- subset(clarifications, tolower(ClarificationSynonym) == synonym & ClarificationDefinition != "NA")$ClarificationDefinition[1]
  definitions <- append(definitions, definition)
}
synonyms$definition <- definitions

# Clarified terms per letter (deduplication causes missings in here because duplicates are per participant not per letter)
freqs <- as.data.frame(table(clarifications[which(clarifications$ClarifiesDifficultTerm == 1),]$Report.Parent))
colnames(freqs) <- c("Report.Name.Custom", "TermsClarified")
medicalLetters <- merge(medicalLetters, freqs, by = c("Report.Name.Custom"), all.x = TRUE)

# Clarifications per letter
freqs <- as.data.frame(table(clarifications$Report.Parent))
colnames(freqs) <- c("Report.Name.Custom", "Clarifications")
medicalLetters <- merge(medicalLetters, freqs, by = c("Report.Name.Custom"), all.x = TRUE)
# set medical letters number of clarifications to 0 number is NA
medicalLetters[is.na(medicalLetters$Clarifications),]$Clarifications <- 0

# if there are 0 clarifications and 0 terms, are they missing or actually 0? --> terms clarified should be only 0 if they do not overlap otherwise NA
# if Terms is NA and Clarifications is NA, then 
medicalLetters[which(IsEmpty(medicalLetters$TermsClarified) & !IsEmpty(medicalLetters$Terms) & !IsEmpty(medicalLetters$Clarifications)),]$TermsClarified <- 0

# if there are 0 clarifications and 1 or more difficult terms, terms clarified should be 0 (for NA values)
medicalLetters[which(medicalLetters$Terms > 0 & medicalLetters$Clarifications == 0),]$TermsClarified <- 0


#### Clarifications per participant ####

### find duplicate clarification synonyms per participant and remove duplicates from clarifications
duplicateClarifications <- clarifications[duplicated(clarifications[c("Record.Id", "ClarificationSynonym")]),]
clarifications <- clarifications[!duplicated(clarifications[c("Record.Id", "ClarificationSynonym")]),]

### duplicate difficult terms and remove duplicates from terms
duplicateDifficultTerms <- terms[duplicated(terms[c("Record.Id", "Term")]),]
terms <- terms[!duplicated(terms[c("Record.Id", "Term")]),]

# clarified terms per participant
# number of clarified difficult terms per participant
freqs <- as.data.frame(table(clarifications[which(clarifications$ClarifiesDifficultTerm == 1),]$Record.Id))
colnames(freqs) <- c("Record.Id", "TermsClarified")
participants <- merge(participants, freqs, by = c("Record.Id"), all.x = TRUE)
participants[is.na(participants$TermsClarified),]$TermsClarified <- 0
participants$ClarifiedPercentage <- round(participants$TermsClarified / participants$Terms, digits = 3)

# subset of clarifications of difficult terms that were clarified
difficultTermClarifications <- clarifications[which(clarifications$ClarifiesDifficultTerm == 1),]
difficultTermClarificationDifficulty <- c()
difficultTermClarificationNAs <- c()
difficultTermClarificationUsefulness <- c()
for (id in participants$Record.Id) {
  clarificationsForRecordId <- subset(difficultTermClarifications, Record.Id == id)
  length <- length(clarificationsForRecordId$Record.Id)
  if (length == 0) {
    difficultTermClarificationDifficulty <- append(difficultTermClarificationDifficulty, NA)
    difficultTermClarificationNA <- NA
    difficultTermClarificationUsefulness <- append(difficultTermClarificationUsefulness, NA)
  } else if (length == 1) {
    difficultTermClarificationDifficulty <- append(difficultTermClarificationDifficulty, strtoi(clarificationsForRecordId$ClarificationDifficulty[1]))
    difficultTermClarificationNA <- 0
    difficultTermClarificationUsefulness <- append(difficultTermClarificationUsefulness, strtoi(clarificationsForRecordId$ClarificationUsefulness[1]))
  } else {
    difficultySummary <- summary(strtoi(clarificationsForRecordId$ClarificationDifficulty))
    difficultTermClarificationDifficulty <- append(difficultTermClarificationDifficulty, difficultySummary[["Median"]])
    if ("NA's" %in% names(difficultySummary)) {
      difficultTermClarificationNA <- difficultySummary[["NA's"]]
    } else {
      difficultTermClarificationNA <- 0
    }
    usefulnessSummary <- summary(strtoi(clarificationsForRecordId$ClarificationUsefulness))
    difficultTermClarificationUsefulness <- append(difficultTermClarificationUsefulness, usefulnessSummary[["Median"]])
  }
  difficultTermClarificationNAs <- append(difficultTermClarificationNAs, difficultTermClarificationNA)
}
participants$TermsClarifiedClarificationNotRated <- difficultTermClarificationNAs
participants$TermsClarifiedClarificationDifficulty <- difficultTermClarificationDifficulty
participants$TermsClarifiedClarificationUsefulness <- difficultTermClarificationUsefulness

easyTermClarifications <- clarifications[which(clarifications$ClarifiesDifficultTerm == 0),]
easyTermClarificationDifficulty <- c()
easyTermClarificationNAs <- c()
easyTermClarificationUsefulness <- c()
easyTermDifficulty <- c()
for (id in participants$Record.Id) {
  clarificationsForRecordId <- subset(easyTermClarifications, Record.Id == id)
  length <- length(clarificationsForRecordId$Record.Id)
  if (length == 0) {
    easytTermClarificationDifficulty <- append(easyTermClarificationDifficulty, NA)
    easyTermClarificationNA <- NA
    easyTermClarificationUsefulness <- append(easyTermClarificationUsefulness, NA)
  } else if (length == 1) {
    easyTermClarificationDifficulty <- append(easyTermClarificationDifficulty, strtoi(clarificationsForRecordId$ClarificationDifficulty[1]))
    easyTermClarificationNA <- 0
    easyTermClarificationUsefulness <- append(easyTermClarificationUsefulness, strtoi(clarificationsForRecordId$ClarificationUsefulness[1]))
  } else {
    difficultySummary <- summary(strtoi(clarificationsForRecordId$ClarificationDifficulty))
    easyTermClarificationDifficulty <- append(easyTermClarificationDifficulty, difficultySummary[["Median"]])
    if ("NA's" %in% names(difficultySummary)) {
      easyTermClarificationNA <- difficultySummary[["NA's"]]
    } else {
      easyTermClarificationNA <- 0
    }
    usefulnessSummary <- summary(strtoi(clarificationsForRecordId$ClarificationUsefulness))
    easyTermClarificationUsefulness <- append(easyTermClarificationUsefulness, usefulnessSummary[["Median"]])
  }
  easyTermClarificationNAs <- append(easyTermClarificationNAs, easyTermClarificationNA)
  easyTermDifficulty <- append(easyTermDifficulty, fivenum(strtoi(clarificationsForRecordId$TermDifficultyAtClarification))[3])
}

participants$EasyClarifiedClarificationNotRated <- easyTermClarificationNAs
participants$EasyClarifiedClarificationDifficulty <- easyTermClarificationDifficulty
participants$EasyClarifiedClarificationUsefulness <- easyTermClarificationUsefulness
participants$EasyTermDifficulty <- easyTermDifficulty

# filter out unrated clarifications
ratedClarifications <- subset(clarifications, IsEmpty(ClarificationDifficulty) & IsEmpty(ClarificationUsefulness))

# number of clarifications per record
participants$Clarifications <- as.data.frame(table(clarifications$Record.Id))$Freq

# clarifications of difficult terms (where both term and clarification were rated)
difficultTermsClarified <- subset(clarifications, strtoi(ClarifiesDifficultTerm) == 1 & !is.na(ClarificationDifficulty))

# clarifications of easy terms
easyTermsClarified <- subset(clarifications, strtoi(ClarifiesDifficultTerm) == 0 & !is.na(ClarificationDifficulty))

difficultTermsCount <- sum(participants$Terms)
termsClarifiedCount <- sum(participants$TermsClarified)
clarificationCount <- sum(participants$Clarifications)
difficultTermsNotClarifiedCount <- difficultTermsCount - termsClarifiedCount
clarificationNotRequestedCount <- clarificationCount - termsClarifiedCount

clarifications$ClarificationUsefulness <- strtoi(clarifications$ClarificationUsefulness)

#### Summary statistics ####

# statistics averaged over participants
statistics <- c()

statistics <- AddStatistic("Number of letters", "Per participant", WriteMedianAndIqr(participants$NumberOfLetters), "median (IQR)")
statistics <- AddStatistic("Number of words", "Per letter", WriteMedianAndIqr(wordsPerFile), "median (IQR)")
statistics <- AddStatistic("Number of difficult terms", "Per participant", WriteMedianAndIqr(participants$Terms), "median (IQR)")
statistics <- AddStatistic("Difficult term ease medians", "Per participant", WriteMedianAndIqr(participants$TermDifficultyMedian), "median (IQR)")
statistics <- AddStatistic("Number of clarified terms", "Per participant", WriteMedianAndIqr(participants$TermsClarified), "median (IQR)")
statistics <- AddStatistic("Number of clarifications", "Per participant", WriteMedianAndIqr(participants$Clarifications), "median (IQR)")
statistics <- AddStatistic("Percentage of terms clarified", "Per participant", WriteMedianAndIqr(participants$ClarifiedPercentage), "median (IQR)")
statistics <- AddStatistic("Difficult term clarification ease", "Per participant", WriteMedianAndIqr(participants$TermsClarifiedClarificationDifficulty), "median (IQR)")
statistics <- AddStatistic("Difficult term clarification usefulness", "Per participant", WriteMedianAndIqr(participants$TermsClarifiedClarificationUsefulness), "median (IQR)")
statistics <- AddStatistic("Easy term clarification ease", "Per participant", WriteMedianAndIqr(participants$EasyClarifiedClarificationDifficulty), "median (IQR)")
statistics <- AddStatistic("Easy term clarification usefulness", "Per participant", WriteMedianAndIqr(participants$EasyClarifiedClarificationUsefulness), "median (IQR)")
statistics <- AddStatistic("Easy term ease", "Per participant", WriteMedianAndIqr(participants$EasyTermDifficulty), "median (IQR)")

# precision per participant
participants$precision <- participants$TermsClarified / participants$Clarifications

participants$lowerPrecision <- mapply(LowerCIofProportion, participants$precision, participants$Clarifications)
participants$upperPrecision <- mapply(UpperCIofProportion, participants$precision, participants$Clarifications)

# recall per participant
participants$recall <- participants$TermsClarified / participants$Terms

participants$lowerRecall <- mapply(LowerCIofProportion, participants$recall, participants$Terms)
participants$upperRecall <- mapply(UpperCIofProportion, participants$recall, participants$Terms)

statistics <- AddStatistic("Precision", "Per participant", WriteMedianAndIqr(participants$precision), "median (IQR)")
statistics <- AddStatistic("Recall", "Per participant", WriteMedianAndIqr(participants$recall), "median (IQR)")

# true positives
TPs <- length(subset(clarifications, ClarifiesDifficultTerm == 1)$Record.Id)
# false positives
FPs <- length(clarifications$Record.Id) - TPs
# false negatives
FNs <- length(terms$Record.Id) - TPs

clarificationCount <- length(clarifications$Record.Id)
termCount <- length(terms$Record.Id)

precision <- TPs / clarificationCount
recall <- TPs / termCount

lowerPrecision <- LowerCIofProportion(precision, clarificationCount)
upperPrecision <- UpperCIofProportion(precision, clarificationCount)

lowerRecall <- LowerCIofProportion(recall, termCount)
upperRecall <- UpperCIofProportion(recall, termCount)

statistics <- AddStatistic("Precision (positive predictive value)", "Overall", round(precision * 100, digits = 2), "%")
statistics <- AddStatistic("Recall (sensitivity)", "Overall", round(recall * 100, digits = 2), "%")
statistics <- AddStatistic("Precision confidence interval", "Overall", paste(lowerPrecision * 100, upperPrecision * 100, sep = " - "), "%")
statistics <- AddStatistic("Recall confidence interval", "Overall", paste(lowerRecall * 100, upperRecall * 100, sep = " - "), "%")

#### Tool evaluation ####
#
participants$ToolDifficulty <- strtoi(studyResults$ToolDifficulty)
participants$ToolUsefulness <- strtoi(studyResults$ToolUsefulness)
statistics <- AddStatistic("Tool ease", "Per participant", WriteMedianAndIqr(strtoi(participants$ToolDifficulty)), "median (IQR)")
statistics <- AddStatistic("Tool usefulness", "Per participant", WriteMedianAndIqr(strtoi(participants$ToolUsefulness)), "median (IQR)")

#### Results ####
medicalLetters <- medicalLetters[order(medicalLetters$Letter.Id),]
logs <- Log(logs, "Information", "Finished script")

termSummary <- terms[c("Record.Id", "Term", "TermDifficulty")]

participants

#### Output results to Xlsx file ####
outputToXlsx <- function() {
  dir.create(file.path(getwd(), "Output"), showWarnings = FALSE)
  write.xlsx(x = logs, file = outputXlsxFileName, sheetName = "Log")
  workbook = loadWorkbook(outputXlsxFileName)
  addWorksheet(wb = workbook, sheetName = "Table1")
  writeData(workbook, sheet = "Table1", x = table1)
  addWorksheet(wb = workbook, sheetName = "Participants")
  writeData(workbook, sheet = "Participants", x = participants)
  addWorksheet(wb = workbook, sheetName = "Letters")
  writeData(workbook, sheet = "Letters", x = medicalLetters)
  addWorksheet(wb = workbook, sheetName = "Terms")
  writeData(workbook, sheet = "Terms", x = termSummary)
  addWorksheet(wb = workbook, sheetName = "Clarifications")
  writeData(workbook, sheet = "Clarifications", x = synonyms)
  addWorksheet(wb = workbook, sheetName = "Statistics")
  writeData(workbook, sheet = "Statistics", x = statistics)
  saveWorkbook(workbook, outputXlsxFileName, overwrite = TRUE)
}

# # Run this command to output the xlsx-file
# outputToXlsx()


#### Figures ####

# Figure 1

plot(participants$precision * 100,
     participants$recall * 100,
     xlab = "Precision as percentage",
     ylab = "Recall as percentage",
     xlim = c(0,50),
     ylim = c(0,25))


# Figure 2

par(mfrow = c(1,1))
vectors <- participants[c("TermDifficultyMedian", "EasyTermDifficulty")]
bp <- boxplot(vectors, 
              names = c("Difficult term", "Easy term"), 
              ylab = "Term ease VAS score",
              at = c(1.2,2.2))
stripchart(vectors, vertical = TRUE, method = "jitter", jitter = 0.15, add = TRUE, pch = 20)
medians <- c(bp$stats[3,1], bp$stats[3,2])
text(x = c(1.7, 2.7), y = medians, labels = medians)

# Figure 3
par(mfrow = c(1, 1))
vectors <- participants[c("TermsClarifiedClarificationDifficulty", "EasyClarifiedClarificationDifficulty")]
bp <- boxplot(vectors, 
              names = c("Difficult term", "Easy term"), 
              ylab = "Clarification ease VAS score",
              at = c(1.2,2.2),
              ylim = c(0,100))
stripchart(vectors, vertical = TRUE, method = "jitter", jitter = 0.15, add = TRUE, pch = 20)
medians <- c(bp$stats[3,1], bp$stats[3,2])
text(x = c(1.7, 2.7), y = medians, labels = medians)

# Figure 4
par(mfrow = c(1, 1))
vectors <- participants[c("TermsClarifiedClarificationUsefulness", "EasyClarifiedClarificationUsefulness")]
bp <- boxplot(vectors, 
              names = c("Difficult term", "Easy term"), 
              ylab = "Clarification usefulness VAS score",
              at = c(1.2,2.2))
stripchart(vectors, vertical = TRUE, method = "jitter", jitter = 0.15, add = TRUE, pch = 20)
medians <- c(bp$stats[3,1], bp$stats[3,2])
text(x = c(1.7, 2.7), y = medians, labels = medians)

# Figure 5
par(mfrow = c(1, 1))
mu <- ddply(subset(clarifications, !is.na(ClarificationUsefulness)), "ClarifiesDifficultTerm", summarise, grp.mean = fivenum(ClarificationUsefulness)[3])
p <- ggplot(data = clarifications, aes(x = strtoi(ClarificationUsefulness), fill = ClarifiesDifficultTerm)) +
  geom_density(alpha = 0.4) +
  scale_fill_discrete(name = "Term", labels = c("Easy", "Difficult")) +
  geom_vline(data = mu, aes(xintercept = grp.mean, color = ClarifiesDifficultTerm), linetype = "dashed") +
  
  scale_color_discrete(name = "Median", labels = c("Easy", "Difficult")) +
  xlab("Clarification Usefulness") +
  ylab("Density") +
  ylim(0, 0.025)
p


#### Additional figures ####

# Figure 6
par(mfrow = c(1, 2))
vector <- strtoi(terms$TermDifficulty)
bp <- boxplot(vector,
              xlab = "Difficult term",
              ylab = "Term ease VAS score",
              at = 1.3)
mtext(paste("n = ", bp$n, sep = ""), side = 1, line = 1)
text(x = 1.6, y = c(bp$stats[3]), labels = c(bp$stats[3]))
stripchart(vector, vertical = TRUE, method = "jitter", jitter = 0.19, add = TRUE, pch = 20, at = 1)

vector <- strtoi(subset(clarifications, ClarifiesDifficultTerm == 0)$TermDifficultyAtClarification)
bp <- boxplot(vector,
              xlab = "Easy term",
              ylab = "Term ease VAS score",
              at = 1.3)
mtext(paste("n = ", bp$n, sep = ""), side = 1, line = 1)
text(x = 1.6, y = c(bp$stats[3]), labels = c(bp$stats[3]))
stripchart(vector, vertical = TRUE, method = "jitter", jitter = 0.19, add = TRUE, pch = 20, at = 1)

# Figure 7
par(mfrow = c(1, 2))
vector <- strtoi(subset(clarifications, ClarifiesDifficultTerm == 1)$ClarificationDifficulty)
bp <- boxplot(vector,
              xlab = "Difficult term",
              ylab = "Clarification ease VAS score",
              ylim = c(0,100),
              at = 1.3)
mtext(paste("n = ", bp$n, sep = ""), side = 1, line = 1)
text(x = 1.6, y = c(bp$stats[3]), labels = c(bp$stats[3]))
stripchart(vector, vertical = TRUE, method = "jitter", jitter = 0.19, add = TRUE, pch = 20, at = 1)


vector <- strtoi(subset(clarifications, ClarifiesDifficultTerm == 0)$ClarificationDifficulty)
bp2 <- boxplot(vector,
               xlab = "Easy term",
               ylab = "Clarification ease VAS score",
               ylim = c(0,100),
               at = 1.3)
mtext(paste("n = ", bp2$n, sep = ""), side = 1, line = 1)
text(x = 1.6, y = c(bp2$stats[3]), labels = c(bp2$stats[3]))
stripchart(vector, vertical = TRUE, method = "jitter", jitter = 0.15, add = TRUE, pch = 20, at = 1)

# Figure 8

par(mfrow = c(1, 2))

vector <- strtoi(subset(clarifications, ClarifiesDifficultTerm == 1)$ClarificationUsefulness)
bp <- boxplot(vector,
              xlab = "Difficult term",
              ylab = "Clarification usefulness VAS score",
              at = 1.3)
mtext(paste("n = ", bp$n, sep = ""), side = 1, line = 1)
text(x = 1.6, y = c(bp$stats[3]), labels = c(bp$stats[3]))
stripchart(vector, vertical = TRUE, method = "jitter", jitter = 0.19, add = TRUE, pch = 20, at = 1)

vector <- strtoi(subset(clarifications, ClarifiesDifficultTerm == 0)$ClarificationUsefulness)
bp2 <- boxplot(vector,
               xlab = "Easy term",
               ylab = "Clarification usefulness VAS score",
               at = 1.3)
mtext(paste("n = ", bp2$n, sep = ""), side = 1, line = 1)
text(x = 1.6, y = c(bp2$stats[3]), labels = c(bp2$stats[3]))
stripchart(vector, vertical = TRUE, method = "jitter", jitter = 0.15, add = TRUE, pch = 20, at = 1)

# Figure 9

par(mfrow = c(1, 1))
hardDifficultyBp <- boxplot(strtoi(ClarificationDifficulty) ~ factor(Record.Id, levels = unique(clarifications$Record.Id)), 
                            data = subset(clarifications, ClarifiesDifficultTerm == 1),
                            names = seq(1:15),
                            xlab = "Record Id",
                            ylab = "Clarification ease VAS score",
                            ylim = c(0,100))
mtext(hardDifficultyBp$n, at = seq_along(hardDifficultyBp$n), line = 1, side = 3)
mtext("n =", at = 0, line = 1, side = 3)
hardDifficultyBp

# Figure 10
par(mfrow = c(1, 1))
easyDifficultyBp <- boxplot(strtoi(ClarificationDifficulty) ~ Record.Id, 
                            data = subset(clarifications, ClarifiesDifficultTerm == 0),
                            names = seq(1:15),
                            xlab = "Record Id",
                            ylab = "Clarification ease VAS score")
mtext(easyDifficultyBp$n, at = seq_along(easyDifficultyBp$n), line = 1, side = 3)
mtext("n =", at = 0, line = 1, side = 3)
easyDifficultyBp

# Figure 11
par(mfrow = c(1, 1))
hardUsefulnessBp <- boxplot(strtoi(ClarificationUsefulness) ~ factor(Record.Id, levels = unique(clarifications$Record.Id)), 
                            data = subset(clarifications, ClarifiesDifficultTerm == 1),
                            names = seq(1:15),
                            xlab = "Record Id",
                            ylab = "Clarification usefulness VAS score")
mtext(hardUsefulnessBp$n, at = seq_along(hardUsefulnessBp$n), line = 1, side = 3)
mtext("n =", at = 0, line = 1, side = 3)
hardUsefulnessBp

# Figure 12
par(mfrow = c(1, 1))
easyUsefulnessBp <- boxplot(strtoi(ClarificationUsefulness) ~ Record.Id, 
                            data = subset(clarifications, ClarifiesDifficultTerm == 0),
                            names = seq(1:15),
                            xlab = "Record Id",
                            ylab = "Clarification usefulness VAS score")
mtext(easyUsefulnessBp$n, at = seq_along(easyUsefulnessBp$n), line = 1, side = 3)
mtext("n =", at = 0, line = 1, side = 3)
easyUsefulnessBp