7
$\begingroup$

Preamble: I often work with the JournalArticle Stylesheet and use in it the styles "Figure" for graphics and "FigurCaption" for the corresponding caption. The figures should be numbered. To make this I must 1) Select the cell with the graphics and make its style be "Figure", then 2) make a tag for this cell, then 3) make a new cell below with the style "FigureCaption" and type there "Fig." and finally 5) go to Menu/Insert/AutomaticNumbering and enter a number in a standard way.

It is much too long. Now I am trying to make a function "makeFig" to shorten this procedure. So far, I have the following:

makeFig[expr_, tag_String] := Module[{},
  CellPrint[
   Cell[BoxData[ToBoxes[expr]], {"Figure", CellTags -> "Fig" <> tag}]];
  CellPrint[Cell[BoxData[ToBoxes[Fig ]], {"FigureCaption"}]];
  ]

This works, if the StyleSheet is JournalArticle.

Example:

makeFig[Plot[Sin[x], {x, 0, 2 \[Pi]}], "A"]

enter image description here

The question:

Main: Have you any idea of how I could programmatically after the word "Fig" insert the automatic numbering?

Secondary: In this code, I cannot put the word Fig in quotes like this: "Fig.". If I do that the quotes appear in the resulting image. Therefore, I have to put the word Fig without a point. This is a minor problem, but maybe you know how to easily deal with it too?

Edit: The answer to the secondary question may be as follows (thanks to @Ben Izd):

makeFig2[expr_, tag_String] := Module[{},
      CellPrint[
   ExpressionCell[expr, "Figure", TextAlignment -> Center, 
    CellTags -> "Fig" <> tag]];
      CellPrint[
   TextCell["Fig." , "FigureCaption", FontSize -> 12, 
    TextAlignment -> Center]];
      ]

The main question still persists.

$\endgroup$
13
  • $\begingroup$ I haven't used cell manipulations, so I might be wrong, with regard to your secondary part, when we create a new cell with the "FigureCaption" style, it is just a cell without any Box, like CellPrint[Cell["Fig 1", {"FigureCaption"}]] which solves your problem, is there any reason you chose your code? $\endgroup$
    – Ben Izd
    Jun 28, 2022 at 11:02
  • $\begingroup$ @Ben Izd Thank you. Please have a look at the edit. $\endgroup$ Jun 28, 2022 at 11:20
  • $\begingroup$ You are most welcome. Since we can create labels with strings, wouldn't a global variable like $FigureIndex=0 solve the problem? (like ... TextCell["Fig. " <> ToString[$FigureIndex += 1] ...) or it should be in a specific order other than execution? $\endgroup$
    – Ben Izd
    Jun 28, 2022 at 11:43
  • 1
    $\begingroup$ @Ben Izd I seem to have found a certain drawback in your approach. Since each time it adds a unit to $FigureIndex if I want to change something in a figure and evaluate it once more it will increase its number. Moreover, this approach will make it larger than the maximum value of $FigureIndex=0in the moment I make the reevaluation of the figure. I would better like to make the numeration on the vases of the cell tags. $\endgroup$ Jun 28, 2022 at 13:57
  • 1
    $\begingroup$ I've used something like CounterBox["Figure"] or CounterBox["Figure", celltag]. Something like CellPrint@Cell[TextData[{StyleBox["Fig. ", FontWeight -> "Bold"], StyleBox[CounterBox["Figure"], FontWeight -> "Bold"], StyleBox[".", FontWeight -> "Bold"], " ", "A caption."}], "FigureCaption"] for the caption. You can refer to the counter in the cell through its tag: CellPrint@Cell[TextData[{"In figure ", CounterBox["Figure", "fig:myfirst"], " we see..."}], "Text"]. See also CounterIncrements etc. I used it in stylesheets and editing, not in programming. I think it might work, though. $\endgroup$
    – Michael E2
    Jun 28, 2022 at 15:32

3 Answers 3

5
$\begingroup$

Explanation

Some of questions have come up about how CounterBox["Figure"] and CounterBox["Figure", tag] work in the comments under the OP. This box seem to be an approach that can solve the problem at hand (see also @Carl Woll's answer), so instead of a potentially long exchange of comments, which have to be short, I thought an answer that can be edited would be more appropriate. I also have a correction to make to my comments.

First, I don't know where there is much documentation on CounterBox[] thanks to @BenIzd, there is this webpage that introduces CounterBox[] in V3.0.2; it seems to be an HTML version of this Wolfram Library tech note. This answer is based on what I inferred by examining cell expressions of the following:

  1. A cell after doing the menu command Insert > AutomaticNumber... of tutorial that numbered things.

  2. Styles like "ItemNumbered" and "DisplayFormulaNumbered" in stylesheets like Default.nb (find it with FileNameJoin[{$InstallationDirectory, "SystemFiles", "FrontEnd", "StyleSheets", "Default.nb"}]).

  3. Tutorials that numbered things.

CounterBox[counter] — for numbering cells

The one-argument version is typeset by the Front End to show the number of cells with style counter from the beginning of a "unit" (my term, see below) up to and including the current cell, provided the style is counted. (This is the correction I needed to make; see Counter versus style below.) It is generally used to label a cell with a number. If you want to have as style that is sometimes numbered and sometimes not, it is better to have two styles like "DisplayFormula" and "DisplayFormulaNumbered", with the numbered style inheriting from the unnumbered one.

CounterBox[counter, tag] — for referring to numbered cells

The two-argument version is typeset by the Front End to show the value of CounterBox[counter] in the (first) cell tagged tag. The menu command Insert > Automatic Numbering... presents a dialog for inserting a CounterBox[]. You have to select the style, which it and what documentation there is calls a "Counter". The style/counter will be automatically initialized with the style of the cell the cursor is in. And if you also select a tag from the list of tagged cells, it will insert the corresponding two-argument form. If you type a tag that does not exist in the notebook, the CounterBox[] will be displayed as "XXX".

Options (including "unit")

One can explore the symbols returned by Names["Counter*"]. All but one relate to CounterBox. Some are Cell options and some are CounterBox options. Some have usage messages, some have documentation pages, and some have neither. Two are worth mentioning, meaning only that I have something meaningful and seemingly accurate to say about them. See the next section for something about CounterIncrements. The other option CounterAssignments controls what I called the "unit". This option causes the cell to reset the counters to the values indicated. Here is an example of the option value from the default stylesheet for the styles "Title" and "Section":

CurrentValue[{StyleDefinitions, "Title", CounterAssignments}]
(*
{{"Section", 0}, {"Equation", 0}, {"Figure", 0},
 {"Subtitle", 0}, {"Subsubtitle", 0}, {"Item", 0},
 {"Subitem", 0}, {"Subsubitem", 0}, {"ItemNumbered", 0},
 {"SubitemNumbered", 0}, {"SubsubitemNumbered", 0}}
*)

CurrentValue[{StyleDefinitions, "Section", CounterAssignments}]
(*
{{"Subsection", 0}, {"Subsubsection", 0}, {"Item", 0},
 {"Subitem", 0}, {"Subsubitem", 0}, {"ItemNumbered", 0},
 {"SubitemNumbered", 0}, {"SubsubitemNumbered", 0}}
*)

One can see that, assuming there is just one cell of style "Title" at the beginning of the notebook, that "Equation" and "Figure" are numbered sequentially through the whole notebook. One can also see that the "Section" counter is reset by "Title" but not the "Subsection" counter. So there is an assumption about the document structure build into the stylesheet.

"Counter" versus style

When I initially made my comments, it had been long time since I had really looked at CounterBox[]. I had in mind that the term "Counter" used in Mathematica is interchangeable with "style." That is not strictly true. The CounterBox[counter] counts the cells whose CounterIncrements option value is counter. This is usually set in a stylesheet. In the default stylesheet, most but not all styles have CounterIncrements set to the name of the style. A typical example of not are the styles that have a numbered variant:

CurrentValue[{StyleDefinitions, "DisplayFormula",
  CounterIncrements}]
CurrentValue[{StyleDefinitions, "DisplayFormulaNumbered", 
  CounterIncrements}]
(*
{}
"DisplayFormulaNumbered"
*)

I believe the Cell option CounterIncrements -> {counter,...} takes a list of counters, where each counter is a string. I would guess that multiple cell styles can increment the same counter and that a single cell can increment multiple counters.

Example application to OP's task

The following is modified from a comment by the OP:

makeFig3[expr_, tag_String] := (
   CellPrint@Cell[BoxData[
      ToBoxes[expr]], "Figure",
     CounterIncrements -> {"Figure"}, (* N.B. *)
     CellTags -> "Fig" <> tag];       (* N.B. *)
   CellPrint@Cell[TextData[
      {StyleBox["Fig. ", FontWeight -> "Bold"], 
       StyleBox[CounterBox["Figure"], FontWeight -> "Bold"], 
       StyleBox[".", FontWeight -> "Bold"]}],
     "FigureCaption"]);  (* Note no CellTag needed *)

Let's make two figures:

makeFig3[Plot[Sin[x], {x, 0, 2 Pi}], "PlotSin"]
makeFig3[Plot[Cos[x], {x, 0, 2 Pi}], "PlotCos"]

Now let's discuss them in a "Text" cell, which was created by hand. A question about the use of cell tags was raised in a comment. The cell tags created by makeFig3[] are used here for reference. This text cell needs no tag, at least not for the purpose of referring to the figures. Likewise the caption cell created by makeFig3[] needs no tag.

CellPrint@Cell[TextData[
   {"Compare ",
    StyleBox["Fig. ", FontWeight -> "Bold"], 
    StyleBox[CounterBox["Figure", "FigPlotSin"], (* Note tag *)
     FontWeight -> "Bold"], StyleBox[".", FontWeight -> "Bold"], 
    " with ",
    StyleBox["Fig. ", FontWeight -> "Bold"], 
    StyleBox[CounterBox["Figure", "FigPlotCos"], (* Note tag *)
     FontWeight -> "Bold"], StyleBox[".", FontWeight -> "Bold"], 
    "  "}],
  "Text", CellTags -> "foo"]

Now let's look at the outputs (I don't have styles "Figure" or "FigureCaption", so they display with no cell margins in whatever default styling there is for undefined styles; the "Text" cell gets indented, not centered):

