Date Редакция Категория comp Теги R / Markdown / LaTeX

Задача: требуется создать конспект лекций по R в LaTeX.

Почему в LaTeX? Потому что он мне нравится.

Обычный путь решения этой задачи: пишем текст в LaTeX, вставляя в него фрагменты кода на R и результаты его выполнения (текст и графики). Нужно держать открытыми редактор TeX-а и R и время от времени копировать в TeX нужные фрагменты.

Просто, но скучно.

Нельзя ли сделать так, чтобы с помощью одного инструмента писать и текст и код? И чтобы результаты выполнения кода вставлялись в документ "сами собой"? Оказывается, можно.

Для этого в R существует пакет R Markdown. Установим его

install.packages("rmarkdown")

Чтобы получить документ LaTeX понадобится также дистрибутив TeX-a: MiKTeX (Windows), TeX Live (Linux, Windows), MacTeX (Mac OS).

Пакет R Markdown позволяет оформлять тексты на языке Markdown и вставлять в них "живой" исполняемый код на R. Так, вставка блока

```{r}
dim(iris)
```

превращается в итоговом документе в:

dim(iris)

## [1] 150   5

Подробнее о синтаксисе Markdown смотрите здесь.

Подготовленные таким образом документы можно сохранять в форматах HTML, PDF и некоторых других. Но нас сейчас интересует LaTeX. Он является промежуточным форматом в цепочке создания PDF-документов: Markdown -> LaTeX -> PDF.

При этом можно сохранять не только окончательный PDF, но и промежуточный LaTeX — а это то, что нам нужно. Сделать это можно, указав соответствующие настройки в заголовке Markdown-документа.

Сохранение LaTeX-документа

Заголовок документа окружен сверху и снизу тройными дефисами:

---
output:
  pdf_document:
---

В данном случае, в заголовке указано, что на выходе должен получиться PDF-документ. При этом промежуточный TeX-файл не сохраняется. Чтобы его сохранить, нужно добавить одну опцию keep_tex со значением yes в настройки PDF-документа:

---
output:
  pdf_document:
    keep_tex: yes
---

Однако при использовании русского языка в настроенном таким образом Markdown-документе мы, скорее всего, получим сообщение об ошибке. Дело в том, что шаблон LaTeX-овского документа, используемый пакетом по умолчанию, не поддерживает русский язык.

Настройка шаблона документа

Для настройки отображения русского языка нужно в заголовке уже LaTeX-овского документа подключить следующие пакеты:

\usepackage[T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}

Но как сделать так, чтобы эти пакеты добавлялись туда из Markdown? Используем опцию header-includes:

----
title: "Title"
author: "Me"
output:
    pdf_document
        keep_tex: yes
header-includes:
   - \usepackage[T2A]{fontenc}
   - \usepackage[utf8]{inputenc}
   - \usepackage[russian]{babel}
----

Когда изменений в шаблоне LaTeX-овского документа накопится достаточно много, можно переделать шаблон целиком.

Путь к шаблону можно найти с помощью команды

system.file("rmd/latex/default.tex", package="rmarkdown")

или посмотрев на сообщение, выдаваемое Markdown при трансляции документа

markdown_log.png

Запишем в этот шаблон вызов указанных выше пакетов и сохраним его копию с именем mystyle.tex в рабочем каталоге R. Последний можно узнать командой getwd(). Предполагается, что в этом же каталоге находится Markdown-файл с которым мы сейчас работаем.

Включение файлов в заголовок документа больше не нужно, а вот что нужно — так это указать новый шаблон LaTeX-документа опцией template:

----
title: "Title"
author: "Me"
output:
    pdf_document
        keep_tex: yes
        template: mystyle.tex
----

Вообще, у PDF-документа множество настроек, познакомиться с которыми можно с помощью обычной справки R:

> ?pdf_document

pdf_document(toc = FALSE, toc_depth = 2, number_sections = FALSE,
  fig_width = 6.5, fig_height = 4.5, fig_crop = TRUE,
  fig_caption = FALSE, highlight = "default", template = "default",
  keep_tex = FALSE, latex_engine = "pdflatex", includes = NULL,
  pandoc_args = NULL)

Отметим лишь аргумент latex_engine, позволяющий задавать транслятор LaTeX'а. По умолчанию это PDFTeX, но может быть и XeTeX ("xelatex") и LuaTeX ("lualatex").

Аргументы для pandoc

Итак, когда мы указываем опцию pdf_document в заголовке Rmd-файла, мы тем самым применяем функцию pdf_document из пакета RMarkdown. Среди её многочисленных аргументов есть pandoc_args — список аргументов, передаваемых программе pandoc, которая и выполняет преобразование из разметки Markdown в LaTeX.

С другой стороны, в шаблоне LaTeX-документа default.tex (как его найти мы показали выше) содержится ряд настроек, которые как раз и задаются pandoc'ом. Вот, например, первые строки шаблона:

\documentclass[$if(fontsize)$$fontsize$,$endif$$if(lang)$$lang$,
$endif$$if(papersize)$$papersize$,$endif$$for(classoption)$$classoption$$sep$,
$endfor$]{$documentclass$}

Таким образом, передавая аргументы pandoc с помощью pandoc_args мы можем настроить внешний вид LaTeX-документа. Например, указав в заголовке

output:
  pdf_document:
    toc: yes
    keep_tex: yes
    fig_caption: yes
    template: rstyle.tex
    pandoc_args: [ "--variable", "fontsize:12pt",
                   "--variable", "papersize:a4paper",
                   "--variable", "lang:russian",
                   "--variable", "geometry:margin=1in"
                 ]

