Emacs Knitr iş akışı nasıl kurulur?


18

RStudio, Knitr ile LaTeX + R kaynağından PDF dosyası üretmek için tek tuşla yol sağlar. Tekrarlanabilir araştırma yapmak için harika görünüyor. Ve Emacs'ımı aşağıdakiler için yapılandırmaya çalışıyorum:

  • sol tamponda LaTeX + R kodunda Knitr şeklinde;
  • sağ tamponda PDF çıktı önizlemesi;
  • Derleme için bir tuş kombinasyonu.

Mümkünse: bunu nasıl ayarlamalıyım, lütfen?

(ESS iyi çalışıyor, ancak Knitr yolunu ve derleme için tek düğmeyi nasıl ayarlayacağımı bilmiyorum.)


Bunu yapmak için daha iyi bir yol olduğundan eminim, ama diğer pencerede pdf güncelleyecek geçerli rmarkdown::render(üzerinden shell-command) üzerinde çalışan bir anahtar bağlama ile kısa bir Elisp işlevi var buffer-file-name.
daroczig

1
@daroczig LaTeX için mi işe yarayacak, yoksa sadece markdown mı?
Tyler

@daroczig: Cevabımda muhtemelen bunu Rnw dosyaları (LaTeX + R) için yapmaya çalıştım. Daha basit olan Rmd dosyaları (Rmd + R) ile ilgili olarak, lütfen ayrı bir yazı başlatın.
antonio

