In [1]:
%load_ext notexbook
In [2]:
%texify -v
Out[2]:
The notebook is using no$\TeX$book Jupyter Theme (release 2.0.1).
Theme Settings:
  • Notebook: Computer Modern font; 16px; Line spread 1.4.
  • Code Editor: Fira Code font; 14px; Material Theme.
  • Markdown Editor: Hack font; 14px; Material Theme.

First things first: Thank you so much for getting here (whatever is your referral URL)

Valerio 🤗

noTeXbook logo

This notebook introduces the $\text{no}\TeX\text{book}$ Jupyter Notebooks theme.

In the next two sections, we will start with a quick overview spoiler of the theme's main typesetting features, then we will dive into all of its very nuts and bolts, including Editor Colour Themes, ad-hoc formattings, monospace fonts, and much more.

$\text{no}\TeX\text{book}$ shall be thy name

When I had to come up with a name for the theme, I aimed almost immediately at finding a single word that would convey the idea of integration of the Jupyter notebooks with $\LaTeX$ I had in mind. Indeed, no$\TeX$book seemed quite an obvious choice: this name is a unique portmanteau1 that blends together the words noTeXbook, and noTeXbook, that is the original name of Donald E. Knuth's book on $\TeX$.

That was the omen! One!... Two!... Five! 2

The $\text{no}\TeX\text{book}$ theme wishes to pay a tribute of gratitude to two of the technologies I do use and love the most as a researcher and a data scientist.

**[1]**: `port·​man·​teau | \ pȯrt-ˈman-(ˌ)tō` **[2]**: [The Holy Hand Granade](https://www.youtube.com/watch?v=xOrgLj9lOwk) - Monthy Python and the Holy Grail

$\text{no}\TeX\text{book}$ Theme in a Nutshell

  • Notebook typesetting based on Computer Modern fonts;
    • Code editor uses `Fira Code` font, with ligatures support;
    • Markdown editor uses `Hack` font (slightly better for text writing, ed.);
  • Colour themes with syntax highlighting for Code and Markdown editors
    • easy to personalise and extend (via CSS variables)
  • Highly customisable settings via IPython Magic arguments (%texify? to see all available options)
  • Complete support for Jupyterlab and Jupyter Notebooks (version 2.0x);
    • (Extra) Support for Google Colab Notebooks via Stylus) (Firefox & Chrome) browser extension;
  • Special Output formatting for stderr and pandas.DataFrame;
  • Extra CSS classes for additional LaTeX-ish formatting use cases (e.g. footnotes, dropcap).

Moreover, the theme also includes a few tweaks to the general Notebook/Jupyterlab UI: the colours of all the icons and Kernel status indicators uses the theme's main palette, and a special emphasising effects is applied on active cell in either command or edit modes, as well as on multiple cells selections.



Colour Palette

In [3]:
import numpy as np
import cv2
import matplotlib as mpl
import matplotlib.pyplot as plt

# Matplotlib Configuration Params
%matplotlib inline
%config InlineBackend.figure_format = 'retina'

mpl.rcParams['figure.figsize'] = (18,1)
In [4]:
# Color Palette
colours = {"red": "#d43133", 
           "magenta" : "#D14187", 
           "torquoise" : "#009489",
           "azure": "#00afde", 
           "blue": "#2875d9",
           "light-grey": "#828282", 
           "dark-grey": "#383838",
           "yellow": "#f9ab00",
           "orange": "#e8710a",
          }
In [5]:
def hex2rgb(h: str):
    """helper to convert hex colours into RGB tuple"""
    h = h.lstrip('#')
    return tuple(int(h[i:i+2], 16) for i in (0, 2, 4))

# Create a black image
image = np.full((1024,1024,3), 255, np.uint8)

def show_palette(colours):
    n_cols = len(colours)
    fig = plt.figure()
    for i, (colour, hexcode) in enumerate(sorted(colours.items(), key=lambda e: hex2rgb(e[1]))):
        axis = fig.add_subplot(1,n_cols,i+1)
        rgb = hex2rgb(hexcode)
        cv2.circle(image, (512, 512), 512, (rgb[0], rgb[1], rgb[2]), -1)
        plt.title(colour, y=-0.5)
        plt.axis('off')
        plt.imshow(image);
        
show_palette(colours)

The theme main colour palette is based on these main 7 colours.

These colours can also be used in special formattings for text colouring using ad-hoc CSS classes (all following the same naming rule): .texbook-<COLOUR NAME>

$\rightarrow$ Turquoise; Azure; Blue; Dark Grey; Light Grey; Magenta; Red; Orange; Yellow $\leftarrow$

$\uparrow$ top


Fonts and Typeface

All the fonts used in the $\text{no}\TeX\text{book}$ theme typeface design are open source, freely available on public font repositories (e.g., Google Fonts, CDN Fonts, FontSquirrel), and released under the OFL (Open Font License), and alike. Original reference and download links are provided below.

$\text{no}\TeX\text{book}$ typeface

The main goal of the $\text{no}\TeX\text{book}$ theme is to allow Jupyter notebooks to render like a $\LaTeX$-generated article. Therefore, the (Markdown) text rendering adopts the good ol' Computer Modern font family for both serif and monospace text (i.e. CMUSerif and CMUTypewriter fonts, respectively).

In edit mode, the Hack font is used for Markdown editor, whereas Fira Code font is used for code editor. The former looks slightly better for text writing (imho), being also based on the Bitstream Vera and the DejaVu fonts. Fira Code on the other hand has been specifically designed for source code, combining a clean and elegant style with ligratures support3.

**[3]**: Support for ligatures in the Markdown editor would be quite pointless, as the cell will be ultimately rendered in Computer Modern font.

Notebook UI

The font used for everything else in the Notebook UI and look-and-feel (e.g. header, navbar, jupyter-server home page (notebook list) uses the Roboto Slab font.

Font References and Links

Font Format Reference License Download
Computer Modern OpenType (otf) tug.org SIL OFL Link
Hack TrueType (ttf) Github MIT Link
Fira Code OpenType (otf) Github SIL OFT Link
Roboto Slab OpenType (otf) Google Fonts Apache License, v2.0 Link

$\uparrow$ top


Markdown

(Miscellaneous of text formatting and emphasis - adapted from Markdown Cheatsheet) - License: CC-BY

Emphasis, aka italics, with asterisks or underscores.

Strong emphasis, aka bold, with asterisks or underscores.

Combined emphasis with asterisks and underscores, also for bold italic mono

Mono blocks are supported too.

Strikethrough uses two tildes, colored in red: Scratch this.

Headers

Part (h1)

Chapter (h2)

Section (h3)

Subsection (h4)

Subsubsection (h5)
Paragraph (h6)

Lists

  • First item
  • Second item
    • Third item
      • Another level
  1. First ordered list item
  2. Another item with mono
    • Unordered sub-list.
  3. Actual numbers don't matter, just that it's a number
    1. Ordered sub-list
  4. And another item.

Tables

Tables Are Cool
col 3 is right-aligned \$1600
col 2 is centered \$12
zebra stripes are neat \$1

Blockquotes and Monospace Paragraphs

Blockquotes are very handy in email to emulate reply text. This line is part of the same quote.

This paragraph will be using monospace font.

$\uparrow$ top

Code Highlighting

Special mention goes to code syntax highlighting support in Markdown cells: they will still be using the default CMUTypewriter monospace font, but they will also share the same colour scheme used for code cells (more on this in the Code Editor Section).

For example:

// Javascript Highlighting
var x = 3.14;    // A number with decimals
var y = 3;       // A number without decimals
# Python highlighting
import antigravity
from __future__ import barry_as_FLUFL  # PEP401
echo "Shell syntaxt highlighting"

$\uparrow$ top

Math

Math and $LaTeX$ text style integration is supported (via MathJax) both in inline and block modes.

Inline math: $ X^2 + 1 = 1 $ works fine.

Math block:

$$ X^2 + 1 = 1 $$

Some more Math examples taken from Latex/Advanced Mathematics:

$$ \begin{equation} f(x)=(x+a)(x+b) \end{equation} $$$$ \begin{equation} L' = {L}{\sqrt{1-\frac{v^2}{c^2}}} \end{equation} $$

Maxwell's equations: $$ \begin{equation} \left.\begin{aligned} B'&=-\partial \times E,\\ E'&=\partial \times B - 4\pi j, \end{aligned} \right\} \qquad \text{Maxwell's equations} \end{equation} $$

