#! /usr/bin/python3
# -*- coding: utf-8 -*-
"""
*****
tools
*****
"""
__author__ = ['Alan Loh']
__copyright__ = 'Copyright 2019, nenupytf'
__credits__ = ['Alan Loh']
__maintainer__ = 'Alan Loh'
__email__ = 'alan.loh@obspm.fr'
__status__ = 'Production'
__all__ = [
'idx_of',
'to_unix',
'rebin1d',
'ProgressBar'
]
import numpy as np
from astropy.time import Time
from sys import stdout as _stdout
[docs]def idx_of(array, value, order='low'):
""" Find the index of value in array.
Parameters
----------
array : np.ndarray
Array upon which to search for indices.
value : float
Value to find the index for.
order : str
Could be 'low' or 'high'.
Let's say array[2] < value < array[3].
If 'low', the result will be `2`.
If 'high', the result will be `3`.
"""
if not order in ['low', 'high']:
raise ValueError(
'`order` should only be low or high.'
)
diff = array - value
if order == 'low':
# If value lower than anything, return index 0
if not np.any(array <= value):
return 0
# else, return the low value index
else:
return np.argwhere(
diff == diff[diff <= 0.].max()
)[0, 0]
elif order == 'high':
# If value greater than anything, return the last index
if not np.any(array >= value):
return array.size - 1
# else, return the high index value
else:
return np.argwhere(
diff == diff[diff >= 0.].min()
)[0, 0]
[docs]def to_unix(time):
"""
"""
if isinstance(time, str):
time = Time(time, precision=7).unix
time = Time(time, format='unix', precision=7)
return time
[docs]def rebin1d(array, shape):
"""
"""
dx = array.size // shape
array = array[:dx*shape]
array = array.reshape((shape, dx))
array = np.mean(array, axis=1)
return np.squeeze(array)
[docs]class ProgressBar(object):
"""
Class to do fancy progressbars
by G. Schworer
https://github.com/ceyzeriat/patiencebar
Provides a terminal-friendly single-thread progress bar
Args:
* valmax (float): the finish value of the progress bar. Default is 100.
* barsize (int >0): the size of the bar in the opened terminal. If ``None``, the bar will automatically fit the width of the window.
* title (str): the title, printed one line above the progress bar
* bar (bool): whether the bar should be displayed or not. If ``False``, only the text given at each :func:`update` will be printed
* up_every (int [0-100]): if ``bar`` is ``True``, the progress bar will be updated every ``up_every`` percent of progress. Setting ``up_every`` = 0 updates the progress bar at each :func:`update`
>>> import patiencebar as PB
>>> n_calc = 34
>>> pb = PB.ProgressBar(valmax=n_calc, barsize=50, title="Test bar")
>>> for i in range(n_calc):
>>> do_stuff()
>>> pb.update()
"""
def __init__(self, valmax=100, barsize=None, title=None, bar=True, up_every=2):
self.reset(valmax=valmax, barsize=barsize, title=title, bar=bar, up_every=up_every)
@property
def valmax(self):
return self._valmax
@valmax.setter
def valmax(self, value):
raise AttributeError("Read-only")
@property
def barsize(self):
return self._barsize
@barsize.setter
def barsize(self, value):
raise AttributeError("Read-only")
@property
def title(self):
return self._title
@title.setter
def title(self, value):
raise AttributeError("Read-only")
@property
def running(self):
return self._running
@running.setter
def running(self, value):
raise AttributeError("Read-only")
@property
def bar(self):
return self._bar
@bar.setter
def bar(self, value):
raise AttributeError("Read-only")
@property
def up_every(self):
return self._up_every
@up_every.setter
def up_every(self, value):
raise AttributeError("Read-only")
[docs] def reset(self, valmax=None, barsize=None, title=None, bar=None, up_every=None):
"""
Resets the progress bar with initialization values, unless new values are given
Args:
* valmax (float): the finish value of the progress bar. Default is 100.
* barsize (int >0): the size of the bar in the opened terminal. If ``None``, the bar will automatically fit the width of the window.
* title (str): the title, printed one line above the progress bar.
* bar (bool): whether the bar should be displayed or not. If ``False``, only the text given at each :func:`update` will be printed.
* up_every (int [0-100]): if ``bar`` is ``True``, the progress bar will be updated every ``up_every`` percent of progress. Setting ``up_every`` = 0 updates the progress bar at each :func:`update`.
>>> n_calc = 34
>>> pb = PB.Patiencebar(valmax=n_calc, barsize=50, title="Test bar")
>>> for i in range(n_calc):
>>> do_stuff()
>>> pb.update()
>>> pb.reset(title="Second trial", barsize=70)
>>> for i in range(n_calc):
>>> do_stuff()
>>> pb.update()
"""
self.win_width = 50 #_get_terminal_size()[1]
self.step = 0
self._nextup = 0
self._title_written = False
self._running = False
if valmax is not None:
self._valmax = float(valmax)
else:
self._valmax = float(getattr(self, 'valmax', 100))
if barsize is not None:
self._barsize = int(barsize)
else:
self._barsize = int(getattr(self, 'barsize', self.win_width-8))
if title is not None:
self._title = str(title)
elif getattr(self, 'title', None) is not None:
self._title = str(getattr(self, 'title'))
else:
self._title = None
if bar is not None:
self._bar = bool(bar)
else:
self._bar = bool(getattr(self, 'bar', True))
if up_every is not None:
self._up_every = int(min(100,max(0,up_every)))
else:
self._up_every = int(getattr(self, 'up_every', 2))
[docs] def update(self, step=None):
"""
Updates the progress bar to a newer value
Args:
* step (None): adds 1 to the progress of the bar, where ``valmax`` is the finish value.
* step (float): sets the progress of the bar to the ``step`` value, where ``valmax`` is the finish value.
* step (str): displays ``step`` on a new line. For this to work, ``bar`` must be ``False`` (no progress bar displayed) otherwise the update instruction is ignored.
"""
self._doupdate(step=step)
def _doupdate(self, step=None):
# initialization
if not self._title_written:
if self.title is not None: print(self.title)
self._title_written = True
self._running = True # in case it was not yet done
if self.bar: # if display progressbar
if step is None: # no step given
self.step += 1
else: # step given
try: # make sure we got some number
self.step = min(float(step), self.valmax)
except: # if not.. WTF.. don't change anything
return
# render bar
perc = int(self.step*100./self.valmax)
if perc < self._nextup: return
self._nextup = min(100, perc+self._up_every)
bar = int(perc/100.*self.barsize)
spacing = (self.win_width-self.barsize-8)/2.
out = '\r%s[%s%s] %3d %%%s' % (' ' * int(spacing), '=' * bar, ' ' * int(self.barsize - bar), perc, ' ' * int(spacing+0.5))
_stdout.write(out)
_stdout.flush()
else: # if no bar display
if step is None: step = 'tic'
print(str(step))
self.step += 1
if self.step >= self.valmax: # finished
print("\r")
self._running = False