Skip to content

Instantly share code, notes, and snippets.

@mattbierbaum
Created August 20, 2015 17:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattbierbaum/01cf43d50615ad7a99db to your computer and use it in GitHub Desktop.
Save mattbierbaum/01cf43d50615ad7a99db to your computer and use it in GitHub Desktop.
import sys
import time
import numpy as np
#=============================================================================
# Progress bar
#=============================================================================
class ProgressBar(object):
def __init__(self, num, label='Progress', value=0, screen=79,
time_remaining=True, bar=True, bar_symbol='=', bar_caps='[]',
bar_decimals=2, display=True):
"""
ProgressBar class which creates a dynamic ASCII progress bar of two
different varieties:
1) A bar chart that looks like the following:
Progress [================ ] 63.00%
2) A simple number completed look:
Progress : 17 / 289
Parameters:
-----------
num : integer
The number of tasks that need to be completed
label : string [default: 'Progress']
The label for this particular progress indicator,
value : integer [default: 0]
Starting value
screen : integer [default: 79]
Size the screen to use for the progress bar
time_remaining : boolean [default: True]
Display estimated time remaining
bar : boolean [default: True]
Whether or not to display the bar chart
bar_symbol : char [default: '=']
The character to use to fill in the bar chart
bar_caps : string [default: '[]']
Characters to use as the end caps of the. The string will be split in
half and each half put on a side of the chart
bar_decimals: integer [default: 2]
Number of decimal places to include in the _percentage
display : boolean [default: True]
a crutch so that we don't have a lot of `if`s later. display
or don't display the progress bar
"""
self.num = num
self.value = value
self._percent = 0
self.time_remaining = time_remaining
self._deltas = []
self.display = display
self.label = label
self.bar = bar
self._bar_symbol = bar_symbol
self._bar_caps = bar_caps
self._decimals = bar_decimals
self.screen = screen
if len(self._bar_caps) % 2 != 0:
raise AttributeError("End caps must be even number of symbols")
if self.bar:
# 3 digit _percent + decimal places + '.'
self._numsize = 3 + self._decimals + 1
# end caps size calculation
self._cap_len = len(self._bar_caps)/2
self._capl = self._bar_caps[:self._cap_len]
self._capr = self._bar_caps[self._cap_len:]
# time remaining calculation for space
self._time_space = 11 if self.time_remaining else 0
# the space available for the progress bar is
# 79 (screen) - (label) - (number) - 2 ([]) - 2 (space) - 1 (%)
self._barsize = (
self.screen - len(self.label) - self._numsize -
len(self._bar_caps) - 2 - 1 - self._time_space
)
self._formatstr = '\r{label} {_capl}{_bars:<{_barsize}}{_capr} {_percent:>{_numsize}.{_decimals}f}%'
self._percent = 0
self._dt = '--:--:--'
self._bars = ''
if self.time_remaining:
self._formatstr += " ({_dt})"
else:
self._digits = str(int(np.ceil(np.log10(self.num))))
self._formatstr = '\r{label} : {value:>{_digits}} / {num:>{_digits}}'
self._dt = '--:--:--'
if self.time_remaining:
self._formatstr += " ({_dt})"
self.update()
def _estimate_time(self):
if len(self._deltas) < 3:
self._dt = '--:--:--'
else:
dt = np.diff(self._deltas[-25:]).mean() * (self.num - self.value)
self._dt = time.strftime('%H:%M:%S', time.gmtime(dt))
def _draw(self):
""" Interal draw method, simply prints to screen """
if self.display:
print self._formatstr.format(**self.__dict__),
sys.stdout.flush()
def increment(self):
self.update(self.value + 1)
def update(self, value=0):
"""
Update the value of the progress and update progress bar.
Parameters:
-----------
value : integer
The current iteration of the progress
"""
self._deltas.append(time.time())
self.value = value
self._percent = 100.0 * self.value / self.num
if self.bar:
self._bars = self._bar_symbol*int(np.round(self._percent / 100. * self._barsize))
if (len(self._deltas) < 2) or (self._deltas[-1] - self._deltas[-2]) > 1e-1:
self._estimate_time()
self._draw()
if self.value == self.num:
self.end()
def end(self):
if self.display:
print '\r{lett:>{screen}}'.format(**{'lett':'', 'screen': self.screen})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment