48
$\begingroup$

This is my oldest question on SO. It still hasn't generated a useful answer there, so I thought I'd give it a try here.

The question was: I don't seem to be able to find the method to generate the table of contents for a Mathematica notebook. AuthorTools, an old v5.1 utility package is still hidden in Mathematica, but it doesn't work for me. The TOC should contain correct section numbers (if present in the stylesheet) and list page numbers (this requires taking page size settings into account).

$\endgroup$
6
  • $\begingroup$ @Nasser This is for printing purposes (and making PDF's). So I want the TOC to be interpreted in terms of the page settings in File>Printing settings>Page Setup. Mathematica is aware of the page breaks because you can have them shown using the option File>Printing settings>Show page breaks. And indeed, I'm looking for an automatic method. It used to be possible, and it looks like all MMA books written in MMA have there TOC made up with MMA. So, how do they do it? $\endgroup$ Jan 22, 2012 at 12:49
  • $\begingroup$ I was going to ask this as well. I also want to know how to generate a list of all the functions used in a notebook, to check coverage of topics for a chapter, for example. $\endgroup$
    – cormullion
    Jan 22, 2012 at 16:46
  • $\begingroup$ There must be an easy way to do this because WRI does have a couple of downloadable PDFs, which have a ToC with page numbers, that were generated from notebooks: wolfram.com/learningcenter/tutorialcollection/GraphDrawing/… (this is from some help browser notebooks) $\endgroup$
    – Szabolcs
    Jan 22, 2012 at 21:31
  • $\begingroup$ @SjoerdC.deVries have you tried hacking the old AuthorTools code to see if you can update the bits you need? I hope Wolfram are reading this and will give us a working AuthorTools in version 9. $\endgroup$ Jan 22, 2012 at 22:54
  • $\begingroup$ @MikeHoneychurch If I would have a couple of weeks of free time (or someone pays me, like WRI payed me as an external consultant to write part of the first version of AuthorTools 15 years ago) I would start here and then test on all kind of platforms with different notebooks: library.wolfram.com/infocenter/Conferences/4878 $\endgroup$ Jan 23, 2012 at 2:12

1 Answer 1

32
$\begingroup$

A bit of warning from the OP: this code locked-up my Mathematica session, so be sure to save everything before you try this. Update: Problem seems to be related to a problem MMA has with paginating a particular notebook of mine (see comments).

This code creates a separate TOC for a notebook saved at the location bookUrl. It works by iterating over all the cells in the book. If a cell is encountered whose type is in typeList, a tag is added to the cell and a line is written to the TOC notebook. We use CounterBox["Page", {bookUrl, tag}] to print the appropriate page number.

Note that due to the nature of CounterBox, the page numbers are only shown in the TOC is the notebook of the book is open and ShowPageBreaks -> True is set, but you should be able to print the TOC to a pdf.

createToc[bookUrl_, typeList_] :=
  Module[{toc, book, createCell, counter, cell, type, tag},

    (*create TOC file and open book*)
    toc = CreateDocument[];
    book = NotebookOpen[bookUrl];
    SetOptions[book, ShowPageBreaks -> True];

    (* helper file for creating cell *)
    createCell[text_, tag_, level_] := Cell[BoxData[
         TagBox[GridBox[{{"", text, CounterBox["Page", {bookUrl, tag}]}},  
           GridBoxAlignment -> {"Columns" -> {Left, Left, Right}}, 
           GridBoxItemSize -> {"Columns" -> {2 level - 1, 35 - 2 level, 5}}], 
          "Grid"]], "Text"];

    (* iterate over cells to set tags and write lines to TOC *)
    Scan[(counter[#] = 0) &, typeList];
    SelectionMove[book, Before, Notebook];
    SelectionMove[book, Next, Cell];
    While[(cell = NotebookRead[book]) =!= {},
      If[Length[cell] >= 2,
       type = cell[[2]];
       If[MemberQ[typeList, type],
        counter[type] += 1;
        tag = type <> ToString[counter[type]];
        SetOptions[NotebookSelection[book], 
         CellTags -> Union[Flatten[{Options[NotebookSelection[book], 
           CellTags][[1, 2]], tag}]]];
        SelectionMove[book, All, CellContents];
        NotebookWrite[toc, 
         createCell[NotebookRead[book], tag, 
          Position[typeList, type][[1, 1]]]]];
       SelectionMove[book, Next, Cell]]];
    SetSelectedNotebook[toc]];

To see the code in action, lets create a very simple document with 2 sections and 3 subsections on 3 pages

book = CreateDocument[];
NotebookWrite[book, Cell["This is section 1", "Section"]];
NotebookWrite[book, Cell["This is a subsection", "Subsection"]];
NotebookWrite[book, Cell["This is some text", "Text"]];
NotebookWrite[book, 
  Cell["Another section which begins on a new page", "Section", 
   PageBreakAbove -> True]];
NotebookWrite[book, 
  Cell["Subsection 2.1", "Subsection", PageBreakBelow -> True]];
NotebookWrite[book, Cell["Subsection 2.2", "Subsection"]];
bookUrl = ExpandFileName["book1.nb"];
NotebookSave[book, bookUrl];

Then createToc[bookUrl, {"Section", "Subsection"}] creates something like this

Mathematica graphics

$\endgroup$
9
  • $\begingroup$ It looks very promising but it just locked-up my Mathematica session, so I'm going to insert a warning above first. $\endgroup$ Jan 22, 2012 at 21:15
  • $\begingroup$ @SjoerdC.deVries I'm sorry about that. I've only tried it on small examples but for those it seems to work fine on my machine. $\endgroup$
    – Heike
    Jan 22, 2012 at 21:25
  • $\begingroup$ Did some further testing. It's probably not the code itself that is the problem. It seems that setting the pagebreak option (SetOptions[book, ShowPageBreaks -> True]) is a problem for this particular file. Same lock-up happens when you do it manually, with File>Printing settings. It never finishes repagination. I made it under MMA7, using a tweaked Article/JournalArticle style file (mostly counter boxes for section numbering). $\endgroup$ Jan 22, 2012 at 21:35
  • $\begingroup$ I put a minimal version of the problem notebook at dl.dropbox.com/u/3675222/test6.nb. Please don't forget to save your other stuff before you try this. $\endgroup$ Jan 22, 2012 at 23:29
  • 1
    $\begingroup$ Maybe we should petition to have something like this done more simply. All this code just to generate a TOC? Surely there should be an easier way. $\endgroup$
    – Eric
    Jan 28, 2012 at 4:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.