Is there a way to get table of contents I can click on?
I'm looking for something like Table of Contents module in Jupyter notebooks where I can jump between sections easily, here's what my scratch-space usually looks like
Is there a way to get table of contents I can click on?
I'm looking for something like Table of Contents module in Jupyter notebooks where I can jump between sections easily, here's what my scratch-space usually looks like
AFAIK there's nothing built-in.
On the other hand I use this sort-of functionality all the time. Here's a quick way to generate a table of contents palette:
nbTOC[nb_] :=
Button[
Mouseover[#, Style[#, "HyperlinkActive"]] &@First@NotebookRead@#,
SelectionMove[#, All, CellContents],
Appearance -> None,
BaseStyle -> "Hyperlink",
Alignment -> Left,
ImageSize -> 100
] & /@
Cells[CellStyle -> {"Title", "Chapter", "Section", "Subsection",
"Subsubsection"}] // CreatePalette[
Panel[
Column[#,
Dividers -> Center],
ImageSize -> 100
],
FrontEnd`ClosingSaveDialog -> False,
WindowTitle -> "Table of Contents",
Magnification -> 1.5
] &;
nbTOC[Optional[Automatic, Automatic]] :=
nbTOC@EvaluationNotebook[]
It assumes you just want to navigate to the "Title", "Chapter", "Section",etc. cells and that the CellObject available at the time the palette was generated will still exist.
The other way I've done this is, at click time, searched for a cell with the same contents and style as the original cell in the notebook. That way it'll work even after the notebook has been closed and reopened.
{"Title", "Chapter", "Section", "Subsection", "Subsubsection"} for the cell styles you actually have
– b3m2a1
Mar 12 '21 at 19:03
I made a nbTOC based on b3m2a1's nbTOC to make it more ready to use. Improvements are listed below:
Here is the function:
ClearAll[openSelectedCellGroup];
openSelectedCellGroup[nb_NotebookObject]:=Module[{},
If[CurrentValue[First@Cells[NotebookSelection[nb]],"CellGroupOpen"]===Closed,
FrontEndTokenExecute[nb,"OpenCloseGroup"]]];
ClearAll[nbTOC];
Options[nbTOC]={
"width"->250,
"indentUnit"->10,
"fontSizeList"->{16,14,12,12,10,10},
"colorList"->{Darker@Red,Darker@Blue,Darker@Darker@Green,Darker@Orange,Black,Darker@Magenta},
"fontWeightList"->{Bold,Bold,Bold,Bold,Bold,Bold}};
nbTOC[notebookObj_NotebookObject,opts:OptionsPattern[]]:=Module[
{defaultCellStyleList,cellList,cellInfoList,currentCellStyleList,
width,indentUnit,fontSizeList,colorList,fontWeightList,
cellStyleAssocFormatStyle,cellStyleAssocButtonImageMargin,buttonList,
cellName,buttonImageMargin,tocNotebookObj,createNewTOCwindows},
width=OptionValue["width"];
indentUnit=OptionValue["indentUnit"];
fontSizeList=OptionValue["fontSizeList"];
colorList=OptionValue["colorList"];
fontWeightList=OptionValue["fontWeightList"];
defaultCellStyleList={"Title","Subtitle","Chapter","Section","Subsection","Subsubsection"};
cellList=Cells[notebookObj,CellStyle->defaultCellStyleList];
cellInfoList=List@@@(NotebookRead/@cellList)[[;;,1;;2]];
currentCellStyleList=DeleteDuplicates@cellInfoList[[;;,-1]];
currentCellStyleList=Cases[defaultCellStyleList,Alternatives@@currentCellStyleList];
cellStyleAssocFormatStyle=Association@Table[
currentCellStyleList[[i]]->With[{i=i},Style[#,fontSizeList[[i]],fontWeightList[[i]],colorList[[i]]]&],
{i,1,Length@currentCellStyleList}];
cellStyleAssocButtonImageMargin=Association@Table[
currentCellStyleList[[i]]->indentUnit*(i-1),
{i,1,Length@currentCellStyleList}];
buttonList=Table[
cellName=Row[{"",(Last[cellInfoList[[i]]]/.cellStyleAssocFormatStyle)[First@cellInfoList[[i]]]}];
(For unknown reason, Row[{"",xxx}] will make TOC more compact)
buttonImageMargin=Last[cellInfoList[[i]]]/.cellStyleAssocButtonImageMargin;
With[{cell=cellList[[i]]},
Button[
cellName,
Do[
SelectionMove[cell,All,CellGroup,k];
openSelectedCellGroup[notebookObj]
,{k,1,6}];(There are at most 6 level of TOC. Open them all from bottom to top)
SelectionMove[cell,All,CellGroup];
If[Length@Cells[NotebookSelection[notebookObj],CellStyle->{"Title","Subtitle","Chapter","Section","Subsection","Subsubsection"}]==1,
(If there are no more sections below, then open all sub cell groups, this will open all Out cells)
FrontEndTokenExecute["SelectionOpenAllGroups"],
(If there are more sections below, then only open one level further)
openSelectedCellGroup[notebookObj]];
(moving back to cell title)
SelectionMove[cell,All,CellContents]
,
Appearance->None,BaseStyle->"Hyperlink",Alignment->Left,
FrameMargins->{{buttonImageMargin, 0}, {0, 0}},
ImageSize->width]],
{i,1,Length@cellList}];
createNewTOCwindows[]:=Module[{},NotebookClose[tocNotebookObj];nbTOC[notebookObj]];
PrependTo[buttonList,
Button[Style["Click to update",White,Bold,15],createNewTOCwindows[],Background->Black]];
tocNotebookObj=CreatePalette[Column[buttonList,Dividers->Center],FrontEnd`ClosingSaveDialog->False,
WindowMargins->{{Automatic,-5},{Automatic,0}},WindowElements->{"VerticalScrollBar"},WindowTitle->"TOC",Magnification->0.85];
(SetOptions[EvaluationNotebook[],WindowSize[Rule]{1047,Automatic},WindowMargins[Rule]{{0,0},{0,0}}])];
nbTOC[opts:OptionsPattern[]]:=nbTOC[EvaluationNotebook[],opts];
Note that I deliberately make non-fixed font style for each level. So if the notebook only contains Section, Subsection, Subsubsection. We will have red biggest font for Section and so on like this
You can create tables of contents programmatically BUT there are a few large problems:
the tables are only somewhat “live”. In particular when you change the type of a subsection (eg change from cmd-3 to cmd-4 formatting) it’s hit or miss whether the live ToC will update to show this.
more serious is that constructing the ToC becomes something that you need to mark as an initialization cell, and so every time you open your document there’s some friction because you have to force initialization cells to execute before you can do what you want to do. I have been surprised at how much friction this induces.
the most obvious ways to construct a ToC (ie the sort of code you will find on the internet) mean that the ToC is a shared construct (single name) when you duplicate a document. This can become very messy if you want to have two versions of the document open simultaneously, eg to compare the current version with an older version.
More generally, I don’t know how Wolfram and the Mathematica employees do it! While writing in MMA is very productive in many ways (I much prefer it to, eg, LyX) it’s just HORRIBLE for large documents. Lack of live ToC is one problem, diff’s between versions is another problem, no version control (eg no easily managed connection to git, like XCode has) is a third problem. Yes, you can (and probably should) write in MMA compared to the alternatives, but the fact that it’s better than everything else, doesn’t mean it’s great; it means that everything else is even worse…
The bottom line is that there simply aren't any solutions that I consider very good right now. LyX is far superior to Mathematica in terms of its overview functionality, allowing you to see the entire document and move sections around. But it's clumsier than MMA (IMHO) in terms of the actual writing.
For me, the writing is more important than the overview which forces the choice.
– Maynard Handley Dec 21 '22 at 04:19