real-time printing to console with R in jupyter
Asked Answered
E

4

5

Using an R GUI or just R from a command line, this code results in integers being printed 0.2 seconds apart.

In contrast when I use R in a jupyter notebook, all of the printing happens only after the loop is complete.

for(x in 1:10){
    print(x)
    Sys.sleep(0.2)
}

I tried to force real-time printing inside of Jupyter with

for(x in 1:10){
    print(x)
    flush.console()
    Sys.sleep(0.2)
}

...to no effect. The results were the same -- printing from within a for loop in jupyter always seems to be delayed until after the loop.

Is there a way to ensure the notebook outputs the results of print statements in a real time way?

Epoxy answered 7/6, 2016 at 21:28 Comment(2)
this is prbly worth posting an issue on IRKernel. There are hacks for it in python but not R.Postman
Thanks for the tip. I did file an issue. Afterwards, I found an interesting related issue that recommends using message() instead of print.Epoxy
R
10

Currently, the only way to "trigger" processing of printed output is either using message("text") (instead of print("text") or cat("text")) or not writing it into the loop but in a statement of it's own.

The underlying problem is in https://github.com/IRkernel/IRkernel/issues/3 and a proposed fix is in https://github.com/hadley/evaluate/pull/62 -> It needs a change in evaluate to allow flush.console() and friends to work. The gist of the problem: we use evaluate to execute the code and evaluate process the output one statement at a time and handles the output after the statement completes. Unfortunately, in this case, a for-loop is just one statement (as is everything in {...} blocks), so printed output only appears in the client after the for-loop is done.

A workaround is using the IRdisplay package and the display_...() functions instead of print()/cat() (or plots...). But this needs full control over the printed stuff: It's either everything is using print (and it gets delayed until after the complete statement is finished) or nothing should print (or plot) in that statement. If a called functions prints something, the output would be in the wrong order ({print("a"); display_text("b"); print("c")} would end up as b a c). Using capture.output() might get you around this limitation, if you really have to... If you use plots, there are currently no workarounds apart from writing the plot to disc and sending it via display_png(..) and friends.

Rociorock answered 8/6, 2016 at 8:28 Comment(1)
Thanks. It would be a "nice-to-have" to get this fixed but probably the most common use case is simply adding debugging or tracking statements to code blocks that are actively under development or that take a long time to run. For that use, message() works just fine. Getting plots to display in a certain order seems like a much less commonly-needed thing.Epoxy
M
2

This is not an issue any more. The following code works in jupterLab now

for(x in 1:10){
    print(x)
    flush.console()
    Sys.sleep(0.2)
}
Matthia answered 31/1, 2021 at 21:51 Comment(0)
C
0

R version of the answer for Python Flush output in for loop in Jupyter notebook works for me:

cat(paste0('Your text', '\r'))

Apparently \r will trigger a flush.

Chromolithography answered 4/11, 2020 at 22:40 Comment(1)
This is not correct, consider (\(){cat(paste0('Your text', '\r'));Sys.sleep(3)})() where Your text is only printed after 3 seconds.Languor
L
0

Jan Katins presented the relevant issue that has been resolved by now as David Chen writes.

For scenarios where foreign packages eventually rely on the function base::print() to continuously relay information, one could use trace() to flush after every print():

trace(what = "print", where = getNamespace("base"), exit = flush.console, print = FALSE)
Languor answered 7/4, 2023 at 10:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.