10
$\begingroup$

A similar question has been asked before, with no answers. I would love to have a way to easily reference objects associated with counters. To provide such a capability for things like figures, tables, etc., it would be great if it was possible to automatically create tags as part of a Stylesheet definition. Can this be done?

For example, I have a Stylesheet definition for my figure captions that reads like this:

Cell[StyleData["FigureCaption", StyleDefinitions -> StyleData["SmallText"]],
 TextAlignment->Center,
 TextJustification->0.,
 CounterIncrements->"Figure",
 MenuSortingValue->10000,
 FontFamily->"Source Sans Pro",
 FontSize->12,
 FontWeight->"Plain",
 FontSlant->"Plain",
 FontVariations->{"StrikeThrough"->False,
 "Underline"->False},
 FontProperties->{"ScreenResolution"->Automatic}]

Is it possible to add to this some code that will automatically create a tag of the form, say, "figctr", where ctr would be the value of the counter associated with the caption?

CLARIFICATION: Suppose I have a document that includes many FigureCaption cells that reference the counter above. Is it possible to programmatically create CellTags that reference the current value of the counter on each of these cells?

For example, I would like the 5th FigureCaption cell in notebook to have the CellTag "fig'ctr'", where 'ctr' is 5.

I use CellTags for navigation in a lecture notebook. It would very helpful to have the ability to add and delete FigureCaption cells in the notebook and then have some code that would update the cell tags to their appropriate values. Here is a related question I asked.

Note: As outlined in my comment, updating cell tags after having inserted more figures cannot be done in isolation: If we update the tags, the question comes up as to what happens to links after you edit the notebook. The part that's problematic about this is of course not the updating of the CellTags, but the fact that if we simply update the tags so they correspond to the counters, then existing references will point to the wrong cells. This means that we also need to search for and update the references to all of the tags.

$\endgroup$
7
$\begingroup$

Here's a solution. The inspiration for much of the code came from Eric Schulz's lecture on "Wisdom Gained from Publishing a CDF ebook" as well as as some code from this post. Below are the components for creating automatic cell tags for FigureCaption cells, but the idea can be extended to more than one type. The following are the components needed to keep everything updated for the cell type "FigureCaption" but can be used for multiple cell types.

  1. A custom stylesheet that includes a definition for a "FigureCaption" cell. Make sure to setup the counters as shown.

    Cell[StyleData["FigureCaption"], CellMargins->{{54, 24}, {10, -5}}, TextAlignment->Center, LineSpacing->{1, 2}, ParagraphSpacing->{0, 5}, LanguageCategory->"NaturalLanguage", ScriptLevel->1, CounterIncrements->"FigureCaption", FontFamily->"Times New Roman", FontSize->12]

  2. A notebook that contains some FigureCaption cells. This is the notebook we will be manipulating I will refer to as the lecture notebook.

  3. A function that builds the cell tags for the lecture notebook. The function is located in the Action Menu below.

DynamicModule[{found}, celltagdialog = Tooltip[Dynamic[ ActionMenu[ "C", {"Build Cell Tags" :> {SelectionMove[InputNotebook[], Before, Notebook]; found = NotebookFind[InputNotebook[], "FigureCaption", Next, CellStyle]; While[! FailureQ[found], SetOptions[NotebookSelection[], CellTags -> "Figure " <> ToString[ CurrentValue[ NotebookSelection[InputNotebook[]], {"CounterValue", "FigureCaption"}]]]; found = NotebookFind[InputNotebook[], "FigureCaption", Next, CellStyle];];}}, Appearance -> "Palette", FrameMargins -> None, Alignment -> Center, BaselinePosition -> Axis, ImageSize -> {24, 24}]], "Show Gridbox Dialog", TooltipDelay -> 0]]

  1. A function that creates the links to the cell tags in the lecture notebook. These are basically pointers that point to updated tags so that you can hyperlink to them... and them opens and closes groups to make it look nice.

CreateLinks[nb_] := Module[{tagLis = {}, data, imax, i}, SelectionMove[nb, Before, Notebook]; SelectionMove[nb, Next, Cell]; data = NotebookRead[nb]; While[data =!= {}, tagLis = Join[tagLis, Cases[data, Rule[CellTags, tg_] :> tg]]; SelectionMove[nb, Next, Cell]; data = NotebookRead[nb]]; MapThread[ Which[StringContainsQ[#1, "Figure"], " " <> #1, True, Style[#1, Bold]] :> {FrontEndExecute[FrontEndToken["SelectAll"]]; FrontEndExecute[{FrontEndToken[InputNotebook[], "SelectionCloseAllGroups"]}]; NotebookLocate[#1], FrontEndExecute[{FrontEndToken[ "SelectionOpenAllGroups"]}];} &, {tagLis}]]

Applying the functions given in 3 will keep the cell tags automatically generated so that even when you insert a new cell, the cell tags are renamed using 3. The function in 4 will rebuild the links which can be used for hyperlinking. These need to be rebuilt whenever we add or remove or move cells that have cell tags in the notebook or they won't match up. Let me know if you would like to see more code.

Below is a short gif I made to illustrating how we can do this in pratice. I have many cells with tags and some of them with counters that I reference in the tags. As you can see, I used a docked cell with a dropdown menu to rebuild the celltags.

enter image description here

The pointers created in 4 can be used for hyperlinks to any celltag in the notebook. Below is a gif illustrating how this can be implemented. Make sure to rebuild the docked cell to keep these pointers updated. I prefer to update the docked cell at the same time as I build the celltags, so it's one click instead of two. Again I used a dropdown menu and use the CreateLinks function above for its content.

enter image description here

$\endgroup$
  • 1
    $\begingroup$ This gets us closer. However, the issue now comes up as to what happens if you edit the notebook, adding more FigureCaptions somewhere in between existing ones, so the counters will update. This turns out to be a problem I haven't thought about before. The part that's problematic about this is of course not the updating of the CellTags (which is easy), but the fact that if we simply update the tags so they correspond to the counters, then existing references will be wrong. This means that we need to search for and update the references to all of the tags. $\endgroup$ – Pirx Oct 11 '16 at 20:40
  • $\begingroup$ Yes. I built a function that parses through the notebook to build the tags. You just execute it after adding a new tag and it resets everything so all tags match up with counters. I'll include a small snippet of my code above. I have it linked to button so it makes it easy. $\endgroup$ – Michael McCain Oct 11 '16 at 20:46
  • $\begingroup$ So does this update any existing hyperlinks? $\endgroup$ – Pirx Oct 11 '16 at 20:47
  • $\begingroup$ Yes... it parses through the whole notebooks and resets every tag according to its counter. I'll include a code along with a video example above. $\endgroup$ – Michael McCain Oct 11 '16 at 20:48
  • 1
    $\begingroup$ Thanks very much! Yes, I'd be interested in obtaining the entire code you have for this, Dropbox is fine. Also, I'm curious about these docked cells; I have never thought of these,and I'm not even sure this can be done in Windows. I'll have to play around with this to see exactly how it works, and I'm really busy right now, but I will get back to you on this. $\endgroup$ – Pirx Oct 12 '16 at 11:33

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.