Factorials and Binomials: $$ \frac{n!}{k!(n-k)!} = \binom{n}{k} $$

fraction within a fraction $$ \frac{\frac{1}{x}+\frac{1}{y}}{y-z} $$

Limits: $$ \begin{equation} \lim_{a\to \infty} \tfrac{1}{a} \end{equation} $$

Math formulas with comments:

$$ [ y = a + f(\underbrace{b x}_{ \ge 0 \text{ by assumption}}) = a + f(\underbrace{b x}_{ \ge 0 \text{ by assumption}}) ] $$

gather: Consecutive equations without alignment $$ \begin{gather*} a_0=\frac{1}{\pi}\int\limits_{-\pi}^{\pi}f(x)\,\mathrm{d}x\\[6pt] \begin{split} a_n=\frac{1}{\pi}\int\limits_{-\pi}^{\pi}f(x)\cos nx\,\mathrm{d}x=\\ =\frac{1}{\pi}\int\limits_{-\pi}^{\pi}x^2\cos nx\,\mathrm{d}x \end{split}\\[6pt] \begin{split} b_n=\frac{1}{\pi}\int\limits_{-\pi}^{\pi}f(x)\sin nx\,\mathrm{d}x=\\ =\frac{1}{\pi}\int\limits_{-\pi}^{\pi}x^2\sin nx\,\mathrm{d}x \end{split}\\[6pt] \end{gather*} $$

alignat: Allows control of the horizontal space between equations. $$ \begin{alignat}{2} \sigma_1 &= x + y &\quad \sigma_2 &= \frac{x}{y} \\ \sigma_1' &= \frac{\partial x + y}{\partial x} & \sigma_2' &= \frac{\partial \frac{x}{y}}{\partial x} \end{alignat} $$

$\uparrow$ top

Extras

In addition to standard Markdown integration, the $\text{no}\TeX\text{book}$ theme provides extra CSS classes to allow for additional $\LaTeX$-ish formatting, and extra typesetting for notebooks:

  1. Footnotes
  2. Drop Cap
  3. Image Width
  4. Badges
  5. Inline Math
  6. Inline Mono

1. Footnotes

Any HTML link targeting a bookmark or an anchor including fn (as in footnote) in their name will be automatically interpreted as links to a footnote. For example:

