Commit df704e78 authored by Daniel Boeckenhoff's avatar Daniel Boeckenhoff
Browse files

added in_out methods, logging and the default style

parent ea37e807
......@@ -27,7 +27,7 @@ publish:
git tag -a v$(VERSION) -m "Version $(VERSION) tag" # tag version
git push origin v$(VERSION) # explicitly push tag to the shared server
rm dist/* # could become unnecessary, if you find a way to specify 'twine upload dist/tfields-$(VERSION).tag.gz' in last step
rm -f dist/* # could become unnecessary, if you find a way to specify 'twine upload dist/tfields-$(VERSION).tag.gz' in last step
python setup.py sdist # building package
twine upload dist/* # publish package
......
......@@ -21,4 +21,8 @@ To check the coverage, we prefere the 'coverage' tool
Use it in the tfields directory like so:
```bash
coverage run tfields test
```
\ No newline at end of file
```
or
```bash
make coverage
```
......@@ -30,6 +30,7 @@ setup(
'numpy',
'sympy',
'scipy',
'pathlib',
],
entry_points={
'console_scripts': ['tfields = tfields.__main__:runDoctests']
......
......@@ -1428,7 +1428,7 @@ class TensorMaps(TensorFields):
item.maps = [mp.copy() for mp in item.maps]
indices = np.array(range(len(self)))
keep_indices = indices[index]
if isinstance(keep_indices, int):
if isinstance(keep_indices, (int, np.int64)):
keep_indices = [keep_indices]
delete_indices = set(indices).difference(set(keep_indices))
......
"""
Input output utilities
"""
import os
import shutil
import subprocess
import contextlib
import logging
def resolve(path):
"""
Returns:
path with resolved ~, symbolic links and relative paths.
Examples:
Resolves relative paths
>>> import os
>>> from tfields.lib.in_out import resolve
>>> resolve("../tfields") == resolve(".")
True
Resolves user variables
>>> resolve("~") == os.path.expanduser("~")
True
Also resolves symlincs which i will not test.
"""
# return str(Path(path).expanduser().resolve())
# resolve: relative paths, symlinks and ~
return os.path.realpath(os.path.abspath(os.path.expanduser(path)))
def cp(source, dest, overwrite=True):
"""
copy with shutil
"""
source = resolve(source)
dest = resolve(dest)
if os.path.isfile(dest) and not overwrite:
raise ValueError("Attempting to overwrite destination path"
" {0}.".format(dest))
if os.path.isfile(source):
shutil.copy(source, dest)
elif os.path.isdir(source):
shutil.copytree(source, dest)
else:
raise TypeError("source is not file or dir")
def scp(source, dest):
"""
ssh copy
"""
# subprocess.check_call does not execute in bash, so it does not know ~
# Carefull when giving remote host : ~ replacement is not tested
subprocess.check_call(['scp', source, dest])
def mv(source, dest, overwrite=True):
"""
Move files or whole folders
"""
source = resolve(source)
dest = resolve(dest)
log = logging.getLogger()
if os.path.isfile(dest) and not overwrite:
raise ValueError("Attempting to move to already existing destination"
" path {0}.".format(dest))
log.info("Moving file or dir {0} to {1}".format(source, dest))
if os.path.isfile(source):
shutil.move(source, dest)
elif os.path.isdir(source):
shutil.move(source, dest)
# shutil.copytree(source, dest)
else:
raise TypeError("source is not file or dir")
def rm(path):
"""
Remove path or (empty) directory
"""
path = resolve(path)
if os.path.isfile(path):
os.remove(path)
elif os.path.isdir(path):
if len(ls(path)) > 0:
raise ValueError("Directory {0} is not empty".format(path))
os.rmdir(path)
else:
raise ValueError("Path {0} is not directory and not file".format(path))
def cd(directory):
"""
Change directory
"""
os.chdir(resolve(directory))
@contextlib.contextmanager
def cd_tmp(tmpPath):
"""
Temporarily change directory. change back afterwards
"""
cwd = os.getcwd()
cd(resolve(tmpPath))
try:
yield
finally:
cd(cwd)
def ls(directory, recursive=False):
"""
a bash ls imitation.
"""
if recursive:
return dir_structure(resolve(directory))
else:
return os.listdir(resolve(directory))
def dir_structure(fileDir):
"""
Creates a nested dictionary that represents the folder structure of fileDir
"""
directory = {}
fileDir = fileDir.rstrip(os.sep)
start = fileDir.rfind(os.sep) + 1
for path, dirs, files in os.walk(fileDir):
folders = path[start:].split(os.sep)
subdir = dict.fromkeys(files)
parent = reduce(dict.get, folders[:-1], directory)
parent[folders[-1]] = subdir
if len(directory) == 0:
return {}
return directory[directory.keys()[0]] # first entry is always fileDir
from contextlib import contextmanager
import logging
import time
def progressbar(iterable, log=None):
"""
Examples:
>>> import logging
>>> import tfields
>>> import sys
>>> sys.modules['tqdm'] = None
>>> log = logging.getLogger(__name__)
>>> a = range(3)
>>> for value in tfields.lib.log.progressbar(a, log=log):
... _ = value * 3
"""
if log is None:
log = logging.getLogger()
try:
from tqdm import tqdm as progressor
tqdm_exists = True
except ImportError as err:
def progressor(iterable):
"""
dummy function. Doe nothing
"""
return iterable
tqdm_exists = False
try:
nTotal = len(iterable)
except:
nTotal = None
for i in progressor(iterable):
if not tqdm_exists:
if nTotal is None:
log.info("Progress: item {i}".format(**locals()))
else:
log.info("Progress: {i} / {nTotal}".format(**locals()))
yield i
@contextmanager
def timeit(msg="No Description", log=None, precision=1):
"""
Context manager for autmated timeing
Args:
msg (str): message to customize the log message
log (logger)
precision (int): show until 10^-<precision> digits
"""
if log is None:
log = logging.getLogger()
startTime = time.time()
log.log(logging.INFO, "-> " * 30)
message = "Starting Process: {0} ->".format(msg)
log.log(logging.INFO, message)
yield
log.log(logging.INFO, "\t\t\t\t\t\t<- Process Duration:"
"{value:1.{precision}f} s".format(value=time.time() - startTime,
precision=precision))
log.log(logging.INFO, "<- " * 30)
if __name__ == '__main__':
import doctest
doctest.testmod()
......@@ -12,7 +12,7 @@ import numpy as np
from .mpl import *
def setDefault(dictionary, attr, value):
def set_default(dictionary, attr, value):
"""
Set defaults to a dictionary
"""
......@@ -197,8 +197,8 @@ class PlotOptions(object):
def set(self, attr, value):
self.plotKwargs[attr] = value
def setDefault(self, attr, value):
setDefault(self.plotKwargs, attr, value)
def set_default(self, attr, value):
set_default(self.plotKwargs, attr, value)
def retrieve(self, attr, default=None, keep=True):
if keep:
......
......@@ -157,7 +157,7 @@ def plot_array(array, **kwargs):
Artist or list of Artists (imitating the axis.scatter/plot behaviour).
Better Artist not list of Artists
"""
tfields.plotting.setDefault(kwargs, 'methodName', 'scatter')
tfields.plotting.set_default(kwargs, 'methodName', 'scatter')
po = tfields.plotting.PlotOptions(kwargs)
labelList = po.pop('labelList', ['x (m)', 'y (m)', 'z (m)'])
......@@ -428,9 +428,9 @@ def to_colors(scalars, cmap=None, vmin=None, vmax=None):
vmin = min(scalars)
if vmax is None:
vmax = max(scalars)
colorMap = plt.get_cmap(cmap)
color_map = plt.get_cmap(cmap)
norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax)
return colorMap(map(norm, scalars))
return color_map(map(norm, scalars))
def to_scalars(colors, cmap, vmin, vmax):
......@@ -474,14 +474,14 @@ def colormap(seq):
return mpl.colors.LinearSegmentedColormap('CustomMap', cdict)
def color_cycle(colormap=None, n=None):
def color_cycle(cmap=None, n=None):
"""
Args:
colormap (matplotlib colormap): e.g. plotTools.plt.cm.coolwarm
n (int): needed for colormap argument
cmap (matplotlib colormap): e.g. plt.cm.coolwarm
n (int): needed for cmap argument
"""
if colormap:
color_rgb = to_colors(np.linspace(0, 1, n), cmap=colormap, vmin=0, vmax=1)
if cmap:
color_rgb = to_colors(np.linspace(0, 1, n), cmap=cmap, vmin=0, vmax=1)
colors = map(lambda rgb: '#%02x%02x%02x' % (rgb[0] * 255,
rgb[1] * 255,
rgb[2] * 255),
......@@ -564,7 +564,10 @@ def autoscale_3d(axis, array=None, xLim=None, yLim=None, zLim=None):
axis.set_zlim([zMin, zMax])
def setLegend(axis, artists):
def set_legend(axis, artists):
"""
Convenience method to set a legend from multiple artists to an axis.
"""
handles = []
for artist in artists:
if isinstance(artist, list):
......@@ -574,7 +577,7 @@ def setLegend(axis, artists):
axis.legend(handles=handles)
def set_color_bar(axis, artist, label=None, divide=True, **kwargs):
def set_colorbar(axis, artist, label=None, divide=True, **kwargs):
"""
Note:
Bug found in matplotlib:
......@@ -583,7 +586,7 @@ def set_color_bar(axis, artist, label=None, divide=True, **kwargs):
>> import tfields
>> axis = tfields.plotting.gca()
>> artist = ...
>> cbar = tfields.plotting.set_color_bar(axis, artist)
>> cbar = tfields.plotting.set_colorbar(axis, artist)
>> tfields.plotting.save(...)
>> cbar.remove() # THIS IS IMPORTANT. Otherwise you will have problems
# at the next call of savefig.
......
legend.numpoints : 1 # the number of points in the legend line
legend.scatterpoints : 1
figure.figsize: 12.8, 8.8
axes.labelsize: 20
axes.titlesize: 24
xtick.labelsize: 20
ytick.labelsize: 20
legend.fontsize: 20
grid.linewidth: 1.6
lines.linewidth: 2.8
patch.linewidth: 0.48
lines.markersize: 11.2
lines.markeredgewidth: 0
xtick.major.width: 1.6
ytick.major.width: 1.6
xtick.minor.width: 0.8
ytick.minor.width: 0.8
xtick.major.pad: 11.2
ytick.major.pad: 11.2
savefig.transparent : True
savefig.dpi: 300
figure.autolayout : True
# IMAGES
image.cmap: viridis
# SAVING / saving
# savefig.dpi: 600
# LATEX / LaTeX / latex
text.usetex : True
font.family : 'serif'
font.size : 40 # 20 was a duplicate definition
# mathtext.fontset = 'custom'
# mathtext.rm = 'Bitstream Vera Sans'
# mathtext.it = 'Bitstream Vera Sans:italic'
# mathtext.bf = 'Bitstream Vera Sans:bold'
# mathtext.fontset = 'stix'
# font.family = 'STIXGeneral'
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment