2
$\begingroup$

I've long been peeved that the front end scrolls automatically during evaluations, and I've finally sat down to pin down the exact behavior.

It seems that the front end auto-scrolls whenever printing occurs with the input cell offscreen. I'm inclined to think this behavior is a bug, because it doesn't seem helpful in any way -- the auto-scrolling never seems to improve one's view of the output or anything else.

Of course a workaround is to avoid printing, but it's just so convenient for displaying information about the evaluation that doesn't need to be accessed later (e.g., the time taken in AbsoluteTiming). Also, I use packages that print some information (version info, etc) upon loading, and often reload them (as initialization cells) as part of my workflow. (This is what made me sufficiently annoyed to investigate further.) To be clear: I like these messages, and I do not find some way of turning them off to be a satisfying workaround.

I'm still not entirely sure what the exact behavior is

  • Sometimes the behavior seems well-defined
    • If the input cell and printing area is entirely in view, do not auto-scroll
    • If the input cell or printing area (location on the screen where the printing will show up) is only partially in view, scroll so that more of the printing area is in view
      • I suspect this might be the intended behavior, but it is broken for other cases
    • If the printing area is partially in view (but the input cell is not), auto-scroll to the top of the printing area
    • If the current view is entirely below the printing area, scroll to the bottom of the output cell
      • This seems to fail if the current view is 'too far' below the output cell, though I haven't been able to quantify this
  • Sometimes the behavior seems less defined (particularly in a very long notebook when the current view is far away from the evaluated cell)
    • When in doubt, evaluate a long notebook first (so the notebook is significantly larger than the view on a single screen), and then check this behavior again

A few things to note:

  • The auto-scrolling is the same when Echo is used rather than Print.
  • I noticed this first for initialization cells, but the same thing seems to happen for all cells
  • EvaluationCompletionAction is globally set to {}
    • I double checked that my initialization cells have the same EvaluationComplettionAction set
    • lol at EvaluationCompletionAction being introduced in V4 and still not "fully integrated into the long-term Wolfram Language"
  • Another question (116047) seems to ask the same question, but was closed when workaround (Monitor rather than Print) was introduced.
    • Again, I like the look and persistence of printed output, and any workaround would have to mimic the behavior and look of `Print'ed output fairly well
  • Here's a Dropbox link to a notebook which should reproduce the problem
    • Just put the cursor inside one of the Do[Print[... input cells, scroll down so that input cell and printing area is no longer in view (the further down you scroll, the better), and press Shift-Enter to evaluate the cell. You should see the notebook scroll (at least a little bit) and then stop somewhere seemingly arbitrary
  • I'm using $Version "11.2.0 for Microsoft Windows (64-bit) (September 11, 2017)" on Windows 10

Is there any way to Print without suffering form auto-scrolling in the front end?

$\endgroup$
  • 1
    $\begingroup$ What version are you using? I don't see any scroll action if I do this in 11: Do[Pause[.5]; Print[1], 100]. As for the "not integrated fully" note, most front-end options say that, but until the FE is completely rewritten (which supposedly is coming) they're probably here to stay. $\endgroup$ – b3m2a1 Oct 5 '17 at 19:02
  • $\begingroup$ @b3m2a1 See my edit. Perhaps the input cell/ printing area was still in view? $\endgroup$ – jjc385 Oct 5 '17 at 21:11
3
$\begingroup$

Is there any way to Print without suffering form auto-scrolling in the front end?

You can define a custom myPrint function with AutoScroll -> False:

myPrint[expr_] := 
 NotebookWrite[EvaluationNotebook[], 
  Cell[BoxData@ToBoxes@expr, "Print"], AutoScroll -> False]

As it is noted in the comments, with this version clicking anywhere inside of the Notebook may result in changing the insertion point and further outputs will be printed starting from the new location. Also there are issues with evaluation of multiple cells at once. Here is an improved version which binds the printing to the EvaluationCell[] and as a result prints in the reverse order (what may be desirable in some situations):

myPrint[expr_] := (
  SelectionMove[EvaluationCell[], After, Cell, AutoScroll -> False];
  NotebookWrite[EvaluationNotebook[], 
   Cell[BoxData@ToBoxes@expr, "Print"], AutoScroll -> False])

And here is a version that prints in the usual order (based on the method from this answer):

myPrint[expr_] := (
  SelectionMove[EvaluationCell[], All, CellGroup, AutoScroll -> False];
  If[SelectedCells[] === {},
   SelectionMove[EvaluationCell[], After, Cell, AutoScroll -> False],
   SelectionMove[EvaluationNotebook[], After, CellGroup, AutoScroll -> False]];
  NotebookWrite[EvaluationNotebook[], 
   Cell[BoxData@ToBoxes@expr, "Print"], AutoScroll -> False])

Another implementation (based on the same answer):

myPrint[expr_] := (SelectionMove[EvaluationCell[], Before, CellGroup, AutoScroll -> False];
  SelectionMove[EvaluationNotebook[], Next, CellGroup, AutoScroll -> False];
  SelectionMove[EvaluationNotebook[], After, CellGroup, AutoScroll -> False];
  NotebookWrite[EvaluationNotebook[], 
   Cell[BoxData@ToBoxes@expr, "Print"], AutoScroll -> False])

And a completely different implementation which is based on the assumption that EvaluationCell[] can be only the first cell in a group (what usually holds, but in general isn't true):

myPrint[expr_] := (
  If["FirstCellInGroup" /. Developer`CellInformation@EvaluationCell[],
   SelectionMove[EvaluationCell[], All, CellGroup, AutoScroll -> False];
   SelectionMove[EvaluationNotebook[], After, CellGroup, AutoScroll -> False];,
   SelectionMove[EvaluationCell[], After, Cell, AutoScroll -> False]
   ];
  NotebookWrite[EvaluationNotebook[], 
   Cell[BoxData@ToBoxes@expr, "Print"], AutoScroll -> False])

