We are very pleased to have received such positive feedback on our work and are grateful to both reviewers for their critical evaluation of the paper. Our responses to each of their individual comments are shown in bold font below. Edits made to the manuscript are indicated in blue: additions are underlined and deletions denoted by "...". Note that line numbers refer to the original submission, rather than the revised manuscript.
# Can be customised file.name <- NULL output.dir <- NULL
# Can be customised include_summary <- TRUE comment_font <- "standard" # (or "italics" or "bold") response_font <- "bold" # (or "italics" or "standard") highlight_textrevisions <- "underline" # (or "bold", "italics", "standard") text_unchanged <- "Text unchanged" newpage_sections <- TRUE
# All code below this line should be left as is. knitr::opts_chunk$set(echo = FALSE, cache = FALSE, messages = FALSE, warning = FALSE) # Required libraries library(tidyverse) # Packages for data science library(janitor) # Simple Tools for Examining and Cleaning Dirty Data library(magrittr) # Pipe operators library(docxtractr) # Extract Data Tables and Comments from 'Microsoft' 'Word' Documents library(respondR) # RMarkdown template for responses to peer-review comments library(kableExtra) # Construct Complex Table with 'kable' and Pipe Syntax library(knitr) # A General-Purpose Package for Dynamic Report Generation in R library(gt) # Easily Create Presentation-Ready Display Tables library(diffobj) # Diffs for R Objects word.document <- respondR::create_doc(output.dir = output.dir, file.name = file.name) # Import response document (.docx) doc <- docxtractr::read_docx(path = word.document) # Table count tbl_count <- docxtractr::docx_tbl_count(docx = doc) # Extract table content tbl_txt <- purrr::map(.x = 1:tbl_count, .f = ~ docxtractr::docx_extract_tbl(docx = doc, tbl_number = .x, header = TRUE, preserve = TRUE) %>% janitor::clean_names(.)) # Deal with special characters like ampersand and dollar signs for(p in 1:(tbl_count - 1)){ for(pp in 1:nrow(tbl_txt[[p]])){ # Ampersand tbl_txt[[p]]$comment[pp] <- str_replace_all(string = tbl_txt[[p]]$comment[pp], pattern = "\\&", replacement = "\\\\&") tbl_txt[[p]]$response[pp] <- str_replace_all(string = tbl_txt[[p]]$response[pp], pattern = "\\&", replacement = "\\\\&") tbl_txt[[p]]$txt_orig[pp] <- str_replace_all(string = tbl_txt[[p]]$txt_orig[pp], pattern = "\\&", replacement = "\\\\&") tbl_txt[[p]]$txt_revised[pp] <- str_replace_all(string = tbl_txt[[p]]$txt_revised[pp], pattern = "\\&", replacement = "\\\\&") # Dollar sign tbl_txt[[p]]$comment[pp] <- str_replace_all(string = tbl_txt[[p]]$comment[pp], pattern = "\\$", replacement = "\\\\$") tbl_txt[[p]]$response[pp] <- str_replace_all(string = tbl_txt[[p]]$response[pp], pattern = "\\$", replacement = "\\\\$") tbl_txt[[p]]$txt_orig[pp] <- str_replace_all(string = tbl_txt[[p]]$txt_orig[pp], pattern = "\\$", replacement = "\\\\$") tbl_txt[[p]]$txt_revised[pp] <- str_replace_all(string = tbl_txt[[p]]$txt_revised[pp], pattern = "\\$", replacement = "\\\\$") # Dollar sign tbl_txt[[p]]$comment[pp] <- str_replace_all(string = tbl_txt[[p]]$comment[pp], pattern = "\\%", replacement = "\\\\%") tbl_txt[[p]]$response[pp] <- str_replace_all(string = tbl_txt[[p]]$response[pp], pattern = "\\%", replacement = "\\\\%") tbl_txt[[p]]$txt_orig[pp] <- str_replace_all(string = tbl_txt[[p]]$txt_orig[pp], pattern = "\\%", replacement = "\\\\%") tbl_txt[[p]]$txt_revised[pp] <- str_replace_all(string = tbl_txt[[p]]$txt_revised[pp], pattern = "\\%", replacement = "\\\\%") } } # If the references table exists, need to lower the table count name_last <- names(tbl_txt[[tbl_count]][1]) # References if(name_last=="references" & !tbl_txt[[tbl_count]][1]==""){ biblio <- tbl_txt[[tbl_count]] tbl_txt <- tbl_txt[1:(tbl_count-1)] }else{ biblio <- NULL} if(name_last=="references") tbl_count <- tbl_count - 1 # Number of editors and reviewers tbl_types <- purrr::map_chr(.x = 1:tbl_count, .f = ~names(tbl_txt[[.x]])[1]) n_editors <- sum(tbl_types=="editor") n_reviewers <- sum(tbl_types=="reviewer") # Prepare headers if(n_editors > 1) header_names <- paste(rep("editor", n_editors), 1:n_editors) else header_names <- rep("editor", n_editors) if(n_reviewers > 1) header_names <- c(header_names, paste(rep("reviewer", n_reviewers), 1:n_reviewers)) else header_names <- c(header_names, rep("reviewer", n_reviewers)) header_names <- header_names %>% stringr::str_to_title(.) # Define terms for NA not.applicable <- c("n/a", "na", "N/A", "NA", "Not applicable", "not applicable", "Not Applicable")
#' ---------------------------------------- # SUMMARY SECTION #' ---------------------------------------- if(include_summary){ cat(paste0("\\section{Summary}")) comments.box <- comments <- list() n.col <- 20 pal.fnc <- c("#F2FAE8", "#C1E29E", "#55B762", "#FFC232") for (i in 1:tbl_count) { nc <- seq_len(nrow(tbl_txt[[i]])) nl <- split(nc, ceiling(seq_along(nc)/n.col)) nn <- stringr::str_pad(string = seq_len(nrow(tbl_txt[[i]])), width = 2, pad = "0") nn <- split(nn, ceiling(seq_along(nn)/n.col)) comments[[i]] <- data.frame(matrix(data = NA, nrow = 1, ncol = nrow(tbl_txt[[i]]))) for(j in 1:nrow(tbl_txt[[i]])){ # List action taken against each comment - and apply formatting if(tbl_txt[[i]][j, ]$action == "") comments[[i]][,j] <- 1 if(!tbl_txt[[i]][j, ]$action == "" & tbl_txt[[i]][j, ]$as_is %in% c("Yes", "yes", "YES", "true", "TRUE", "Y", "y", "")) comments[[i]][,j] <- 2 if(!tbl_txt[[i]][j, ]$action == "" & tbl_txt[[i]][j, ]$as_is %in% c("No", "no", "N", "NO", "FALSE", "false")) comments[[i]][,j] <- 3 if(tbl_txt[[i]][j, ]$action %in% not.applicable) comments[[i]][,j] <- 4 comments.box[[i]] <- purrr::map(.x = nl, .f = ~comments[[i]][.x]) for(j in 1:length(comments.box[[i]])) names(comments.box[[i]][[j]]) <- nn[[j]] } # End j loop } # End i loop # Assign colours to table cells table.colours <- lapply(X = comments.box, FUN = function(x) purrr::map(.x = x, .f = ~pal.fnc[as.numeric(.x)])) # Print table legend cat(paste0("\\mbox{\\textcolor[HTML]{", gsub(pattern = "#", replacement = "", x = pal.fnc[1]), "}{\\rule{0.3cm}{0.3cm}} \\hspace{2pt} No edits required} \\hspace{5pt} \\mbox{ \\textcolor[HTML]{", gsub(pattern = "#", replacement = "", x = pal.fnc[2]), "}{\\rule{0.3cm}{0.3cm}} \\hspace{2pt} Revised, as suggested} \\hspace{5pt} \\mbox{\\textcolor[HTML]{", gsub(pattern = "#", replacement = "", x = pal.fnc[3]), "}{\\rule{0.3cm}{0.3cm}} \\hspace{2pt} Revised, with other edits} \\hspace{5pt} \\mbox{\\textcolor[HTML]{", gsub(pattern = "#", replacement = "", x = pal.fnc[4]), "}{\\rule{0.3cm}{0.3cm}} \\hspace{2pt} No action taken} \\newline{} \\newline{}")) # Print table for (i in 1:tbl_count) { if(i > 1) cat("\\vspace{15pt}") cat("\\textbf{", header_names[i], "}") summary.table <- comments.box[[i]] for(j in 1:length(summary.table)){ tab <- kableExtra::kbl(summary.table[[j]]) %>% kableExtra::row_spec(1, color = table.colours[[i]][[j]], background = table.colours[[i]][[j]]) cat("\\vspace{-5pt}") cat(tab) cat("</td>")}} cat("\\color{black}") # For each row in each table: # for (i in 1:tbl_count) { # for(j in 1:nrow(tbl_txt[[i]])){ # # # List action taken against each comment - and apply formatting # if(tbl_txt[[i]][j, ]$action %in% not.applicable){ # action_main <- paste0("\\enspace \\xmark \\enspace ", text_unchanged) # }else if(tbl_txt[[i]][j, ]$action == ""){ # action_main <- paste0("\\enspace\\checkmark \\enspace ", "No edits required") # }else{ # action_main <- tbl_txt[[i]][j, ]$action # action_main <- paste0("\\enspace \\checkmark \\enspace ", action_main)} # # # Create appropriate label # if(header_names[i] %in% c("Editor", "Reviewer")){ # if(n_editors==1) label <- paste0(substr(header_names[i], 1, 1), ".", j, " \\hspace{3.5pt} | ") else # label <- "" # }else{ # label <- c(seq_len(n_editors), seq_len(n_reviewers))[i] # label <- paste0(substr(header_names[i], 1, 1), label, ".", j, " | ")} # # # Print text # cat(label) # cat(paste0(action_main)) # cat("\\newline") # cat("\\color{black}") # } # } } # End include_summary #' ---------------------------------------- # MAIN DOCUMENT #' ---------------------------------------- # For each row in each table for (i in 1:tbl_count) { for(j in 1:nrow(tbl_txt[[i]])){ # Create section if(j==1){ if(newpage_sections){section_txt <- paste0("\\newpage \\section{", header_names[i], "}") }else{section_txt <- paste0("\\section{", header_names[i], "}")} }else{section_txt <- paste0("\\newline{}", "\\newline{}")} # Define header if(header_names[i] %in% c("Editor", "Reviewer")) ind <- "" else ind <- c(seq_len(n_editors), seq_len(n_reviewers))[i] # Retrieve line numbers if present if(grepl(pattern = "Figure", ignore.case = TRUE, x = tbl_txt[[i]][j, ]$line) | grepl(pattern = "Table", ignore.case = TRUE, x = tbl_txt[[i]][j, ]$line)){ line_no_numeric <- FALSE } else { line_no_numeric <- ifelse(gsub("[^0-9.-]", "", tbl_txt[[i]][j, ]$line)=="", FALSE, TRUE) } if(line_no_numeric){ line_no <- paste0("L", tbl_txt[[i]][j, ]$line, ". ") } else { if(tbl_txt[[i]][j, ]$line == "") line_no <- "" else line_no <- paste0(tbl_txt[[i]][j, ]$line, ". ")} line_edits <- "Edits" # List action taken in response to reviewer comment # List action taken in response to reviewer comment if(tbl_txt[[i]][j, ]$action %in% not.applicable){ # No action taken action_txt <- paste0("\\color{noaction} \\textbf{Action: }", text_unchanged, " \\xmark") }else if(tbl_txt[[i]][j, ]$action == ""){ # No edits required action_txt <- paste0("\\color{midcolour} \\textbf{Action: }No edits required \\checkmark") }else if(!tbl_txt[[i]][j, ]$action == "" & tbl_txt[[i]][j, ]$as_is %in% c("No", "no", "N", "NO", "FALSE", "false") & tbl_txt[[i]][j, ]$extra == ""){ # Revised, with additional edits (unspecified) action_txt <- paste0("\\color{midcolour} \\textbf{Action: }", tbl_txt[[i]][j, ]$action, ", with additional edits \\checkmark") }else if(!tbl_txt[[i]][j, ]$action == "" & tbl_txt[[i]][j, ]$as_is %in% c("No", "no", "N", "NO", "FALSE", "false") & !tbl_txt[[i]][j, ]$extra == ""){ # Revised, with additional edits action_txt <- paste0("\\color{midcolour} \\textbf{Action: }", tbl_txt[[i]][j, ]$action, " + ", tbl_txt[[i]][j, ]$extra, " \\checkmark") }else if(!tbl_txt[[i]][j, ]$action == "" & tbl_txt[[i]][j, ]$as_is %in% c("Yes", "yes", "YES", "true", "TRUE", "Y", "y", "") & !tbl_txt[[i]][j, ]$extra == ""){ # Revised, as suggested + additional edits action_txt <- paste0("\\color{midcolour} \\textbf{Action: }", "\\normalfont Revised, as suggested + ", tbl_txt[[i]][j, ]$extra, " \\checkmark") }else if(!tbl_txt[[i]][j, ]$action == "" & tbl_txt[[i]][j, ]$as_is %in% c("Yes", "yes", "YES", "true", "TRUE", "Y", "y", "") & tbl_txt[[i]][j, ]$extra == ""){ # Revised, as suggested action_txt <- paste0("\\color{midcolour} \\textbf{Action: }", "\\normalfont Revised, as suggested", " \\checkmark")} # Identify changes in the revised text if(tbl_txt[[i]][j, ]$txt_orig %in% c(not.applicable, "") & tbl_txt[[i]][j, ]$txt_revised %in% c(not.applicable, "")){ revised_txt <- "\\vspace{-15pt}" }else{ out <- compare_sentences(sentence1 = tbl_txt[[i]][j, ]$txt_orig, sentence2 = tbl_txt[[i]][j, ]$txt_revised, highlight_diff = highlight_textrevisions) if(out == "") out <- paste0("\"", out, "\"") out <- gsub(pattern = " ,", replacement = ",", x = out) out <- gsub(pattern = " \\.", replacement = "\\.", x = out) out <- gsub(pattern = "\\(ie", replacement = "(i.e.", x = out) out <- gsub(pattern = "\\(eg", replacement = "(e.g.", x = out) revised_txt <- paste0("\\color{midcolour}\\textbf{", line_edits, ": }", out)} if(response_font == "bold") response_txt <- "\\bf \\uline{Response:} " if(response_font == "italics") response_txt <- "\\uline{Response:} \\em " if(response_font == "standard") response_txt <- "\\uline{Response:} " # Parse reviewer comments if(comment_font == "standard") comment_txt <- paste0(substr(header_names[i], 1, 1), ind, ".", j, " | ", line_no, tbl_txt[[i]]$comment[j]) if(comment_font == "bold") comment_txt <- paste0("\\textbf{", substr(header_names[i], 1, 1), ind, ".", j, " | ", line_no, tbl_txt[[i]]$comment[j], "}") if(comment_font == "italics") comment_txt <- paste0("\\textit{", substr(header_names[i], 1, 1), ind, ".", j, " | ", line_no, tbl_txt[[i]]$comment[j], "}") # Print cat(section_txt) cat(comment_txt) cat("\\vspace{5pt}") cat("\\newline") cat(paste0(response_txt, tbl_txt[[i]]$response[j], "\\normalfont")) cat("\\par ") cat(paste0(action_txt)) cat("\\color{black}") cat("\\newline") cat(revised_txt) cat("\\color{black}") } } cat("\\newpage") #' ---------------------------------------- # REFERENCES #' ---------------------------------------- # Print bibliography if(!is.null(biblio)){ bibrefs <- biblio$references bibrefs <- stringr::str_replace_all(string = bibrefs, "\n", "\\\\par ") bibrefs <- stringr::str_sub(bibrefs, 6, nchar(bibrefs)) cat(paste0("\\textbf{References} ")) cat("\\vspace{5pt}") cat("\\newline ") cat(paste0(bibrefs)) }
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.