Using Nikola to blog with ipython notebooks.
http://www.damian.oquanta.info/posts/ipython-plugin-for-nikola-updated.html
Installing Nikola¶
Update January 2020: I recommend installing Nikola from a conda environment.yml
file. I keep one on anaconda cloud so you can just go:
conda env create mforbes/blog
such as the following:
```yml
# environment.yml
name: blog
channels:
- defaults
- conda-forge
- mforbes
dependencies:
- jinja2 # Jinja2 Template engine for my styles.
- nbstripout # Cleaning output from notebooks
- typogrify # Required for the typogrify filter
# These are needed by Nikola. We install them so Conda has control.
- babel>=2.6.0
- blinker>=1.3
- docutils>=0.13
- doit>=0.32.0
- lxml>=3.3.5
- mako>=1.0.0
- markdown>=3.0.0
- natsort>=3.5.2
- piexif>=1.0.3
- pillow>=2.4.0
- pygments>=1.6
- python-dateutil>=2.6.0
- requests>=2.2.0
- setuptools>=24.2.0
- unidecode>=0.04.16
- yapsy>=1.11.223
# Additional dependencies not in conda - they will be installed by pip.
#- PyRSS2Gen>=1.1
# Needed of ipynb format
- nbconvert
- notebook>=4.0.0
# Needed for nikola auto
- watchdog>=0.8.3 # Conda version gives "Failed to import fsevents. Fall back to kqueue"
- aiohttp
# My packages.
- mmf_setup
- pip
- pip:
#- nikola>=8.1.1
# Need dev version for this issue with templates
# https://github.com/getnikola/nikola/issues/3457
- git+https://github.com/getnikola/nikola.git@master
- pipdeptree
#- watchdog>=0.8.3
- ghp-import2 # Needed for github_deploy
#- pyrss2gen>=1.1
#- python-hglib==2.6.1
There is no conda recipe yet for Nikola, so it needs to be pip installed.
To uses some html features like SASS, I needed to install npm
which I did at the system level.
conda env create -f environment.blog.yml
conda activate blog
npm install -g less # lessc compiler required for CSS in zen- themes
sudo gem install sass # sass compiler required for SASS based CSS
nikola plugin -i less
nikola plugin -i sass
Old Notes and Problems¶
I had some trouble pip-installing nikola with pip so had to install a few of the dependencies first with conda.
# This worked with python 3 in an anaconda install.
!pip install nikola webassets
!conda install ws4py watchdog # Required for nikola auto
!pip install typogrify # Required for the typogrify filter
!npm install -g less # lessc compiler required for CSS in zen- themes
!sudo gem install sass # sass compiler required for SASS based CSS
!nikola plugin -i less
!nikola plugin -i sass
# I needed this before with python 2
!conda install pillow
!pip install nikola livereload webassets
!conda update lxml
Compiler¶
I had trouble installing macfsevents
using the HPC compilers, so I had to disable them. When using the Xcode compilers, everything worked.
Lack of Root Permissions¶
If you don't have root access, then running npm
or gem
might cause issues (i.e. on Sage Mathcloud.) For npm
, the suggestion here to:
npm config set prefix ~/.npm
cat > ~/.bash_aliases <<EOF
# Add local npm package to path
# http://stackoverflow.com/a/23889603/1088938
# http://stackoverflow.com/a/40830016/1088938
export PATH="$PATH:$HOME/.npm/bin"
export GEM_HOME="$HOME/.gem"
export PATH="$PATH:$GEM_HOME/bin"
EOF
. ~/.bash_aliases
npm install less
gem install sass
works.
New Blog/Website¶
These new instructions are based on my custom themes. See below to base your blog on public themes.
-
Install Nikola (above) and activate the
blog
environment.conda env create -f environment.blog.yml
You can also use
anaconda-client
to do this from myenvironment.blog.yml
file on anaconda cloud. Note: Make sure there is no localenvironment.yml
file, or creating the environment from anaconda cloud may fail.conda install anaconda-client conda env create mforbes/blog
CoCalc¶
Here is a complete walk-through using CoCalc. The example will be for the iSciMath main website. We do a couple of things here:
- Store all images in a separate repo since these can be big.
Here is the play by play:
Initial Setup¶
- Create a new project on CoCalc and enable internet access. (This will require that you have some access to at least one upgrade... they needed to do this to prevent people from abusing the resources.)
-
Create and activate the
blog
environment.anaconda2020 # CoCalc-specific way of activating conda. conda install anaconda-client # Not needed on CoCalc, but may be needed elsewhere conda env create mforbes/blog # Make sure there is no local environment.yml file! conda clean -y --all # Free disk space from downloads. conda activate blog
As a check, you should now be able to run Nikola:
$ nikola --version Nikola v8.1.1
-
Create a Jupyter kernel (optional). Here we create a Jupyter Kernel so that we can activate the
blog
kernel fromREADME.ipynb
providing some interactive instructions. This is not needed for the general functionality of Nikola.mkdir -p ~/.local/share/jupyter/kernels/ cp -r /ext/anaconda2020.02/share/jupyter/kernels/python3 ~/.local/share/jupyter/kernels/blog-py vi ~/.local/share/jupyter/kernels/blog-py/kernel.json
Here is how I modified the
kernel.json
file:#kernel.json { "argv": [ "/home/user/.conda/envs/blog/bin/python", "-m", "ipykernel_launcher", "-f", "{connection_file}" ], "display_name": "Blog", "language": "python" }
-
Create a repo for your website and add some files:
mkdir -p ~/repositories/iscimath_website cd ~/repositories/iscimath_website hg init tee .hgignore <<EOF syntax: glob syntax: regexp ^.output/ ^.cache/ EOF tee Makefile <<EOF auto: echo "https://cocalc.com/ff1cb986-feb2-4122-b55d-1700a5fd8553/server/8000" nikola auto -a 0.0.0.0 -p 8000 .PHONY: auto EOF
-
Use Nikola to create the site.
(blog) ~/repositories/iscimath_website$ nikola init . Creating Nikola Site ==================== This is Nikola v8.1.1. We will now ask you a few easy questions about your new site. If you do not want to answer and want to go with the defaults instead, simply restart with the `-q` parameter. --- Questions about the site --- Site title [My Nikola Site]: iSciMath: Integrated Science and Mathematics Site author [Nikola Tesla]: Michael McNeil Forbes Site authors e-mail [n.tesla@example.com]: cdlg.iscimath+admin@gmail.com Site description [This is a demo site for Nikola.]: iSciMath Website. Site URL [https://example.com/]: https://www.iscimath.org/ Enable pretty URLs (/page/ instead of /page.html) that do not need web server configuration? [Y/n] --- Questions about languages and locales --- We will now ask you to provide the list of languages you want to use. Please list all the desired languages, comma-separated, using ISO 639-1 codes. The first language will be used as the default. Type '?' (a question mark, sans quotes) to list available languages. Language(s) to use [en]: Please choose the correct time zone for your blog. Nikola uses the tz database. You can find your time zone here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones Time zone [Etc/UTC]: America/Los_Angeles Current time in America/Los_Angeles: 13:43:22 Use this time zone? [Y/n] --- Questions about comments --- You can configure comments now. Type '?' (a question mark, sans quotes) to list available comment systems. If you do not want any comments, just leave the field blank. Comment system: That is it, Nikola is now configured. Make sure to edit conf.py to your liking. If you are looking for themes and addons, check out https://themes.getnikola.com/ and https://plugins.getnikola.com/. Have fun! [2020-10-10 20:47:27] INFO: init: Created empty site at .. (blog) ~/repositories/iscimath_website$ tree . ├── conf.py ├── files ├── galleries ├── images ├── listings ├── pages └── posts 6 directories, 1 file
The main thing this does is create the
conf.py
file, which we should now commit to version control.(blog) ~/repositories/iscimath_website$ hg add adding .hgignore adding conf.py (blog) ~/repositories/iscimath_website$ hg com -m "Initial commit of Nikola-generated conf.py"
Content¶
Now we add some content. For demo purposes, we add simple markdown content from geometricanalysis.org.
-
First we create a repo for the assets, and download some images
mkdir -p ~/repositories/iscimath_website_assets cd ~/repositories/iscimath_website_assets hg init mkdir images wget https://images.squarespace-cdn.com/content/v1/5cb91b1c70468025fd21e98b/1555698446161-7CZZ16Y5BMUKXK4BXY15/ke17ZwdGBToddI8pDm48kHtOJuqdoEFYKNzpMbCdjQ1Zw-zPPgdn4jUwVcJE1ZvWQUxwkmyExglNqGp0IvTJZamWLI2zvYWH8K3-s_4yszcp2ryTI0HqTOaaUohrI8PI84wy8WKf6jeaYut84yuMMxu-RozL28G4_z9WCTpl1xsKMshLAGzx4R3EDFOm1kBS/events.jpg -O images/banner1.jpg wget https://images.squarespace-cdn.com/content/v1/5cb91b1c70468025fd21e98b/1555728634489-WHSXTS0E32WU1OHYS8Y6/ke17ZwdGBToddI8pDm48kNaADO1I1V8iOHJQMUQI2H1Zw-zPPgdn4jUwVcJE1ZvWQUxwkmyExglNqGp0IvTJZamWLI2zvYWH8K3-s_4yszcp2ryTI0HqTOaaUohrI8PIBCpzMMEguc8VVUBIRTMwFWs2R71F1SeBH0ohOKrYXboKMshLAGzx4R3EDFOm1kBS/upcomingevents.jpg -O images/ideas.jpg hg add hg commit -m "IMG: Added images"
-
Link this into our main repo
cd ~/repositories/iscimath_website mkdir _ext ln -s ~/repositories/iscimath_website_assets _ext/ rmdir images ln -s _ext/iscimath_website_assets/images . hg add images
-
Now create an index file. We can do this in a variety of formats, but ReStructuredText gives us more control than Markdown.
.. title: Center for Geometric Analysis and Data .. slug: index .. date: 2020-10-10 15:03:35 UTC-07:00 .. tags: .. category: .. link: .. description: .. type: text .. image:: images/banner1.jpg :width: 100% :alt: Alternative text The Center for Geometric Analysis and Data is the research group led by Kevin R. Vixie. As the name suggests, the research is focused on topics at the intersection of analysis and geometry as well as those suggested by challenges from data science or data generated by scientific questions. To find out more about Kevin and his circle of collaborators, visit the Group Members page, peruse the notes and papers, read the blog, or follow the links that abound throughout. EOF
At this point we now need to edit the conf.py
file to convert this to a website rather than a blog. We follow the process described here. The following was changed:
# Modified conf.py
...
# Website: remove destination directory to generate pages in the root directory
PAGES = (
("pages/*.rst", "", "page.tmpl"),
("pages/*.md", "", "page.tmpl"),
("pages/*.txt", "", "page.tmpl"),
("pages/*.html", "", "page.tmpl"),
)
...
# Website: we will provide our own index, so blog stuff goes here instead
INDEX_PATH = "blog"
Commit these changes:
hg add
hg com -m "Initial version of website."
Preview¶
Now you can build and view the page:
nikola auto -a 0.0.0.0 -p 8000
This will be hosted on CoCalc as described here as long as the nikola server is running. Only users authenticated to the CoCalc project can see it.
I have also put these commands into the Makefile, so one can do
make auto
Theming¶
To use my new themes, based on the zen-jinja theme, I needed to install that SASS plugin:
nikola plugin -i sass
and add the following to the conf.py
file:
# conf.py
...
NAVIGATION_LINKS = {
DEFAULT_LANG: (
('/index.html', 'Home', 'fa fa-home'),
('/archive.html', 'Archives', 'fa fa-folder-open'),
('/categories/index.html', 'Tags', 'fa fa-tags'),
('/rss.xml', 'RSS', 'fa fa-rss'),
('https://getnikola.com', 'About me', 'fa fa-user'),
('https://twitter.com/getnikola', 'My Twitter', 'fab fa-twitter'),
('https://github.com/getnikola', 'My Github', 'fab fa-github'),
)
}
...
# Compiler to process Sass files.
SASS_COMPILER = 'sass'
# A list of options to pass to the Sass compiler.
# Final command is: SASS_COMPILER SASS_OPTIONS file.s(a|c)ss
SASS_OPTIONS = []
Setup Blog (Old Version)¶
-
nikola init test_blog
- Answer the questions
-
Follow the instructions on http://www.damian.oquanta.info/posts/ipython-plugin-for-nikola-updated.html for setting up your blog to work with IPython notebooks:
nikola install_theme zen-ipython
-
Add the following to your
conf.py
file:NAVIGATION_LINKS = { # Specific for the zen-ipython theme DEFAULT_LANG: ( ('/index.html', 'Home', 'icon-home'), ('/archive.html', 'Archives', 'icon-folder-open-alt'), ('/categories/index.html', 'Tags', 'icon-tags'), ('/rss.xml', 'RSS', 'icon-rss'), ('http://getnikola.com', 'About me', 'icon-user'), ('https://twitter.com/getnikola', 'My Twitter', 'icon-twitter'), ('https://github.com/getnikola', 'My Github', 'icon-github'), ) } ... POSTS = ( # Keep only one so that ``nikola new_post`` defaults to ipynb #("posts/*.rst", "posts", "post.tmpl"), #("posts/*.txt", "posts", "post.tmpl"), ("posts/*.ipynb", "posts", "post.tmpl"), ) PAGES = ( ("stories/*.rst", "stories", "story.tmpl"), ("stories/*.txt", "stories", "story.tmpl"), ("stories/*.ipynb", "stories", "story.tmpl"), ) ... THEME = "zen-ipython"
Generating Metadata¶
I have a bunch of notebooks I want to "blog" but need to generate metadata. Here is some code to do this programatically from the file information.
import os.path
import time
import nikola.utils
POST_DIR = 'mmfblog/posts/'
all_files = os.listdir(POST_DIR)
new_posts = [_f for _f in all_files
if _f.endswith('.ipynb')
and _f[:-6] + ".meta" not in all_files]
_template = '''\
.. title: {title}
.. slug: {slug}
.. date: {date}
.. tags:
.. link:
.. description:
.. type: text
'''
TIME_FMT = '%Y-%m-%d %H:%M:%S %Z'
doit = True
for f in new_posts:
subs = {}
filename = os.path.join(POST_DIR, f)
title, ext = os.path.splitext(f)
slug = nikola.utils.slugify(unicode(title))
date = time.strftime(TIME_FMT, time.localtime(os.path.getmtime(filename)))
subs.update(title=title, slug=slug, date=date)
if slug != title:
new_filename = os.path.join(POST_DIR, slug+ext)
print("mv {0} {1}".format(filename, new_filename))
if doit:
os.rename(filename, new_filename)
meta_filename = os.path.join(POST_DIR, ".".join([slug, 'meta']))
meta = _template.format(**subs)
print meta
if doit:
with open(meta_filename, 'w') as _mf:
_mf.write(meta)
f = "mmfblog/posts/optimization.ipynb"
time.strftime(TIME_FMT, time.gmtime(os.path.getmtime(f)))
Updating Nikola¶
If you need the latest development version of Nikola, you can install form sources:
conda install notebook nbformat nbconvert pillow cloudpickle docutils lxml mako natsort python-dateutil requests unidecode
pip install git+https://github.com/getnikola/nikola.git webassets
I needed this before v7.3.1 to fix issue #1582.
Later I needed this before version v7.8.0 to deal with Ipython version 4.0 deprecations.
Later I needed this before this commit when sys.path
was not including the root directory (where I keep a module that needs to be imported.)
import IPython.nbformat
IPython.version_info
IPython.nbformat.read
from IPython.nbconvert.exporters import HTMLExporter
exportHtml = HTMLExporter()
with open('test_blog/posts/test.ipynb') as f:
nb_json = IPython.nbformat.reads(f.read(), IPython.nbformat.current_nbformat)
(body, resources) = exportHtml.from_notebook_node(nb_json)
MathJax¶
If you want to use LaTeX in your notebook, be sure to add the following to your conf.py
file.
# If you are using the compile-ipynb plugin, just add this one:
MATHJAX_CONFIG = """
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [ ['$','$'], ["\\\(","\\\)"] ],
displayMath: [ ['$$','$$'], ["\\\[","\\\]"] ],
processEscapes: true
},
displayAlign: 'left', // Change this to 'center' to center equations.
"HTML-CSS": {
styles: {'.MathJax_Display': {"margin": 0}}
}
});
</script>
"""
Comments¶
I am trying the Disqus comment system since this was recommended in the Nikola manual. I had to create a Disqus account, and then register a new site to get the shortname
. Some immediately apparent issues:
- Disqus puts a lot of things in a global namespace. For example, the username (my usual handle was already taken) and when registering a new site, you need to guess a unique identifier
<something>.disqus.com
.
Website¶
Nikola can also be used for a static website. Here is the list of packages and versions I used when doing this:
!conda list -n blog
$ nikola init forbes-group
Creating Nikola Site
====================
This is Nikola v7.8.3. We will now ask you a few easy questions about your new site.
If you do not want to answer and want to go with the defaults instead, simply restart with the `-q` parameter.
--- Questions about the site ---
Site title [My Nikola Site]: Forbes Group Website
Site author [Nikola Tesla]: Michael McNeil Forbes
Site author's e-mail [n.tesla@example.com]: m.forbes@wsu.edu
Site description [This is a demo site for Nikola.]: Forbes Group Research Site
Site URL [https://example.com/]: http://swan.physics.wsu.edu/forbes/
Enable pretty URLs (/page/ instead of /page.html) that don't need web server configuration? [Y/n]
--- Questions about languages and locales ---
We will now ask you to provide the list of languages you want to use.
Please list all the desired languages, comma-separated, using ISO 639-1 codes. The first language will be used as the default.
Type '?' (a question mark, sans quotes) to list available languages.
Language(s) to use [en]:
Please choose the correct time zone for your blog. Nikola uses the tz database.
You can find your time zone here:
https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
Time zone [America/Vancouver]:
Current time in America/Vancouver: 00:53:13
Use this time zone? [Y/n]
--- Questions about comments ---
You can configure comments now. Type '?' (a question mark, sans quotes) to list available comment systems. If you do not want any comments, just leave the field blank.
Comment system: disqus
You need to provide the site identifier for your comment system. Consult the Nikola manual for details on what the value should be. (you can leave it empty and come back later)
Comment system site identifier: forbes-group
That's it, Nikola is now configured. Make sure to edit conf.py to your liking.
If you are looking for themes and addons, check out https://themes.getnikola.com/ and https://plugins.getnikola.com/.
Have fun!
[2017-01-21T08:53:36Z] INFO: init: Created empty site at forbes-group.
Now version control the generated files:
cd forbes-group
hg init
hg add
hg com -m "Initial Commit"
We now switch the theme to zen-ipython
which requires installing some themes:
$ nikola install_theme zen-ipython
[2017-01-21T09:01:18Z] WARNING: Nikola: Cannot load theme "zen-ipython", using 'bootstrap3' instead.
[2017-01-21T09:01:18Z] INFO: theme: Downloading 'https://themes.getnikola.com/v7/zen-ipython.zip'
[2017-01-21T09:01:19Z] INFO: theme: Extracting 'zen-ipython' into themes/
[2017-01-21T09:01:19Z] NOTICE: theme: This theme has a sample config file. Integrate it with yours in order to make this theme work!
Contents of the conf.py.sample file:
NAVIGATION_LINKS = {
DEFAULT_LANG: (
('/index.html', 'Home', 'icon-home'),
('/archive.html', 'Archives', 'icon-folder-open-alt'),
('/categories/index.html', 'Tags', 'icon-tags'),
('/rss.xml', 'RSS', 'icon-rss'),
('https://getnikola.com', 'About me', 'icon-user'),
('https://twitter.com/getnikola', 'My Twitter', 'icon-twitter'),
('https://github.com/getnikola', 'My Github', 'icon-github'),
)
}
[2017-01-21T09:01:19Z] INFO: theme: Downloading 'https://themes.getnikola.com/v7/zen-jinja.zip'
[2017-01-21T09:01:19Z] INFO: theme: Extracting 'zen-jinja' into themes/
[2017-01-21T09:01:19Z] NOTICE: theme: This theme has a sample config file. Integrate it with yours in order to make this theme work!
Contents of the conf.py.sample file:
NAVIGATION_LINKS = {
DEFAULT_LANG: (
('/index.html', 'Home', 'icon-home'),
('/archive.html', 'Archives', 'icon-folder-open-alt'),
('/categories/index.html', 'Tags', 'icon-tags'),
('/rss.xml', 'RSS', 'icon-rss'),
('https://getnikola.com', 'About me', 'icon-user'),
('https://twitter.com/getnikola', 'My Twitter', 'icon-twitter'),
('https://github.com/getnikola', 'My Github', 'icon-github'),
)
}
[2017-01-21T09:01:19Z] NOTICE: theme: Remember to set THEME="zen-ipython" in conf.py to use this theme.
Organization¶
In addition to static content, I would like to have posts on my webpage describe research, projects, etc. These can be organized in "sections" by placing them in appropriate directories in posts
and then specifying the output directories in the POSTS
variable in conf.py
. One can then filter them, for example, with {% for post in posts if post.section_name().lower() == "highlights" %}
in a template.
I use this with a special template templates/research_highlights_list.tmpl
to format the research highlights on my index page.
Customization¶
Themes¶
Here we collect some notes about how themes work and can be customized. Themes are stored in the themes
directory. For example, themes/zen-ipython
. I have a separate repo for custom themes which I include in _ext/forbes_group_website_theme
and then link into the themes
.
A Nikola site can be customized in several ways:
-
conf.py
: Many customizations appear in this file, including some that might not be obvious:-
INDEX_READ_MORE_LINK
: This variable is used to customize the "Read more" link. We used this to modify these to look like a button matching the "Editorial" style. -
NAVIGATION_LINKS
: These appear in the side-bar, so you can specify the icons here (from Font Awesome if you use thezen-*
themes). -
POSTS
/PAGES
: Here you can specify which template files are used for posts and pages.
-
-
Modify the templates. To do this, I found it easiest to copy all of the inherited template files into a new theme's
template
directory so I can see what is happening. Here are some important templates:-
index.tmpl
: Used for the index page collecting your blog posts. -
post.tmpl
: Used for the individual blog posts. This can be selected inPOSTS
variable ofconf.py
. These can also be controlled in the actual posts with thetemplate
variable. -
story.tmpl
: Used for static pages. This can be selected inPAGES
variable ofconf.py
. These can also be controlled in the actual posts with thetemplate
variable.
-
zen-ipython
¶
This directory contains a file themes/zen-ipython/parent
that specify the parent theme - in this case themes/zen-jinja
. Thus, to find assets, etc. one might need to look in several places. Here is the full hierarchy for the themes/zen-ipython
theme:
themes/zen-ipython
themes/zen-jinja
-
themes/base-jinja
(locate files withnikola theme -g base-jinja
) -
themes/base
(locate files withnikola theme -g base
)
The last two are pre-installed themes whose location on disk can be found using the specified command. I copied them into my site folder for easy reference.
Icons¶
The zen-ipython
theme uses icons from Font Awesome. To see the available icons and names, look at the icon list for the appropriate version (version 3.2.1 here). You can then specify the appropriate fonts in conf.py
.
Less/Sass¶
The zen themes use [less
], which they tell you in the Readme.md
file can be enabled by setting USE_BUNDLES = False
in conf.py
after installing the lessc
compiler and nikola plugin -i less
, however, you also need to rename/remove themes/zen-jinja/assets/css/main.cssmain.css
file or else you will get the following error (since it is also built with lessc
...)
ERROR: Two different tasks can't have a common target.'output/assets/css/main.css' is a target for copy_assets:output/assets/css/main.css and build_less:output/assets/css/main.css.
Targets for less
are specified in the file themes/zen-jinja/less/targets.
I am using a custom theme which provides sass
stylesheets. This requires installing the sass
compiler and then one can use the sass
plugin to generate appropriate CSS files. This theme was inheriting from the zen-jinja
theme and so the main.css
file was clashing with the previous file specified in themes/zen-jinja/less/targets. To resolve this, I added a custom less directory in the new theme with an empty themes/html5up-editorial/less/targets
file.
Jinja2¶
Here are some tips for working with Jinja2 (see the references section below for details.)
- You can see the value of variables using code like this:
{{ post.tags|pprint }}
or if you need to{{ post.__dict__.keys()|pprint }}
.
Images¶
One issue I had is how to include images in posts. The usual approach for notebooks is to include the images in a file relative to the notebook. For example, if the files are in a folder images
then one can refer to this as
![Image](images/eli-francis-100644.jpg)
There are two issues with this approach:
- Nikola will not copy these images to the output. This can be overcome by storing the files in the
images
folder at the root of your project, and then specifying where these should appear in the output by specifyingIMAGE_FOLDERS = {'images': 'images'}
(the default value) in yourconf.py
file. You can then symlink this file to your posts directory. -
The second issue is that this image will produce a link like this in the output:
/highlights/prerequesites/images/eli-francis-100644.jpg
I.e. this is a link relative to the post which would require a complicated set of non-standard
IMAGE_FOLDERS = {'images': 'images'}
mappings.
The standard Nikola solution is to place the images in a images/
folder in the top level of your project as above with IMAGE_FOLDERS = {'images': 'images'}
in your conf.py
file. Then refer with an absolute address:
![Image](/images/eli-francis-100644.jpg)
Unfortunately, this breaks in the notebook rendering which cannot see higher-level directories. For example, if you start the Jupyter notebook server in the same directory as the post, then one would have to use the following absolute path in the notebook in order to see the image:
![Image](/tree/images/eli-francis-100644.jpg)
This location could then be hacked with Nikola using IMAGE_FOLDERS = {'images': 'tree/images'}
.
Solutions¶
I see three possible solutions:
-
Use the modified "tree" hack above:
-
Place images in
images/eli-francis-100644.jpg
-
Symlink this to an images folder next to your posts.
-
Refer to your images as
![Image](/tree/images/eli-francis-100644.jpg)
-
Use the following mapping in your
conf.py
file:IMAGE_FOLDERS = {'images': 'tree/images'}
-
-
Mirror the structure of your posts in your images directory. For example, if your posts are in
posts/highlights/my_post.ipynb
, then:-
Place images in
images/highlights/my_post/images/eli-francis-100644.jpg
-
Symlink these images to your posts directory:
link -s ../../images/highlights/my_post/images .
-
Refer to images with a relative path:
![Image](images/eli-francis-100644.jpg)
-
Map the images to the root level so they are included in the relative path:
IMAGE_FOLDERS = {'images': ''}
-
-
Use the Nikola recommend approach of linking to an absolute path and extend the jupyter notebook server to properly redirect these requests.
-
Place images in
images/eli-francis-100644.jpg
-
Refer to your images using an absolute path
![Image](/images/eli-francis-100644.jpg)
-
Run
jupyter notebook
from the top level (whereimages
is) after installing and loading my notebook server extension mmf_nikola_nbserver_extension (this is done in the filejupyter_notebook_config.py
:pip install -e mmfsite/mmf_nikola_nbserver_extension jupyter serverextension enable mmf_nikola_nbserver_extension
-
I am presently using the last approach.
Notebook Conversion¶
The notebooks are converted to HTML through the nbcovert
process. This can be customized through templates or providing plugins.
-
The
'IPYNB_CONFIG'
variable inconf.py
is passed to theHTMLExporter
. To see possible options, runjupyter nbconvert --help-all
. For example, I have added a preprocessormmf_nikola_nbserver_extension.ArXivLinks
which replaces references to preprints with a URL. This is enabled as follows inconf.py
:IPYNB_CONFIG = {
'Exporter': { 'preprocessors': ['mmf_nikola_nbserver_extension.ArXivLinks'] }
}
Plugins¶
Sometimes you just can't seem to do what you want with the existing tools. One way of extending Nikola is to use a plugin. First check the Nikola Plugins to see if you can find something, otherwise you can create your own in the plugins
directory. To add a simple reStructuredText directive, for example, you can install and copy the book_figure plugin, which is a fairly simple plugin that creates a book_figure
directive:
nikola plugin -i book_figure
mv plugins/book_figure plugins/mmf
then edit the plugin.
There are also some useful plugins: here is a list of the plugins I sometimes use:
nikola plugin -i less
nikola plugin -i sass
nikola plugin -i localsearch
References¶
People who have customized Nikola and describe the process:
-
How I customized my Nikola-powered site: A nice discussion about customizing a website powered with Nikola. Based on the
ipython
theme. - Blogging with Nikola + Ipython + Git(Hub)
Official Documentation:
- Creating a Site (Not a Blog)
- Nikola Theming
- Nikola Internals Describes the type of data available for use in templates etc.
Jinja Templating:
Some nice HTML and CSS templates:
- HTML5 UP: Some nice, responsive, and clean HTML and CSS templates. We have tried to massage one of these into a website.