[1](#fnlink)

The above link will be automatically rendered as superscript and within square-brackets1

To actually generate the footnote text, every HTML tag mapped to an id starting with fn (or alternatively using the fn class) will be automatically formatted as footnote text. Footnote symbol should be emphasised in bold:

<span id="fnlink"><b>[1]:</b> This is an example of a footnote</span>

[1]: This is an example of a footnote

2 Drop Cap

A special class to display a drop cap could not be missing in the $\text{no}\TeX\text{book}$ theme.

It is just required to use the drop CSS class:

<span class="drop">O</span>nce upone a time...

Once upone a time...

3. Image Width

As default, the max-width of images (and SVG) is automatically capped at the 70% to allow for a proper rendering of large images, whilst avoiding any potential overflow.

Nonetheless, there may be cases in which it would be required to control the max-width parameter in order to enlarge or shrink an image. Special CSS classes are available controlling the max-width attribute of displaying images.

All this classes share the same name prefix (i.e. .maxw) followed by the corresponding ma-width expressed as percentage value. The list of available CSS Classes is:

>>> [f"maxw{i}" for i in range(5, 101, 5)]
['maxw10', 'maxw15', 'maxw20', 'maxw25', 'maxw30', 'maxw35', 'maxw40', 'maxw45', 'maxw50', 
 'maxw55', 'maxw60', 'maxw65', 'maxw70', 'maxw75', 'maxw80', 'maxw85', 'maxw90', 'maxw95', 
 'maxw100']

Examples:

<!-- max-width: 10% -->
<img [...] class="maxw10" />

<!-- max-width: 35% -->
<img [...] class="maxw35" />

4. Badges

The theme also defines special classes to include badges.

This may turn out to be particularly useful in notebooks to include links to external services like Google Colab, MyBinder, or NBViewer,

In order to do so, the theme provides the CSS class .badges that can be used in a Markdown cell:

<div class="badges"> ... </div>

Here is an example:

[![Colab](https://colab.research.google.com/assets/colab-badge.svg)]() [![myBinder](https://mybinder.org/badge_logo.svg)]() [![nbviewer](https://raw.githubusercontent.com/jupyter/design/master/logos/Badges/nbviewer_badge.svg)]()

5. Inline Math

The inline-math CSS class forces to display inline Math blocks. This may be particularly useful in cases we do want to use the $\LaTeX$ Math-block environment to write equation, but we do not want to have it displayed in a separate paragraph:

$$ \sum_{i=1}^{N} x_i^2 $$

To do so, let's just wrap the equation with a span HTML tag with class .inline-math:

<span class="inline-math">... </span>

This equation will be displayed inline: $$ \sum_{i=1}^{N} x_i^2 $$

6. Inline Mono

The default monospace font used in Markdown Cell rendering is CMUTypewriter, that is the monospace font of the Computer Modern Family. However, the $\text{no}\TeX\text{book}$ theme also utilises two additional monospace fonts (for Code and Markdown editors), and sometimes it may also be required to use any of these fonts in rendered text.

To do so, the theme provides two special CSS classes, namely .codemono and .mdmono that will serve exactly this purpose.

The example below demonstrates how to force the rendering of the following inline mono using code editor font

<span class="codemono">`Code Monospace Font` with Ligatures **support** `--> >= !=`</span>

`Code Monospace Font` with Ligatures **support** `--> >= !=`

Code Sample

Here is how Python code looks like in $\text{no}\TeX\text{book}$ theme.

The following code excerpt has been taken from the PyTorch code base (source)

In [6]:
class Dataset(object):
    r"""An abstract class representing a :class:`Dataset`.
    All datasets that represent a map from keys to data samples should subclass
    it. All subclasses should overwrite :meth:`__getitem__`, supporting fetching a
    data sample for a given key. Subclasses could also optionally overwrite
    :meth:`__len__`, which is expected to return the size of the dataset by many
    :class:`~torch.utils.data.Sampler` implementations and the default options
    of :class:`~torch.utils.data.DataLoader`.
    .. note::
      :class:`~torch.utils.data.DataLoader` by default constructs a index
      sampler that yields integral indices.  To make it work with a map-style
      dataset with non-integral indices/keys, a custom sampler must be provided.
    """

    def __getitem__(self, index):
        raise NotImplementedError

    def __add__(self, other):
        return ConcatDataset([self, other])

    # No `def __len__(self)` default?
    # See NOTE [ Lack of Default `__len__` in Python Abstract Base Classes ]
    # in pytorch/torch/utils/data/sampler.py

Code Editor

The CSS style for code and markdown editor integrated in $\text{no}\TeX\text{book}$ adopts a strategy that aims at flexibility and extensibility.

The main style file for code editors is editors.css. This file imports each theme for both code and markdown editors. The themes for the two editors are defined in two different files, to allow for maxmimum flexibility in the choice of the colours schemes to adopt.

In each theme file, the base colour palette is defined, along with the mapping of each of these colours to specific (editor) variables. These variables are then used to define the CSS style rules.

In this way, it is very easy to change or try multiple themes, or even defining custom new ones.

The default colour scheme used for code and markdown editor is based on the Material Design Light Theme. In addition, other editor themes are bundled with the $\text{no}\TeX\text{book}$ Jupyter theme, e.g. GitHub Light for code, Typora theme for markdown.

The base colour palettes for each of those themes are showed below.

(Code & Markdown) Material Design Light Theme (material)

The default colour palette used for both Code and Markdown editors is inspired by the Material Design Light Theme.

The colour palette is declined on 12 colours, reported below:

In [7]:
material_code_colours = {
    "light-white": "#FAFAFA",
    "black": "#212121",
    "dark-blue" : "#01579B11",
    "dark-blue-2": "#01579B22",
    "blue": "#1565C0",
    "green": "#2E7D32",
    "yellow": "#A8601A",
    "cyan": "#00838f",
    "magenta": "#9C00B0",
    "red": "#C0392B",
    "grey": "#9E9E9E",
    "light-blue": "#78909c"
}

show_palette(material_code_colours)

The Markdown editor uses only a subset of those colours. In particular:

In [8]:
material_md_colours = {
    "black": "#212121",
    "dark-blue" : "#01579B11",
    "blue": "#1565C0",
    "yellow": "#A8601A",
    "red": "#C0392B",
    "grey": "#9E9E9E",
    "light-blue": "#78909c"
}

show_palette(material_md_colours)

(Code only) GitHub Theme (github)

This theme builds on the new code editor theme available on GitHub.

In [9]:
github_code_colours = {
    "white": "#fafafa",
    "red": "#d65b67",
    "orange": "#df7b41",
    "yellow": "#f5e17b",
    "blue": "#0259be",
    "dark-blue": "#053060",
    "black": "#24292e",
    "azure": "#c0d8f4",
    "grey": "#868c94",
    "light-grey": "#b3b4b6",
    "purple": "#724abd",
}

show_palette(github_code_colours)

(Code only) GitHub Light Theme (github-light)

The GitHub Light theme is an alternative theme inspired by the (previous) GitHub light theme.

Reference: Github Syntax Highlighting

In [10]:
github_code_colours = {
    "dark-grey": "#505050",
    "grey": "#b8b8b8",
    "light-grey": "#6a737d",
    "lighter-grey": "#e2e2e2",
    "antrax": "#24292e",
    "red": "#d73a49",
    "orange": "#e36209",
    "dark-orange": "#f14c00",
    "purple": "#6f42c1",
    "light-yellow": "#fff9eb",
    "yellow": "#ffea7f",
    "blue": "#005cc5",
    "dark-blue": "#032f62",
    "green": "#22863a"
}

show_palette(github_code_colours)

(Code only) Crisp Light Theme (crisp)

The colour palette of the Crisp Light editor theme is inspired by the Crisp light theme included in the Rainglow collection of VSCode Themes

Reference: https://github.com/rainglow/vscode/

In [11]:
crisp_code_colours = {
    "lilac": "#c6a7c6",
    "black": "#221a22",
    "grey": "#b8b8b8",
    "yellow": "#fc9a0f",
    "dark-orange": "#fc6a0f",
    "purple": "#765478",
    "dark-purple": "#4f3c4f",
    "light-purple": "#99769b",
    "red": "#cf433e"
}

show_palette(crisp_code_colours)

(Markdown only) Typora Theme (typora)

This theme is inspired by the default (markdown) source code visualiser available built-in in Typora*

*: Typora is definitely my default editor for Markdown! Highly recommended $\rightarrow$ [typora.io](http://typora.io)

In [12]:
typora_md_colours = {
    "pink": "#d14187",
    "dark-grey": "#383838",
    "darker-grey": "#333333",
    "taupe": "#a99f9f",
    "light-orange": "#be7716",
    "light-red": "#a34343",
    "grey-blue": "#48599b",
    "dark-bg": "#252a2f",
    "dirty-white": "#8d8e8f"
}

show_palette(typora_md_colours)

Dataframe

The look and feel of dataframes (tables) is slightly changed.

I've chosen a post-it note color for the table background so that dataframe output standsout, especially when scrolling through a long notebook.

In [13]:
from sklearn.datasets import load_iris
import pandas as pd 


iris = load_iris()
iris_df = pd.DataFrame(data= np.c_[iris['data'], iris['target']], 
                       columns= iris['feature_names'] + ['target'])
iris_df.head()
Out[13]:
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) target
0 5.1 3.5 1.4 0.2 0.0
1 4.9 3.0 1.4 0.2 0.0
2 4.7 3.2 1.3 0.2 0.0
3 4.6 3.1 1.5 0.2 0.0
4 5.0 3.6 1.4 0.2 0.0

Errors and Exceptions

In [14]:
from wherever import non_existing_module
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-14-40a1e5a99230> in <module>
----> 1 from wherever import non_existing_module

ModuleNotFoundError: No module named 'wherever'
In [15]:
from scipy import linalg
linalg.det(np.ones((3, 4)))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-15-5162a496210c> in <module>
      1 from scipy import linalg
----> 2 linalg.det(np.ones((3, 4)))

~/anaconda3/envs/notexbook-test/lib/python3.9/site-packages/scipy/linalg/basic.py in det(a, overwrite_a, check_finite)
   1018     a1 = _asarray_validated(a, check_finite=check_finite)
   1019     if len(a1.shape) != 2 or a1.shape[0] != a1.shape[1]:
-> 1020         raise ValueError('expected square matrix')
   1021     overwrite_a = overwrite_a or _datacopied(a1, a)
   1022     fdet, = get_flinalg_funcs(('det',), (a1,))

ValueError: expected square matrix

Extensions

JupyterLab (and HTML export)

Jupyter Lab is fully supported!

Moreover: the latest versions of jupyter-nbconvert apply the lab template as default HTML template for export. This generates a DOM structure which is compliant with Jupyter Lab.

Here is an example of this notebook exported with lab template $\Rightarrow$ Jupyter Lab Light

custom.css Jupyter theme

The $\text{no}\TeX\text{book}$ theme is also available as a full-fledged custom Jupyter notebook theme (HTML/CSS). This is useful in case one would prefer to enable the theme as the global custom default Jupyter theme.

The noTeXbook theme package is available for download, along with its corresponding documentation.

The documentation also contains details on the original CSS design, and instructions on how to define your own CSS Editor Colour theme.

Google Colaboratory

The HTML of a Colaboratory notebook is nothing similar to the standard Jupyter notebook/lab HTML structure (so the custom-css cannot work). In addition, every single Colaboratory notebook cell generates a new HTML iframe, so making the texify IPython magic pretty much useless too.

Therefore, the only solution I could resort to was using the Stylus) browser extension. Unfortunately this is not as customisable and portable as the IPython magic, but hey?! Better than nothing 🤓

All the instructions on how to install $\text{no}\TeX\text{book}$ for Google Colaboratory Notebooks are available $\Rightarrow$ here) on the branch specifically dedicated to the Colab version of the theme.

Once you are done, try to open the sample notebook in Colab, and enjoy 🙌

Open In Colab


Credits

  • The spinzero jupyter theme has been inspirational in the design of the early version of this theme;
  • The idea of overlay of selected cells has been inspired from this custom theme.
  • Inspiration on the choice of Monospace fonts for code and markdown has come from this article
  • Original versions of colour themes for code and markdown editors:

(Some links I found useful along the way):

Acknowledgments

Special thanks to cdesio, ninadicara, and alanderex for testing earlier versions of the theme!