Как рендерить R Markdown в PDF на кириллице

от автора

Так получилось, что за всё время, что я использую в работе R, мне не доводилось рендерить markdown-файлы в формат PDF. Иногда я хранил наработки просто в фалах .R, а исследования оформлял в Google Docs, накидывая туда скринов из viewer-а. Иногда это был рендер в .html, с интерактивной графикой, или проекты Shiny в облаке Posit. Да мало ли вариантов.

Но в связи с некоторыми изменениями в форматах хранения аналитических артефактов, судьба привела меня к PDF.

“Дело-то не хитрое, просто меняем формат вывода в markdown” — подумал я. Однако всё оказалось не так просто: и тексты и ggplot не видят кириллицу, движок xelatex не находит кастомные шрифты, LaTeX вообще бесится на всё.

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

Рассмотрим на примере классического markdown, а в конце реализация для Quarto.

В общем, по порядку.

В качестве IDE я использую RStudio.

Для рендера в PDF, в первую очередь нужно поставить LaTeX, я не изучал там нюансы движков, а выбрал наиболее цитируемый TinyTex. Устанавливается через CRAN или через Git, кому как нравится:

install.packages('tinytex')  tinytex::install_tinytex()  #после этой команды нужно полностью перезапустить ваш R-клиент

За основу возьмём вот такой файл .Rmd, с базовым набором элементов: заголовок, текст, код и график.

--- title: "Cyrillic markdown" date: "`r Sys.Date()`" output: pdf_document ---  ```{r include = F} library(tidyverse) ```  ```{r include = F} # Создаём датасет dates <- rep(seq(as.Date("2023-01-01"), length.out = 7, by = "days"), each = 2) values <- sample(100:130, 14, replace = TRUE) categories <- rep(c("Cat_A", "Cat_B"), 7)  df <- data.frame(date = dates,                   value = values,                   category = categories) ```  ## Заголовок  Тут у нас кириллический текст с некоторыми вставками english words.  ```{r} head(df) ```  Ну и график прилагается:  ```{r} # plot 1 ggplot(df, aes(x = date,                y = value,                col = category)) +    geom_line() +   labs(title = "График",        x = "Дата",        y = "Метрика") +   theme_minimal() ```

При попытке рендера, если у вас локаль RU, консоль выкатит первую ошибку (или отрендерит без кириллического текста и с кучей warning-ов):

! LaTeX Error: Unicode character З (U+0417)                not set up for use with LaTeX.

Решается она, например, таким способом:

  1. В YAML-заголовке указываем движок и включаем дополнения в виде файла header.tex:

--- title: "Cyrillic markdown" date: "`r Sys.Date()`" output:   pdf_document:     latex_engine: xelatex     includes:       in_header: header.tex --- 

2. Сам файл header.tex лежит в папке с нашим markdown-файлом и выглядит примерно так:

\usepackage{fontspec} \setmainfont{Segoe UI} \setsansfont{Segoe UI} \setmonofont{Segoe UI} \usepackage{polyglossia} \setmainlanguage{russian} \setotherlanguage{english}

Теперь LaTeX перестанет ругаться и кое-как, но PDF-ку соберёт.

Ну, пока хоть так

Ну, пока хоть так

Кириллица в тексте обрабатывается, а вот ggplot форматирует даты в текст и ломается.

Если вы не любитель описывать labs в графиках, а уж тем более кириллицей, то тут можно ограничиться сменой локали прям в markdown-файле, добавив куда-нибудь в начало такую строку:

Sys.setlocale("LC_TIME", "en_US.UTF-8")

Второй вариант — использовать библиотеку showtext:

install.packages("showtext") library(showtext)  # после загрузки библиотеки, отдаём распознавание на откуп движку showtext_auto()

Предупреждения ушли, график видит кириллицу как в лабсах, так и в датах:

В целом готово. Но мне вообще не нравится как выглядят блоки с кодом. Я люблю для этого использовать шрифты Cascadia Mono PL Light или Cascadia Code Light. Но если шрифт кастомный, просто переписать header.tex не поможет. Я перепробовал разные варианты, и переустановить шрифты, и прописать полное название, и скормить ему весь путь к файлу шрифта — безрезультатно.

В итоге помогла смена движка на lualatex, который тоже поддерживает fontscpec.

--- title: "Cyrillic markdown" date: "`r Sys.Date()`" output:   pdf_document:     latex_engine: lualatex     includes:       in_header: header.tex ---

Ну другое дело же)

На этом, пожалуй, и все нюансы рендера markdown в PDF.

Я потратил на это пару вечеров (а мог пить пиво), надеюсь кому-нибудь поможет сэкономить время.

Quarto

Тут намного всё проще, никаких костылей с header.tex не нужно, шрифты прописываются прям в YAML, кириллица на графике лечится тем же showtext:

--- title: "Cyrillic markdown" format: pdf pdf-engine: lualatex mainfont: Segoe UI sansfont: Segoe UI monofont: Cascadia Mono PL Light editor: visual ---  ```{r include = F} library(showtext) showtext_auto() ```

По традиции, приглашаю вас в свой ТГ-канал. Там я пишу о продуктовой аналитке, в основном для ребят, которые уже работают, но только начинают свой карьерный путь.


ссылка на оригинал статьи https://habr.com/ru/articles/781136/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *