library(knitr) library(rmsutilityr) library(stringi) library(kableExtra) library(png) library(xtable) options(kableExtra.auto_format = FALSE) knitr::opts_chunk$set(echo = TRUE, include = TRUE, eval = FALSE)
Retention of collaborative interactions that appear as back and forth comments within source documents of a project is a valuable source of history and subsequent education and process improvement. However, it is often the case that at the end of the development phase those interactions need to be removed before sending the source files to further review or production. This tutorial provides one method and a set of tools to both collaborate via HTML comments and remove comments selectively when needed.
HTML comments can be inserted into an RMarkdown document as a means of
communicating with others or making a note to yourself.
The workflow illustrated herein uses a text label immediately after the
beginning characters of the HTML comment (i.e., <!--
). White space, including
blank lines are ignored.
Thus, any of the following will be seen as a comment.
`<!-- This is a comment without a useful label -->` `<!-- RMS This is a one line comment that has my intitials as its label.-->` `<!-- RMS Comments can span multiple lines and later can be entirely removed by either selecting to remove all comments or only those comments that have labels you provide as a character vector to the "label" parameter -->`
Collaboration will usually involve suggestions and perhaps corrections.
xt_print(all_unusual_wts_sex, caption = stri_c(common_name, ": ", animal_count, " ", sex_str, " with weights outside the ", signif(conf_int * 100, 3), "\\% predicted range."), label = stri_c("tbl:", arc_species_code, "-", sex), format.args = list(big.mark = ",", decimal.mark = "."), size = size) `<!-- RMS I added some formating code (format.args) in the call to xt_print please look at the output to see whether or not you prefer that formating decision.-->`
The collaborator (TJH) can add his own comment or add to the original to inform RMS that the change was considered.
`<!-- RMS I added some formating code (format.args) in the call to xt_print please look at the output to see whether or not you prefer that formating decision. *** TJH I like the change as some of the numbers are over 10^5 -->`
Alternatively, TJH may decide to keep his response separate from the original comment by adding his own separate comment.
`<!-- RMS I added some formating code (format.args) in the call to xt_print please look at the output to see whether or not you prefer that formating decision. -->` `<!-- TJH I like the change as some of the numbers are over 10^5 -->`
We recommend the first convention as it keeps related comments together and still allows identification of participants within the conversation.
Later, reasons for selecting one convention over the other will be discussed again when removal of comments is described.
HTML comments can also be used as a part of a review process. This is not conceptually different that other forms of collaboration but the need to indicate acceptance or rejection of suggestions and final approval is demonstrated in the following versions of text.
xt_print(bad_sample_dates_df, caption = "Bad Sample Dates", label = "tbl:bad-sample-dates", type = type, ...) `<!-- RMS The caption reads like a title. Consider using a caption that allows the table to be understood without forcing the reader to go find the narrative that describes the table contents. -->`
The document author can respond to the request by simply editing the code. However, editing to comment allows the review to quickly see that the concern was acknowledged and addressed.
if (nrow(bad_sample_dates_df) == 1) { caption <- stri_c( "There was 1 bad sample date identified where the animal was not present on the date indicated.") } else { caption <- stri_c( "There were ", nrow(bad_sample_dates_df), " bad sample dates identified where the animals were not present on the dates indicated.") } xt_print(bad_sample_dates_df, caption = caption, label = "tbl:bad-sample-dates", type = type, ...) `<!-- RMS The caption reads like a title. Consider using a caption that allows the table to be understood without forcing the reader to go find the narrative that describes the table contents. *** TJH I added a more helpful dynamically generated caption so that the text reflects the number of bad dates shown. -->`
The reviewer can then note that the change was seen and accepted.
`<!-- RMS The caption reads like a title. Consider using a caption that allows the table to be understood without forcing the reader to go find the narrative that describes the table contents. *** TJH I added a more helpful dynamically generated caption so that the text reflects the number of bad dates shown. *** RMS Nicely done. I like the dynamically generated caption. accepted 20210215 -->`
Retention of comments during the document development phase is helpful so that decisions made earlier are not forgotten with the result of time being wasted rethinking earlier topics of discussion.
There are several functions that can be used to produce various inventories of HTML comments within RMarkdown source files.
Takes a vector of files^[This example uses a single file, however, multiple files with fully qualified file names in the character vector is expected.] and labels to retrieve and returns a dataframe with full file paths, the base file names, starting line number of each comment, the end line number of each comment, and the identifying labels. This dataframe is ordered by path, label, and starting line number of the comment.
The default value of the label
argument is ""
when no definition is
provided.
files <- system.file("testdata","find_html_comment_test_file_1.Rmd", package = "rmsutilityr") files <- c(files, system.file("testdata", "sample_dir", "find_html_comment_test_file_2.Rmd", package = "rmsutilityr")) html_comment_lines_and_labels <- get_html_comment_text_lines_and_labels_from_files(files) caption <- knitr:::escape_latex(stri_c("Output of the ", "get_html_comment_text_lines_and_labels_from_files ", "function includes all comments when no 'label' parameter is ", "provided. The columns include the file name (no path), ", "the possible label, the line number where the comment ", "starts, and the line number where the comment ends.")) kbl(html_comment_lines_and_labels[ , c("file", "comment_label", "comment_start_line", "comment_end_line")], format = ifelse(knitr::is_latex_output(), "latex", "html"), longtable = TRUE, booktabs = TRUE, caption = caption, row.names = FALSE, col.names = c("File", "Label", "Start", "End")) %>% kable_styling(latex_options = c("repeat_header", "striped"), font_size = ifelse(knitr::is_latex_output(), 8, 12))
This same function can be used to review the text of comments from selected collaborators.
files = system.file("testdata","find_html_comment_test_file_1.Rmd", package = "rmsutilityr") html_comment_lines_and_labels <- get_html_comment_text_lines_and_labels_from_files(files, label = "RMS") caption <- knitr:::escape_latex(stri_c("Output of the ", "get_html_comment_text_lines_and_labels_from_files ", "function includes text of comments from selected ", "comment labels.")) kbl(html_comment_lines_and_labels[ , c("file", "comment_label", "comment_start_line", "comment_text")], format = ifelse(knitr::is_latex_output(), "latex", "html"), booktabs = TRUE, caption = caption, row.names = FALSE, col.names = c("File", "Label", "Start", "Text"), longtable = TRUE) %>% kable_styling(latex_options = c("repeat_header", "striped"), font_size = ifelse(knitr::is_latex_output(), 8, 12)) %>% column_spec(1, width = "15em") %>% column_spec(2, width = "5em") %>% column_spec(3, width = "5em") %>% column_spec(4, width = "25em")
As stated earlier, in some workflows it is an advantage to remove collaborators' and reviewers' comments from the final document to clean up the presentation and to prevent unintended influence on subsequent readers of the source RMarkdown document.
This can be done by providing a character vector of full or relative path names
and a directory to place the edited files in to using the
write_files_after_deleting_selected_comments
function.
files <- system.file("testdata","find_html_comment_test_file_1.Rmd", package = "rmsutilityr") files <- c(files, system.file("testdata", "sample_dir", "find_html_comment_test_file_2.Rmd", package = "rmsutilityr")) new_files <- write_files_after_deleting_selected_comments(files, new_path = tempdir(), label = "RMS", overwrite = TRUE) new_files
You can count comments in your files quickly with this helper function^[ A commented version of the same convenience function is included in this package.]
count_selected_comments <- function(files, label = "") { comment_count <- 0 for (file in files) { lines <- readLines(file) lines_and_labels <- return_html_comment_text_lines_and_labels(lines, label) comment_count <- comment_count + length(lines_and_labels[[1]]) } comment_count }
You can count selected comments in the original files.
count_selected_comments(new_files$original_file, label = "RMS")
You can then demonstrate that those comments were removed in the Deleting Comments section above.
count_selected_comments(new_files$new_file, label = "RMS")
Finally, you can see how many comments remain from TJH.
count_selected_comments(new_files$new_file, label = "TJH")
You can see the differences in the before and after versions of a file with
the Rdiff
and diffr
functions^[
There is only one file in each of files
and new_files
so the subsetting
that is shown and will normally be needed is unnecessary in this example.].
tools::Rdiff(from = new_files$original_file[1], to = new_files$new_file[1], useDiff = TRUE, Log = TRUE)
I prefer the HTML output of the diffr
package^[HTML image is shown.].
Its use is very similar.
library(diffr) diffr(new_files$original_file[1], new_files$new_file[1])
img <- png::readPNG("./diffr_example.png") grid::grid.raster(img)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.