I have data on students exam results. Each student takes a 100 question exam. Each question has been allocated (unequally) to one of 5 domains and also has a unique learning outcome associated with it. I need to summarise the data in a table (likely spread over multiple pdf pages), identifying for each domain, the learning outcomes the student got correct/incorrect.
For each Domain I have managed to get a table which shows the the learning outcomes the student got correct/incorrect, but I can't figure out how to join the tables together after the loop. I'd really appreciate some help with this...
Please find below a copy of my code:
library(tidyverse)
library(dplyr)
library(gridExtra)
library(grid)
library(gtable)
library(ids)
# Create some random Learning Objectives:
LO <- ids::adjective_animal(2500, 2, style = "sentence")
# Create data:
testdata <- data.frame(cbind(StudentID=rep(1:25,each=100),
QuestionNumber=rep(1:100),
Correct=sample(c(0,1),replace=TRUE,size=2500),
Domain=c("A","A","A","B","C","C","C","D","D","E"),
LearningOutcome=LO))
rm(LO)
# Create lists for Loops:
DomainList <- unique(testdata$Domain)
StudentList <- unique(testdata$StudentID)
Domain.Colours <- list("steelblue3","red2","violetred3","forestgreen","chocolate1")
for (i in 1:length(unique(testdata$StudentID))){
for (j in 1:length(DomainList)){
# Select Domain Specfic Data
TEMP.DatabyDomain <- testdata[testdata$Domain==DomainList[j],]
# Split Learning Outcomes into Correct/Incorrect Lists
TEMP.Correct <- TEMP.DatabyDomain$LearningOutcome[TEMP.DatabyDomain$StudentID == StudentList[i] & TEMP.DatabyDomain$Correct == 1]
TEMP.Incorrect <- TEMP.DatabyDomain$LearningOutcome[TEMP.DatabyDomain$StudentID == StudentList[i] & TEMP.DatabyDomain$Correct == 0]
# Update the lengths to be the same
n <- max(length(TEMP.Correct), length(TEMP.Incorrect))
length(TEMP.Correct) <- n
length(TEMP.Incorrect) <- n
# Combine the data into a new df
FeedbackData <- data.frame(TEMP.Correct, TEMP.Incorrect)
FeedbackData <- sapply(FeedbackData, as.character)
# Replace NAs with ""
FeedbackData[is.na(FeedbackData)] <- " "
# Create column headings
colnames(FeedbackData) <- c(paste("Correctly answered questions\n in domain:",DomainList[j]),paste("Incorrectly answered questions\n in domain:",DomainList[j]))
# Table Settings
tt1 <- ttheme_default(core=list(fg_params=list(fontsize=8)),
rowhead=list(fg_params=list(hjust=0, x=0)),
colhead=list(bg_params=list(fill=paste(Domain.Colours[j])),
fg_params=list(col="white")))
# Table Results
tfeedback <- tableGrob(FeedbackData, theme=tt1, rows = NULL)
}
### Here is where I get stuck ###
# I would like to append the 5 Domain tables together, so that they are one long table with the column headings in-between
tfeedbacktitle <- textGrob(paste("Feedback for Students"),gp=gpar(fontsize=20))
padding <- unit(10,"mm")
table <- gtable_add_rows(
tfeedback,
heights = grobHeight(tfeedbacktitle) + padding,
pos = 0)
table <- gtable_add_grob(
table,
tfeedbacktitle,
1, 1, 1, ncol(table))
# Code below to allow table to cover multiple pages
# Taken from <https://stackoverflow.com/questions/15937131/print-to-pdf-file-using-grid-table-in-r-too-many-rows-to-fit-on-one-page>
fullheight <- convertHeight(sum(table$heights), "cm", valueOnly = TRUE)
margin <- unit(0,"in")
margin_cm <- convertHeight(margin, "cm", valueOnly = TRUE)
a4height <- 29.7 - margin_cm
nrows <- nrow(table)
npages <- ceiling(fullheight / a4height)
heights <- convertHeight(table$heights, "cm", valueOnly = TRUE)
rows <- cut(cumsum(heights), include.lowest = FALSE,
breaks = c(0, cumsum(rep(a4height, npages))))
groups <- split(seq_len(nrows), rows)
gl1 <- lapply(groups, function(id) table[id,])
mypath <- file.path(pathOutput,paste("StudentID_", StudentList[i], ".pdf", sep = ""))
pdf(file=mypath, paper = "a4", width = 0, height = 0)
for(page in seq_len(npages)){
grid.newpage()
grid.rect(width=unit(21,"cm") - margin,
height=unit(29.7,"cm")- margin)
grid.draw(gl1[[page]])
}
dev.off()
}
The link shows a picture of what I hope to achieve: Example Final Result