Printing on the same line on a jupyter notebook - python

In python 3, we can easily print on the same line using the following script. I use this to understand the progress of my loop (how much time will be left). However, in jupyter it doesnt work (it prints on different lines)
import time
for f in range(10):
print(f, end='\r', flush=True)
time.sleep(10)
It doesnt work to turn pretty print off %pprint, and I tried the same with sys.stdout.write() but also there I have this issue.

Found the solution to this a bit later (note that it does not work in pycharm jupyter, but only in the browser implementation). For me print works fine, but here display is advised, but it prints apostrophes around strings.
from time import sleep
from IPython.display import clear_output, display
for f in range(10):
clear_output(wait=True)
print(f) # use display(f) if you encounter performance issues
sleep(10)
Edit: Just wanted to add that TQDM is often also a good tool for this goal. It displays progress bars and allows you to write output below it or differ the description of each bar. See also this post.
import sys
from tqdm import tqdm
from time import sleep
values = range(3)
with tqdm(total=len(values), file=sys.stdout) as pbar:
for i in values:
pbar.set_description('processed: %d' % (1 + i))
pbar.update(1)
sleep(1)
And the notebook one with nice colours
from tqdm import tqdm, tqdm_notebook
from time import sleep
for i in tqdm_notebook(range(2), desc='1st loop'):
sleep(0.01)
tqdm.write(f"Done task {i}")

Prefix a \r and add an argument end="" to print, like so
print("\rThis will be printed on the same line", end="")
This works in the Jupyter notebook in Google Colab.

The part "\r" overwrites the line, if you leave that you append to the line. Your version print(f, end='', flush=False) could work but I've read under Python 3 you need to use sys.stdout.write() and best is if you add flush command too.
import sys
import time
for f in range(10):
#delete "\r" to append instead of overwrite
sys.stdout.write("\r" + str(f))
sys.stdout.flush()
time.sleep(10)
The stdout.flush is required on some systems or you won't get any output

In some cases, the issue could arise when multiple arguments are given to the print statement.
for i in range(3):
print(i, "-", i ** 2, end="\r")
The above snippet prints 2 - 0 - 1 - 4 in a jupyter notebook. However, passing a single argument to print will give the desired result of 2 - 4 i.e. 0 - 0 is overwritten by 1 - 2 which is in-turn overwritten by 2 - 4
for i in range(3):
print(f"{i} - {i ** 2}", end="\r")
Here are the package versions that I am using.
# Name Version
notebook 6.4.12
ipython 8.4.0
python 3.8.13
jupyter-client 7.3.4

Related

Update only two lines in print inside jupyter notebbok

I want to print only two lines in my cycles, I started with the following:
import time
for i in range(10):
time.sleep(0.5)
for j in range(10):
time.sleep(0.5)
print('Index1:', i)
print('Index2:', j)
I tried different combinations of \r, \n, flush=True etc. at the beginning and end of print, but wasn't successful((
What I'd like to see is as in the GIF of accepted answer here
I tried those code, but it didn't help, maybe because my OS is Windows or I use jupyter notebook, I have no idea((
For Jupyter import clear_output from IPython.display. On terminal you can use something like os.system('clear') for Linux or os.system('cls') for Windows.
import time
import os
from IPython.display import clear_output
for i in range(10):
for j in range(10):
print(f'Index1: {i}\nIndex2: {j}')
time.sleep(0.5)
# for terminal ('clear' for Linux, 'cls' for Windows)
# os.system('clear')
# for Jupyter
clear_output(wait=True)
In Jupyter Notebook, you can clear current cell output using IPython.display.clear_output(wait=True)
In terminal, similiar behaviour can be achieved using ANSI escape codes, as in the following snippet:
import time
n = 15
for i in range(n):
print(f"{i}s passed")
print(f"{n-i}s remaining")
time.sleep(1)
print("\u001b[2A", end="") #ANSI escape code for cursor up 2 lines
remember that you must use end inside print()
try this code:
import time
for i in range(10):
time.sleep(0.5)
for j in range(10):
time.sleep(0.5)
print(f'\rIndex1: {i}, Index2: {j}', flush=True, end='')

