3
$\begingroup$

Is there any way to reference a particular output in Mathematica notebook robustly?

The usual way we refer a particular output is by invoking the command %n where n is the number that is alloted to a particular result based on the order of evaluation. If I re-run the same input, the output reference gets modified to n+1, so one has to refer to as %n+1. Is there a way to refer to particular output by some way that is not susceptible to this evaluation scheme. I know that just assigning a name will do the job. But lets say, I don't want to and just want to do something similar to % yet robust enough that it doesn't change even if I evaluate it again.

Workflow sample :

first draft

You can see that output nos 150,151,159 are referenced. Now, if I modify input 150 say, I cannot re-run all the subsequent operations without changing all the output reference nos. In a much bigger project that demands a lot of experimentation, you can see I how frustrating this can be. Given that I don't want to use Set as I have too many things to start naming myself, I thus want a way of referencing the outputs that is somehow just positional.

$\endgroup$
  • $\begingroup$ Like this? $\endgroup$ – Lukas Lang Jun 9 '18 at 15:04
  • $\begingroup$ You might also be interested in CellTags $\endgroup$ – Lukas Lang Jun 9 '18 at 15:19
  • 1
    $\begingroup$ I'm curious: why is this important to do? E.g., can't you use Set, possibly with Protect, to create globals to refer to the outputs? $\endgroup$ – Alan Jun 9 '18 at 15:27
  • $\begingroup$ @Alan This is because my current workflow requires me to try a lot of possibilities and I will soon run out of reasonable names using Set. Once I have a good idea of what exactly will be the named variables in my project(of which I don't have a good idea to begin with), I can fall back on the usual way by Set $\endgroup$ – Subho Jun 9 '18 at 15:31
  • 2
    $\begingroup$ @Subho95 You could still build up a list of results, which requires only a single symbol. $\endgroup$ – Alan Jun 9 '18 at 15:37
5
$\begingroup$

You can try the following (evaluate the code once at the beginning of your session):

SetOptions[EvaluationNotebook[],
 StyleDefinitions -> Notebook[
   {
    Cell[StyleData[StyleDefinitions -> "Default.nb"]],
    Cell[
     StyleData["Input"],
     ShowCellTags -> True,
     CellProlog :>
      ($Line = PersistentIDs`curLine=
        CurrentValue[EvaluationCell[], {TaggingRules, "ID"}] /. 
          Inherited :> (CurrentValue[EvaluationCell[], {TaggingRules, "ID"}] = 
            Last[DownValues[Out], {{{0}}}][[1, 1, 1]] + 1)),
     CellEpilog :> SetOptions[
       EvaluationCell[],
       CellLabel -> StringTemplate["In[``]:="]@PersistentIDs`curLine
     ]
    ]
   }
  ]
]

Essentially, this freezes the line numbers of any cell evaluated after this point. As the complete state is stored in StyleDefinitions and TaggingRules, this should persist across different sessions, without needing to reevaluate anything.

To unfreeze the line numbers, go select Format>Stylesheet>Default.

Installing

If you intend to use this frequently, you can install the stylesheet for easier reuse. To do so, execute the above code, go to Format>Edit Stylesheet.... Then, go to File>Install, select "Stylesheet" and the notebook that just opened (most likely called Untitled-1 or so) and give it a name. Now, you can apply this to any notebook by choosing Format>Stylesheet>"Name you entered"

How it works

This works by defining CellProlog and CellEpilog of all input cells to do the following (via the stylesheet):

  • Before the cell is evaluated: Set $Line to the following (also, save this value in curLine for later):
    • If the Cell is tagged with "ID" (i.e. was already executed), this value
    • Otherwise, take the highest defined Out value +1. Also, assign this value to {TaggingRules,"ID"}
  • After the cell is evaluated: Set the CellLabel to curLine (we need to do this in CellEpilog as it gets overridden after CellProlog
$\endgroup$
  • $\begingroup$ This is exactly what I wanted! Thanks $\endgroup$ – Subho Jun 9 '18 at 17:32
  • $\begingroup$ Glad it works for you! The modification should even persist across restarts of Mathematica, haven't tested that though $\endgroup$ – Lukas Lang Jun 9 '18 at 17:36
  • $\begingroup$ Only one thing, a curious situation is when one switches between a notebook with this robust mode on and another with the conventional implementation. Then there can be a situation where one can override the freeze you have implemented. So I think its best to make the implementation Global and not notebook specific. $\endgroup$ – Subho Jun 9 '18 at 17:41
  • 1
    $\begingroup$ What exactly do you mean? The only thing that should happen is that the other notebook might reuse the same line numbers (which is still not ideal, but somewhat reasonable). Making the definition global is difficult, as it's done using a stylesheet. But I've added an explanation of how to install the stylesheet for easier reuse, so you can simply apply it to all notebooks that you're working on simultaneously. $\endgroup$ – Lukas Lang Jun 9 '18 at 19: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.