Getting started with Pelican and IPython notebooks

Sat 03 January 2015 | tags: python

This site was created with the static site generator, Pelican. I chose Pelican in order to use jakevdp's liquid_tags notebook plugin that allows for posting a subset of IPython notebook cells. The comments below are for Pelican v3.5.0, IPython v1.2, and a December 30, 2014 clone of pelican-plugins.

Below are steps used to install Pelican. Python and node.js must be installed (I was unable to generate posts containing IPython notebook files without node.js). Console/terminal commands are contained in brackets.

An older version of IPython is needed because the CSS class names used for python syntax highlighting changed in IPython v2.3. The liquid_tags notebook plugin appears to only know about the v1.2 CSS class names. For example, in an IPython notebook, a function named foo gets wrapped in a class by way of a <span> element. In IPython v1.2 this becomes <span class="nf">foo</span>, but in v2.3 this is <span class="cm-def">foo</span> (I used Chrome to inspect the elements). I'm not smart enough to fix it, but I assume the problem begins in the plugin's notebook.custom_highlighter() function. Inside this function a call is made to HtmlFormatter(cssclass='highlight-ipynb') where HtmlFormatter comes from the Pygments library.

Quick pelican setup

  1. Make a dedicated directory to house the site's contents and change into it.
  2. Set up a virtual environment
    a. [virtualenv env]
    b. [env\scripts\activate]
    c. [pip install pelican markdown ipython==1.2]
  3. Install plugins/themes
    a. [git clone https://github.com/getpelican/pelican-plugins.git]
    b. [git clone https://github.com/getpelican/pelican-themes.git]
    c. Find other themes by looking at other users' github repositories (e.g. octopress, middle-theme)
  4. [pelican-quickstart] // see here for a list of questions that are asked
  5. Configure Pelican via pelicanconf.py
    a. DELETE_OUTPUT_DIRECTORY = False
    b. PLUGIN_PATHS = ['path/to/pelican-plugins']
    c. PLUGINS = ['liquid_tags.notebook', 'liquid_tags.literal']
    d. EXTRA_HEADER = open('_nb_header.html').read().decode('utf-8') if os.path.exists('_nb_header.html') else None
    e. NOTEBOOK_DIR = 'notebooks'
    f. THEME = 'path/to/theme'
    g. LOAD_CONTENT_CACHE = False
  6. Edit the chosen theme's 'base.html' and add {% if EXTRA_HEADER %}{{ EXTRA_HEADER }}{% endif %} to the <head> block
  7. Configure 'content' directory
    a. [mkdir content/images]
    b. [mkdir content/notebooks]
  8. Run the site generator with [make html] or [make regenerate]
  9. Serve the site locally with [make serve] or regenerate files + serve with [make devserver] if not on Windows.

Posts are written in markdown by the user and stored in content/, where each post's filename should have extension 'md'. Notebooks are incorporated in a markdown post with:

{% notebook file.ipynb cells[i:j] %}

The 'cells' argument is optional and can be omitted; the slices are standard python syntax. The LOAD_CONTENT_CACHE setting should be False if notebooks are edited after they're added to content/notebooks/. Otherwise, the cached version is used by Pelican.

Initially, [make html] must be run twice because '_nb_header.html' is only generated after the first run. This file contains all the CSS/JS present in an IPython notebook.

Math blocks were left-aligned in IPython v1.2 but are centered in IPython v2.3, which is the preferred behavior. To force centering of math blocks while using v1.2, I made copy of _nb_header.html, edited it to include the addition below, and pointed to it in pelicanconf.py's EXTRA_HEADER setting.

<style type="text/css">
.MathJax_Display{text-align: center !important;}
</style>

Repositories

My choice was to have two repositories.

  • Inside the master directory where [pelican-quickstart] is run.
  • A subdirectory of the above that holds the content pushed to the web server.

The former has a .gitignore file that contains:

*.pyc
cache/
env/
output/
username.github.io/

The latter repository is a GitHub Pages repository. The 'output/' directory generated by Pelican is copied to this repository.

This site's repository containing the raw Pelican content can be found here. The generated site can be found here.

Helpful references

Script to summarize available Pelican themes

"""
Ugly script used to summarize all pelican-themes.
https://github.com/getpelican/pelican-themes.

Place this script one level below THEMES_DIR.
It will generate summary.html containing the themes.  
"""
import os
from collections import OrderedDict as od

THEMES_DIR = 'pelican-themes'

# first, discover all themes that have screenshots
# each screenshot's filename is stored
contents = os.listdir(THEMES_DIR)
accumulated_screenshots = od()
for entry in contents:
    theme_directory = os.path.join(THEMES_DIR, entry)
    if os.path.isdir(theme_directory) and entry != '.git':
        theme_contents = os.listdir(theme_directory)
        accumulated_screenshots[entry] = []
        for theme_file in theme_contents:
            if theme_file[-3:] in ('jpg', 'png', 'gif'):
                accumulated_screenshots[entry].append(theme_file)

# second, create an HTML file
# the IMG elements point to the accumulated screenshots
to_write = ['<html><body>\n']
for theme, screenshots in accumulated_screenshots.iteritems():
    path = os.path.join(THEMES_DIR, theme)
    for i, screenshot in enumerate(screenshots):
        if i == 0:
            # print the theme's name only once
            to_write.append('<h1>%s</h1><br />\n' % theme)
        screenshot_path = os.path.join(path, screenshot)
        to_write.append('<center>\n')
        to_write.append(
            '<img src="%s" height=500>\n' % screenshot_path
        )
        to_write.append('</center><br />\n')
    to_write.append('<br />\n')
to_write.append('</body></html>\n')

with open('summary.html', 'w') as f:
    f.writelines(to_write)

Comments !

social