¿Cómo solicitar una salida temprana al tejer un documento Rmd?


Digamos que tiene un documento R markdown que no se renderizará de forma limpia.

Sé que puede establecer la opción knitr chunk error en TRUE para solicitar que la evaluación continúe, incluso en presencia de errores. Puede hacer esto para un fragmento individual a través de error = TRUE o de una manera más global a través de knitr::opts_chunk$set(error = TRUE).

Pero a veces hay errores que todavía son fatales para el proceso de tejer. Dos ejemplos que he encontrado recientemente: tratando de unlink() el directorio de trabajo actual (oops!) y llamando rstudioapi::getVersion() desde código R inline cuando RStudio no está disponible. ¿Hay una descripción general de este tipo de errores, es decir, los que están fuera del alcance de error = TRUE? ¿Hay alguna forma de tolerar errores en código R en línea vs en trozos?

Además, ¿hay más formas oficiales de detener el tejido temprano o de automatizar la depuración en esta situación?

Author: jennybryan, 2015-11-14

2 answers

Para salir temprano del proceso de tejer, puede usar la función knitr::knit_exit() en cualquier lugar del documento fuente (en un fragmento de código o expresión en línea). Una vez que se llama knit_exit(), knitr ignorará todo el resto del documento y escribirá los resultados que ha recopilado hasta ahora.

No hay forma de tolerar errores en el código R en línea en este momento. Debe asegurarse de que el código R en línea siempre se ejecute sin errores1. Si se producen errores, debería ver el rango de líneas eso produjo el error del log knitr en la consola, de la forma Quitting from lines x1-x2 (filename.Rmd). A continuación, puede ir al archivo filename.Rmd y ver lo que está mal con las líneas de x1 a x2. Lo mismo se aplica a los fragmentos de código con la opción chunk error = FALSE.

Más allá de los tipos de errores mencionados anteriormente, puede ser difícil encontrar la fuente del problema. Por ejemplo, cuando involuntariamente unlink() el directorio actual, no debe detener el proceso de tejido, porque unlink() tuvo éxito de todos modos. Usted puede tener problemas después del proceso de tejido, por ejemplo, LaTeX / HTML no puede encontrar los archivos de figura de salida. En este caso, puede intentar aplicar knit_exit() a todos los fragmentos de código del documento uno por uno. Una forma de lograr esto es configurar un chunk hook para ejecutar knit_exit() después de un determinado chunk. A continuación se muestra un ejemplo de uso de búsqueda lineal (se puede mejorar mediante el uso de bisección en su lugar):

#' Render an input document chunk by chunk until an error occurs
#' 
#' @param input the input filename (an Rmd file in this example)
#' @param compile a function to compile the input file, e.g. knitr::knit, or
#'   rmarkdown::render
knit_debug = function(input, compile = knitr::knit) {
  library(knitr)
  lines = readLines(input)
  chunk = grep(all_patterns$md$chunk.begin, lines)  # line number of chunk headers

  knit_hooks$set(debug = function(before) {
    if (!before) {
      chunk_current <<- chunk_current + 1
      if (chunk_current >= chunk_num) knit_exit()
    }
  })

  opts_chunk$set(debug = TRUE)

  # try to exit after the i-th chunk and see which chunk introduced the error
  for (chunk_num in seq_along(chunk)) {
    chunk_current = 0  # a chunk counter, incremented after each chunk
    res = try(compile(input))
    if (inherits(res, 'try-error')) {
      message('The first error came from line ', chunk[chunk_num])
      break
    }
  }
}

  1. Esto es por diseño. Creo que es una buena idea tener error = TRUE para los trozos de código, ya que a veces queremos mostrar errores, por ejemplo, con fines de enseñanza. Sin embargo, si permito errores para el código en línea también, los autores pueden no reconocer errores fatales en el código en línea. El código inline se usa normalmente para incrustar valores inline, y no creo que tenga mucho sentido si un valor inline es un error. Imagine una oración en un informe como The P-value of my test is ERROR, y si knitr no señaló el error, requerirá que los autores lean la salida del informe con mucho cuidado para detectar este problema. Me creo que es una mala idea tener que confiar en los ojos humanos para encontrar tales errores.
 25
Author: Yihui Xie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-14 17:47:21

En mi humilde opinión, la dificultad para depurar un documento Rmd es una advertencia de que algo está mal. Tengo una regla general: Hacer el trabajo pesado fuera de la Rmd. Haga renderizado dentro del Rmd, y solo renderizado. Eso mantiene el código Rmd simple.

Mis grandes programas R se ven así.

data <- loadData()
analytics <- doAnalytics(data)
rmarkdown::render("theDoc.Rmd", envir=analytics)

(Aquí, doAnalytics devuelve una lista o entorno. Esa lista o entorno se pasa al documento Rmd a través del parámetro envir, haciendo que los resultados de la cálculos analíticos disponibles dentro del documento.)

La función doAnalytics hace los cálculos complicados. Puedo depurar usando las herramientas regulares, y puedo comprobar fácilmente su salida. Cuando llamo rmarkdown::render, sé que las cosas difíciles están funcionando correctamente. El código Rmd es solo "imprimir esto" y "formatear eso", fácil de depurar.

Esta división de responsabilidades me ha servido bien, y puedo recomendarla. Especialmente en comparación con la mente-flexión tarea de depuración cálculos complicados enterrados dentro de un documento renderizado dinámicamente.

 5
Author: pteetor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-15 19:31:21