progressbar - Barra de progreso de Python
tqdm print (21)
¿Cómo uso una barra de progreso cuando mi script está realizando alguna tarea que probablemente lleve tiempo?
Por ejemplo, una función que tarda un tiempo en completarse y devuelve True
cuando termina. ¿Cómo puedo visualizar una barra de progreso durante el tiempo que se está ejecutando la función?
Tenga en cuenta que necesito que esto sea en tiempo real, por lo que no puedo imaginar qué hacer al respecto. ¿Necesito un thread
para esto? No tengo idea.
En este momento no estoy imprimiendo nada mientras la función se está ejecutando, sin embargo, una barra de progreso sería agradable. También estoy más interesado en cómo se puede hacer esto desde el punto de vista del código.
@Massagran: Funciona bien en mis programas. Además, necesitamos agregar un contador para indicar los tiempos de ciclo. Este contador juega como el argumento de la update
método. Por ejemplo: lea todas las líneas de un archivo de prueba y trátelas en algo. Supongamos que la función dosth()
no se refiere a la variable i
.
lines = open(sys.argv[1]).readlines()
i = 0
widgets=[Percentage(), Bar()]
pbar = ProgressBar(widgets=widgets,maxval=len(lines)).start()
pbar.start()
for line in lines:<pre>
dosth();
i += 1
pbar.update(i)</pre>
pbar.finish()
La variable i
controla el estado de pbar
través de la update
método
Acabo de hacer una clase de progreso simple para mis necesidades después de buscar aquí una solución equivalente. Es difícil que pueda publicarlo.
from __future__ import print_function
import sys
import re
class ProgressBar(object):
DEFAULT = ''Progress: %(bar)s %(percent)3d%%''
FULL = ''%(bar)s %(current)d/%(total)d (%(percent)3d%%) %(remaining)d to go''
def __init__(self, total, width=40, fmt=DEFAULT, symbol=''='',
output=sys.stderr):
assert len(symbol) == 1
self.total = total
self.width = width
self.symbol = symbol
self.output = output
self.fmt = re.sub(r''(?P<name>%/(.+?/))d'',
r''/g<name>%dd'' % len(str(total)), fmt)
self.current = 0
def __call__(self):
percent = self.current / float(self.total)
size = int(self.width * percent)
remaining = self.total - self.current
bar = ''['' + self.symbol * size + '' '' * (self.width - size) + '']''
args = {
''total'': self.total,
''bar'': bar,
''current'': self.current,
''percent'': percent * 100,
''remaining'': remaining
}
print(''/r'' + self.fmt % args, file=self.output, end='''')
def done(self):
self.current = self.total
self()
print('''', file=self.output)
Ejemplo:
from time import sleep
progress = ProgressBar(80, fmt=ProgressBar.FULL)
for x in xrange(progress.total):
progress.current += 1
progress()
sleep(0.1)
progress.done()
Se imprimirá lo siguiente:
[======== ] 17/80 ( 21%) 63 to go
Aquí hay una solución corta que construye la barra de carga programáticamente (debe decidir cuánto tiempo la quiere).
import time
n = 33 # or however many loading slots you want to have
load = 0.01 # artificial loading time!
loading = ''.'' * n # for strings, * is the repeat operator
for i in range(n+1):
# this loop replaces each dot with a hash!
print(''/r%s Loading at %3d percent!'' % (loading, i*100/n), end='''')
loading = loading[:i] + ''#'' + loading[i+1:]
time.sleep(load)
Con tqdm , puede agregar un medidor de progreso a sus bucles en un segundo:
In [20]: import time
In [21]: from tqdm import tqdm
In [23]: for i in tqdm(range(10)):
....: time.sleep(3)
60%|██████ | 6/10 [00:18<00:12, 0.33 it/s]
Debe vincular la barra de progreso a la tarea en cuestión (para que mida el progreso: D). Por ejemplo, si está transfiriendo un archivo FTP, puede decirle a ftplib que tome un cierto tamaño de búfer, digamos 128K, y luego agregue a su barra de progreso cualquier porcentaje del tamaño del archivo 128k. Si está utilizando la CLI, y su medidor de progreso tiene 20 caracteres, agregará un carácter cuando se haya transferido la 20/20 del archivo.
El siguiente código es una solución bastante general y también tiene un tiempo transcurrido y el tiempo estimado restante. Puedes usar cualquier iterable con él. La barra de progreso tiene un tamaño fijo de 25 caracteres pero puede mostrar actualizaciones en pasos de 1% usando caracteres de bloque completo, medio y cuarto. La salida se ve así:
18% |████▌ | [0:00:01, 0:00:07]
Código con un ejemplo:
import sys, time
from numpy import linspace
def LoopWithProgressBar(iterObj, refreshTime=10):
#refreshTime=10: refresh the time estimate at least every 10 sec.
L = len(iterObj)
startT = time.time(); endT = startT
steps = {int(x):(int(y/4.0),int(y%4)) for x,y in zip(linspace(0,L-1,min(101,L)), linspace(0,100,min(101,L)))}
timeStr = '' [0:00:00, -:--:--]'' # [time elapsed, time remaining]
qSteps = ('''', u''/u258E'',u''/u258C'',u''/u258A'') # quarter and half block chars
def SecToStr(sec):
m, s = divmod(sec, 60)
h, m = divmod(m, 60)
return u''%d:%02d:%02d'' %(h,m,s)
for nn,op in enumerate(iterObj):
if nn in steps:
done = u''/u2588''*(steps[nn][0])+qSteps[steps[nn][1]]
todo = '' ''*(25-len(done))
barStr = ''%4d%% |%s%s|'' %((nn)/(L-1.0)*100.0, done, todo)
if nn>0:
barStr = ''/r''+barStr
endT = time.time()
timeStr = '' [%s, %s]''%(SecToStr(endT-startT), SecToStr((endT-startT)*(L/(nn+1.0)-1)))
if nn == L-1: timeStr += ''/n''
sys.stdout.write((barStr+timeStr).encode(''utf-8'')); sys.stdout.flush()
elif time.time()-endT > refreshTime:
endT = time.time()
timeStr = '' [%s, %s]''%(SecToStr(endT-startT), SecToStr((endT-startT)*(L/(nn+1.0)-1)))
sys.stdout.write((''/r''+barStr+timeStr).encode(''utf-8'')); sys.stdout.flush()
yield op
# Example
s = ''''
for op in LoopWithProgressBar(list(''Disassemble and reassemble this string'')):
time.sleep(0.5)
s += op
print s
Sugerencias de mejoras u otros comentarios son bienvenidos. Que te diviertas.
Es bastante sencillo en Python3:
import time
import math
def show_progress_bar(bar_length, completed, total):
bar_length_unit_value = (total / bar_length)
completed_bar_part = math.ceil(completed / bar_length_unit_value)
progress = "*" * completed_bar_part
remaining = " " * (bar_length - completed_bar_part)
percent_done = "%.2f" % ((completed / total) * 100)
print(f''[{progress}{remaining}] {percent_done}%'', end=''/r'')
bar_length = 30
total = 100
for i in range(0, total + 1):
show_progress_bar(bar_length, i, total)
time.sleep(0.1)
print(''/n'')
Hay bibliotecas específicas ( como esta aquí ) pero tal vez algo muy simple haría:
import time
import sys
toolbar_width = 40
# setup toolbar
sys.stdout.write("[%s]" % (" " * toolbar_width))
sys.stdout.flush()
sys.stdout.write("/b" * (toolbar_width+1)) # return to start of line, after ''[''
for i in xrange(toolbar_width):
time.sleep(0.1) # do real work here
# update the bar
sys.stdout.write("-")
sys.stdout.flush()
sys.stdout.write("/n")
Nota: esta barra de progreso es una bifurcación de la barra de progressbar que no se ha mantenido en años.
Las sugerencias anteriores son bastante buenas, pero creo que la mayoría de la gente solo quiere una solución preparada, sin dependencias en paquetes externos, pero también es reutilizable.
Obtuve los mejores puntos de todo lo anterior y lo convertí en una función, junto con un caso de prueba.
Para usarlo, simplemente copie las líneas en "def update_progress (progress)" pero no en el script de prueba. No olvides importar sys. Llámalo cuando necesites visualizar o actualizar la barra de progreso.
Esto funciona enviando directamente el símbolo "/ r" a la consola para mover el cursor de nuevo al inicio. "print" en python no reconoce el símbolo anterior para este propósito, por lo tanto, necesitamos ''sys''
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()
# update_progress test script
print "progress : ''hello''"
update_progress("hello")
time.sleep(1)
print "progress : 3"
update_progress(3)
time.sleep(1)
print "progress : [23]"
update_progress([23])
time.sleep(1)
print ""
print "progress : -10"
update_progress(-10)
time.sleep(2)
print ""
print "progress : 10"
update_progress(10)
time.sleep(2)
print ""
print "progress : 0->1"
for i in range(100):
time.sleep(0.1)
update_progress(i/100.0)
print ""
print "Test completed"
time.sleep(10)
Esto es lo que muestra el resultado del guión de prueba (la última barra de progreso se anima):
progress : ''hello''
Percent: [----------] 0% error: progress var must be float
progress : 3
Percent: [##########] 100% Done...
progress : [23]
Percent: [----------] 0% error: progress var must be float
progress : -10
Percent: [----------] 0% Halt...
progress : 10
Percent: [##########] 100% Done...
progress : 0->1
Percent: [##########] 99.0%
Test completed
Me gusta esta page
Comienza con un ejemplo simple y se mueve a una versión de subprocesos múltiples. Funciona de la caja. No se requieren paquetes de terceros.
El código se verá más o menos así:
import time
import sys
def do_task():
time.sleep(1)
def example_1(n):
for i in range(n):
do_task()
print ''/b.'',
sys.stdout.flush()
print '' Done!''
print ''Starting '',
example_1(10)
O aquí hay un ejemplo para usar subprocesos para ejecutar la barra de carga giratoria mientras el programa se está ejecutando:
import sys
import time
import threading
class progress_bar_loading(threading.Thread):
def run(self):
global stop
global kill
print ''Loading.... '',
sys.stdout.flush()
i = 0
while stop != True:
if (i%4) == 0:
sys.stdout.write(''/b/'')
elif (i%4) == 1:
sys.stdout.write(''/b-'')
elif (i%4) == 2:
sys.stdout.write(''/b//')
elif (i%4) == 3:
sys.stdout.write(''/b|'')
sys.stdout.flush()
time.sleep(0.2)
i+=1
if kill == True:
print ''/b/b/b/b ABORT!'',
else:
print ''/b/b done!'',
kill = False
stop = False
p = progress_bar_loading()
p.start()
try:
#anything you want to run.
time.sleep(1)
stop = True
except KeyboardInterrupt or EOFError:
kill = True
stop = True
Me gusta la respuesta de Brian Khuu por su simplicidad y por no necesitar paquetes externos. Lo cambié un poco, así que estoy agregando mi versión aquí:
import sys
import time
def updt(total, progress):
"""
Displays or updates a console progress bar.
Original source: https://.com/a/15860757/1391441
"""
barLength, status = 20, ""
progress = float(progress) / float(total)
if progress >= 1.:
progress, status = 1, "/r/n"
block = int(round(barLength * progress))
text = "/r[{}] {:.0f}% {}".format(
"#" * block + "-" * (barLength - block), round(progress * 100, 0),
status)
sys.stdout.write(text)
sys.stdout.flush()
runs = 300
for run_num in range(runs):
time.sleep(.1)
updt(runs, run_num + 1)
Toma el número total de ejecuciones ( total
) y el número de ejecuciones procesadas hasta el momento ( progress
) asumiendo total >= progress
. El resultado es así:
[#####---------------] 27%
Me gusta la respuesta de Gabriel , pero la cambié para ser flexible. Puede enviar una barra de longitud a la función y obtener su barra de progreso con la longitud que desee. Y no puede tener una barra de progreso con longitud cero o negativa. Además, puede utilizar esta función como la respuesta de Gabriel (Mire el ejemplo n. ° 2).
import sys
import time
def ProgressBar(Total, Progress, BarLength=20, ProgressIcon="#", BarIcon="-"):
try:
# You can''t have a progress bar with zero or negative length.
if BarLength <1:
BarLength = 20
# Use status variable for going to the next line after progress completion.
Status = ""
# Calcuting progress between 0 and 1 for percentage.
Progress = float(Progress) / float(Total)
# Doing this conditions at final progressing.
if Progress >= 1.:
Progress = 1
Status = "/r/n" # Going to the next line
# Calculating how many places should be filled
Block = int(round(BarLength * Progress))
# Show this
Bar = "[{}] {:.0f}% {}".format(ProgressIcon * Block + BarIcon * (BarLength - Block), round(Progress * 100, 0), Status)
return Bar
except:
return "ERROR"
def ShowBar(Bar):
sys.stdout.write(Bar)
sys.stdout.flush()
if __name__ == ''__main__'':
print("This is a simple progress bar./n")
# Example #1:
print(''Example #1'')
Runs = 10
for i in range(Runs + 1):
progressBar = "/rProgress: " + ProgressBar(10, i, Runs)
ShowBar(progressBar)
time.sleep(1)
# Example #2:
print(''/nExample #2'')
Runs = 10
for i in range(Runs + 1):
progressBar = "/rProgress: " + ProgressBar(10, i, 20, ''|'', ''.'')
ShowBar(progressBar)
time.sleep(1)
print(''/nDone.'')
# Example #2:
Runs = 10
for i in range(Runs + 1):
ProgressBar(10, i)
time.sleep(1)
Resultado:
Esta es una barra de progreso simple.
Ejemplo 1
Progreso: [### -------] 30%
Ejemplo n. ° 2
Progreso: [|||||||||||| ........] 60%
Hecho.
Muchas de las respuestas anteriores se basan en paquetes externos, pero también creo (como se dijo anteriormente) que la mayoría de la gente solo quiere una solución preparada. El código de abajo se puede adaptar a sus necesidades personalizando la parte de la cadena.
Es más simple y funciona sin la necesidad de un segundo hilo para actualizar la barra. Algunos paquetes anteriores hacen eso. Un segundo hilo puede ser un problema, por ejemplo, para un cuaderno ipython.
El siguiente código solo funciona con iteradores que proporcionan una longitud (es decir, se debe definir len (iterador)).
import sys
def progressbar(it, prefix="", size=60):
count = len(it)
def _show(_i):
x = int(size*_i/count)
sys.stdout.write("%s[%s%s] %i/%i/r" % (prefix, "#"*x, "."*(size-x), _i, count))
sys.stdout.flush()
_show(0)
for i, item in enumerate(it):
yield item
_show(i+1)
sys.stdout.write("/n")
sys.stdout.flush()
Ejemplo:
import time
for i in progressbar(range(15), "Computing: ", 40):
time.sleep(0.1) # any calculation you need
Salida:
Computing: [........................................] 0/15
...
Computing: [########................................] 3/15
...
Computing: [########################################] 15/15
puede ser cualquier objeto iterable con un len
, por ejemplo [''a'', ''b'', ''c''] `funciona bien.
Prueba PyProg. PyProg es una biblioteca de código abierto para que Python cree indicadores y barras de progreso súper personalizables.
Actualmente se encuentra en la versión 1.0.2; está alojado en Github y está disponible en PyPI (enlaces abajo). Es compatible con Python 3 y 2 y también se puede usar con Qt Console.
Es realmente fácil de usar. El siguiente código:
import pyprog
from time import sleep
# Create Object
prog = pyprog.ProgressBar(" ", "", 34)
# Update Progress Bar
prog.update()
for i in range(34):
# Do something
sleep(0.1)
# Set current status
prog.set_stat(i + 1)
# Update Progress Bar again
prog.update()
# Make the Progress Bar final
prog.end()
Producirá:
Initial State:
Progress: 0% --------------------------------------------------
When half done:
Progress: 50% #########################-------------------------
Final State:
Progress: 100% ##################################################
De hecho, hice PyProg porque necesitaba una biblioteca de barra de progreso simple pero súper personalizable. Puedes instalarlo fácilmente con: pip install pyprog
.
PyProg Github: https://github.com/Bill13579/pyprog
PyPI: https://pypi.python.org/pypi/pyprog/
Pruebe el progreso desde pypi.python.org/pypi/progress .
from progress.bar import Bar
bar = Bar(''Processing'', max=20)
for i in range(20):
# Do some work
bar.next()
bar.finish()
El resultado será una barra como la siguiente:
Processing |############# | 42/100
Realmente me gusta la python-progressbar , ya que es muy simple de usar.
Para el caso más simple, es simplemente:
import progressbar
import time
progress = progressbar.ProgressBar()
for i in progress(range(80)):
time.sleep(0.01)
La apariencia se puede personalizar y puede mostrar el tiempo restante estimado. Para un ejemplo use el mismo código que arriba pero con:
progress = progressbar.ProgressBar(widgets=[progressbar.Bar(''='', ''['', '']''), '' '',
progressbar.Percentage(), '' '',
progressbar.ETA()])
Si se trata de un gran bucle con una cantidad fija de iteraciones que lleva mucho tiempo, puede usar esta función que hice. Cada iteración del ciclo agrega progreso. Donde count es la iteración actual del bucle, total es el valor al que está pasando el bucle y el tamaño (int) es el tamaño que desea la barra en incrementos de 10, es decir (tamaño 1 = 10 caracteres, tamaño 2 = 20 caracteres)
import sys
def loadingBar(count,total,size)
percent = float(count)/float(total)*100
sys.stdout.write("/r" + str(int(count)).rjust(3,''0'')+"/"+str(int(total)).rjust(3,''0'') + '' ['' + ''=''*int(percent/10)*size + '' ''*(10-int(percent/10))*size + '']'')
ejemplo:
for i in range(0,100):
loadingBar(i,100,2)
#do some code
salida:
i = 50
>> 050/100 [========== ]
Si su trabajo no se puede dividir en trozos medibles, podría llamar a su función en un nuevo hilo y determinar cuánto tiempo lleva:
import thread
import time
import sys
def work():
time.sleep( 5 )
def locked_call( func, lock ):
lock.acquire()
func()
lock.release()
lock = thread.allocate_lock()
thread.start_new_thread( locked_call, ( work, lock, ) )
# This part is icky...
while( not lock.locked() ):
time.sleep( 0.1 )
while( lock.locked() ):
sys.stdout.write( "*" )
sys.stdout.flush()
time.sleep( 1 )
print "/nWork Done"
Obviamente, puede aumentar la precisión de sincronización según sea necesario.
También puedes usar enlighten . La principal ventaja es que puede iniciar sesión al mismo tiempo sin sobrescribir su barra de progreso.
import time
import enlighten
manager = enlighten.Manager()
pbar = manager.counter(total=100)
for num in range(1, 101):
time.sleep(0.05)
print(''Step %d complete'' % num)
pbar.update()
También maneja múltiples barras de progreso.
import time
import enlighten
manager = enlighten.Manager()
odds = manager.counter(total=50)
evens = manager.counter(total=50)
for num in range(1, 101):
time.sleep(0.05)
if num % 2:
odds.update()
else:
evens.update()
para una aplicación similar (haciendo un seguimiento del progreso en un bucle) simplemente utilicé la python-progressbar :
Su ejemplo es algo como esto,
from progressbar import * # just a simple progress bar
widgets = [''Test: '', Percentage(), '' '', Bar(marker=''0'',left=''['',right='']''),
'' '', ETA(), '' '', FileTransferSpeed()] #see docs for other options
pbar = ProgressBar(widgets=widgets, maxval=500)
pbar.start()
for i in range(100,500+1,50):
# here do something long at each iteration
pbar.update(i) #this adds a little symbol at each iteration
pbar.finish()
print