Есть отличный инструмент для обучения/отчётов/написания умных книг про код — Jupyter Notebook. Если отчёт или книга, например, пишутся на кириллице, а нужно быстро сделать из этого PDF с красивыми формулами и тире правильной длины, то сразу обнаруживается проблема: в стандартном шаблоне, который Jupyter использует для конвертации блокнотов в PDF через LaTeX, нет подключения нужных пакетов с нужными параметрами, поэтому LaTeX просто не компилируется и PDF не получить.
Постоянно действующие предположения: будем говорить о Jupyter, который отсоединился от основного проекта IPython в релизе IPython 4; если вы хотите поговорить об IPython 3.x, заменяйте в командах
Самый простой способ решить проблему с недостающими пакетами —
Если проблема не решается в одну строчку (нужно серьёзно менять шаблон и не хочется копаться в неприятном результате конвертирования в LaTeX) / у меня много блокнотов / я хочу более общее решение, то продолжаем.
TL;DR: для того, чтобы получить pdf с кириллицей, добавьте к себе два файла (ссылка ведёт на комментарий с кратчайшим описанием).
Нужно объяснить конвертеру, что для конвертации блокнота в LaTeX он должен использовать не стандартный шаблон, а наш, с расширенным заголовком, самым правильным шрифтом и корпоративной темой оформления.
Проблемы:
Сначала про конфигурацию и местонахождение файлов. Это быстро решается написанием собственного файла настроек. Файл настроек для
Файл настроек выглядит примерно так:
Здесь
Теперь если запустить
Самая интересная часть — как писать шаблоны. Шаблоны пишутся с использованием шаблонизатора Jinja2; во избежание конфликтов со специальными символами LaTeX служебные последовательности шаблонизатора переопределены (первая
Как написать свой шаблон, в котором будут выполняться все необходимые лично вам вещи? Создать файл
Во-первых — аккуратно унаследоваться от шаблона, определяющего конкретный стиль отрисовки клеток с кодом (как в примере):
Здесь я наследуюсь от шаблона
Во-вторых — определить
В-третьих — подключить вожделенные пакеты с поддержкой кириллицы (и ещё десяток-другой любимых):
Полный список блоков описан в
Если мы хотим использовать полученный шаблон не в конкретном проекте, но во всех блокнотах, можно положить его, например, в
После небольших исправлений в шаблоне для отрисовки клеток с кодом (мне не нравились надписи In[*]) у меня получились вот такие отчёты (скриншот из PDF-файла):
Постоянно действующие предположения: будем говорить о Jupyter, который отсоединился от основного проекта IPython в релизе IPython 4; если вы хотите поговорить об IPython 3.x, заменяйте в командах
jupyter
на ipython
и проверяйте возможные несовпадения имён файлов. Для генерации PDF мы используем либо командную строку (jupyter nbconvert --to pdf myfile.ipynb
), либо кнопку из веб-интерфейса Download as -> PDF via LaTeX.Самый простой способ решить проблему с недостающими пакетами —
jupyter nbconvert --to latex myfile.ipynb
, открываем полученный TeX-исходник и дописываем недостающие пакеты. Компилируем исходник (pdflatex myfile.tex
или что кому нравится), цель достигнута.Если проблема не решается в одну строчку (нужно серьёзно менять шаблон и не хочется копаться в неприятном результате конвертирования в LaTeX) / у меня много блокнотов / я хочу более общее решение, то продолжаем.
TL;DR: для того, чтобы получить pdf с кириллицей, добавьте к себе два файла (ссылка ведёт на комментарий с кратчайшим описанием).
Нужно объяснить конвертеру, что для конвертации блокнота в LaTeX он должен использовать не стандартный шаблон, а наш, с расширенным заголовком, самым правильным шрифтом и корпоративной темой оформления.
jupyter nbconvert --to pdf --template mytemplate.tplx myfile.ipynb
Проблемы:
mytemplate.tplx
успешно находится только в той директории, откуда запускается nbconvert
, через веб-интерфейс это не протащить, как писать шаблон — непонятно.Файлы настроек
Сначала про конфигурацию и местонахождение файлов. Это быстро решается написанием собственного файла настроек. Файл настроек для
nbconvert
— это файл с кодом на Python. Как указать файл настроек при вызове конвертера:jupyter nbconvert --to pdf --config cfg.py myfile.ipynb
Файл настроек выглядит примерно так:
c = get_config()
c.NbConvertApp.export_format = 'pdf'
c.TemplateExporter.template_path = ['.']
c.Exporter.template_file = 'article'
Здесь
export_format
— значение по умолчанию для --to
, template_path
— список директорий с шаблонами, здесь говорит, что файлы шаблонов должны искаться в той директории, откуда запускается nbconvert, template_file
означает, что, если не указано иначе, нужно пользоваться шаблоном article.tplx
.Теперь если запустить
jupyter notebook --config cfg.py
, то все настройки для конвертации будут браться сначала из файла конфигурации, что нам и нужно. Если нужно, чтобы эти настройки были по умолчанию при любом запуске nbconvert
этим пользователем, их нужно положить в файл ~/.jupyter/jupyter_nbconvert_config.py
. Соответственно, для notebook
общий файл настроек — ~/.jupyter/jupyter_notebook_config.py
.Шаблоны
Самая интересная часть — как писать шаблоны. Шаблоны пишутся с использованием шаблонизатора Jinja2; во избежание конфликтов со специальными символами LaTeX служебные последовательности шаблонизатора переопределены (первая
{
заменена на ((
, остальные {
на (
, с обратными скобками зеркально). Набор шаблонов, которые используются по умолчанию, находится в NBCONVERT_INSTALLATION_DIR/nbconvert/templates/latex/
. Они хорошо документированы, от них имеет смысл наследоваться при создании своих шаблонов. Ещё примеры шаблонов есть в репозитории nbconvert-examples на Github. Скриншоты различных вариантов оформления можно посмотреть в readme к одному из разделов этого репозитория.Как написать свой шаблон, в котором будут выполняться все необходимые лично вам вещи? Создать файл
mytemplate.tplx
, в котором написать несколько необходимых вещей.Во-первых — аккуратно унаследоваться от шаблона, определяющего конкретный стиль отрисовки клеток с кодом (как в примере):
% Default to the notebook output style
((* set cell_style = 'style_notebook.tplx' *))
% Inherit from the specified cell style.
((* extends cell_style *))
Здесь я наследуюсь от шаблона
style_notebook.tplx
, который не является стандартным, а лежит в nbconvert-examples. Ещё этот шаблон написан, видимо, для старой версии nbconvert, поэтому в нём нужно будет поменять строчку ((* extends 'latex_base.tplx' *))
на ((* extends 'base.tplx' *))
.Во-вторых — определить
\documentclass
будущего LaTeX-файла и не делать заголовка (можно вместо этого написать код, берущий заголовок из метаданных файла .ipynb
или откуда-нибудь ещё):((* block docclass *))
\documentclass{article}
((* endblock docclass *))
((* block maketitle *))((* endblock maketitle *))
В-третьих — подключить вожделенные пакеты с поддержкой кириллицы (и ещё десяток-другой любимых):
((* block packages *))
((( super() ))) % load all other packages
\usepackage[T2A]{fontenc}
\usepackage[english, russian]{babel}
\usepackage{mathtools}
((* endblock packages *))
Полный список блоков описан в
nbconvert/templates/latex/skeleton/null.tplx
и nbconvert/templates/latex/base.tplx
(и это тоже ссылки на GitHub).Если мы хотим использовать полученный шаблон не в конкретном проекте, но во всех блокнотах, можно положить его, например, в
~/.jupyter/templates/
и изменить соответствующую строчку в файле настроек (спасибо spitty за замечание о том, что относительные пути просто так работать не будут):import os
c.TemplateExporter.template_path = ['.', os.path.expanduser('~/.jupyter/templates/')]
После небольших исправлений в шаблоне для отрисовки клеток с кодом (мне не нравились надписи In[*]) у меня получились вот такие отчёты (скриншот из PDF-файла):
spitty
Спасибо за статью. В своё время решал задачу получения pdf с кириллическими символами через скрипт, который делал выгрузку в
tex
-файл, редактировал его и преобразовывал вpdf
.Не думали оформить pull request?
Эксперимент показал, что указание относительных путей не работает. В обсуждении на Github рекомендуют преобразовывать относительные пути в абсолютные:
PS
Возможно будет полезным указать, что минимальный набор действий для починки функциональности выгрузки
ipynb
-файлов с кириллическими символами вpdf
из интерфейса Jupyter Notebook состоит из добавления всего двух файлов:~/.jupyter/templates/mytemplate.tplx
~/.jupyter/jupyter_notebook_config.py
stacymiller
Pull request — не собиралась, и с точки зрения обратной совместимости это, наверное, спорное решение.
Спасибо за замечание про относительные пути, я столкнулась с этим, когда настраивала у себя, но забыла упомянуть.
Поставила из текста ссылку на комментарий как на кратчайшее решение проблемы.
spitty
От примеров обычно не требуют обратной совместимости. И, по-хорошему, они должны версионироваться вместе с
nbconvert
. Но разработчики, как я вижу, больше сосредоточены на разработке основного продукта.То, что примеры требуется "доточить", чтобы они работали с актуальной версией
nbconvert
, может быть проблемой для неподготовленных пользователей вроде меня. Так что всё равно спасибо, что указали на несоответствие в примере.