2
$\begingroup$

I make a progress indicator like this:

(* prepare global variables for dynamic progress bar ... *)
messages = {{"initial message"}};       (* during runtime will be appended to it *)
count = 0;   
maxCount = 1;  (* initial value>0. It will later be be set to the maximum which count shall actually reach *)
dynAnzeige =   (* dynAnzeige is anpother global variable *)
 Column[
   { Dynamic[count]
   , Pane[
       ProgressIndicator[
          Dynamic[count]
       , {0, Dynamic[maxCount]}
       ]  
     ] (* Pane *)
   , Dynamic[TextGrid[messages]]   (* further will appended to the global variable messages *)
   }
 ]; (* Column *)
...
(* use case ... *)
Dynamic[dynAnzeige]                (* a semicolon here would suppress it! *)
(* read data from file and set maxCount to number of lines read... *)
For[count = 1, count <= maxCount, count++
  (* process data ... *)
  ...
  (* if worth reporting... *)
  AppendTo[messages
  , {"...report what has happened..."
  ];
]; (* For loop to process data *)

My actual processing steps happen in deeply nested Modules: the communication with Dynamic[dynAnzeige] is done through the above mentioned global variables.

When Dynamic[dynAnzeige] is processed before time consuming statements in an input cell, another numbered oputput cell is generated and it is updated during the evaluation of that cell. My notebook uses messages = {{"initial message"}}; together with Dynamic[dynAnzeige] in several cells.

How can I programatically get rid of an output cell generated by Dynamic[dynAnzeige] after my lengthy computation is finished?

How can I determine the number of that output cell to address it.

I want to equip several time consuming input cells each with their own progress bar. But they shall only be live while the cell which outputs them is running and they shall be programatically removed after the time consuming processing is finished in that cell. The output of Print statements which goes below that dynamic progress bar shall not be affected by removing the dynamic thing.

Currently I see several of them and they are all live in parallel - due to the nature of Dynamic. But I only want one progress bar just below the currently running input cell.

$\endgroup$
3
  • 3
    $\begingroup$ Have you seen PrintTemporary? $\endgroup$
    – Michael E2
    Jan 20, 2022 at 20:48
  • $\begingroup$ PrintTemporary is a good hint. I had heard of it before, but it hadn't settled in my head enough to come to mind. Thanks for the hint! It has helped further. - PrintTemporary however removes the progress bar after the cell containing PrintTemporary[Dynamic[dynAnzeige]] is closed. Would it be possible to let the progress bar stay in the notebook until another one is activated (then in its own place)? $\endgroup$ Jan 22, 2022 at 14:23
  • $\begingroup$ Sounds tricky. What about using DockedCells? Or something like statuscell = AttachCell[ProgressIndicator[Dynamic@dynAnzeige]]? $\endgroup$
    – Michael E2
    Jan 22, 2022 at 18:42

1 Answer 1

2
$\begingroup$

The hint AttachCell is the right one. Here a worked out solution:

DynProgressBar[] defines the dynamic progress bar, which will not be stored together with the notebook (due to the nature of AttachCell used in it). The function can be called in any input cell in order to show a progress bar below the input cell together with some messages. These messages can be manipulated later because messages is a Dynamic object associated with the progress bar.

The current value of the global variable count is shown continuously on the left upper corner of the progress bar itself.

DynProgressBar[] shows the current values count and messages and uses these global variables:

count loop variable of the process bar: Its value is initially set to 0 and shall be incremented to maxCount in the code after calling DynProgressBar[].

maxCount upper limit for count: shall later be set to the proper value. It is initialized to 1 in order to guarantee that it is bigger than count.

dynPrBar the CellObject which represents the progress bar. If this variable already is a cell object (e.g. after this function has been used at least once), it is internally discarded first using NotebookDelete.

messages A list of lists to be shown below the progress bar. Each element on the first level is one line, each one on the second level one column in that line.

If the function DynProgressBar is called again later, the old progress bar is automatically discarded. Other than by calling DynProgressBar again, the old progress bar can also be completely discarded by calling NotebookDelete[dynPrBar]; Clear[dynPrBar]; (provided dynPrBar is a CellObject[_Interger]):

DynProgressBar[] :=
  Module[{}              (* Module DynProgressBar *)
   , (* if another dynPrBar exists, get rid of it... *)
     If[MatchQ[dynPrBar, CellObject[_Integer]]
     , NotebookDelete[dynPrBar];
       Clear[dynPrBar];
     ];
     (* prepare global variables... *)
     messages = {{""}};   (* further messages can be appended to it later *)
     count = 0;
     maxCount = 1;        (* initial value>0.*)
     dynPrBar = AttachCell[Dynamic[
         Column[{Dynamic[count]
           , Pane[ProgressIndicator[
                 Dynamic[count]
               , {0, Dynamic[maxCount]}
               ] (* ProgressIndicator *)
             ] (* Pane *)
           , Dynamic[TextGrid[messages]]
           }
         ] (* Column *)
      ] (* Dynamic *)
    ] (* AttachCell *)  
  ]; (* Module DynProgressBar *)

Application:

DynProgressBar[];    (* 1: attaches the progress bar to the end of this input cell *)
messages={{"first demo"}};  (* 2: to be effective, messages, count and maxCount may be manipulated after after step 1 *)
maxCount = 3;
(* read data from file and set maxCount to number of lines read... *)
For[count = 1, count <= maxCount (* For loop to process data *)
, AppendTo[messages
  , {"waiting " <> ToString[3+count] <> "seconds."}
  ];
  Print[count]; Pause[3+count]; (* <== instead of this demo read an process lines here *)
  count++
]; (* For loop to process data *)
Print["finished!"];
$\endgroup$
1
  • $\begingroup$ My solution has one drawback: If you have to quit the kernel, the dynamic progress bar remains in the notebook. After quitting the kernel, the variable dynPrBar is gone and you can't get rid of the progress bar issuing NotebookDelete[dynPrBar]. After starting a new kernel, the new progress bar will overlay the old one, making it hard to read any messages associated with it. I have found no alternative to storing the notebook and loading it again: the progress bar is not stored. I would be interested if someone could supply a better solution to this detail. $\endgroup$ Mar 2, 2022 at 17:02

Your Answer

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

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