# -*- coding: utf-8 -*-
"""
========
utility
========
This module contains useful utility functions, decorators, and plotting helpers
that are useful throughout the ``kpfm`` package.
**Should my function go here?**
If you find yourself wanting it in many IPython notebooks, yes!
Just add a docstring and make sure the function is useful on its own
(not dependent on any external data, doesn't make assumptions that limit
broader usefulness of the code).
"""
from __future__ import division, print_function, absolute_import
import io
import os
import errno
import six
import h5py
import scipy
from distutils.version import LooseVersion
from decorator import decorator
# Fix errors on readthedocs by defining a dummy version of
# next_fast_len if scipy is "mocked" (see docs/conf.py)
try:
if LooseVersion(scipy.__version__) > LooseVersion("0.18"):
from scipy import fftpack
next_fast_len = fftpack.next_fast_len
else:
from scipy.signal import signaltools
next_fast_len = signaltools._next_regular
except TypeError:
def next_fast_len(x):
return x
[docs]def silent_remove(filename):
"""If ``filename`` exists, delete it. Otherwise, return nothing.
See http://stackoverflow.com/q/10840533/2823213."""
try:
os.remove(filename)
except OSError as e: # this would be "except OSError, e:" before Python 2.6
if e.errno != errno.ENOENT: # errno.ENOENT = no such file or directory
raise # re-raise exception if a different error occured
[docs]def align_labels(axes_list, lim, axis='y'):
"""Align matplotlib axis labels to the same horizontal (y-axis)
or vertical (x-axis) position.
"""
for ax in axes_list:
if axis == 'y':
t = ax.yaxis.label.get_transform()
x,y = ax.yaxis.label.get_position()
ax.yaxis.set_label_coords(lim, y, t)
else:
t = ax.xaxis.label.get_transform()
x,y = ax.xaxis.label.get_position()
ax.xaxis.set_label_coords(x, lim, t)
[docs]def color2gray(x):
"""Convert an RGB or RGBA (Red Green Blue Alpha) color tuple
to a grayscale value."""
if len(x) == 3:
r, g, b = x
a = 1
elif len(x) == 4:
r, g, b, a = x
else:
raise ValueError("Incorrect tuple length")
return (r * 0.299 + 0.587*g + 0.114*b) * a
@decorator
[docs]def txt_filename(f, fname_or_fh, *args, **kwargs):
"""Decorator to allow seamless use of filenames rather than
file handles for functions that operate on a text file.
Usage
-----
To use this decorator, write the function to take a file object
as the function's first argument."""
if isinstance(fname_or_fh, six.string_types):
with io.open(fname_or_fh, 'r') as fh:
return f(fh, *args, **kwargs)
else:
return f(fname_or_fh, *args, **kwargs)
@decorator
[docs]def h5filename(f, fname_or_fh, *args, **kwargs):
"""Decorator to allow seamless use of filenames rather than
file handles for functions that operate on an HDF5 file.
Usage
-----
To use this decorator, write the function to take an HDF5 file handle as
the function's first argument.
Example: We create a simple function and HDF5 file.
>>> @h5filename
>>> def h5print(fh):
>>> print(fh.values())
>>>
>>> fh = h5py.File('test.h5')
>>> fh['x'] = 2
We can call the function on the file handle
>>> h5print(fh)
[<HDF5 dataset "x": shape (), type "<i8">]
or call the function on the filename
>>> fh.close()
>>> h5print('test.h5')
[<HDF5 dataset "x": shape (), type "<i8">]
"""
if isinstance(fname_or_fh, six.string_types):
with h5py.File(fname_or_fh, 'r') as fh:
return f(fh, *args, **kwargs)
else:
return f(fname_or_fh, *args, **kwargs)
[docs]def h5ls_str(g, offset='', print_types=True):
"""Prints the input file/group/dataset (g) name and begin iterations on its
content.
See goo.gl/2JiUQK."""
string = []
if isinstance(g, h5py.File):
string.append(offset+repr(g.file))
elif isinstance(g, h5py.Dataset):
if print_types:
string.append(offset+g.name+' '+repr(g.shape)+' '+(g.dtype.str))
else:
string.append(offset+g.name+' '+repr(g.shape))
elif isinstance(g, h5py.Group):
string.append(offset+g.name)
else:
raise ValueError('WARNING: UNKNOWN ITEM IN HDF5 FILE'+g.name)
if isinstance(g, h5py.File) or isinstance(g, h5py.Group):
for key, subg in dict(g).items():
string.append(h5ls_str(subg, offset + ' ',
print_types=print_types))
return "\n".join(string)
[docs]def h5ls(*args):
"""List the contents of an HDF5 file object or group.
Accepts a file / group handle, or a string interpreted as the hdf5
file path."""
for arg in args:
if isinstance(arg, six.string_types):
fh = h5py.File(arg, mode='r')
print(h5ls_str(fh))
fh.close()
else:
print(h5ls_str(arg))
[docs]def prnDict(aDict, br='\n', html=0,
keyAlign='l', sortKey=0,
keyPrefix='', keySuffix='',
valuePrefix='', valueSuffix='',
leftMargin=4, indent=1, braces=True):
'''Return a string representive of aDict in the following format::
{
key1: value1,
key2: value2,
...
}
Spaces will be added to the keys to make them have same width.
Parameters
----------
sortKey: 0 or 1
set to 1 if want keys sorted;
keyAlign:
either 'l' or 'r', for left, right align, respectively.
keyPrefix, keySuffix, valuePrefix, valueSuffix: string
The prefix and suffix to wrap the keys or values. Good for formatting
them for html document (for example, keyPrefix='<b>', keySuffix='</b>').
Note: The keys will be padded with spaces to have them equally-wide.
The pre- and suffix will be added OUTSIDE the entire width.
html: 0 or 1
If set to 1, all spaces will be replaced with ' ', and
the entire output will be wrapped with '<code>' and '</code>'.
br: string
Determine the carriage return. If html, it is suggested to set
br to '<br>'. If you want the html source code easy to read,
set br to ``'<br>\n'``.
References
----------
version: 04b52
author : Runsun Pan
require: odict() # an ordered dict, if you want the keys sorted.
Dave Benjamin
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/161403'''
if aDict:
#------------------------------ sort key
if sortKey:
dic = aDict.copy()
keys = dic.keys()
keys.sort()
aDict = OrderedDict()
for k in keys:
aDict[k] = dic[k]
#------------------- wrap keys with ' ' (quotes) if str
tmp = ['{']
ks = [type(x)==str and "'%s'"%x or x for x in aDict.keys()]
#------------------- wrap values with ' ' (quotes) if str
vs = [type(x)==str and "'%s'"%x or x for x in aDict.values()]
maxKeyLen = max([len(str(x)) for x in ks])
for i in range(len(ks)):
#-------------------------- Adjust key width
k = {1 : str(ks[i]).ljust(maxKeyLen),
keyAlign=='r': str(ks[i]).rjust(maxKeyLen) }[1]
v = vs[i]
tmp.append(' '* indent+ '%s%s%s:%s%s%s,' %(
keyPrefix, k, keySuffix,
valuePrefix,v,valueSuffix))
tmp[-1] = tmp[-1][:-1] # remove the ',' in the last item
tmp.append('}')
if leftMargin:
tmp = [ ' '*leftMargin + x for x in tmp ]
if not braces:
tmp = tmp[5:-2]
if html:
return '<code>%s</code>' %br.join(tmp).replace(' ',' ')
else:
return br.join(tmp)
else:
return '{}'
from kpfm.util.readtxt import kpfm_data