3
$\begingroup$

I am writing a notebook programmatically. I would like the FrontEnd to wait until an evaluation is finished, before continuing. This is best explained with examples:

The following opens a notebook, writes a text cell, writes an input cell, evaluates it, and continues to write more text cells. Notice that the evaluation doesn't finish until the the the the FrontEnd finishes.

NotebookWrite[exampleNB, 
 Cell["example of evaluating input programmatically", 
  "Text"]]; NotebookWrite[exampleNB,
 Cell["D[Sin[ RandomReal[] x],x]" , "Input", CellTags -> 1]];
SelectionMove[exampleNB, Previous, Cell];
SelectionEvaluate[exampleNB];
NotebookWrite[exampleNB, Cell[RandomWord[], "Text"]];
Pause[5];
NotebookWrite[exampleNB, Cell[RandomWord[], "Text"]];

This is related to a similar post, the answer to which almost gets me to a solution. How to wait a Cell in a Notebook to be executed until another Notebook's Cell expressions executed?

That post's solution doesn't work for my case, because this will evaluate all input cells:

NotebookWrite[exampleNB, 
 Cell["example of evaluating input programattically", 
  "Text"]]; NotebookWrite[exampleNB,
 Cell["D[Sin[ RandomReal[] x],x]" , "Input", CellTags -> 1]];
SelectionMove[exampleNB, Previous, Cell];
NotebookEvaluate[exampleNB, InsertResults -> True];
NotebookWrite[exampleNB, Cell[RandomWord[], "Text"]];
Pause[1];
NotebookWrite[exampleNB,
  Cell["D[Sin[ RandomReal[] x],x]" , "Input", CellTags -> 1]];
SelectionMove[exampleNB, Previous, Cell];
NotebookEvaluate[exampleNB, InsertResults -> True];
Pause[1];
NotebookWrite[exampleNB, Cell[RandomWord[], "Text"]];

I've tried a solution with CellTags. This works, but there is a problem: there is no output from the evaluation.

NotebookWrite[exampleNB, 
 Cell["example of evaluating input programattically", 
  "Text"]]; NotebookWrite[exampleNB,
 Cell["D[Sin[ RandomReal[] x],x]" , "Input", CellTags -> 1]];
SelectionMove[exampleNB, Previous, Cell];
NotebookEvaluate[exampleNB, 
  EvaluationElements -> {"CellTags" -> 1}];
NotebookWrite[exampleNB, Cell[RandomWord[], "Text"]];
Pause[2];
NotebookWrite[exampleNB,
  Cell["D[Sin[ RandomReal[] x],x]" , "Input", CellTags -> 2]];
SelectionMove[exampleNB, Previous, Cell];
NotebookEvaluate[exampleNB, EvaluationElements -> {"CellTags" -> 2}];
Pause[2];
NotebookWrite[exampleNB, Cell[RandomWord[], "Text"]];

One might think that adding the InsertResults->True option would insert results, but it doesn't:

NotebookWrite[exampleNB, 
 Cell["example of evaluating input programattically", 
  "Text"]]; NotebookWrite[exampleNB,
 Cell["D[Sin[ RandomReal[] x],x]" , "Input", CellTags -> 1]];
SelectionMove[exampleNB, Previous, Cell];
NotebookEvaluate[exampleNB, InsertResults -> True, 
  EvaluationElements -> {"CellTags" -> 1}];
NotebookWrite[exampleNB, Cell[RandomWord[], "Text"]];
Pause[2];
NotebookWrite[exampleNB,
  Cell["D[Sin[ RandomReal[] x],x]" , "Input", CellTags -> 2]];
SelectionMove[exampleNB, Previous, Cell];
NotebookEvaluate[exampleNB, InsertResults -> True, 
  EvaluationElements -> {"CellTags" -> 2}];
Pause[2];
NotebookWrite[exampleNB, Cell[RandomWord[], "Text"]];

I think that this may be a buglet.

Is there a work-around? My goal here is simple. Get the input's evaluation to display before the rest of the cells are written.

It may seem like a strange thing to want to do, but if is anyone is interested a out why, I'll add this as a comment.

$\endgroup$
6
  • $\begingroup$ Maybe TaskWait may help $\endgroup$ Commented Mar 21, 2021 at 17:16
  • 2
    $\begingroup$ I think your best option is to write the cells you want to evaluate into a separate notebook, evaluate that, and copy the results where you need them. (At least that's what I've ended up doing when I had this issue) $\endgroup$
    – Lukas Lang
    Commented Mar 21, 2021 at 18:14
  • $\begingroup$ I looked at TaskWait. That is a rabbit hole that I will spelunk if need be. Holding out hope for a simpler trick. $\endgroup$ Commented Mar 21, 2021 at 18:20
  • $\begingroup$ @Lukas that’s a viable solution. I’ll try it and see. If successful, I’ll report back. $\endgroup$ Commented Mar 21, 2021 at 18:22
  • $\begingroup$ @LukasLang, That strategy works for me. $\endgroup$ Commented Mar 21, 2021 at 21:21

2 Answers 2

3
$\begingroup$

You could try the following approach, with a secondary kernel (K2) and using CellInformation to check if a cell or notebook is currently in the "Evaluating" state:

  1. Get the current evaluator names:
evaluators = EvaluatorNames /. Options[$FrontEnd, EvaluatorNames];
  1. Add a "K2" kernel if there isn't one:
SetOptions[$FrontEnd, Union[Join[evaluators, {"K2" -> {"AutoStartOnLaunch" -> False}}]]]
  1. Function which checks if any cell in a notebook is currently evaluating:
NotebookEvaluatingQ[nb_] := Module[{},
  SelectionMove[nb, All, Notebook];
  Or @@ Map["Evaluating" /. # &, Developer`CellInformation[nb]]
  ]
  1. Make a new notebook with a "K2" kernel:
nb = CreateDocument[{}, Evaluator -> "K2"]
  1. Write a test input Pause[2], evaluate it and pause until it is done. Repeat for a total of three times:
SelectionMove[nb, All, Notebook];
FrontEndTokenExecute[nb, "Cut"];
Do[
 NotebookWrite[nb, 
  Cell[BoxData[MakeBoxes[Pause[2], StandardForm]], "Input"]];
 SelectionMove[nb, Previous, Cell];
 FrontEndTokenExecute[nb, "Evaluate"];
 SelectionMove[nb, Previous, Cell];
 While[NotebookEvaluatingQ[nb], Pause[.1]];
 SelectionMove[nb, After, Notebook];
 , 3]
$\endgroup$
1
  • 1
    $\begingroup$ This works very well for my purposes and is the best answer to the original question---thank you. I am also accepting this as an answer. $\endgroup$ Commented Mar 27, 2021 at 15:00
2
$\begingroup$

An example of evaluating the expression outside the notebook and then write the result in the notebook.

exampleNB = CreateDocument[];
NotebookWrite[exampleNB, 
 Cell["example of evaluating input programmatically", 
  "Text"]]; NotebookWrite[exampleNB, 
 Cell["D[Sin[ RandomReal[] x],x]", "Input", CellTags -> 1]];
NotebookWrite[exampleNB, 
  Cell[StandardForm@ToString@D[Sin[ RandomReal[] x], x], "Output"]];
Pause[2];
NotebookWrite[exampleNB, Cell[RandomWord[], "Text"]]
Pause[2];
NotebookWrite[exampleNB, Cell[RandomWord[], "Text"]]
$\endgroup$
1
  • $\begingroup$ Clever solution!; accepted it as answered. Also recognizing Lukas Lang for his suggestion. $\endgroup$ Commented Mar 23, 2021 at 12:15

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.