Как рендерить 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.
Решается она, например, таким способом:
В 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()
```
По традиции, приглашаю вас в свой ТГ-канал. Там я пишу о продуктовой аналитке, в основном для ребят, которые уже работают, но только начинают свой карьерный путь.