| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- """
- GUI progressbar decorator for iterators.
- Includes a default `range` iterator printing to `stderr`.
- Usage:
- >>> from tqdm.gui import trange, tqdm
- >>> for i in trange(10):
- ... ...
- """
- # future division is important to divide integers and get as
- # a result precise floating numbers (instead of truncated int)
- from __future__ import division, absolute_import
- # import compatibility functions and utilities
- from .utils import _range
- # to inherit from the tqdm class
- from .std import tqdm as std_tqdm
- from .std import TqdmExperimentalWarning
- from warnings import warn
- __author__ = {"github.com/": ["casperdcl", "lrq3000"]}
- __all__ = ['tqdm_gui', 'tgrange', 'tqdm', 'trange']
- class tqdm_gui(std_tqdm): # pragma: no cover
- """
- Experimental GUI version of tqdm!
- """
- # TODO: @classmethod: write() on GUI?
- def __init__(self, *args, **kwargs):
- import matplotlib as mpl
- import matplotlib.pyplot as plt
- from collections import deque
- kwargs['gui'] = True
- super(tqdm_gui, self).__init__(*args, **kwargs)
- # Initialize the GUI display
- if self.disable or not kwargs['gui']:
- return
- warn('GUI is experimental/alpha', TqdmExperimentalWarning, stacklevel=2)
- self.mpl = mpl
- self.plt = plt
- self.sp = None
- # Remember if external environment uses toolbars
- self.toolbar = self.mpl.rcParams['toolbar']
- self.mpl.rcParams['toolbar'] = 'None'
- self.mininterval = max(self.mininterval, 0.5)
- self.fig, ax = plt.subplots(figsize=(9, 2.2))
- # self.fig.subplots_adjust(bottom=0.2)
- total = self.__len__() # avoids TypeError on None #971
- if total is not None:
- self.xdata = []
- self.ydata = []
- self.zdata = []
- else:
- self.xdata = deque([])
- self.ydata = deque([])
- self.zdata = deque([])
- self.line1, = ax.plot(self.xdata, self.ydata, color='b')
- self.line2, = ax.plot(self.xdata, self.zdata, color='k')
- ax.set_ylim(0, 0.001)
- if total is not None:
- ax.set_xlim(0, 100)
- ax.set_xlabel('percent')
- self.fig.legend((self.line1, self.line2), ('cur', 'est'),
- loc='center right')
- # progressbar
- self.hspan = plt.axhspan(0, 0.001,
- xmin=0, xmax=0, color='g')
- else:
- # ax.set_xlim(-60, 0)
- ax.set_xlim(0, 60)
- ax.invert_xaxis()
- ax.set_xlabel('seconds')
- ax.legend(('cur', 'est'), loc='lower left')
- ax.grid()
- # ax.set_xlabel('seconds')
- ax.set_ylabel((self.unit if self.unit else 'it') + '/s')
- if self.unit_scale:
- plt.ticklabel_format(style='sci', axis='y',
- scilimits=(0, 0))
- ax.yaxis.get_offset_text().set_x(-0.15)
- # Remember if external environment is interactive
- self.wasion = plt.isinteractive()
- plt.ion()
- self.ax = ax
- def __iter__(self):
- # TODO: somehow allow the following:
- # if not self.gui:
- # return super(tqdm_gui, self).__iter__()
- iterable = self.iterable
- if self.disable:
- for obj in iterable:
- yield obj
- return
- # ncols = self.ncols
- mininterval = self.mininterval
- maxinterval = self.maxinterval
- miniters = self.miniters
- dynamic_miniters = self.dynamic_miniters
- last_print_t = self.last_print_t
- last_print_n = self.last_print_n
- n = self.n
- # dynamic_ncols = self.dynamic_ncols
- smoothing = self.smoothing
- avg_time = self.avg_time
- time = self._time
- for obj in iterable:
- yield obj
- # Update and possibly print the progressbar.
- # Note: does not call self.update(1) for speed optimisation.
- n += 1
- # check counter first to avoid calls to time()
- if n - last_print_n >= self.miniters:
- miniters = self.miniters # watch monitoring thread changes
- delta_t = time() - last_print_t
- if delta_t >= mininterval:
- cur_t = time()
- delta_it = n - last_print_n
- # EMA (not just overall average)
- if smoothing and delta_t and delta_it:
- rate = delta_t / delta_it
- avg_time = self.ema(rate, avg_time, smoothing)
- self.avg_time = avg_time
- self.n = n
- self.display()
- # If no `miniters` was specified, adjust automatically
- # to the max iteration rate seen so far between 2 prints
- if dynamic_miniters:
- if maxinterval and delta_t >= maxinterval:
- # Adjust miniters to time interval by rule of 3
- if mininterval:
- # Set miniters to correspond to mininterval
- miniters = delta_it * mininterval / delta_t
- else:
- # Set miniters to correspond to maxinterval
- miniters = delta_it * maxinterval / delta_t
- elif smoothing:
- # EMA-weight miniters to converge
- # towards the timeframe of mininterval
- rate = delta_it
- if mininterval and delta_t:
- rate *= mininterval / delta_t
- miniters = self.ema(rate, miniters, smoothing)
- else:
- # Maximum nb of iterations between 2 prints
- miniters = max(miniters, delta_it)
- # Store old values for next call
- self.n = self.last_print_n = last_print_n = n
- self.last_print_t = last_print_t = cur_t
- self.miniters = miniters
- # Closing the progress bar.
- # Update some internal variables for close().
- self.last_print_n = last_print_n
- self.n = n
- self.miniters = miniters
- self.close()
- def update(self, n=1):
- # if not self.gui:
- # return super(tqdm_gui, self).close()
- if self.disable:
- return
- if n < 0:
- self.last_print_n += n # for auto-refresh logic to work
- self.n += n
- # check counter first to reduce calls to time()
- if self.n - self.last_print_n >= self.miniters:
- delta_t = self._time() - self.last_print_t
- if delta_t >= self.mininterval:
- cur_t = self._time()
- delta_it = self.n - self.last_print_n # >= n
- # elapsed = cur_t - self.start_t
- # EMA (not just overall average)
- if self.smoothing and delta_t and delta_it:
- rate = delta_t / delta_it
- self.avg_time = self.ema(
- rate, self.avg_time, self.smoothing)
- self.display()
- # If no `miniters` was specified, adjust automatically to the
- # maximum iteration rate seen so far between two prints.
- # e.g.: After running `tqdm.update(5)`, subsequent
- # calls to `tqdm.update()` will only cause an update after
- # at least 5 more iterations.
- if self.dynamic_miniters:
- if self.maxinterval and delta_t >= self.maxinterval:
- if self.mininterval:
- self.miniters = delta_it * self.mininterval \
- / delta_t
- else:
- self.miniters = delta_it * self.maxinterval \
- / delta_t
- elif self.smoothing:
- self.miniters = self.smoothing * delta_it * \
- (self.mininterval / delta_t
- if self.mininterval and delta_t
- else 1) + \
- (1 - self.smoothing) * self.miniters
- else:
- self.miniters = max(self.miniters, delta_it)
- # Store old values for next call
- self.last_print_n = self.n
- self.last_print_t = cur_t
- def close(self):
- # if not self.gui:
- # return super(tqdm_gui, self).close()
- if self.disable:
- return
- self.disable = True
- with self.get_lock():
- self._instances.remove(self)
- # Restore toolbars
- self.mpl.rcParams['toolbar'] = self.toolbar
- # Return to non-interactive mode
- if not self.wasion:
- self.plt.ioff()
- if not self.leave:
- self.plt.close(self.fig)
- def display(self):
- n = self.n
- cur_t = self._time()
- elapsed = cur_t - self.start_t
- delta_it = n - self.last_print_n
- delta_t = cur_t - self.last_print_t
- # Inline due to multiple calls
- total = self.total
- xdata = self.xdata
- ydata = self.ydata
- zdata = self.zdata
- ax = self.ax
- line1 = self.line1
- line2 = self.line2
- # instantaneous rate
- y = delta_it / delta_t
- # overall rate
- z = n / elapsed
- # update line data
- xdata.append(n * 100.0 / total if total else cur_t)
- ydata.append(y)
- zdata.append(z)
- # Discard old values
- # xmin, xmax = ax.get_xlim()
- # if (not total) and elapsed > xmin * 1.1:
- if (not total) and elapsed > 66:
- xdata.popleft()
- ydata.popleft()
- zdata.popleft()
- ymin, ymax = ax.get_ylim()
- if y > ymax or z > ymax:
- ymax = 1.1 * y
- ax.set_ylim(ymin, ymax)
- ax.figure.canvas.draw()
- if total:
- line1.set_data(xdata, ydata)
- line2.set_data(xdata, zdata)
- try:
- poly_lims = self.hspan.get_xy()
- except AttributeError:
- self.hspan = self.plt.axhspan(
- 0, 0.001, xmin=0, xmax=0, color='g')
- poly_lims = self.hspan.get_xy()
- poly_lims[0, 1] = ymin
- poly_lims[1, 1] = ymax
- poly_lims[2] = [n / total, ymax]
- poly_lims[3] = [poly_lims[2, 0], ymin]
- if len(poly_lims) > 4:
- poly_lims[4, 1] = ymin
- self.hspan.set_xy(poly_lims)
- else:
- t_ago = [cur_t - i for i in xdata]
- line1.set_data(t_ago, ydata)
- line2.set_data(t_ago, zdata)
- ax.set_title(self.format_meter(
- n, total, elapsed, 0,
- self.desc, self.ascii, self.unit, self.unit_scale,
- 1 / self.avg_time if self.avg_time else None, self.bar_format,
- self.postfix, self.unit_divisor),
- fontname="DejaVu Sans Mono", fontsize=11)
- self.plt.pause(1e-9)
- def tgrange(*args, **kwargs):
- """
- A shortcut for `tqdm.gui.tqdm(xrange(*args), **kwargs)`.
- On Python3+, `range` is used instead of `xrange`.
- """
- return tqdm_gui(_range(*args), **kwargs)
- # Aliases
- tqdm = tqdm_gui
- trange = tgrange
|