# -*- coding: utf-8 *-*
import numpy
import bottleneck as bn
from sys import exit
from copy import deepcopy
from scipy.interpolate import griddata
#own modules
#from diaGrabber import source
from diaGrabber import _utils
from diaGrabber.source._source import mergeDimension, basisDimension
[docs]class matrixMethods(object):
def __init__(self):
pass
[docs] def autoZoom(self, **kwargs):
'''
**Required kwargs** ("keyword arguments") are:
================== =============== ============= ================
Keyword Type Example Description
================== =============== ============= ================
*value* float/string *max* The merge-value to zoom in. Type 'min' or 'max' to use the equivalent extrem-value in the matrix
*scale* string *'relative'*
**OR**
*'absolute'*
*level* float 0.3 The relative zoom-level
0.3 means +-30% around the zoom-point
================== =============== ============= ================
**Optional kwargs** ("keyword arguments") are:
================== =============== ========= ================
Keyword Type Default Description
================== =============== ========= ================
*mergeDim* list(mergeDim) [{all}] one or more merge-dims to do the method on
*basisDim* list(basisDim) [{all}] Which basisDimensions get a new scale.
*operator* string "==" The zoom-point is defined as the first point in matrix where a value in "==" (equal), ">" (bigger) etc. than the given *value*
================== =============== ========= ================
'''
#standard
mergeDim=None
value=None
scale=None
level=None
operator = "=="
basisDim = range(self.nBasis)
#individual
for key in kwargs:
if key == "mergeDim":
_utils.checkClassInstance(kwargs[key],mergeDimension)
mergeDim = kwargs[key]
elif key == "value":
if type(kwargs[key]) == str:
if kwargs[key] != "max" and kwargs[key] != "min":
exit("ERROR: 'value' can only be 'max', 'min' or a float")
value = kwargs[key]
else:
value = str(kwargs[key])
elif key == "scale":
if kwargs[key] != "absolute" and kwargs[key] != "relative":
exit("ERROR: 'scale' in method 'autoZoom' has to be 'absolute' or 'relative'")
scale = str(kwargs[key])
elif key == "level":
level = abs(float(kwargs[key]))
elif key == "operator":
operator = str(kwargs[key])
elif key == "basisDim":
basisDim = list(kwargs[key])
for n,b in enumerate(basisDim):
_utils.checkClassInstance(b,basisDimension)
if b not in self._basis_dim:
exit("ERROR: the given basisDimension does not belong to those from target")
basisDim[n] = self._basis_dim.index(b)
else:
raise KeyError("keyword '%s' not known" %key)
_utils.checkRequiredArgs({
"mergeDim":mergeDim,
"value":value,
"scale":scale,
"level":level})
#which mergeMatrix is involved?
m=self.mergeMatrix[self._merge_dim.index(mergeDim)]
#prepare value
if value=="max":
value = bn.nanmax(m)
elif value=="min":
value = bn.nanmin(m)
#value = eval("m" + "." + value + "()")
if numpy.isnan(value):
raise ValueError("cannot autoZoom to nan")
#get position in matrix
positions=numpy.argwhere(eval(str(value) + operator + "m"))[0]
print "\n... do autoZoom for basisDimensions at a mergeValue of %s" %value
for n,p in enumerate(positions):
if n in basisDim:
#get basis-values at those positions
zoompoint = self.basisMatrix[n][p]
#calc. the new range
if scale == "relative":
basis_range = self._basis_dim[n]._include_from_to[1]-self._basis_dim[n]._include_from_to[0]
zoomrange=[zoompoint-abs(basis_range*level),zoompoint+abs(basis_range*level)]
ampl = zoomrange[1]-zoomrange[0]
elif scale == "absolute":
zoomrange=[zoompoint-level,zoompoint+level]
#define a new include_from_to-range for that basisDim
print "%s --> %s (offset: %s, amplitude: %s)" %(self._basis_dim[n].name,zoomrange, zoompoint, ampl)
self._basis_dim[n]._includeFromTo(zoomrange)
else:
print "ignored %s for autozoom" %self._basis_dim[n].name
[docs] def interpolate(self, method = "nearest"):
'''interpolate NaNs (empty points) in matrix
:param method: {"nearest", "linear", "cubic"}
:type method: string
'''
if method == "cubic" and self.nBasis > 2:
method = "linear"
print "method='cubic' works only for one and two basisDimensions"
print "--> interpolate matrix with method '%s'" %method
#build a nD-meshgrid in which the interolation can be solved
nDgrid = self._multiDimMeshgrid()
#extract points from matrix
points,merge = self.transformMatrixToPoints(nDgrid)
#merge a dim-lists to a vector-list
#--> X(1,2,3) Y(4,5,6) -> XY([1,4],[2,5],[3,6])
pointsT = zip(*points)
#do the interpolation
print "do interpolation"
for i in range(self.nMerge):
try:
self.mergeMatrix[i] = griddata(pointsT, numpy.array(merge[i]),
tuple(nDgrid), method)
except ValueError, exInstance:
print "WARNING: interpolation of mergeMatrix %s FAILED because of:" %self._merge_dim[i].name
print " ValueError:",exInstance.args
print " continue with original values"
print "done"
[docs] def posterize(self, **kwargs):
'''
This method discretize/posterize the values in the mergeMatrix (of a given mergeDimension)
to a given ammount of values (e.g. nValues= 4 ) or to a given list or values
(e.g. values = [1,2,4])
**Optional kwargs** ("keyword arguments") are:
================== =============== ========= ================
Keyword Type Default Description
================== =============== ========= ================
*mergeDim* list(mergeDim) [{all}] one or more merge-dims to do the method on
*nValues* int 5 the ammount of different values
*values* list None given different values
================== =============== ========= ================
'''
#standard
mergeDim = self._merge_dim
nValues=5
values=None
#individual
for key in kwargs:
if key == "mergeDim":
if type(kwargs[key]) != list or type(kwargs[key]) != tuple:
kwargs[key] = [ kwargs[key] ]
for m in kwargs[key]:
_utils.checkClassInstance(m,mergeDimension)
mergeDim = kwargs[key]
elif key == "nValues":
nValues = int(kwargs[key])
elif key == "values":
values = list(kwargs[key])
else:
raise KeyError("keyword '%s' not known" %key)
_utils.checkRequiredArgs({
"mergeDim":mergeDim})
merge_names = ""
for i in mergeDim:
merge_names += "%s " %i.name
merge_names = merge_names[:-1]
print "--> Posterize mergeMatrices of (%s) to the values %s" %(merge_names, values)
for i in mergeDim:
#which mergeMatrix is involved?
m=self.mergeMatrix[self._merge_dim.index(i)]
if values == None:
#create values-list
values = numpy.linspace(bn.nanmin(m),bn.nanmax(m),nValues)
else:
values = numpy.array(values)
#do posterizing
for x in numpy.nditer(m, op_flags=['readwrite']):
diff=values-x
diff=abs(diff)
nearest = diff.argmin()
x[...] = values[ nearest ]
#######PRIVATE########
[docs] def _multiDimMeshgrid(self):
'''like numpy.meshgrid but can also produce multi-dimensional meshgrids
takes list of arrays, where len(list)=nBasis'''
print "create a multiDimMeshgrid"
#if type(basisMatrix)=array an error will be produced in numpy.repeat
basisMatrix = list(self.basisMatrix)
basisMatrix.reverse()
lenBasis = []
newShape = [self.nBasis]
for i in basisMatrix:
lenBasis.append(len(i))
lenBasisrev = deepcopy(lenBasis)
lenBasisrev.reverse()
newShape.extend(lenBasisrev)
for i in range(self.nBasis):
if i==0:
nRepeat = 1
else:
nRepeat = lenBasis[i-1]
lenBasis[i]*=nRepeat
#double items
basisMatrix[i] = basisMatrix[i].repeat(nRepeat)
lenGrid = len(basisMatrix[-1])
for i in range(self.nBasis):
#repeate blocks
basisMatrix[i] = numpy.lib.stride_tricks.as_strided(
basisMatrix[i], (lenGrid/len(basisMatrix[i]),)+basisMatrix[i].shape, (0,)+basisMatrix[i].strides).flatten()
#reshape blocks
basisMatrix = numpy.array(basisMatrix)#reshape need an array
print "done"
return list(basisMatrix.reshape(tuple(newShape)))