Hendrik Wiese
Hendrik Wiese

Reputation: 2219

Trying to convert Jupyter Notebook to PDF slides

I'm trying to convert a Jupyter notebook that is using RISE to visualize the slides as a slideshow in the browser into a PDF file. The PDF file should have all pages in landscape mode and resemble the view in the browser. Of course, animations are not possible, but it should be possible to have fragments either combined in a single PDF slide or spread across multiple sort of "accumulating" slides (i.e. building upon their forerunner slides) .

I've been trying to create my own Jinja template that generates a LaTeX document utilizing the beamer document class, with not much success so far.

Do you know if there are any tools or templates or exporters or anything available that can help me with this process? Preferably automatically, like, utilizing nbconvert?

Upvotes: 11

Views: 4605

Answers (3)

pplonski
pplonski

Reputation: 5839

Some time ago, I needed to programmatically convert Jupyter Notebook presentations to PDF slides. I did some research and you can use puppeteer to automate the process. You need a simple Python script for this:

import asyncio
import os
import tempfile

from subprocess import PIPE, Popen
from pyppeteer import launch

import concurrent.futures

async def html_to_pdf(html_file, pdf_file, pyppeteer_args=None):
    """Convert a HTML file to a PDF"""
    browser = await launch(
        handleSIGINT=False,
        handleSIGTERM=False,
        handleSIGHUP=False,
        headless=True,
        args=["--no-sandbox"],
    )

    page = await browser.newPage()
    await page.setViewport(dict(width=994, height=768))
    await page.emulateMedia("screen")

    await page.goto(f"file://{html_file}", {"waitUntil": ["networkidle2"]})

    page_margins = {
        "left": "20px",
        "right": "20px",
        "top": "30px",
        "bottom": "30px",
    }

    dimensions = await page.evaluate(
        """() => {
        return {
            width: document.body.scrollWidth,
            height: document.body.scrollHeight,
            offsetWidth: document.body.offsetWidth,
            offsetHeight: document.body.offsetHeight,
            deviceScaleFactor: window.devicePixelRatio,
        }
    }"""
    )
    width = dimensions["width"]
    height = dimensions["height"]

    await page.pdf(
        {
            "path": pdf_file,
            "format": "A4",
            "printBackground": True,
            "margin": page_margins,
        }
    )

    await browser.close()



if __name__ == "__main__":
    
    html_input_file = "/you/need/full/path/here/presentation.slides.html?print-pdf"
    pdf_output_file = "slides.pdf"

    pool = concurrent.futures.ThreadPoolExecutor()
    pool.submit(
        asyncio.run,
        html_to_pdf(
            html_input_file,
            pdf_output_file
        ),
    ).result()

The script accepts the HTML slides as input and produces the PDF slides as output. Please note that you need to provide full path for the HTML file. I wrote an article on how to convert notebook presentations to pdf slides. If you would like to apply styling, here is longer version of the script.

Upvotes: 2

Tejas Shetty
Tejas Shetty

Reputation: 715

I guess jupyter nbconvert --to pdf the_notebook.ipynb should work fine. You do need to install latex though.

Upvotes: 0

Hendrik Wiese
Hendrik Wiese

Reputation: 2219

Figured it out myself. Take these steps:

  1. launch jupyter nbconvert --to slides --post serve the_notebook.ipynb; the browser will open the node hosted the_notebook.slides.html
  2. replace the # after the the_notebook.slides.html in the browser URL with ?print-pdf so that the url looks most likely like http://127.0.0.1:8000/the_notebook.slides.html?print-pdf
  3. print to PDF file

Upvotes: 13

Related Questions