Emacs에서 Knitr 워크 플로우를 설정하는 방법은 무엇입니까?


18

RStudio는 Knitr을 사용하여 LaTeX + R 소스에서 PDF 파일을 생성하는 원 버튼 방식을 제공합니다. 재현 가능한 연구를 수행하는 데 좋습니다. 그리고 Emacs를 다음과 같이 구성하려고합니다.

  • 왼쪽 버퍼에서 니트로 방식으로 LaTeX + R 코드;
  • 오른쪽 버퍼에서 PDF 출력 미리보기;
  • 컴파일을위한 하나의 키 조합.

가능하다면 어떻게 설정해야합니까?

(ESS는 잘 작동하지만 Knitr-way 및 one-button-for-compiling을 설정하는 방법을 모르겠습니다.)


더 좋은 방법이 있다고 확신하지만 current 에서 키 바인딩을 rmarkdown::render통해 (약을 통해 shell-command) 짧은 Elisp 함수를 사용 buffer-file-name하여 다른 창에서 pdf를 업데이트합니다.
daroczig

1
@daroczig는 LaTeX에서 작동합니까, 아니면 마크 다운입니까?
Tyler

@ daroczig : 내 대답에서 Rnw 파일 (LaTeX + R)에 대해서만이 작업을 시도했습니다. 더 간단한 Rmd 파일 (Rmd + R)에 대해서는 별도의 게시물을 시작하십시오.
안토니오

1
올바른 설정을 할 수 없었습니다. 폴리 모드 직조로 먼저 짜야합니다. 그런 다음 내보내기 및 모든 항목을 선택하여 .tex 파일을 만듭니다. 거기에서 나는 라텍스를 실행해야합니다. 위의 스크립트를 수정하려고 시도했지만 elisp는 아직 없습니다. 내가 원하는 것은 .Rnw 파일을 짜서 pdf (pdflatex)를 만들고 보는 것입니다. 라텍스 파일에 "Cc Ca"(Tex-Command-run-all)를 입력하면 pdf가 작성되어 표시되지만 my_knitr ()에서 tex-file에 대해 해당 함수를 호출 할 수 없도록 시스템을 설정했습니다. . 도움을 주시면 감사하겠습니다. (defun my_knitr () "R-Poly 모드에서 Knitr를 실행하고 pdf 생성 및보기"(interacti
Krisselack

@Krisselack 아래 답변에 설명 된 기능이 ESS에서 제거 된 것처럼 보입니다. 그들이 사용하는 새로운 접근 방식을 반영하기 위해 업데이트해야합니다.
Tyler

답변:


12

최신 정보

ESS 19.04부터 ess-nowebess-swv라이브러리는 더 이상 사용되지 않습니다.

결과적으로 내 원래 답변 (아래)이 더 이상 적용되지 않습니다. 이러한 라이브러리가 제공하는 기능은 이제 폴리 모드에서 제공되며 구성이 더 간단합니다. 최소한의 지원을 얻으려면, 당신이 필요로하는 모든이를 설치하는 것입니다 ess, polymode그리고 poly-R패키지 (MELPA에서, 또는 소스에서 해당의 경우 어떻게 당신에게 롤).

그게 다야! 이제 Rnw파일 을 열면 모델에 PM-Rnw플래그가 Polymode표시되고 상단에 메뉴가 나타납니다. (또는 폴리 모드 메뉴) .tex를 통해 파일을 파일로 M-n w짜서 (또는 메뉴)를 .pdf통해 내보낼 수 M-n e있습니다. 처음이 작업을 수행하면 내보내기를 요청하는 메시지가 나타납니다. 방금 골랐어 요 knitr.

참고 : ( M-n e) 내보내기는 자동으로 코드를 실행하고 pdf를 생성하여 한 번에 표시합니다. 아래에 설명 된 이전 버전에서는 "원 클릭"동작을 얻을 수 없었습니다.

생성 된 파일에는 단어가 -woven있고 -exported추가됩니다. 당신이 마음에 들지 않으면, 당신은 옵션을 사용자 정의 할 수 있습니다 polymode-weaver-output-file-formatpolymode-exporter-output-file-format.

이 프로세스는 RMarkdown 파일 ( .Rmd) 과 유사합니다 .

자세한 내용은 폴리 모드 매뉴얼을 참조하십시오

원래 답변 (ESS 19.04 이후 폐기)

세 가지 변수를 설정해야합니다.

  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 모드에서 실행 중이라고 가정합니다. 또한 사용해야 PDF-도구 는 이맥스 내장 된 PDF 뷰어 훨씬 바람직하다로, 모든 가능한에서합니다.

후크를 사용하여 BibTeX 및 texi2pdf 호출을위한 두 개의 키 바인딩을 추가합니다.

(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 b를 짜서 bibtex하고 M-n Ppdflatex로 처리합니다.

편직이 완료 될 때 Emacs가 알 수있는 간단한 방법은 없으므로 한 단계에서 편직 및 라텍스로 설정할 수 없습니다. 뜨개질이 완료된 후에 pdflatex를 수동으로 트리거해야합니다 .

여기에 Rnw-> Latex-> PDF의 여러 단계가 있다고 가정하면 Synctex가 pdf 및 Rnw 파일을 함께 스크롤하도록 유지할 수는 없지만 잘못되었다고 생각합니다.

창문 배열에 관해서는, 내가 원하는 곳에 머물러있게 할 수 없습니다. 그래서 보상하기 위해 필요에 따라 창과 버퍼를 섞는 데 꽤 익숙해졌습니다.)

Yihui는 knitr 사이트에이 중 일부를 보여주는 짧은 비디오 를 게시했습니다 .


내 .emacs에서 필요한 모든 구성과 필요한 구성 만 추출하기 위해 최선을 다했습니다. 나는 뭔가를 놓쳤을 수도 있습니다.
Tyler

편물 문서를 컴파일 할 수있었습니다. 그러나 여전히 하나의 키 콤보를 찾으십시오 (Rnw-> PDF). Rstudio가 이것을 가지고 있기 때문에 가능하기를 바랍니다.
drobnbobn

@ 타일러 : 감사합니다. 솔루션은 구성을 편집하지 않아도 매력 ootb처럼 작동합니다! 패키지 : ess,
polymode

5

이것은 올인원 솔루션입니다. 그것은 것입니다 만들고 RNW에서 PDF를 표시합니다 .
구체적으로 다음과 같습니다.

  1. Rnw 버퍼를 저장하고 편직하십시오.
  2. 주어진 LaTeX 엔진을 결과 TeX 파일에 적용하십시오.
  3. BibTeX 엔진 실행 파일 (예 : biber, bibtex8)을 식별하십시오.
  4. bib 파일이 TeX 파일보다 최신 인 경우 TeX 파일에서 BibTeX 엔진을 실행하십시오.
  5. LaTeX를 다시 실행하십시오. 6 지정된 뷰어에서 결과 PDF를 엽니 다.

위의 단계 중 하나가 실패하면 절차는 정보 메시지와 함께 종료를 시도합니다.
필요한 경우 R 인스턴스가 열리거나 현재의 인스턴스가 편직 프로세스를 표시하는 데 사용됩니다.
LaTeX 출력은 "TeX-output"버퍼로 전송되며, 컴파일 오류가 발생하면 팝업됩니다.

용법

Meta- x knit-me작성하고 PDF를 볼 수 있습니다.
Meta- x knit-me-clear중간 LaTeX 파일을 제거합니다 knit-me.

참고 문헌에는 "biblatex"패키지가 필요합니다.

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

턱받이 엔진의 이름은 (예를 들어 bibtex, biber)를 구문 분석 얻을 backend키워드를.
\addbibresource참고 문헌 파일을 얻기 위해 명령을 구문 분석합니다. foo.bibTeX 파일보다 최신 파일이면 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.

노트

와, 윈도우 MiKTeX에서 테스트 biberbibtex8백엔드와 GNU 이맥스 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.