$\endgroup$
3
  • $\begingroup$ Thank you very much for the detailed explanation. $\endgroup$ Jun 29, 2022 at 16:00
  • 2
    $\begingroup$ (+1) Great and comprehensive answer, much appreciated. Accidently I'd found kind of documentation/guide - Using Counters in Mathematica which was written by Paul J. Hinton in 1998 (probably for version 3) that could perhaps make your answer pluperfect. $\endgroup$
    – Ben Izd
    Jun 29, 2022 at 17:16
  • $\begingroup$ @BenIzd Thanks & nice find! The Front End menus have changed a little since that was written, but maybe/probably the rest is accurate. $\endgroup$
    – Michael E2
    Jun 29, 2022 at 17:34
3
$\begingroup$

I think you can use CounterBox for this purpose:

makeFig[expr_] := (
    CellPrint[Cell[BoxData[ToBoxes[expr]], "Figure"]];
    CellPrint[Cell[BoxData[RowBox[{"Fig. ", CounterBox["Figure"]}]], "FigureCaption"]]
)
$\endgroup$
4
  • $\begingroup$ Thank you. There is one problem with this idea. I need to be able to give cross-references to these graphics in the text. Therefore, I need the graphics cell to be tagged. I tried the following modification of your code: makeFig[expr_, tag_String] := (CellPrint[ Cell[BoxData[ToBoxes[expr]], "Figure", CellTags -> "Fig" <> tag, , TextAlignment -> Center]]; CellPrint[ Cell[BoxData[RowBox[{"Fig. ", CounterBox["Figure"]}]], "FigureCaption", TextAlignment -> Center]]). $\endgroup$ Jun 28, 2022 at 18:07
  • $\begingroup$ (continuation) This nicely makes the enumeration of the figures. However, as soon as I try to go to a text cell and enter a reference, I see that Menu/Insert/AutomaticNumbering menu element is ausblended for whatever reason. Do you have a remedy for that? $\endgroup$ Jun 28, 2022 at 18:09
  • $\begingroup$ @AlexeiBoulbitch it works for me. What does ausblended mean? $\endgroup$
    – Carl Woll
    Jun 28, 2022 at 18:55
  • $\begingroup$ Yes, after I waited for some time it started working for me too. Looks good. I will test it more tomorrow. $\endgroup$ Jun 28, 2022 at 19:23
0
$\begingroup$

A very basic solution was discussed in the comments but as mentioned, each time you call, the index increments without considering the cell position.

This solution will assign a CellTag to each FigureCaption cell it generates and uses Cells[] with EvaluationCell[] to count the number of generated cells before it. In this method it doesn't matter how many times you execute the cell, it'll output the cell unless you'd inserted another figure previously.

I'm sure the OP can understand the final code, I'll explain this, so everybody can understand.

Let's assume you, we'll assign tag "FG" to FigureCaption cells we generate.

Cells[] return all the cells of the current notebook, with the code below we can take all the previous cells of the current evaluated cell:

TakeWhile[Cells[], # =!= EvaluationCell[] &]

Now we need to count the "FG"s since some cells can have one Tag and unfortunately, (it seems) Mathematica does not warp it in tags List if it's a single tag, here is how we count them:

Count[TakeWhile[Cells[], # =!= EvaluationCell[] &], 
 x_ /; Block[{temp = CurrentValue[x, CellTags]}, 
   temp === "FG" || MemberQ[temp, "FG"]]]

Here is the final code:

ClearAll[makeFig3];

makeFig3[expr_, tag_String] := 
 Module[{}, 
  CellPrint[
   ExpressionCell[expr, "Figure", TextAlignment -> Center, 
    CellTags -> "Fig" <> tag]];
  CellPrint[
   TextCell[
    "Fig. " <> 
     ToString[1+
      Count[TakeWhile[Cells[], # =!= EvaluationCell[] &], 
       x_ /; Block[{temp = CurrentValue[x, CellTags]}, 
         temp === "FG" || MemberQ[temp, "FG"]]]], "FigureCaption", 
    CellTags -> "FG", FontSize -> 12, TextAlignment -> Center]];]

Example:

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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