How to perform a multiline flush with print or sys.stdout.write [duplicate]

I know it is possible to consistently rewrite the last line displayed in the terminal with "\r", but I am having trouble figuring out if there is a way to go back and edit previous lines printed in the console.
What I would like to do is reprint multiple lines for a text-based RPG, however, a friend was also wondering about this for an application which had one line dedicated to a progress bar, and another describing the download.
i.e. the console would print:
Moving file: NameOfFile.txt
Total Progress: [######## ] 40%
and then update appropriately (to both lines) as the program was running.
On Unix, use the curses module.
On Windows, there are several options:
PDCurses: http://www.lfd.uci.edu/~gohlke/pythonlibs/
The HOWTO linked above recommends the Console module
http://newcenturycomputers.net/projects/wconio.html
http://docs.activestate.com/activepython/2.6/pywin32/win32console.html
Simple example using curses (I am a total curses n00b):
import curses
import time
def report_progress(filename, progress):
"""progress: 0-10"""
stdscr.addstr(0, 0, "Moving file: {0}".format(filename))
stdscr.addstr(1, 0, "Total progress: [{1:10}] {0}%".format(progress * 10, "#" * progress))
stdscr.refresh()
if __name__ == "__main__":
stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
try:
for i in range(10):
report_progress("file_{0}.txt".format(i), i+1)
time.sleep(0.5)
finally:
curses.echo()
curses.nocbreak()
curses.endwin()
Like this:
#!/usr/bin/env python
import sys
import time
from collections import deque
queue = deque([], 3)
for t in range(20):
time.sleep(0.5)
s = "update %d" % t
for _ in range(len(queue)):
sys.stdout.write("\x1b[1A\x1b[2K") # move up cursor and delete whole line
queue.append(s)
for i in range(len(queue)):
sys.stdout.write(queue[i] + "\n") # reprint the lines
I discovered this in the Jiri project, written in Go.
Even better: erase all lines after done:
#!/usr/bin/env python
import sys
import time
from collections import deque
queue = deque([], 3)
t = 0
while True:
time.sleep(0.5)
if t <= 20:
s = "update %d" % t
t += 1
else:
s = None
for _ in range(len(queue)):
sys.stdout.write("\x1b[1A\x1b[2K") # move up cursor and delete whole line
if s != None:
queue.append(s)
else:
queue.popleft()
if len(queue) == 0:
break
for i in range(len(queue)):
sys.stdout.write(queue[i] + "\n") # reprint the lines
Ultimately, if you want to manipulate the screen, you need to use the underlying OS libraries, which will typically be:
curses (or the underlying terminal control codes as tracked by the terminfo/termcap database) on Linux or OSX
the win32 console API on Windows.
The answer from #codeape already gives you some of the many options if you don't mind sticking to one OS or are happy to install third party libraries on Windows.
However, if you want a cross-platform solution that you can simply pip install, you could use asciimatics. As part of developing this package, I've had to resolve the differences between environments to provide a single API that works on Linux, OSX and Windows.
For progress bars, you could use the BarChart object as shown in this demo using this code.
Here is a Python module for both Python 2/3, which can simply solve such situation with a few line of code ;D
reprint - A simple module for Python 2/3 to print and refresh multi line output contents in terminal
You can simply treat that output instance as a normal dict or list(depend on which mode you use). When you modify that content in the output instance, the output in terminal will automatically refresh :D
For your need, here is the code:
from reprint import output
import time
if __name__ == "__main__":
with output(output_type='dict') as output_lines:
for i in range(10):
output_lines['Moving file'] = "File_{}".format(i)
for progress in range(100):
output_lines['Total Progress'] = "[{done}{padding}] {percent}%".format(
done = "#" * int(progress/10),
padding = " " * (10 - int(progress/10)),
percent = progress
)
time.sleep(0.05)
Carriage return can be used to go to the beginning of line, and ANSI code ESC A ("\033[A") can bring you up a line. This works on Linux. It can work on Windows by using the colorama package to enable ANSI codes:
import time
import sys
import colorama
colorama.init()
print("Line 1")
time.sleep(1)
print("Line 2")
time.sleep(1)
print("Line 3 (no eol)", end="")
sys.stdout.flush()
time.sleep(1)
print("\rLine 3 the sequel")
time.sleep(1)
print("\033[ALine 3 the second sequel")
time.sleep(1)
print("\033[A\033[A\033[ALine 1 the sequel")
time.sleep(1)
print() # skip two lines so that lines 2 and 3 don't get overwritten by the next console prompt
print()
Output:
> python3 multiline.py
Line 1 the sequel
Line 2
Line 3 the second sequel
>
Under the hood, colorama presumably enables Console Virtual Terminal Sequences
using SetConsoleMode.
(also posted here: https://stackoverflow.com/a/64360937/461834)
You can try tqdm.
from time import sleep
from tqdm import tqdm
from tqdm import trange
files = [f'file_{i}' for i in range(10)]
desc_bar = tqdm(files, bar_format='{desc}')
prog_bar = trange(len(files), desc='Total Progress', ncols=50, ascii=' #',
bar_format='{desc}: [{bar}] {percentage:3.0f}%')
for f in desc_bar:
desc_bar.set_description_str(f'Moving file: {f}')
prog_bar.update(1)
sleep(0.25)
There is also nested progress bars feature of tqdm
from tqdm.auto import trange
from time import sleep
for i in trange(4, desc='1st loop'):
for k in trange(50, desc='2rd loop', leave=False):
sleep(0.01)
Note that nested progress bars in tqdm have some Known Issues:
Consoles in general: require support for moving cursors up to the previous line. For example, IDLE, ConEmu and PyCharm (also here, here, and here) lack full support.
Windows: additionally may require the Python module colorama to ensure nested bars stay within their respective lines.
For nested progress bar in Python, Double Progress Bar in Python - Stack Overflow has more info.
I found simple solution with a "magic_char".
magic_char = '\033[F'
multi_line = 'First\nSecond\nThird'
ret_depth = magic_char * multi_line.count('\n')
print('{}{}'.format(ret_depth, multi_line), end='', flush = True)

Flush output in for loop in Jupyter notebook

I want to print out i in my iteration on Jupyter notebook and flush it out. After the next iteration, I'll print the next i. I tried solutions from this question and this question, however, it just print out 0123...9 without flushing the output for me. Here is my working code:
import sys
import time
for i in range(10):
sys.stdout.write(str(i)) # or print(i, flush=True) ?
time.sleep(0.5)
sys.stdout.flush()
these are my setup: ipython 5.1, python 3.6. Maybe, I missed something in the previous solution?
#Try this:
import sys
import time
for i in range (10):
sys.stdout.write('\r'+str(i))
time.sleep(0.5)
'\r' will print at the beginning of the line
The first answer is correct but you don't need sys package. You can use the end parameter of the print function. It specifies what to print at the end, and its default value is \n(newline) (docs1, docs2). Use \r(carriage return) instead.
import time
for i in range (10):
print(i, end="\r")
time.sleep(0.5) # This line is to see if it's working or not
Try this
for i in range (10):
print("\r", end=str(i))

How to reset cursor to the beginning of the same line in Python

Most of questions related to this topics here in SO is as follows:
How to print some information on the same line without introducing a
new line
Q1 Q2.
Instead, my question is as follows:
I expect to see the following effect,
>> You have finished 10%
where the 10 keep increasing in the same time. I know how to do this in C++ but cannot
find a good solution in python.
import sys, time
for i in xrange(0, 101, 10):
print '\r>> You have finished %d%%' % i,
sys.stdout.flush()
time.sleep(2)
print
The \r is the carriage return. You need the comma at the end of the print statement to avoid automatic newline. Finally sys.stdout.flush() is needed to flush the buffer out to stdout.
For Python 3, you can use:
print("\r>> You have finished {}%".format(i), end='')
Python 3
You can use keyword arguments to print:
print('string', end='\r', flush=True)
end='\r' replaces the default end-of-line behavior with '\r'
flush=True flushes the buffer, making the printed text appear immediately.
Python 2
In 2.6+ you can use from __future__ import print_function at the start of the script to enable Python 3 behavior. Or use the old way:
Python's print puts a newline after each command, unless you suppress it with a trailing comma. So, the print command is:
print 'You have finished {0}%\r'.format(percentage),
Note the comma at the end.
Unfortunately, Python only sends the output to the terminal after a complete line. The above is not a complete line, so you need to flush it manually:
import sys
sys.stdout.flush()
On linux( and probably on windows) you can use curses module like this
import time
import curses
win = curses.initscr()
for i in range(100):
win.clear()
win.addstr("You have finished %d%%"%i)
win.refresh()
time.sleep(.1)
curses.endwin()
Benfit with curses as apposed to other simpler technique is that, you can draw on terminal like a graphics program, because curses provides moving to any x,y position e.g. below is a simple script which updates four views
import time
import curses
curses.initscr()
rows = 10
cols= 30
winlist = []
for r in range(2):
for c in range(2):
win = curses.newwin(rows, cols, r*rows, c*cols)
win.clear()
win.border()
winlist.append(win)
for i in range(100):
for win in winlist:
win.addstr(5,5,"You have finished - %d%%"%i)
win.refresh()
time.sleep(.05)
curses.endwin()
I had to combine a few answers above to make it work on Python 3.7 / Windows 10. The example runs on Spyder's console:
import sys, time
for i in range(0, 101, 5):
print("\r>> You have finished {}%".format(i), end='')
sys.stdout.flush()
time.sleep(.2)
The time.sleep(.2) is just used to simulates some time-consuming code.
using sys.stdout.write() instead of print works in both python 2 and 3 without any compromises.
The OP didn't specify Py2 or Py3. In Python 3 the 'import' of 'sys' and the 'sys.stdout' call can be replaced with 'flush=True':
import time
for i in range(0,101,25):
print("\r>>TESTING - {:0>3d}%".format(i), end='', flush=True)
time.sleep(.5)
print()
Thanks to Petr Viktorin for showing the "flush" parameter for Python 3 print(). I submit this because his Python 3 example doesn't include a 'format' specifier. It took me awhile to figure out that the additional parameters go after the 'format' specifier parentheses as shown in my example. I just picked an example format of 3 character integer 0 filled on the left. The best doc I found for Py3 format is: 6.1.3.1. Format Specification Mini-Language

How to rewrite output in terminal

I have a Python script and I want to make it display a increasing number from 0 to 100% in the terminal. I know how to print the numbers on the terminal but how can I "rewrite" them so 0 turns into 1, 1 into 2, and so on until 100?
Printing a carriage return (\r) without a newline resets the cursor to the beginning of the line, making the next print overwriting what's already printed:
import time
import sys
for i in range(100):
print i,
sys.stdout.flush()
time.sleep(1)
print "\r",
This doesn't clear the line, so if you try to, say, print decreasing numbers using this methods, you'll see leftover text from previous prints. You can work around this by padding out your output with spaces, or using some of the control codes in the other answers.
This recipe here should prove useful. Using that module as tc, the following code does what you want:
from tc import TerminalController
from time import sleep
import sys
term = TerminalController()
for i in range(10):
sys.stdout.write("%3d" % i)
sys.stdout.flush()
sleep(2)
sys.stdout.write(term.BOL + term.CLEAR_EOL)
The recipe uses terminfo to get information about the terminal and works in Linux and OS X for a number of terminals. It does not work on Windows, though. (Thanks to piquadrat for testing, as per the comment below).
Edit: The recipe also gives capabilities for using colours and rewriting part of the line. It also has a ready made text progress bar.
Using the blessings package - clear your screen (clear/cls) and enter:
import sys
from blessings import Terminal
from time import sleep # <- boy, does this sound tempting a.t.m.
term = Terminal()
for i in range(6):
with term.location(term.width - 3, term.height - 3):
print('{}'.format(i))
sleep(2)
if (i == 3):
print('what was I doing, again?')
print('done')
To install it from CheeseShop, just...
pip install blessings
Based on this answer, but without the terminal controller:
import time
import sys
for i in range(100):
sys.stdout.write("Downloading ... %s%%\r" % (i))
sys.stdout.flush()
time.sleep(1)
Tested on GNOME terminal (Linux) and Windows console.
Tip: Don't run this example in IDLE editor.

Categories