1
Düzgün bir kurulum alamadım. İlk önce çok modlu örgü ile örmem gerekiyor. Sonra ihracatçı ve .tex dosyasını oluşturmak için her şeyi seçin. Oradan lateks koşmam gerekiyor. Yukarıdaki Script'i uyarlamaya çalıştım, ancak elispim henüz orada değil. İstediğim .Rnw dosyasını örmek, pdf (pdflatex) oluşturmak ve görüntülemek. Sistemimi ayarladım, lateks dosyasına "Cc Ca" (Tex-Command-run-all) yazarsam, pdf oluşturulur ve görüntülenir, ancak bu fonksiyonu my_knitr () 'den tex dosyasında çağıramam . Yardım takdir edilecektir. (defun my_knitr () "Knitr'i R-Poly modunda çalıştır ve pdf oluştur ve görüntüle" (interacti
Krisselack

@Krisselack aşağıdaki cevabımda açıkladığım özelliklerin ESS'den kaldırıldığı anlaşılıyor.
Tyler

Yanıtlar:


12

GÜNCELLEME

ESS 19.04 itibariyle ess-nowebve ess-swvkütüphaneleri kullanılmıyor:

Sonuç olarak, orijinal cevabım (aşağıda) artık geçerli değil. Bu kitaplıkların sağladığı özellikler artık çok modlu tarafından sağlanmaktadır ve yapılandırma daha basittir. Minimum destek almak için tek ihtiyacınız olan ess, polymodeve poly-Rpaketleri yüklemektir (MELPA'dan veya bu şekilde yuvarlandığınızda kaynaktan).

Bu kadar! Şimdi bir Rnwdosyayı açarsanız PM-Rnw, modelde bayrağı görmelisiniz Polymodeve üstte bir menü olacaktır . .texDosyanızı M-n w(veya çok modlu menü) aracılığıyla bir dosyaya örtebilir ve (veya menü) .pdfaracılığıyla dışa aktarabilirsiniz M-n e. Bunu ilk kez yaptığınızda bir ihracatçı istenecektir; Yeni seçtim knitr.

NOT: export ( M-n e) kodunuzu otomatik olarak çalıştırır, pdf dosyasını oluşturur ve hepsini tek seferde görüntüler. Aşağıda açıklanan eski sürümle "tek tık" davranışını alamadım.

Oluşturulan dosyalar kelimeye eklenir -wovenve -exportedeklenir. Eğer böyle değilse, sen seçenekleri özelleştirebilirsiniz polymode-weaver-output-file-formatve polymode-exporter-output-file-format.

İşlem, RMarkdown dosyaları ( .Rmd) için benzerdir .

Tüm detaylar çok modlu kılavuzda verilmiştir

Orijinal Yanıt (ESS 19.04'ten sonra kullanılmıyor)

Üç değişkenin ayarlanması gerekir:

  1. ess-swv-pdflatex-commands, özelleştirme grubunda ess-sweaveilk komut olarak "pdflatex" olmalıdır. yani, şöyle görünmelidir:("pdflatex" "texi2pdf" "make")
  2. ess-swv-processor, özelleştirme grubunda ess-R, değer olmalıdır"knitr"
  3. ess-pdf-viewer-prefözelleştirme grubu essiçin "emacsclient". Bu, emacs sunucusunu çalıştırdığınızı veya emacs'ın --daemon modunda çalıştığını varsayar. Ayrıca , yerleşik Emacs pdf görüntüleyicisine çok tercih edildiği için, mümkünse pdf araçları da kullanmalısınız .

BibTeX ve texi2pdf çağırmak için iki keybindings eklemek için bir kanca kullanın:

(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"))))

Bu yapıldıktan sonra, M-n sbelgenizi kaynayacak, M-n bbunu Bibtex olacak ve M-n Ppdflatex ile işleyecektir.

Emacs'ın örgü tamamlandığında bilmesinin basit bir yolu olmadığını unutmayın, bu yüzden bunu bir adımda örme ve lateks olarak ayarlayamazsınız; örgünün bittiğini gördükten sonra pdflatex'i manuel olarak tetiklemelisiniz .

Burada birden fazla adım göz önüne alındığında - Rnw -> Lateks -> PDF, pdf ve Rnw dosyalarınızı birlikte kaydırmak için Synctex alabileceğinizi düşünmüyorum, ancak yanlış olduğum için çok heyecanlıyım.

Pencere düzenlemesine gelince, onları asla istediğim yerde kalmalarını sağlayamıyorum. Yani telafi etmek için onlara ihtiyaç duyduğum pencereleri ve tamponları karıştırmak konusunda oldukça usta oldum;)

Yihui , knitr sitesinde bunlardan bazılarını gösteren kısa bir video yayınladı .


Gerekli tüm yapılandırmayı ve yalnızca gerekli yapılandırmayı .emac'lerimden ayıklamak için elimden geleni yaptım. Bir şeyi özlemiş olabilirim, orada biraz kıllı.
Tyler

knitr belgelerini derlemem mümkün oldu. Ama yine de tek tuşla açılan kombinasyonu bulmaya çalışın (Rnw -> PDF için). Umarım mümkün, çünkü Rstudio buna sahip.
drobnbobn

@Tyler: Teşekkürler, çözümünüz bir çekicilik gibi çalışır (yapılandırmayı düzenlemeden bile)! Paketler: ess, polymode, poly-r
Krisselack

5

Bu hepsi bir arada bir çözümdür. Bu olacak oluşturmak ve bir RNW bir PDF görüntülemek .
Özellikle:

  1. Rnw arabelleğini kaydedin ve örün,
  2. Ortaya çıkan TeX dosyasına belirli bir LaTeX motoru uygulayın,
  3. BibTeX motor yürütülebilir dosyasını tanımlayın (örn. Biber, bibtex8),
  4. Bib dosyası TeX dosyasından daha yeni ise BibTeX motorunu TeX dosyasında çalıştırın,
  5. LaTeX'i tekrar çalıştırın, 6 Ortaya çıkan PDF'yi belirlenen görüntüleyicide açın.

Yukarıdaki adımlardan biri başarısız olursa, yordam bilgilendirici mesajlarla çıkmaya çalışır.
Gerekirse bir R örneği açılır veya mevcut olan örme işlemini göstermek için kullanılır.
LaTeX çıkışı, derleme hatası durumunda da açılan "TeX-çıkış" arabelleğine gönderilir.

kullanım

Meta- x knit-mePDF oluşturmak ve görüntülemek için.
Meta- x knit-me-clearara LaTeX dosyalarını kaldırmak ve knit-me.

Kaynakça "biblatex" paketini gerektirir, yani:

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

Önbellek motorunun adı (ör bibtex. biber) backendAnahtar kelimeyi ayrıştırır .
\addbibresourcekomut bibliyografya dosyasını elde etmek için ayrıştırılır: foo.bibTeX dosyasından daha yeni ise bib motoru çalıştırılır. Bu bağlamda, \addbibresourceçok sayıda varsa sadece ilk komut dikkate alınır.

Özelleştirmek

PDF'yi gerçekten görüntülemek için, görüntüleyici yürütülebilir yolunu aşağıdakilerle ayarlayın:

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

Muhtemelen yeniden derlendiğinde PDF'yi otomatik olarak güncelleyen ve açılan dosyayı engellemeyen yeni derlemeleri önleyen SumatraPDF gibi bir görüntüleyici kullanın .

Varsayılan LaTeX motoru pdflatex(geçerli yolda olduğu varsayılır). Şununla özelleştir:

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

Elbette bağlanmak knit-meve knit-me-clearbazı uygun tuşlara bağlanmak isteyebilirsiniz .

notlar

İle Windows MiKTeX içinde test edilmiş biberve bibtex8backend'e ve GNU Emacs 25.1.1.

Elisp kodu

;; (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")))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.