Merge branch 'progress-bar-class' into development

This commit is contained in:
Philip Eisenlohr 2020-03-10 17:30:21 -04:00
commit 598ce27d1f
2 changed files with 82 additions and 53 deletions

View File

@ -17,7 +17,7 @@ from . import Orientation
from . import Environment from . import Environment
from . import grid_filters from . import grid_filters
class Result(): class Result:
""" """
Read and write to DADF5 files. Read and write to DADF5 files.
@ -925,10 +925,9 @@ class Result():
groups = self.groups_with_datasets(datasets.values()) groups = self.groups_with_datasets(datasets.values())
default_arg = partial(self._job,func=func,datasets=datasets,args=args,lock=lock) default_arg = partial(self._job,func=func,datasets=datasets,args=args,lock=lock)
util.progressBar(iteration=0,total=len(groups)) for result in util.show_progress(pool.imap_unordered(default_arg,groups),len(groups)):
for i,result in enumerate(pool.imap_unordered(default_arg,groups)): if not result:
util.progressBar(iteration=i+1,total=len(groups)) continue
if not result: continue
lock.acquire() lock.acquire()
with h5py.File(self.fname, 'a') as f: with h5py.File(self.fname, 'a') as f:
try: try:

View File

@ -1,9 +1,9 @@
import sys import sys
import time import datetime
import os import os
import subprocess import subprocess
import shlex import shlex
from fractions import Fraction import fractions
from functools import reduce from functools import reduce
from optparse import Option from optparse import Option
@ -11,10 +11,10 @@ import numpy as np
class bcolors: class bcolors:
""" """
ASCII Colors (Blender code). ASCII Colors.
https://svn.blender.org/svnroot/bf-blender/trunk/blender/build_files/scons/tools/bcolors.py https://svn.blender.org/svnroot/bf-blender/trunk/blender/build_files/scons/tools/bcolors.py
http://stackoverflow.com/questions/287871/print-in-terminal-with-colors-using-python https://stackoverflow.com/questions/287871
""" """
HEADER = '\033[95m' HEADER = '\033[95m'
@ -165,49 +165,79 @@ class extendableOption(Option):
Option.take_action(self, action, dest, opt, value, values, parser) Option.take_action(self, action, dest, opt, value, values, parser)
def progressBar(iteration, total, prefix='', bar_length=50): class _ProgressBar:
""" """
Call in a loop to create terminal progress bar. Report progress of an interation as a status bar.
From https://gist.github.com/aubricus/f91fb55dc6ba5557fbab06119420dd6a Works for 0-based loops, ETA is estimated by linear extrapolation.
"""
def __init__(self,total,prefix,bar_length):
"""
Inititalize a progress bar to current time as basis for ETA estimation.
Parameters Parameters
---------- ----------
iteration : int
Current iteration.
total : int total : int
Total iterations. Total # of iterations.
prefix : str, optional prefix : str
Prefix string.
bar_length : int
Character length of bar.
"""
self.total = total
self.prefix = prefix
self.bar_length = bar_length
self.start_time = datetime.datetime.now()
self.last_fraction = 0.0
sys.stderr.write('{} {} 0% ETA n/a'.format(self.prefix, ''*self.bar_length))
sys.stderr.flush()
def update(self,iteration):
fraction = (iteration+1) / self.total
if int(self.bar_length * fraction) > int(self.bar_length * self.last_fraction):
delta_time = datetime.datetime.now() - self.start_time
remaining_time = (self.total - (iteration+1)) * delta_time / (iteration+1)
remaining_time -= datetime.timedelta(microseconds=remaining_time.microseconds) # remove μs
filled_length = int(self.bar_length * fraction)
bar = '' * filled_length + '' * (self.bar_length - filled_length)
sys.stderr.write('\r{} {} {:>4.0%} ETA {}'.format(self.prefix, bar, fraction, remaining_time))
sys.stderr.flush()
self.last_fraction = fraction
if iteration == self.total - 1:
sys.stderr.write('\n')
sys.stderr.flush()
def show_progress(iterable,N_iter=None,prefix='',bar_length=50):
"""
Decorate a loop with a status bar.
Use similar like enumerate.
Parameters
----------
iterable : iterable/function with yield statement
Iterable (or function with yield statement) to be decorated.
N_iter : int
Total # of iterations. Needed if number of iterations can not be obtained as len(iterable).
prefix : str, optional.
Prefix string. Prefix string.
bar_length : int, optional bar_length : int, optional
Character length of bar. Defaults to 50. Character length of bar. Defaults to 50.
""" """
fraction = iteration / float(total) status = _ProgressBar(N_iter if N_iter else len(iterable),prefix,bar_length)
if not hasattr(progressBar, "last_fraction"): # first call to function
progressBar.start_time = time.time()
progressBar.last_fraction = -1.0
remaining_time = ' n/a'
else:
if fraction <= progressBar.last_fraction or iteration == 0: # reset: called within a new loop
progressBar.start_time = time.time()
progressBar.last_fraction = -1.0
remaining_time = ' n/a'
else:
progressBar.last_fraction = fraction
remainder = (total - iteration) * (time.time()-progressBar.start_time)/iteration
remaining_time = '{: 3d}:'.format(int( remainder//3600)) + \
'{:02d}:'.format(int((remainder//60)%60)) + \
'{:02d}' .format(int( remainder %60))
filled_length = int(round(bar_length * fraction)) for i,item in enumerate(iterable):
bar = '' * filled_length + '' * (bar_length - filled_length) yield item
status.update(i)
sys.stderr.write('\r{} {} {}'.format(prefix, bar, remaining_time)),
if iteration == total:
sys.stderr.write('\n')
sys.stderr.flush()
def scale_to_coprime(v): def scale_to_coprime(v):
@ -216,7 +246,7 @@ def scale_to_coprime(v):
def get_square_denominator(x): def get_square_denominator(x):
"""Denominator of the square of a number.""" """Denominator of the square of a number."""
return Fraction(x ** 2).limit_denominator(MAX_DENOMINATOR).denominator return fractions.Fraction(x ** 2).limit_denominator(MAX_DENOMINATOR).denominator
def lcm(a, b): def lcm(a, b):
"""Least common multiple.""" """Least common multiple."""