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))
  }


pjbouchet/respondR documentation built on Feb. 7, 2023, 9:40 a.m.