web-dev-qa-db-ja.com

Rmdドキュメントを編成するときに早期終了をリクエストする方法は?

きれいにレンダリングされないRマークダウンドキュメントがあるとします。

knitrチャンクオプションerrorTRUEに設定して、エラーが発生した場合でも評価を続行するように要求できることを知っています。これは、_error = TRUE_を介して個々のチャンクに対して、またはknitr::opts_chunk$set(error = TRUE)を介してよりグローバルな方法で行うことができます。

しかし、時々、編みプロセスにとって致命的なエラーがあります。私が最近遭遇した2つの例:unlink()を現在の作業ディレクトリ(oops!)に試行することと、RStudioが使用できない場合にインラインRコードからrstudioapi::getVersion()を呼び出すこと。これらの種類のエラー、つまり_error = TRUE_の範囲を超えるエラーの一般的な説明はありますか?インラインRコードとチャンクのエラーを許容する方法はありますか?

また、このような状況で編み物を早期に中止したり、デバッグを自動化したりするための公式の方法はありますか?

41
jennybryan

編成プロセスの早い段階で終了するには、ソースドキュメントの任意の場所(コードチャンクまたはインライン式)で関数knitr::knit_exit()を使用できます。 knit_exit()が呼び出されると、knitrはドキュメントの残りすべてを無視し、これまでに収集した結果を書き出します。

現時点では、インラインRコードのエラーを許容する方法はありません。インラインRコードが常にエラーなしで実行されることを確認する必要があります1。エラーが発生した場合は、コンソールのknitrログから、Quitting from lines x1-x2 (filename.Rmd)の形式でエラーを生成した行の範囲が表示されます。次に、ファイル_filename.Rmd_に移動して、_x1_から_x2_までの行の何が問題かを確認できます。同じことが、チャンクオプション_error = FALSE_を使用したコードチャンクにも当てはまります。

上記のエラーの種類を超えて、問題の原因を見つけるのは難しい場合があります。たとえば、現在のディレクトリを意図せずunlink()にした場合でも、unlink()は成功したため、編成プロセスが停止することはありません。編みプロセス後に問題が発生する可能性があります。たとえば、LaTeX/HTMLが出力の図ファイルを見つけることができません。この場合、knit_exit()をドキュメント内のすべてのコードチャンクに1つずつ適用してみることができます。これを実現する1つの方法は、特定のチャンクの後にknit_exit()を実行するようにチャンクフックを設定することです。以下は、線形検索の使用例です(代わりに二分法を使用して改善できます)。

_#' 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. これは仕様によるものです。コードのチャンクには_error = TRUE_を使用することをお勧めします。たとえば、教育目的などでエラーを表示したい場合があるからです。ただし、インラインコードのエラーも許可すると、作成者はインラインコードの致命的なエラーを認識できない場合があります。インラインコードは通常valuesをインラインで埋め込むために使用されますが、インライン値がエラーである場合はあまり意味がありません。 _The P-value of my test is ERROR_のようなレポート内の文を想像してみてください。knitrがエラーを示していない場合、作成者はこの問題を見つけるためにレポート出力を注意深く読む必要があります。そのような間違いを見つけるために人間の目に頼らなければならないのは悪い考えだと思います。
36
Yihui Xie

私見、Rmdドキュメントのデバッグの困難さは、何かが間違っているという警告です。私は経験則を持っています:重労働outside Rmdを実行します。 Rmd内でレンダリングを行い、onlyレンダリングします。これにより、Rmdコードがシンプルになります。

私の大きなRプログラムは次のようになります。

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

(ここでは、doAnalyticsはリストまたは環境を返します。そのリストまたは環境はenvirパラメータを介してRmdドキュメントに渡され、ドキュメント内で分析計算の結果を利用できます。 。)

doAnalytics関数は複雑な計算を行います。通常のツールを使用してデバッグでき、その出力を簡単に確認できます。 rmarkdown :: renderを呼び出すときまでに、ハードなものが正しく動作していることがわかります。 Rmdコードは、「これを印刷する」と「フォーマットする」だけで、デバッグが簡単です。

この責任の分担は私に役立ち、私はそれを推薦することができます。特に、動的にレンダリングされたドキュメント内に埋め込まれた複雑な計算をデバッグするという心が折れるタスクと比較してください。

9
pteetor