EmacsでKnitrワークフローを設定する方法


18

RStudioは、LaTeX + RソースからKnitrでPDFファイルを生成するためのワンボタン方法を提供します。再現可能な研究を行うのに最適です。そして、私はEmacsを次のように設定しようとしています:

  • Knitr方式の左バッファLaTeX + Rコード。
  • 右側のバッファでPDF出力プレビュー。
  • コンパイルのための1つのキーの組み合わせ。

可能であれば、これをどのように設定すればよいですか?

(ESSは正常に動作しますが、Knitr-wayとコンパイル用の1ボタンを設定する方法がわかりません。)


私はそれを行うためのより良い方法があると確信していますが、現在のでrmarkdown::render(経由でshell-command)キーバインディングを実行する短いElisp関数を使用buffer-file-nameして、別のウィンドウのpdfを更新します。
-daroczig

1
@daroczigはLaTeXでも機能しますか、それとも単なるマークダウンですか?
タイラー

@daroczig:私の答えでは、おそらくRnwファイル(LaTeX + R)に対してこれをやろうとしました。より単純なRmdファイル(Rmd + R)については、別の投稿を開始してください。
アントニオ

1
適切なセットアップを取得できませんでした。最初にポリモード織りで編む必要があります。次に、エクスポーターとすべてを選択して.texファイルを作成します。そこからラテックスを実行する必要があります。上記のスクリプトを適応させようとしましたが、私のelispはまだそこにありません。私が欲しいのは、.Rnwファイルを編んで、pdf(pdflatex)を作成し、表示することです。ラテックスファイルに「Cc Ca」(Tex-Command-run-all)と入力すると、pdfが作成および表示されますが、my_knitr()からtexファイルでその関数を呼び出すことはできません。 。ヘルプをいただければ幸いです。(defun my_knitr()「R-PolyモードでKnitrを実行し、pdfを作成して表示する」(相互作用
Krisselack

@Krisselackは、以下の回答で説明する機能がESSから削除されたようです。彼らが使用する新しいアプローチを反映するように更新する必要があります
タイラー

回答:


12

更新

ESS 19.04の時点で、ess-nowebおよびess-swvライブラリは廃止されています。

その結果、(以下の)私の元の答えはもはや適用されません。これらのライブラリが提供するために使用されていた機能は、ポリモードによって提供されるようになり、構成はより簡単になりました。最小限のサポートを取得するには、あなたが必要とするすべてをインストールすることでesspolymode及びpoly-Rパッケージ(MELPAから、またはソースからその者の場合はどのようにロール)。

それでおしまい!Rnwファイルを開くPM-Rnwと、モードラインにフラグがPolymode表示され、上部にメニューが表示されます。あなたはにあなたのファイルを織ることができます.tex経由でファイルM-n w(またはpolymodeメニュー)、およびにエクスポート.pdfを経由してM-n e(またはメニュー)。初めてこれを行うと、エクスポーターの入力を求められます。選んだだけknitrです。

注:エクスポート(M-n e)は、コードを自動的に実行し、pdfを生成して表示します。以下で説明する古いバージョンでは、「ワンクリック」動作を実現できませんでした。

生成されたファイルには、単語を持っています-wovenし、-exported追加しました。これが気に入らない場合は、オプションpolymode-weaver-output-file-formatとをカスタマイズできますpolymode-exporter-output-file-format

このプロセスは、RMarkdownファイル(.Rmd)でも同様です。

詳細は、ポリモードマニュアルに記載されています。

元の回答(ESS 19.04以降は廃止)

次の3つの変数を設定する必要があります。

  1. ess-swv-pdflatex-commands、カスタマイズグループでess-sweaveは、最初のコマンドとして「pdflatex」が必要です。つまり、次のようになります。("pdflatex" "texi2pdf" "make")
  2. ess-swv-processor、カスタマイズグループess-Rでは、値にする必要があります"knitr"
  3. ess-pdf-viewer-prefにカスタマイズグループess"emacsclient"。これは、emacsサーバーを実行している、またはemacsが--daemonモードで実行されていることを前提としています。可能な場合は、組み込みのEmacs pdfビューアよりもはるかに望ましいため、pdf-toolsも使用する必要があります。

フックを使用して、BibTeXとtexi2pdfを呼び出すための2つのキーバインドを追加します。

(add-hook 'ess-noweb-mode-hook 'my-noweb-hook)

(defun my-noweb-hook ()
  (define-key ess-noweb-mode-prefix-map "b"
    #'(lambda () (interactive) (TeX-command "BibTeX" 'TeX-master-file)))
  (define-key ess-noweb-mode-prefix-map "P"
    #'(lambda () (interactive)
        (ess-swv-PDF "texi2pdf"))))

これが完了M-n sすると、ドキュメントを編んでM-n bbibtexし、M-n Ppdflatexで処理します。

編みが完了したことをEmacsが知る簡単な方法はないので、一度にニットとラテックスを設定することはできません。手動でトリガにpdflatexを持った後、あなたは編み物が終了した見てきました。

ここで複数のステップ-Rnw-> Latex-> PDFを考えると、pdfファイルとRnwファイルを一緒にスクロールするようにSynctexを取得できるとは思いませんが、間違っていることがわくわくします。

ウィンドウの配置に関しては、私は彼らが望む場所にとどまることはできません。それを補うために、私はウィンドウとバッファーを必要に応じてシャッフルすることにかなり慣れてきました;)

Yihuiはknitrサイトに短いビデオを投稿し、その一部を紹介しました。


.emacsから必要なすべての構成を抽出し、必要な構成のみを抽出するように最善を尽くしました。私は何かを見逃したかもしれません、それはそこにある種の毛深いです。
タイラー

私がknitrドキュメントをコンパイルできるようになりました。ただし、まだ1つのキーの組み合わせを見つけてください(Rnw-> PDFの場合)。Rstudioがこれを持っているので、それが可能であることを願っています。
drobnbobn

@タイラー:ありがとう、あなたのソリューションは魅力的なotbのように機能します(設定を編集しなくても)!パッケージ:ess、polymode、poly-r
Krisselack

5

これは、オールインワンソリューションです。RnwからPDF作成して表示します
具体的には:

  1. Rnwバッファーを保存して編成し、
  2. 結果のTeXファイルに特定のLaTeXエンジンを適用し、
  3. BibTeXエンジンの実行可能ファイル(biber、bibtex8など)を特定します。
  4. bibファイルがTeXファイルよりも新しい場合、TeXファイルでBibTeXエンジンを実行します。
  5. LaTeXを再度実行します。6指定されたビューアで結果のPDFを開きます。

上記の手順のいずれかが失敗すると、プロシージャは情報メッセージで終了しようとします。
必要に応じて、Rインスタンスが開かれるか、現在のインスタンスが編みプロセスの表示に使用されます。
LaTeX出力は「TeX-output」バッファに送信されます。これはコンパイルエラーの場合にポップされます。

使用法

Meta-PDF x knit-meを作成および表示します。
Meta- x knit-me-clear中間のLaTeXファイルとknit-me

書誌には「biblatex」パッケージが必要です。つまり:

\usepackage[
    options...      
    backend=ENGINE,
]{biblatex}
\addbibresource{foo.bib}

ビブ・エンジンの名前は、(例えばbibtexbiber)の解析得られたbackendキーワードを。
\addbibresourceコマンドが解析されて参考文献ファイルが取得されますfoo.bib。TeXファイルより新しい場合は、bibエンジンが実行されます。この点で、\addbibresource多くのコマンドがある場合は最初のコマンドのみが考慮されます。

カスタマイズ

PDFを実際に表示するには、ビューアの実行可能パスを次のように設定します。

(setq pdf-viewer "path/to/pdf-viewer")

SumatraPDFなどのビューアを使用することもできます。このビューアは、再コンパイル時にPDFを自動的に更新し、開いているファイルをブロックせずに新しいコンパイルを妨げます。

デフォルトのLaTeXエンジンはpdflatex(現在のパスで想定)です。カスタマイズ:

(setq latex-engine "newengine"
      latex-args   "--option-1 --option-2")

もちろん、いくつかの便利なキーにバインドknit-meしたいかもしれませんknit-me-clear

ノート

で、WindowsのMiKTeXでテストbiberし、bibtex8バックエンドとGNU Emacsの25.1.1。

Elispコード

;; (require 'ess-site) ; assumed in your init file

(defun knit-me-clear () 
  "Delete intermediate LaTeX files and run `knkt-me'.
These are based on extensions .aux, .blg, .out, .run.xml, .bbl, .log, -blx.bib"

  (interactive)
  (check-Rnw)
  (let
      ((file)
       (stem (file-name-sans-extension (buffer-file-name))))
    (dolist (elt
         (list ".aux" ".blg" ".out" ".run.xml" ".bbl" ".log" "-blx.bib"))
      (setq file (concat stem elt))
      (if (file-exists-p file) (delete-file file))))  
  (knit-me))


(defun knit-me () 
  "Knit->LaTeX-engine->bibtex-engine->LaTeX-engine->View.
Default LaTeX engine is \"pdflatex\" and can be customised with `latex-engine';
default LaTeX arguments are set to nil and can be customised with `latex-args';
default PDF viewer is set to nil and can be customised with `pdf-viewer'.
Bibliography must be set via \"biblatex\" LaTeX package.
Bibliography engine is obtained from \"backend\" option in \"biblatex\" package.
A reference  LaTeX bib file is obtained from the first LaTeX command \"\addbibresource{foo.bib}\".
The biblatex-engine is run if the bib file is newer of the TeX file. 
If there are multiple \"\addbibresource\" only the first will be used to decide whether to run the biblatex-engine."

  (interactive)

  ;; Default values
  (defvar pdf-viewer nil)
  (defvar latex-engine "pdflatex")
  (defvar latex-args nil)

  (check-Rnw)

  ;;If 1 R-proc found, associate it with buffer;
  ;;if many found, ask to choose one; if none found, launch and associate
  (ess-force-buffer-current "Process to use: ")

  ;;Save Rnw buffer
  (save-buffer)


  (let*
      (;;Set file paths
       (pathstem (file-name-sans-extension (buffer-file-name)))
       (namestem (file-name-nondirectory pathstem))
       (cur-dir     (file-name-directory pathstem))
       (rnw-name    (concat namestem ".Rnw"))
       (tex-name    (concat namestem ".tex"))

       ;;Create LaTeX commmand
       (latex-args (concat latex-args " " namestem))
       (latex-cmd (concat latex-engine " " latex-args))

       ;;Create knit commmand
       (knit-cmd (format "require(knitr); setwd('%s'); knit('%s')"  cur-dir rnw-name))

       ;;Get R buffer proc
       (r-proc (ess-get-process))
       (r-buf (ess-get-process-buffer))

       ;;TeX executable process and bibtex engine/file
       (tex-proc)
       (tex-buf)
       (bibfile (bib-getfile))
       (bibengine (bib-getengine))
       (bibfile-updated
    (file-newer-than-file-p
     (concat cur-dir (file-name-nondirectory bibfile) ".bib") (concat pathstem ".tex")))


       ;;Command success
       (success nil)
       (error-msg "")
       )


    (setq default-directory cur-dir)

    ;; Exit on error
    (catch 'exit-func

      ;;Check bibtex file and engine
      (when (not bibfile)
    (setq error-msg (bib-getfile t))
    (throw 'exit-func nil))     
      (when (not bibengine)
    (setq error-msg (bib-getengine t))      
    (throw 'exit-func nil))

      ;; Biber wants .bib
      (let ((fail (and (string= bibengine "biber")
              (string= (file-name-nondirectory bibfile) (file-name-base bibfile)))))
    (setq success (not fail)))
      (when (not success)
    (setq error-msg
          (format "biber wants \\addbibresource{%s%s}" (file-name-base bibfile) ".bib"))
    (throw 'exit-func nil))


      ;; Knitting
      (switch-to-buffer-other-window r-buf)
      (message knit-cmd)
      (ess-eval-linewise knit-cmd nil t nil t) 
      ;; Foll. 3 lines are an alternative to ess-eval
      ;; (inferior-ess-mark-as-busy r-proc)  ; knit immediately after this line       
      ;; (process-send-string r-proc (format "cat(\"%s\");%s\n" knit-cmd knit-cmd)) ; real 
      ;; (ess-wait-for-process r-proc nil)

      ;; Check for knitting results
      (with-current-buffer r-buf
    ;; Parse last 3 lines
    (let ((beg) (end) (out))
      (goto-char (point-max))
      (setq end (point))
      (forward-line -3) 
      (setq beg (point))
      (setq out (buffer-substring-no-properties beg end))

      ;; Knitting successful?
      (setq success "output file: %s\n\n[1] \"%s\"\n> ")
      (setq success (string= (format success tex-name tex-name) out))))

      (when (not success)
    (setq error-msg (concat "Unable to knit " rnw-name))
    (throw 'exit-func nil))

      ;; First LaTeXing
      (setq tex-buf (get-buffer-create "TeX-output")) ; Create output buffer or use existing
      (with-current-buffer tex-buf                   
    (buffer-disable-undo)
    (erase-buffer))
      (message "1st latex ...")
      (send-r-mess (format "Starting LaTeX (see \"%s\")" (buffer-name tex-buf)))      
      (send-r-mess latex-cmd)
      (setq success (= 0 (call-process latex-engine nil tex-buf t latex-args)))
      (goto-char (point-max))

      ;; Check 1st LaTeX results
      (when (not success)
    (setq error-msg (concat "Unable to LaTeX " namestem))
    (switch-to-buffer-other-window tex-buf) 
    (other-window 1)
    (throw 'exit-func nil))

      ;; Run bibtex engine
      (when bibfile-updated  
    (message "biblatex ...")
    (send-r-mess (concat bibengine " "  namestem))
    (setq success (= 0 (call-process bibengine nil tex-buf t namestem)))
    (goto-char (point-max))

    ;; Check bibtex results
    (when (not success)
      (setq error-msg (concat "Unable to " bibengine " " namestem))
      (switch-to-buffer-other-window tex-buf) 
      (other-window 1)
      (throw 'exit-func nil)))

      ;; Second LaTeXing
      (message "2nd latex ...")
      (send-r-mess latex-cmd)
      (setq success (= 0 (call-process latex-engine nil tex-buf t latex-args)))
      (goto-char (point-max))

      ;; Check 2nd LaTeX results
      (when (not success)
    (setq error-msg (concat "Unable to LaTeX " pathstem))
    (switch-to-buffer-other-window tex-buf) 
    (other-window 1)
    (throw 'exit-func nil))

      ;; View   
      (if (not pdf-viewer) (throw 'exit-func nil))
      (send-r-mess  "...and now the viewer")
      (goto-char (point-max))
      (setq success (file-exists-p pdf-viewer))
      (when (not success)
    (setq error-msg (concat "Can\\'t find executable " pdf-viewer))
    (throw 'exit-func nil))

      ;; If you need viewer console output, use "(start-process "pdf-viewer" tex-buf ...";
      ;; but you block tex-buf buffer till the viewer is open
      (start-process "pdf-viewer" nil pdf-viewer (concat namestem ".pdf")))

    (if success
    (if bibfile-updated (message (concat "Updated to "  (file-name-nondirectory bibfile))))
      (message error-msg)
      (send-r-mess error-msg))))

(defun bib-getfile(&optional show-messages)
  "Check if 'addbibresource' command and related file exist. 
If found, return .bib file full path, else:
if SHOW-MESSAGES is nil return nil, if SHOW-MESSAGES is non-nil return related error."
  (save-excursion
    (goto-char (point-min))
    (re-search-forward "\\\\addbibresource{\\(.+\\)}" nil t))
  (let ((fmatch (match-string-no-properties 1)) 
    (success nil)
    mess)    
    (cond 
     ((not fmatch) (setq mess "Missing \\addbibresource command."))
     ((not (file-exists-p (concat (file-name-sans-extension fmatch) ".bib")))
      (setq mess (concat "Missing file: " fmatch ".bib")))
     ;; if no problem, sucess=message=bib-file-path
     (t (setq mess (concat (file-name-directory (buffer-file-name)) fmatch)
          success mess)))

    (if show-messages mess success)))

(defun bib-getengine(&optional show-messages)
  "Find biblatex engine.
If found,  engine name, else:
if SHOW-MESSAGES is nil return nil, if SHOW-MESSAGES is non-nil return related error."
  (save-excursion
    (goto-char (point-min))
    (let ((pack (re-search-forward "\\\\usepackage *\\(\\[[^]]*\\)\\] *{ *biblatex *}" nil t))
      (bend nil)
      mess)

      (when pack (setq pack (match-string-no-properties 1)))
      (when (and pack
         (string-match "[^[:alpha:]]+backend *= *\\([^, \n]+\\)" pack))
    (setq bend (match-string 1 pack)))
      (cond 
       ((not pack) (setq mess "Missing biblatex package command."))
       ((not bend) (setq mess "Missing biblatex backend."))
       ;; if no problem, sucess=message=bib-file-path
       (t (setq mess bend)))
      (if show-messages mess bend))))


(defun send-r-mess (mess)
  "Just send MESS at the end of R console buffer"
  (process-send-string (ess-get-process)
             (format "cat('%s\\n')\n" mess)))

(defun check-Rnw ()
  "Give error if `ess-dialect' is not \"R\""
  (if (not (string= "R" ess-dialect))
      (error "Not an Rnw buffer")))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.