Theming IPython

See the IPython NBViewer version of this post

IPython is an awesome tool, but I've found that figuring out how to customize the look and feel of the notebook isn't easy. My goal here is to demonstrate how you can customize the look of your notebooks using a single .css file and use that theme wherever your notebooks go.

Customizing the Notebook

First, to make sure that the required CSS files are created, follow the instructions here.

The interactive notebook has a CSS override file hidden inside of your IPython profile (if you don't know how to locate it, run ipython locate) located at:


or on unix-based systems:


Anything inside this file gets priority over the default IPython theme and any CSS modifications made in this tutorial are saved inside of that file.

Fixing the Typography

There's a great tutorial on updating the IPython typography by here.

I used this tutorial in creating my own CSS theme with a few tweaks (mostly fonts and muting a few interface elements). Here's the code that I used for styling the typography of my own notebook:

@import url('');
@import url('');
@import url(',300,400');
@import url('');

/* Change code font */
.CodeMirror pre {
    font-family: 'Source Code Pro', Consolas, monocco, monospace;

div.input_area {  
    border-color: rgba(0,0,0,0.10);
    background: rbga(0,0,0,0.5);

div.text_cell {  
    max-width: 105ex; /* instead of 100%, */

div.text_cell_render {  
    font-family: "Crimson Text";
    font-size: 12pt;
    line-height: 145%; /* added for some line spacing of text. */

div.text_cell_render h1,  
div.text_cell_render h2,  
div.text_cell_render h3,  
div.text_cell_render h4,  
div.text_cell_render h5,  
div.text_cell_render h6 {  
    font-family: 'Kameron';
    font-weight: 300;

div.text_cell_render h1 {  
    font-size: 24pt;

div.text_cell_render h2 {  
    font-size: 18pt;

div.text_cell_render h3 {  
    font-size: 14pt;

.rendered_html pre,
.rendered_html code {
    font-size: medium;

.rendered_html ol {
    margin: 1em 2em;

Changing the Interface

Next, I wanted to flatten out the look of the interface. Knowing that IPython uses Bootstrap makes modifying things easier, and the rest can be done just using the Google Chrome developer tools.

Here are the tweaks that I thought were important for making my notebook mine:

  • Flatten the toolbar at the top
    • Flatten buttons
    • Remove gradients
    • Make fonts less distracting
  • Mute cells visually
    • Reduce border
    • Reduce colours (use drop shadow for selected cell
    • Mute input prompt

Here's the remainder of my customization code:

.prompt.input_prompt {
    color: rgba(0,0,0,0.5);

.cell.command_mode.selected {
    border-color: rgba(0,0,0,0.1);

.cell.edit_mode.selected {
    border-color: rgba(0,0,0,0.15);
    box-shadow: 0px 0px 5px #f0f0f0;
    -webkit-box-shadow: 0px 0px 5px #f0f0f0;

div.output_scroll {  
    -webkit-box-shadow: inset 0 2px 8px rgba(0,0,0,0.1);
    box-shadow: inset 0 2px 8px rgba(0,0,0,0.1);
    border-radious: 2px;

#menubar .navbar-inner {
    background: #fff;
    -webkit-box-shadow: none;
    box-shadow: none;
    border-radius: 0;
    border: none;
    font-family: lato;
    font-weight: 400;

.navbar-fixed-top .navbar-inner,
.navbar-static-top .navbar-inner {
    box-shadow: none;
    -webkit-box-shadow: none;
    border: none;

div#notebook_panel {  
    box-shadow: none;
    -webkit-box-shadow: none;
    border-top: none;

div#notebook {  
    border-top: 1px solid rgba(0,0,0,0.15);

#menubar .navbar .navbar-inner,
.toolbar-inner {
    padding-left: 0;
    padding-right: 0;

#autosave_status {
    color: rgba(0,0,0,0.5);

#header {
    font-family: lato;

#notebook_name {
    font-weight: 200;

    This is a lazy fix, we *should* fix the 
    background for each Bootstrap button type
#site * .btn {
    background: #fafafa;
    -webkit-box-shadow: none;
    box-shadow: none;

Customizing CSS in NBViewer

In NBViewer (and notebooks) I haven't yet found an elegent way to customize CSS. There is a popular but ugly/dangerous way which involves injecting custom css into each cell. Even the solution I'm posting here I think is poor for the reasons given here; it's likely to break on future versions and is tedious to insert.

My current working solution was borrwed from Cam DP and his book Bayesian Methods for Hackers. The idea is that if there is a <style> tag in IPython, the notebook renders it and NBViewer also renders it. I modified Cam's code to use the default IPython profile's custom.css file.

Just run the following code snippet in the bottom of any IPython notebook:

from IPython import utils  
from IPython.core.display import HTML  
import os  
def css_styling():  
    """Load default custom.css file from ipython profile"""
    base = utils.path.get_ipython_dir()
    styles = "<style>\n%s\n</style>" % (open(os.path.join(base,'profile_default/static/custom/custom.css'),'r').read())
    return HTML(styles)

There is one curious feature in the code for NBVeiwer. This code actually checks the notebook metadata (which is nice and clean) and looks for a css theme (a specified css file, but only in the servers /static/css/theme/ directory. The unfortunate part of this is that you can only use Cam's theme from Bayesian Methods or one other linear algebra notebook theme (cdp_1.css or css_linalg.css respectively, and you need to remove the .css bit when specifying a theme).

Theming NBConvert

Making NBConvert do what you want is one of the trickiest bits about theming IPython. Again, the above code snippet makes NBConvert do exactly what we wanted. You can also specify a custom.css file in the directory that you export your notebooks in and that file will automatically overwrite default styles.

Creating an NBConvert theme is a little bit more involved. NBConvert uses Jinja2 for templates. I'm not going to get into creating NBConvert templates right now because I think the default battery is pretty good for most cases. Minrk has some great examples of how to create a template here. When creating a template you don't always need the config file each time, just the .tpl file and specifying the output format.

The command needed to generate from a custom NBConvert is (from the directory containing custom_template):

ipython nbconvert --template custom_template.tpl <notebook>  

followed by:

ln ~/.ipython/profile_default/static/custom/custom.css ./custom.css  

This will convert your notebook and create a symbolic link (again, unix-based only) so that your nbconverted notebooks will change when you modify your profile's custom.css file.