Jupyter Notebook → PDF 変換方法の比較表をまとめました (以下)。誤りがありましたらご指摘いただけますと幸いです。
LaTeX 経由 PDF 変換については以下の記事を参照ください。
【補足】HTML オブジェクト出力について
例えば Pandas Styler でデータフレーム内の負の数を赤くしたり、最大値を強調したりすることがあるかもしれませんが、これは TeX 経由では PDF 変換できません。
下図の左側は後述のスクリプトで HTML 経由で PDF 化したノートブック、右側は jupyter nbconvert --to pdf Untitled.ipynb
コマンドで (TeX 経由で) PDF 化したノートブックです。左側ではデータフレームが表示できていますが、右側は表示できていません。
つまり、TeX 経由の PDF 変換では display(HTML(...))
などといった HTML としてレンダリングされる要素の変換には対応しておらず、表示できません (なお、 df.style
は display(HTML(...))
としなくてもセル末尾でこれを返せばノートブック上にレンダリングされますが、結局 HTML としてレンダリングされるのでどのみち表示できません)。
【おまけ】Playwright 経由変換スクリプト
上図の左側の、HTML 経由 PDF を生成したときに使用したスクリプトは以下です。コード内かどうかの判定は適当にやっています (Beautiful Soup をつかった方がメンテ性のよいスクリプトになるとは思います)。
- Playwright の pdf メソッドのドキュメントは以下です。余白
margin
はデフォルトでゼロになっていて以下では変更していませんが好きに変更することもできます (はず)。
Page | Playwright Python
from playwright.sync_api import sync_playwright
import subprocess
import re
def repl(match):
spaces = len(match.group(1))
return '\u2423' * spaces # 行頭の空白と同じ個数の空白記号を返す
# ---------- (1) HTML 変換 ----------
subprocess.run(
['jupyter', 'nbconvert', '--to', 'html', 'Untitled.ipynb'],
check=True
)
# ---------- (2) HTML 読み込み兼書き換え ----------
code_flag = False
html = ''
with open('Untitled.html', encoding='utf8') as ifile:
for line in ifile:
# コード内かどうかの判定
if '<div class="highlight hl-ipython3"><pre>' in line:
code_flag = True
if code_flag and '</pre></div>' in line:
code_flag = False
# head が終わる直前に独自スタイルを挿入
if '</head>' in line:
line += (
'<style type="text/css">\n'
'div.jp-MarkdownOutput {\n'
' font-family: "Rounded Mplus 1c";\n'
' line-height: 1.2;\n'
'}\n'
'body {\n'
' margin: 0 !important;\n'
' padding: 0 !important;\n'
'}\n'
'</style>\n'
)
# コード内なら行頭の空白を空白記号に置換
if code_flag:
line = re.sub(r'^( +)', repl, line)
html += line
# デバッグ用
# with open('out.html', mode='w', encoding='utf8') as ofile:
# ofile.write(html)
# ---------- (3) 読み込んだ HTML を PDF として保存 ----------
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.set_content(html)
page.pdf(
path='Untitled.pdf',
format='A4',
print_background=True,
scale=0.9,
)
browser.close()