мы получим в сгенерированном LaTeX-файле:

\documentclass[12pt,russian,a4paper]{article}

и, кроме того, определим отступы в 1 дюйм от края страницы (TeX-пакет geometry также используется в шаблоне default.tex).

Другой способ настройки параметров LaTeX-документа

Оказалось, что для параметры LaTeX'овского документа, вроде размера шрифта или отступов от края страницы можно передать и без использования pandoc_args. Делается это так:

title: "Title"
author: "Me"
fontsize: 12pt
geometry: margin=1in
papersize: a4paper
lang: russian
output:
  pdf_document:
    toc: yes
    keep_tex: yes
    fig_caption: yes
    template: rstyle.tex

Важно разместить fontsize, papersize, geometry и т.п. до раздела output заголовка. Подробнее — см. здесь.

Передача аргументов LaTeX

Передача аргументов командной строки текущему транслятору LaTeX осуществляется посредством аргумента pandoc: --latex-engine-opt. Вот как выглядит запуск из pandoc транслятора latex с аргументом -shell-escape:

pandoc_args: [
"--latex-engine-opt", "-shell-escape"
]

Подсветка синтаксиса

Чтобы отменить подсветку синтаксиса используете pandoc-опцию --no-highlight. Если выходным документом является PDF-файл, то в промежуточном tex-файле код будет заключён в окружение verbatim.

Рисунки

Опция fig_caption = TRUE или

----
title: "Title"
author: "Me"
output:
    pdf_document
        keep_tex: yes
        fig_caption: yes
        template: mystyle.tex
----

позволяет отображать подпись под рисунком. Сам рисунок вставляется в документ так:

![Подпись к рисунку](path/to/image.png)

Размер рисунка, например 640х480px, устанавливается следующим образом

![Подпись к рисунку](path/to/image.png=640x480)

Но это решение работает только в случае, когда форматом выходного документа является HTML. Если нужен PDF (или LaTeX), то можно записать непосредственно на LaTeX-е:

% Рисунок с фиксированным расположением
\begin{center}
\includegraphics[width=200pt]{image.png}
\end{center}

% Плавающий рисунок
\begin{figure}
\centering\includegraphics[width=200pt]{image.png}
\end{figure}

или с помощью функции include_graphics() пакета knitr:

```{r, out.width ="200pt", fig.align="center", echo=FALSE}
knitr::include_graphics("image.png")
```

Как и в LaTeX, изображение можно пометить с помощью \label и затем сослаться на него командой \ref

![Подпись к рисунку\label{mylabel}](path/to/image.png)

См. рис. \ref{mylabel}.

И ещё одни нюанс. Если для вставки рисунков вы используете только LaTeX-овские команды (\includegraphics), то pandoc сочтёт, что никаких рисунков в документе нет вообще — ведь там действительно нет рисунков, оформленных на Markdown. В результате не будет подключать пакет graphicx и \includegraphics будет объявлена неизвестной командой.

Дело в том, что в текущем шаблоне, который использует R для оформления документов LaTeX стоит условие

$if(graphics)$
\usepackage{graphicx}
...
$endif$

Чтобы решить проблему, нужно либо отменить это условие, позволив графике загружаться всегда, либо добавить в заголовок Rmd-документа явное разрешение:

graphics: yes

TikZ и PGFPlots

Рисунки, созданные командами TikZ и PGFPlots, совершенно спокойно можно вставлять в RMarkdown. Вот пример для TikZ:

---
title: "Test TikZ"
author: "Me"
output:
  pdf_document: default
header-includes: 
  - \usepackage{tikz}
---

# TikZ picture

Here is a TikZ picture:

\begin{tikzpicture}
\draw (0,0) circle (1in);
\end{tikzpicture}

rmd_tikz.png

Рисунки, созданные в PGFPlots, вставляются аналогично. Надо только подключить соответствующий пакет в разделе header-includes Rmd-файла.

Таблицы

Простая и без заголовка:

Обозначение | Значение
------------|------------------
`&`, `|`    | И, ИЛИ
`xor(a,b)`  | Исключающее ИЛИ

simple_table.png

С объединением столбцов и заголовком:

| First Header  | Second Header | Third Header         |
| :------------ | :-----------: | -------------------: |
| First row     | Data          | Very long data entry |
| Second row    | **Cell**      | *Cell*               |
| Third row     | Cell that spans across two columns  ||

Table: My Caption

cap_table.png

Как видно из номера таблицы, предыдущая таблица хоть и не имеет заголовка, тем не менее учтена при нумерации.

Шрифт

Имя основного шрифта можно задать в заголовке документа. Например, в данном случае это PT Serif:

---
title: "Тitle"
author: "Me"
date: \today
fontsize: 12pt
fontfamily: PT Serif
...
---

Можно также "спрятать" задание шрифта в latex-овский стилевой файл, подключаемый в заголовке, но, по сути, это будет то же самое.

Курсив и полужирный шрифты задаются разметкой Markdown:

markfonts.png

Другие начертания шрифта можно задать командами LaTeX:

latexfonts.png

Этот подход работает при создании PDF-документов (на основе файлов LaTeX). Если нашей целью является создание HTML-документа, то и пользоваться следует командами HTML. Например:

htmlfonts.png

Клавиатурные комбинации

Действие Комбинация клавиш
Трансляция+просмотр готового документа Ctrl+Shif+K
Проверка орфографии F7
Вставка фрагмента кода Ctrl+Alt+I

Примечание: орфография не проверяется внутри фрагментов кода.



Комментарии

comments powered by Disqus