The problem with loosing some output when clicking inside of the Notebook can be solved using FrontEnd`NotebookSuspendScreenUpdates and FrontEnd`NotebookResumeScreenUpdates as shown in this answer.

$\endgroup$
  • 2
    $\begingroup$ It'd be nice to define this to bind to the EvaluationCell and post after all of the other "Print" cells. $\endgroup$ – b3m2a1 Oct 6 '17 at 21:29
  • $\begingroup$ @b3m2a1 Isn't this is the default behavior already? $\endgroup$ – Alexey Popkov Oct 7 '17 at 1:44
  • 2
    $\begingroup$ Not if you've moved your cursor elsewhere in the notebook I believe. If you don't click in the notebook, yes, this is the default, but if you do click it isn't. $\endgroup$ – b3m2a1 Oct 7 '17 at 1:46
  • $\begingroup$ This seems to work beautifully, until you evaluate multiple cells at once, in which case it completely breaks. Then autoscrolling still happens, and the printing from all but the last evaluated cell disappears. $\endgroup$ – jjc385 Oct 7 '17 at 5:02
  • 1
    $\begingroup$ @jjc385 It is worth to report as a bug that autoscrolling still occurs with AutoScroll -> False. $\endgroup$ – Alexey Popkov Oct 7 '17 at 5:45
1
$\begingroup$

Here's another implementation like Alexey's that tries to preserve the current selection when possible. Only the first Print makes it move.

myInefficientPrint[expr_] :=
 Catch@
  Module[{
    ec = EvaluationCell[],
    enb = EvaluationNotebook[],
    replaceCell
    },
   If[MatchQ[ec, Except@_CellObject] || 
     MatchQ[enb, Except@_NotebookObject], Throw];
   replaceCell =
    Replace[
     Cells[enb,
      CellStyle -> {"Print"},
      CellTags -> ToString@First@ec
      ], {
      {} :> $Failed,
      {___, c_} :>
       If[
        CurrentValue[c, CellTags] === ToString /@ {$Line, First@ec},
        c,
        $Failed
        ]
      }];
   NotebookWrite[
    If[replaceCell === $Failed,
     SelectionMove[ec, After, Cell];
     enb,
     replaceCell
     ],
    {
     If[replaceCell === $Failed,
      Nothing,
      NotebookRead[replaceCell]
      ],
     Cell[BoxData@ToBoxes@expr,
      "Print", "MyPrint",
      CellTags -> ToString /@ {$Line, First@ec},
      GeneratedCell -> True,
      CellAutoOverwrite -> True
      ]
     },
    None,
    AutoScroll -> False
    ]
   ]

Do[Pause[.5]; myInefficientPrint[i], {i, 10}]

Unfortunately it doesn't buffer properly if you have an unresponsive FE, so sometimes it doesn't print if you're selecting something or doing something like that.

$\endgroup$

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.