progreso - python progress bar
Barra de progreso de texto en la consola (30)
¿Hay una buena manera de hacer lo siguiente?
Escribí una aplicación de consola simple para cargar y descargar archivos desde un servidor FTP utilizando el ftplib.
Cada vez que se descargan algunos fragmentos de datos, quiero actualizar una barra de progreso de texto, incluso si es solo un número.
Pero no quiero borrar todo el texto que se ha impreso en la consola. (Haciendo un "claro" y luego imprimiendo el porcentaje actualizado.)
Aquí está mi solución de Python 3:
import time
for i in range(100):
time.sleep(1)
s = "{}% Complete".format(i)
print(s,end=len(s) * ''/b'')
''/ b'' es una barra invertida, para cada carácter en su cadena. Esto no funciona dentro de la ventana de cmd de Windows.
Aquí hay un agregado de muchas de las respuestas a continuación que uso regularmente.
# Print iterations progress
def printProgressBar (iteration, total, prefix = '''', suffix = '''', decimals = 1, length = 100, fill = ''█''):
"""
Call in a loop to create terminal progress bar
@params:
iteration - Required : current iteration (Int)
total - Required : total iterations (Int)
prefix - Optional : prefix string (Str)
suffix - Optional : suffix string (Str)
decimals - Optional : positive number of decimals in percent complete (Int)
length - Optional : character length of bar (Int)
fill - Optional : bar fill character (Str)
"""
percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
filledLength = int(length * iteration // total)
bar = fill * filledLength + ''-'' * (length - filledLength)
print(''/r%s |%s| %s%% %s'' % (prefix, bar, percent, suffix), end = ''/r'')
# Print New Line on Complete
if iteration == total:
print()
#
# Sample Usage
#
from time import sleep
# A List of Items
items = list(range(0, 57))
l = len(items)
# Initial call to print 0% progress
printProgressBar(0, l, prefix = ''Progress:'', suffix = ''Complete'', length = 50)
for i, item in enumerate(items):
# Do stuff...
sleep(0.1)
# Update Progress Bar
printProgressBar(i + 1, l, prefix = ''Progress:'', suffix = ''Complete'', length = 50)
# Sample Output
Progress: |█████████████████████████████████████████████-----| 90.0% Complete
Bueno, aquí hay un código que funciona y lo probé antes de publicar:
import sys
def prg(prog, fillchar, emptchar):
fillt = 0
emptt = 20
if prog < 100 and prog > 0:
prog2 = prog/5
fillt = fillt + prog2
emptt = emptt - prog2
sys.stdout.write("/r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%")
sys.stdout.flush()
elif prog >= 100:
prog = 100
prog2 = prog/5
fillt = fillt + prog2
emptt = emptt - prog2
sys.stdout.write("/r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%" + "/nDone!")
sys.stdout.flush()
elif prog < 0:
prog = 0
prog2 = prog/5
fillt = fillt + prog2
emptt = emptt - prog2
sys.stdout.write("/r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%" + "/nHalted!")
sys.stdout.flush()
Pros:
- Barra de 20 caracteres (1 carácter por cada 5 (número))
- Caracteres de relleno personalizados
- Caracteres vacíos personalizados
- Detener (cualquier número por debajo de 0)
- Hecho (100 y cualquier número por encima de 100)
- Recuento de progreso (0-100 (por debajo y por encima utilizado para funciones especiales)
- Número de porcentaje junto a la barra, y es una sola línea
Contras:
- Solo es compatible con enteros (aunque se puede modificar para
prog2 = prog/5
, al hacer que la división sea una división entera, así que simplemente cambieprog2 = prog/5
aprog2 = int(prog/5)
)
Código para la barra de progreso de la terminal de Python
import sys
import time
max_length = 5
at_length = max_length
empty = "-"
used = "%"
bar = empty * max_length
for i in range(0, max_length):
at_length -= 1
#setting empty and full spots
bar = used * i
bar = bar+empty * at_length
#/r is carriage return(sets cursor position in terminal to start of line)
#/0 character escape
sys.stdout.write("[{}]/0/r".format(bar))
sys.stdout.flush()
#do your stuff here instead of time.sleep
time.sleep(1)
sys.stdout.write("/n")
sys.stdout.flush()
Con los grandes consejos anteriores trabajo la barra de progreso.
Sin embargo, me gustaría señalar algunas deficiencias
Cada vez que la barra de progreso se vacía, se iniciará en una nueva línea.
print(''/r[{0}]{1}%''.format(''#'' * progress* 10, progress))
Me gusta esto:
[] 0%
[#] 10%
[##] 20%
[###] 30%
2.El corchete '']'' y el número de porcentaje en el lado derecho se desplazan hacia la derecha a medida que ''###'' se alarga.
3. Se producirá un error si la expresión ''progreso / 10'' no puede devolver un entero.
Y el siguiente código solucionará el problema anterior.
def update_progress(progress, total):
print(''/r[{0:10}]{1:>2}%''.format(''#'' * int(progress * 10 /total), progress), end='''')
Consulta esta biblioteca: clint
Tiene muchas características que incluyen una barra de progreso:
from time import sleep
from random import random
from clint.textui import progress
if __name__ == ''__main__'':
for i in progress.bar(range(100)):
sleep(random() * 0.2)
for i in progress.dots(range(100)):
sleep(random() * 0.2)
Este link proporciona una visión general rápida de sus características.
Ejecute esto en la línea de comandos de Python ( no en ningún entorno de desarrollo o IDE):
>>> import threading
>>> for i in range(50+1):
... threading._sleep(0.5)
... print "/r%3d" % i, (''=''*i)+(''-''*(50-i)),
Funciona bien en mi sistema de Windows.
Es menos de 10 líneas de código.
La esencia aquí: https://gist.github.com/vladignatyev/06860ec2040cb497f0f3
import sys
def progress(count, total, suffix=''''):
bar_len = 60
filled_len = int(round(bar_len * count / float(total)))
percents = round(100.0 * count / float(total), 1)
bar = ''='' * filled_len + ''-'' * (bar_len - filled_len)
sys.stdout.write(''[%s] %s%s ...%s/r'' % (bar, percents, ''%'', suffix))
sys.stdout.flush() # As suggested by Rom Ruben
Escribí una barra de progreso simple:
def bar(total, current, length=10, prefix="", filler="#", space=" ", oncomp="", border="[]", suffix=""):
if len(border) != 2:
print("parameter ''border'' must include exactly 2 symbols!")
return None
print(prefix + border[0] + (filler * int(current / total * length) +
(space * (length - int(current / total * length)))) + border[1], suffix, "/r", end="")
if total == current:
if oncomp:
print(prefix + border[0] + space * int(((length - len(oncomp)) / 2)) +
oncomp + space * int(((length - len(oncomp)) / 2)) + border[1], suffix)
if not oncomp:
print(prefix + border[0] + (filler * int(current / total * length) +
(space * (length - int(current / total * length)))) + border[1], suffix)
Como puede ver, tiene: longitud de barra, prefijo y sufijo, relleno, espacio, texto en barra en 100% (oncomp) y bordes
aquí un ejemplo:
from time import sleep, time
start_time = time()
for i in range(10):
pref = str((i+1) * 10) + "% "
complete_text = "done in %s sec" % str(round(time() - start_time))
sleep(1)
bar(10, i + 1, length=20, prefix=pref, oncomp=complete_text)
en progreso
30% [###### ]
fuera completo
100% [ done in 9 sec ]
Escriba un /r
en la consola. Eso es un "retorno de carro" que hace que todo el texto que sigue después se haga eco al principio de la línea. Algo como:
def update_progress(progress):
print ''/r[{0}] {1}%''.format(''#''*(progress/10), progress)
lo que te dará algo como: [ ########## ] 100%
Escribir ''/ r'' moverá el cursor de nuevo al principio de la línea.
Esto muestra un contador de porcentaje:
import time
import sys
for i in range(100):
time.sleep(1)
sys.stdout.write("/r%d%%" % i)
sys.stdout.flush()
Estoy usando el progreso de reddit . Me gusta porque puede imprimir el progreso de cada elemento en una línea y no debe borrar las impresiones del programa.
Editar: enlace fijo
Función de Greenstick para 2.7:
def printProgressBar (iteration, total, prefix = '''', suffix = '''',decimals = 1, length = 100, fill = ''#''):
percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
filledLength = int(length * iteration // total)
bar = fill * filledLength + ''-'' * (length - filledLength)
print''/r%s |%s| %s%% %s'' % (prefix, bar, percent, suffix),
sys.stdout.flush()
# Print New Line on Complete
if iteration == total:
print()
Instale tqdm
. ( pip install tqdm
) y utilícelo de la siguiente manera:
import time
from tqdm import tqdm
for i in tqdm(range(1000)):
time.sleep(0.01)
Eso es una barra de progreso de 10 segundos que generará algo como esto:
47%|██████████████████▊ | 470/1000 [00:04<00:05, 98.61it/s]
Intenta instalar este paquete: pip install progressbar2
:
import time
import progressbar
for i in progressbar.progressbar(range(100)):
time.sleep(0.02)
progresssbar github: https://github.com/WoLpH/python-progressbar
La barra de progreso del módulo de Python es una buena opción. Aquí está mi código típico:
import time
import progressbar
widgets = [
'' '', progressbar.Percentage(),
'' '', progressbar.SimpleProgress(format=''(%(value_s)s of %(max_value_s)s)''),
'' '', progressbar.Bar(''>'', fill=''.''),
'' '', progressbar.ETA(format_finished=''- %(seconds)s -'', format=''ETA: %(seconds)s'', ),
'' - '', progressbar.DynamicMessage(''loss''),
'' - '', progressbar.DynamicMessage(''error''),
'' ''
]
bar = progressbar.ProgressBar(redirect_stdout=True, widgets=widgets)
bar.start(100)
for i in range(100):
time.sleep(0.1)
bar.update(i + 1, loss=i / 100., error=i)
bar.finish()
Me doy cuenta de que llego tarde al juego, pero aquí hay un estilo de Yum (Red Hat) que escribí (no voy al 100% de precisión aquí, pero si estás usando una barra de progreso para ese nivel de precisión, entonces estás equivocado de todos modos):
import sys
def cli_progress_test(end_val, bar_length=20):
for i in xrange(0, end_val):
percent = float(i) / end_val
hashes = ''#'' * int(round(percent * bar_length))
spaces = '' '' * (bar_length - len(hashes))
sys.stdout.write("/rPercent: [{0}] {1}%".format(hashes + spaces, int(round(percent * 100))))
sys.stdout.flush()
Debe producir algo parecido a esto:
Percent: [############## ] 69%
... donde los soportes permanecen estacionarios y solo aumentan los hash.
Esto podría funcionar mejor como decorador. Para otro día...
Prueba la biblioteca de click escrita por el Mozart de Python, Armin Ronacher.
$ pip install click # both 2 and 3 compatible
Para crear una barra de progreso simple:
import click
with click.progressbar(range(1000000)) as bar:
for i in bar:
pass
Esto es lo que parece:
# [###-------------------------------] 9% 00:01:14
Personalízalo a tu gusto contenido:
import click, sys
with click.progressbar(range(100000), file=sys.stderr, show_pos=True, width=70, bar_template=''(_(_)=%(bar)sD(_(_| %(info)s'', fill_char=''='', empty_char='' '') as bar:
for i in bar:
pass
Apariencia personalizada:
(_(_)===================================D(_(_| 100000/100000 00:00:02
Hay incluso más opciones, ver la documentación de la API :
click.progressbar(iterable=None, length=None, label=None, show_eta=True, show_percent=None, show_pos=False, item_show_func=None, fill_char=''#'', empty_char=''-'', bar_template=''%(label)s [%(bar)s] %(info)s'', info_sep='' '', width=36, file=None, color=None)
Recomiendo usar tqdm - https://pypi.python.org/pypi/tqdm - que hace que sea fácil convertir cualquier iterable o proceso en una barra de progreso, y maneja todos los problemas con los terminales necesarios.
De la documentación: "tqdm puede admitir fácilmente devoluciones de llamada / enlaces y actualizaciones manuales. Aquí hay un ejemplo con urllib"
import urllib
from tqdm import tqdm
def my_hook(t):
"""
Wraps tqdm instance. Don''t forget to close() or __exit__()
the tqdm instance once you''re done with it (easiest using `with` syntax).
Example
-------
>>> with tqdm(...) as t:
... reporthook = my_hook(t)
... urllib.urlretrieve(..., reporthook=reporthook)
"""
last_b = [0]
def inner(b=1, bsize=1, tsize=None):
"""
b : int, optional
Number of blocks just transferred [default: 1].
bsize : int, optional
Size of each block (in tqdm units) [default: 1].
tsize : int, optional
Total size (in tqdm units). If [default: None] remains unchanged.
"""
if tsize is not None:
t.total = tsize
t.update((b - last_b[0]) * bsize)
last_b[0] = b
return inner
eg_link = ''http://www.doc.ic.ac.uk/~cod11/matryoshka.zip''
with tqdm(unit=''B'', unit_scale=True, miniters=1,
desc=eg_link.split(''/'')[-1]) as t: # all optional kwargs
urllib.urlretrieve(eg_link, filename=''/dev/null'',
reporthook=my_hook(t), data=None)
Reuniendo algunas de las ideas que encontré aquí, y agregando el tiempo estimado restante:
import datetime, sys
start = datetime.datetime.now()
def print_progress_bar (iteration, total):
process_duration_samples = []
average_samples = 5
end = datetime.datetime.now()
process_duration = end - start
if len(process_duration_samples) == 0:
process_duration_samples = [process_duration] * average_samples
process_duration_samples = process_duration_samples[1:average_samples-1] + [process_duration]
average_process_duration = sum(process_duration_samples, datetime.timedelta()) / len(process_duration_samples)
remaining_steps = total - iteration
remaining_time_estimation = remaining_steps * average_process_duration
bars_string = int(float(iteration) / float(total) * 20.)
sys.stdout.write(
"/r[%-20s] %d%% (%s/%s) Estimated time left: %s" % (
''=''*bars_string, float(iteration) / float(total) * 100,
iteration,
total,
remaining_time_estimation
)
)
sys.stdout.flush()
if iteration + 1 == total:
print
# Sample usage
for i in range(0,300):
print_progress_bar(i, 300)
Una solución muy simple es poner este código en su bucle:
Ponga esto en el cuerpo (es decir, arriba) de su archivo:
import sys
Pon esto en el cuerpo de tu bucle:
sys.stdout.write("-") # prints a dash for each iteration of loop
sys.stdout.flush() # ensures bar is displayed incrementally
en base a las respuestas anteriores y otras preguntas similares sobre la barra de progreso de CLI, creo que obtuve una respuesta general común para todas ellas. Compruébelo en https://.com/a/15860757/2254146
En resumen, el código es este:
import time, sys
# update_progress() : Displays or updates a console progress bar
## Accepts a float between 0 and 1. Any int will be converted to a float.
## A value under 0 represents a ''halt''.
## A value at 1 or bigger represents 100%
def update_progress(progress):
barLength = 10 # Modify this to change the length of the progress bar
status = ""
if isinstance(progress, int):
progress = float(progress)
if not isinstance(progress, float):
progress = 0
status = "error: progress var must be float/r/n"
if progress < 0:
progress = 0
status = "Halt.../r/n"
if progress >= 1:
progress = 1
status = "Done.../r/n"
block = int(round(barLength*progress))
text = "/rPercent: [{0}] {1}% {2}".format( "#"*block + "-"*(barLength-block), progress*100, status)
sys.stdout.write(text)
sys.stdout.flush()
Parece
Porcentaje: [##########] 99.0%
jajaja, acabo de escribir una cosita completa para esto, aquí está el código, ten en cuenta que no puedes usar Unicode cuando haces el bloque ASCII, uso cp437
import os
import time
def load(left_side, right_side, length, time):
x = 0
y = ""
print "/r"
while x < length:
space = length - len(y)
space = " " * space
z = left + y + space + right
print "/r", z,
y += "█"
time.sleep(time)
x += 1
cls()
y tu lo llamas asi
print "loading something awesome"
load("|", "|", 10, .01)
asi se ve asi
loading something awesome
|█████ |
y, solo para agregar a la pila, aquí hay un objeto que puedes usar
import sys
class ProgressBar(object):
DEFAULT_BAR_LENGTH = 65
DEFAULT_CHAR_ON = ''=''
DEFAULT_CHAR_OFF = '' ''
def __init__(self, end, start=0):
self.end = end
self.start = start
self._barLength = self.__class__.DEFAULT_BAR_LENGTH
self.setLevel(self.start)
self._plotted = False
def setLevel(self, level):
self._level = level
if level < self.start: self._level = self.start
if level > self.end: self._level = self.end
self._ratio = float(self._level - self.start) / float(self.end - self.start)
self._levelChars = int(self._ratio * self._barLength)
def plotProgress(self):
sys.stdout.write("/r %3i%% [%s%s]" %(
int(self._ratio * 100.0),
self.__class__.DEFAULT_CHAR_ON * int(self._levelChars),
self.__class__.DEFAULT_CHAR_OFF * int(self._barLength - self._levelChars),
))
sys.stdout.flush()
self._plotted = True
def setAndPlot(self, level):
oldChars = self._levelChars
self.setLevel(level)
if (not self._plotted) or (oldChars != self._levelChars):
self.plotProgress()
def __add__(self, other):
assert type(other) in [float, int], "can only add a number"
self.setAndPlot(self._level + other)
return self
def __sub__(self, other):
return self.__add__(-other)
def __iadd__(self, other):
return self.__add__(other)
def __isub__(self, other):
return self.__add__(-other)
def __del__(self):
sys.stdout.write("/n")
if __name__ == "__main__":
import time
count = 150
print "starting things:"
pb = ProgressBar(count)
#pb.plotProgress()
for i in range(0, count):
pb += 1
#pb.setAndPlot(i + 1)
time.sleep(0.01)
del pb
print "done"
resultados en:
starting things:
100% [=================================================================]
done
Esto generalmente se considera "exagerado", pero es útil cuando lo usas mucho
tqdm: agregue un medidor de progreso a sus bucles en un segundo :
>>> import time
>>> from tqdm import tqdm
>>> for i in tqdm(range(100)):
... time.sleep(1)
...
|###-------| 35/100 35% [elapsed: 00:35 left: 01:05, 1.00 iters/sec]
https://pypi.python.org/pypi/progressbar2/3.30.2
Progressbar2 es una buena biblioteca para ascii base progressbar para la línea de comandos tiempo de importación barra de progreso de importación
bar = progressbar.ProgressBar()
for i in bar(range(100)):
time.sleep(0.02)
bar.finish()
https://pypi.python.org/pypi/tqdm
tqdm es una alternativa de progressbar2 y creo que se usa en pip3 pero no estoy seguro de eso
from tqdm import tqdm
for i in tqdm(range(10000)):
...
Aquí hay un buen ejemplo de una barra de progreso escrita en Python: http://nadiana.com/animated-terminal-progress-bar-in-python
Pero si quieres escribirlo tú mismo. Podrías usar el módulo de curses
para facilitar las cosas :)
[editar] Tal vez más fácil no es la palabra para maldiciones. Pero si quieres crear un cui completo, entonces Maldes se encarga de muchas cosas para ti.
[edit] Dado que el enlace anterior está muerto, he puesto mi propia versión de Python Progressbar, consígala aquí: https://github.com/WoLpH/python-progressbar
import sys
def progresssbar():
for i in range(100):
time.sleep(1)
sys.stdout.write("%i/r" % i)
progressbar()
NOTA: si ejecuta esto en el intérprete interactivo, obtendrá números adicionales impresos
import time,sys
for i in range(100+1):
time.sleep(0.1)
sys.stdout.write((''=''*i)+(''''*(100-i))+("/r [ %d"%i+"% ] "))
sys.stdout.flush()
salida
[29%] ===================
- http://code.activestate.com/recipes/168639-progress-bar-class/ (2002)
- http://code.activestate.com/recipes/299207-console-text-progress-indicator-class/ (2004)
- http://pypi.python.org/pypi/progressbar (2006)
Y muchos tutoriales a la espera de googlear.