136

The documentation at http://ipython.org/ipython-doc/stable/interactive/notebook.html says

You can provide a conceptual structure for your computational document as a whole using different levels of headings; there are 6 levels available, from level 1 (top level) down to level 6 (paragraph). These can be used later for constructing tables of contents, etc.

However, I can't find instructions anywhere on how to use my hierarchical headings to create such a table of contents. Is there a way to do this?

NB: I'd also be interested in other kinds of navigation using ipython notebook headings, if any exist. For instance, jumping back and forward from heading to heading in order to quickly find the start of each section, or hiding (folding) the contents of an entire section. This is my wish-list - but any kind of navigation at all would be of interest. Thanks!

joelostblom
  • 25,984
  • 12
  • 108
  • 120
user2428107
  • 2,116
  • 2
  • 15
  • 17
  • 1
    see @Nikolay 's answer below for a general solution that works across all webpages.. this is a great answer. – ihightower Jun 21 '17 at 07:19
  • To complement the existing Jupyter notebook solutions, I added [JupyterLab instructions](https://stackoverflow.com/a/59286150/2166823) below. – joelostblom Dec 11 '19 at 12:51

11 Answers11

115

You can add a TOC manually with Markdown and HTML. Here's how I have been adding:

Create TOC at top of Jupyter Notebook:

## TOC:
* [First Bullet Header](#first-bullet)
* [Second Bullet Header](#second-bullet)

Add html anchors throughout body:

## First Bullet Header <a class="anchor" id="first-bullet"></a>

code blocks...

## Second Bullet Header <a class="anchor" id="second-bullet"></a>

code blocks...

It may not be the best approach, but it works. Hope this helps.

Matt Dancho
  • 4,717
  • 2
  • 27
  • 19
  • 16
    This does not work for me anymore, but [a similar approach does](https://stackoverflow.com/questions/11948245/markdown-to-create-pages-and-table-of-contents/33433098#33433098). – joelostblom May 24 '17 at 02:27
  • 3
    also same "similar approach" as this: https://stackoverflow.com/questions/5319754/cross-reference-named-anchor-in-markdown/7335259#7335259 tl;dr: use `` for anchor and for link use: `Take me to [pookie](#pookie)` – michael May 24 '17 at 19:12
  • 4
    For all headings in your markdowns, notebook automatically adds anchors. You can click on the pilcrow (¶) on the right of the headings that you see when you hover over them, to reveal the anchor in your browser address bar. You can use this anchor instead of adding anchors manually to sections of your markdown. Also the best thing is that it works across cells. – aaruja Apr 11 '20 at 15:21
  • 1
    I have this script [add_toc.py](https://github.com/gerbaudo/python-scripts/blob/master/various/add_toc.py) that adds a markdown cell at the top with a list of contents. A poor man's solution if you don't want to install extensions. – user2148414 May 01 '20 at 15:47
56

There is an ipython nbextension that constructs a table of contents for a notebook. It seems to only provide navigation, not section folding.

Ian
  • 1,367
  • 12
  • 13
  • Thanks, I assume this is what the documentation was referring to. – user2428107 Jan 18 '14 at 04:54
  • 2
    For who want to install it in jupyter 4, [this post](http://stackoverflow.com/questions/21188698/what-happend-to-the-toc-extension-for-ipython-notebook/33051798#33051798) may help. – Syrtis Major Oct 10 '15 at 08:33
  • 11
    Just to update this: there is now an nbextensions extension, which bundles a whole lot of extensions together and allows you to manage them via jupyter itself. I think it's now the easiest way to get ToC2. And it provides other relevant extensions such as section folding. It's at https://github.com/ipython-contrib/jupyter_contrib_nbextensions – user2428107 Mar 30 '17 at 04:55
36

Here is one more option without too much JS hassle: https://github.com/kmahelona/ipython_notebook_goodies

Anaderi
  • 739
  • 5
  • 8
  • This is super useful for notebooks shared with other people! – rerx Jan 19 '18 at 12:00
  • Super useful +1 – Minstein Nov 05 '20 at 10:44
  • 1
    If you're using Jupyter Lab (not Notebook) and want to use this JS option, follow the guidelines in this issue to get it working (the info on the README page does not work for Lab) : https://github.com/kmahelona/ipython_notebook_goodies/issues/6#issue-462642204 – Haskan Feb 19 '21 at 16:17
34

JupyterLab ToC instructions

There are already many good answers to this question, but they often require tweaks to work properly with notebooks in JupyterLab. I wrote this answer to detail the possible ways of including a ToC in a notebook while working in and exporting from JupyterLab.

As a side panel

The jupyterlab-toc extension adds the ToC as a side panel that can number headings, collapse sections, and be used for navigation (see gif below for a demo). This extension is included by default since JupyterLab 3.0, in older version you can install it with the following command

jupyter labextension install @jupyterlab/toc

enter image description here


In the notebook as a cell

At the time being, this can either be done manually as in Matt Dancho's answer, or automatically via the toc2 jupyter notebook extension in the classic notebook interface.

First, install toc2 as part of the jupyter_contrib_nbextensions bundle:

conda install -c conda-forge jupyter_contrib_nbextensions

Then, launch JupyterLab, go to Help --> Launch Classic Notebook, and open the notebook in which you want to add the ToC. Click the toc2 symbol in the toolbar to bring up the floating ToC window (see the gif below if you can't find it), click the gear icon and check the box for "Add notebook ToC cell". Save the notebook and the ToC cell will be there when you open it in JupyterLab. The inserted cell is a markdown cell with html in it, it will not update automatically.

The default options of the toc2 can be configured in the "Nbextensions" tab in the classic notebook launch page. You can e.g. choose to number headings and to anchor the ToC as a side bar (which I personally think looks cleaner).

enter image description here


In an exported HTML file

nbconvert can be used to export notebooks to HTML following rules of how to format the exported HTML. The toc2 extension mentioned above adds an export format called html_toc, which can be used directly with nbconvert from the command line (after the toc2 extension has been installed):

jupyter nbconvert file.ipynb --to html_toc
# Append `--ExtractOutputPreprocessor.enabled=False`
# to get a single html file instead of a separate directory for images

Remember that shell commands can be added to notebook cells by prefacing them with an exclamation mark !, so you can stick this line in the last cell of the notebook and always have an HTML file with a ToC generated when you hit "Run all cells" (or whatever output you desire from nbconvert). This way, you could use jupyterlab-toc to navigate the notebook while you are working, and still get ToCs in the exported output without having to resort to using the classic notebook interface (for the purists among us).

Note that configuring the default toc2 options as described above, will not change the format of nbconver --to html_toc. You need to open the notebook in the classic notebook interface for the metadata to be written to the .ipynb file (nbconvert reads the metadata when exporting) Alternatively, you can add the metadata manually via the Notebook tools tab of the JupyterLab sidebar, e.g. something like:

    "toc": {
        "number_sections": false,
        "sideBar": true
    }

If you prefer a GUI-driven approach, you should be able to open the classic notebook and click File --> Save as HTML (with ToC) (although note that this menu item was not available for me).


The gifs above are linked from the respective documentation of the extensions.

joelostblom
  • 25,984
  • 12
  • 108
  • 120
  • I prefer working with `jupyter lab`, but needed to add a TOC to a large notebook HTML output. **This works flawlessly!** There were some additional steps to get it working: **1.** Enable TOC2, e.g. `conda install -c conda-forge jupyter_nbextensions_configurator`, go to `http://localhost:8888/nbextensions`, uncheck "compatibility" and enable "Toc2" **2.** Launch Classical Notebbok, modify TOC settings to your needs and `Add TOC to Cell` (proceed as described). **3.** Open your `.ipynb` file and search for the `"toc"`, copy json toc configs and add to metadata using tools tab of **Jupyter lab** – Alex Mar 13 '20 at 08:13
  • I couldn't get the toc2 extension working in the classic notebook to add a TOC cell. However, exporting the notebook with nbconvert `--to html_toc` worked. The format is great and adds a nice TOC on the side, plus heading numbers. – aimfeld Sep 09 '20 at 12:34
22

How about using a Browser plugin that gives you an overview of ANY html page. I have tried the following:

They both work pretty well for IPython Notebooks. I was reluctant to use the previous solutions as they seem a bit unstable and ended up using these extensions.

Community
  • 1
  • 1
Nikolay
  • 920
  • 9
  • 8
17

I recently created a small extension to Jupyter named jupyter-navbar. It searches for headers written in markdown cells, and displays links to them in the sidebar in a hierarchical fashion. The sidebar is resizable and collapsible. See screenshot below.

It is easy to install, and takes advantage of the 'custom' JS and CSS codes that get executed whenever a notebook is opened, so you don't need to manually run it.

enter image description here

Shovalt
  • 4,726
  • 2
  • 23
  • 43
  • 1
    Indeed it is easy to install, and the source code is friendly too. Nice project! – Carson Jun 16 '20 at 03:13
  • 1
    Thanks! very nice work, it's by far the best solution that I could wait for a TOC. I have to say that nbextensions worked for me until muy notebook became larger and larger, your solution, as I said, it's perfect, and simple. thanks again for your nice work. – pabloverd Oct 26 '20 at 06:37
  • 1
    wow this is great thank-you for your gift. May grace shine upon you. – clancy Dec 10 '20 at 12:56
  • Awesome. Would be great to have something like this built in to Jupyter – Bryan P Jan 16 '21 at 04:36
15

There are now two packages that can be used to handle Jupyter extensions:

  1. jupyter_contrib_nbextensions that installs extensions, including table of contents;

  2. jupyter_nbextensions_configurator that provides graphical user interfaces for configuring which nbextensions are enabled (load automatically for every notebook) and provides controls to configure the nbextensions' options.

UPDATE:

Starting from recent versions of jupyter_contrib_nbextensions, at least with conda you don't need to install jupyter_nbextensions_configurator because it gets installed together with those extensions.

Sergey Zakharov
  • 1,155
  • 2
  • 14
  • 33
  • And then, when choosing 1.), make sure to enable the use of extensions without explicit compatibility (uncheck the box at the top). Then choose "Table of Contents (2)". See the details at @KeyMaker00's answer. – questionto42 Nov 05 '20 at 09:15
14

nbextensions ToC instructions

Introduction

As @Ian and @Sergey have mentioned, nbextensions is a simple solution. To elaborate their answer, here is a few more information.

What is nbextensions?

The nbextensions contains a collection of extensions that add functionality to your Jupyter notebook.

For example, just to cite a few extensions:

  • Table of Contents

  • Collapsible headings

Install nbextensions

The installation can be done through Conda or PIP

# If conda:
conda install -c conda-forge jupyter_contrib_nbextensions
# or with pip:
pip install jupyter_contrib_nbextensions

You will see the new tab Nbextensions in the jupyter notebook menu. Uncheck the checkbox at the top disable configuration for nbextensions without explicit compatibility (they may break your notebook environment, but can be useful to show for nbextension development) and then check Table of Contents(2). That is all. Screenshot:

choice of "Table of Contents(2)" in Configurable nbextensions

Copy js and css files

To copy the nbextensions' javascript and css files into the jupyter server's search directory, do the following:

jupyter contrib nbextension install --user

Toggle extensions

Note that if you are not familiar with the terminal, it would be better to install nbextensions configurator (see the next section)

You can enable/disable the extensions of your choice. As the documentation mentions, the generic command is:

jupyter nbextension enable <nbextension require path>

Concretely, to enable the ToC (Table of Contents) extension, do:

jupyter nbextension enable toc2/main

Install Configuration interface (optional but useful)

As its documentation says, nbextensions_configurator provides config interfaces for nbextensions.

It looks like the following: nbextensions configurators

To install it if you use conda:

conda install -c conda-forge jupyter_nbextensions_configurator

If you don't have Conda or don't want to install through Conda, then do the following 2 steps:

pip install jupyter_nbextensions_configurator
jupyter nbextensions_configurator enable --user
KeyMaker00
  • 4,589
  • 43
  • 44
  • 1
    This is a great and detailed answer. I guess enabling `toc2/main` is the same as checking "Table of Contents (2)" on http://localhost:8888/tree#nbextensions_configurator. – flow2k Aug 20 '19 at 07:22
4

Here is my approach, clunky as it is and available in github:

Put in the very first notebook cell, the import cell:

from IPythonTOC import IPythonTOC

toc = IPythonTOC()

Somewhere after the import cell, put in the genTOCEntry cell but don't run it yet:

''' if you called toc.genTOCMarkdownCell before running this cell, 
the title has been set in the class '''

print toc.genTOCEntry()

Below the genTOCEntry cell`, make a TOC cell as a markdown cell:

<a id='TOC'></a>

#TOC

As the notebook is developed, put this genTOCMarkdownCell before starting a new section:

with open('TOCMarkdownCell.txt', 'w') as outfile:

    outfile.write(toc.genTOCMarkdownCell('Introduction'))

!cat TOCMarkdownCell.txt

!rm TOCMarkdownCell.txt

Move the genTOCMarkdownCell down to the point in your notebook where you want to start a new section and make the argument to genTOCMarkdownCell the string title for your new section then run it. Add a markdown cell right after it and copy the output from genTOCMarkdownCell into the markdown cell that starts your new section. Then go to the genTOCEntry cell near the top of your notebook and run it. For example, if you make the argument to genTOCMarkdownCell as shown above and run it, you get this output to paste into the first markdown cell of your newly indexed section:

<a id='Introduction'></a>

###Introduction

Then when you go to the top of your notebook and run genTocEntry, you get the output:

[Introduction](#Introduction)

Copy this link string and paste it into the TOC markdown cell as follows:

<a id='TOC'></a>

#TOC

[Introduction](#Introduction)

After you edit the TOC cell to insert the link string and then you press shift-enter, the link to your new section will appear in your notebook Table of Contents as a web link and clicking it will position the browser to your new section.

One thing I often forget is that clicking a line in the TOC makes the browser jump to that cell but doesn't select it. Whatever cell was active when we clicked on the TOC link is still active, so a down or up arrow or shift-enter refers to still active cell, not the cell we got by clicking on the TOC link.

upandacross
  • 367
  • 2
  • 7
2

As Ian already pointed out, there is a table-of-contents extension by minrk for the IPython Notebook. I had some trouble to make it work and made this IPython Notebook which semi-automatically generates the files for minrk's table of contents extension in Windows. It does not use the 'curl'-commands or links, but writes the *.js and *.css files directly into your IPython Notebook-profile-directory.

There is a section in the notebook called 'What you need to do' - follow it and have a nice floating table of contents : )

Here is an html version which already shows it: http://htmlpreview.github.io/?https://github.com/ahambi/140824-TOC/blob/master/A%20floating%20table%20of%20contents.htm

Anna Christine
  • 799
  • 1
  • 5
  • 10
0

Simple markdown solution

You can use markdown hyperlinks to jump to markdown headers without defining html tags. No matter how many hashes # you have in your title, use one for the hyperlink. Any spaces in you title are replaced with hyphens -.

Create the contents table

# Contents
- [Section 1](#Section-1)
- [Section 2](#Section-2)
- [Section 3](#Section-3)

Create headers

# Section 1
## Section 2

You can also add a hyperlink back to the contents.

### Section 3
[top](#Contents)

This is similar to Matt Dancho's answer but I always find html anchors to be fiddly.

D A Wells
  • 463
  • 4
  • 9