def __init__(self, var, *iaxes, **kwargs): from pygeode.var import Var, copy_meta # Get the axes to be squeezed if len(iaxes) == 1 and isinstance(iaxes[0], (list, tuple)): iaxes = iaxes[0] if len(iaxes) == 0: iaxes = [i for i, a in enumerate(var.axes) if len(a) == 1] # Only remove degenerate axes iaxes = [var.whichaxis(a) for a in iaxes] iaxes = [i for i in iaxes if len(var.axes[i]) == 1] # Slice the var along some axes (passed by keyword argument)? if len(kwargs) > 0: for k, v in kwargs.items(): assert var.hasaxis(k), "unknown axis '%s'" % k a = var.whichaxis(k) if a not in iaxes: iaxes.append(a) assert isinstance( v, (int, float) ), "expected a numerical value for keyword '%s' - received %s instead" % ( k, type(v)) var = var( **kwargs) # Do the slicing first, before doing this wrapper self.var = var Var.__init__(self, [a for i, a in enumerate(var.axes) if i not in iaxes], var.dtype) copy_meta(var, self)
def __init__(self, var, axisdict={}, ignore_mismatch=False, newaxes=None, keep_old_name=True, **kwargs): from pygeode.var import Var, copy_meta from inspect import isclass axisdict = dict(axisdict, **kwargs) if newaxes is None: newaxes = list(var.axes) else: assert len(newaxes) == var.naxes, "wrong number of axes provided" for a,newa in axisdict.items(): if not var.hasaxis(a) and ignore_mismatch: continue i = var.whichaxis(a) olda = var.axes[i] # Keep the old axis name? name = olda.name if keep_old_name else newa.name # Convert axis class to axis object, using the existing values? if isclass(newa): # Cram in any 'auxiliary' attributes, in case they're needed by the new class. # (Needed if, say, converting from StandardTime to ModelTime365) # Note: even if these attributes aren't pick up by the new init, # they'll get stored in the 'auxatts' field and stay there as benign, # unused values. Ideally, if we knew ahead of time what attributes are # needed, we could pass only *those* attributes to the new class... newa = newa(olda.values, name=name, **olda.auxatts) # Use this new axis newaxes[i] = newa for a1, a2 in zip(newaxes, var.axes): assert len(a1) == len(a2) self.var = var Var.__init__(self, newaxes, dtype=var.dtype) copy_meta (var, self)
def __init__(self, var, newaxes, name=None, fillvalue=None, scale=None, offset=None, atts={}, plotatts={}): from pygeode.var import Var, copy_meta atts = atts.copy() plotatts = plotatts.copy() assert len(newaxes) == len(var.axes) for a1, a2 in zip(newaxes, var.axes): assert len(a1) == len(a2) self.var = var dtype = var.dtype if fillvalue is not None or scale is not None or offset is not None: dtype = 'float32' self.fillvalue = fillvalue self.scale = scale self.offset = offset Var.__init__(self, newaxes, dtype=dtype) copy_meta(var, self) self.atts = atts self.plotatts = plotatts if name is not None: self.name = name
def __init__ (self, var, slices): # {{{ from pygeode.var import Var, copy_meta self.var = var copy_meta (var, self) #TODO: remove degenerate dimensions when slicing by integer values if not hasattr(slices,'__len__'): slices = [slices] # assert len(slices) == len(var.axes), "expected %i parameters, received %i."%(len(var.axes),len(slices)) slices = list(slices) # make a copy of the list # Append an implicit Ellipsis at the end (makes the logic a big simpler below) # if Ellipsis not in slices: slices.append(Ellipsis) if not any (sl is Ellipsis for sl in slices): slices.append(Ellipsis) # Handle Ellipsis argument # assert slices.count(Ellipsis) == 1, "can't handle more than one Ellipsis argument" ellipsis_index = [i for i,sl in enumerate(slices) if sl is Ellipsis] assert len(ellipsis_index) == 1, "can't handle more than one Ellipsis argument" num_missing = var.naxes - len(slices) + 1 assert num_missing >= 0, "too many slices provided" # i = slices.index(Ellipsis) i = ellipsis_index.pop() slices = slices[:i] + [slice(None)]*num_missing + slices[i+1:] # Slice the output axes axes = [a.slice[s] for a,s in zip(var.axes,slices)] Var.__init__(self, axes, dtype=var.dtype, atts=self.atts, plotatts=self.plotatts)
def __init__(self, var, pos, *newaxes): from pygeode.var import Var, copy_meta self.var = var self.pos = pos self.newaxes = newaxes axes = var.axes[:pos] + tuple(newaxes) + var.axes[pos:] Var.__init__(self, axes, dtype=var.dtype) copy_meta (var, self)
def __init__(self, var, pos, *newaxes): from pygeode.var import Var, copy_meta self.var = var self.pos = pos self.newaxes = newaxes axes = var.axes[:pos] + tuple(newaxes) + var.axes[pos:] Var.__init__(self, axes, dtype=var.dtype) copy_meta(var, self)
def set_axistypes(dataset, dimtypes): # {{{ from pygeode.axis import Axis from pygeode.var import copy_meta from types import FunctionType assert isinstance(dimtypes, dict) replacements = {} for oldaxis in dataset.axes: name = oldaxis.name if name not in dimtypes: continue dt = dimtypes[name] # Determine axis type if isinstance(dt, Axis): # Axis instance if len(dt) != len(oldaxis): raise ValueError( 'Provided axis instance %s is the wrong length (expected length %d, got length %d)' % (repr(dt), len(oldaxis), len(dt))) axis = dt elif hasattr(dt, '__bases__') and issubclass(dt, Axis): # Axis class dimclass = dt axis = dimclass(values=oldaxis.values) # Copy the file metadata (but discard plot attributes from the old axis) # (See issue 22) copy_meta(oldaxis, axis, plotatts=False) elif hasattr(dt, '__len__'): if len(dt) != 2: raise ValueError( 'Got a list/tuple for dimtypes, but did not have 2 elements as expected (Axis class, parameters). Instead, got %s.' % dt) dimclass, dimargs = dt dimargs = dimargs.copy() assert issubclass( dimclass, Axis), "expected an Axis subclass, got %s instead." % dimclass assert isinstance(dimargs, dict) if 'values' not in dimargs: dimargs['values'] = oldaxis.values axis = dimclass(**dimargs) # Axis-creating function? elif isinstance(dt, FunctionType): axis = dt(oldaxis) else: raise ValueError( 'Unrecognized dimtypes parameter. Expected a dictionary, axis class, or axis instance. Got %s instead.' % type(dt)) assert len(axis) == len( oldaxis ), "expected axis of length %s, ended up with axis of length %s" % ( len(oldaxis), len(axis)) replacements[name] = axis return dataset.replace_axes(axisdict=replacements)
def __init__(self, var, order): from pygeode.var import Var, copy_meta self.var = var outaxes = list(var.axes) for iaxis, o in order.items(): reverse = {1: False, 0: None, -1: True}[o] outaxes[iaxis] = var.axes[iaxis].sorted(reverse=reverse) Var.__init__(self, outaxes, dtype=var.dtype) copy_meta(var, self)
def __init__(self, var, fill): from numpy import float32, float64 from pygeode.var import Var, copy_meta self.var = var self._fill = fill # We need floating-point values to have a nan if var.dtype not in (float32, float64): dtype = float32 else: dtype = var.dtype Var.__init__(self, var.axes, dtype) copy_meta (var, self)
def __init__(self, var, order): from pygeode.var import Var, copy_meta self.var = var outaxes = list(var.axes) for iaxis, o in order.items(): reverse = {1:False, 0:None, -1:True}[o] outaxes[iaxis] = var.axes[iaxis].sorted(reverse=reverse) Var.__init__(self, outaxes, dtype=var.dtype) copy_meta (var, self)
def override_values (dataset, value_override): # {{{ from warnings import warn import numpy as np from pygeode.var import Var, copy_meta vardict = {} for name, values in value_override.items(): if name not in dataset: warn ("var '%s' not found - values not overridden"%name, stacklevel=3) continue values = np.asarray(values) oldvar = dataset[name] assert values.shape == oldvar.shape, "bad shape for '%s'. Expected %s, got %s"%(name,oldvar.shape,values.shape) var = Var(oldvar.axes, values=values) copy_meta (oldvar, var) vardict[name] = var dataset = dataset.replace_vars(vardict) return dataset
def __init__ (self, var, iaxis): from pygeode.var import copy_meta, Var # Get the time axis to split iaxis = var.whichaxis(iaxis) taxis = var.getaxis(iaxis) years, days = _splittime(taxis) # Construct the output axes axes = list(var.axes) axes = axes[:iaxis] + [years, days] + axes[iaxis+1:] copy_meta(var,self) Var.__init__(self, axes=axes, dtype=var.dtype) self.iaxis = iaxis self.var = var
def override_values(dataset, value_override): # {{{ from warnings import warn import numpy as np from pygeode.var import Var, copy_meta vardict = {} for name, values in value_override.items(): if name not in dataset: warn("var '%s' not found - values not overridden" % name, stacklevel=3) continue values = np.asarray(values) oldvar = dataset[name] assert values.shape == oldvar.shape, "bad shape for '%s'. Expected %s, got %s" % ( name, oldvar.shape, values.shape) var = Var(oldvar.axes, values=values) copy_meta(oldvar, var) vardict[name] = var dataset = dataset.replace_vars(vardict) return dataset
def __init__(self, var, iaxis): # {{{ from pygeode.var import copy_meta, Var # Get the time axis to split iaxis = var.whichaxis(iaxis) taxis = var.getaxis(iaxis) years, days = _splittime(taxis) # Construct the output axes axes = list(var.axes) axes = axes[:iaxis] + [years, days] + axes[iaxis + 1:] copy_meta(var, self) Var.__init__(self, axes=axes, dtype=var.dtype) self.iaxis = iaxis self.var = var
def set_axistypes (dataset, dimtypes): # {{{ from pygeode.axis import Axis from pygeode.var import copy_meta from types import FunctionType assert isinstance(dimtypes, dict) replacements = {} for oldaxis in dataset.axes: name = oldaxis.name if name not in dimtypes: continue dt = dimtypes[name] # Determine axis type if isinstance(dt, Axis): # Axis instance if len(dt) != len(oldaxis): raise ValueError('Provided axis instance %s is the wrong length (expected length %d, got length %d)' % (repr(dt),len(oldaxis),len(dt))) axis = dt elif hasattr(dt, '__bases__') and issubclass(dt, Axis): # Axis class dimclass = dt axis = dimclass(values=oldaxis.values) # Copy the file metadata (but discard plot attributes from the old axis) # (See issue 22) copy_meta (oldaxis, axis, plotatts=False) elif hasattr(dt, '__len__'): if len(dt) != 2: raise ValueError('Got a list/tuple for dimtypes, but did not have 2 elements as expected (Axis class, parameters). Instead, got %s.'%dt) dimclass, dimargs = dt dimargs = dimargs.copy() assert issubclass (dimclass, Axis), "expected an Axis subclass, got %s instead."%dimclass assert isinstance (dimargs, dict) if 'values' not in dimargs: dimargs['values'] = oldaxis.values axis = dimclass(**dimargs) # Axis-creating function? elif isinstance (dt, FunctionType): axis = dt(oldaxis) else: raise ValueError('Unrecognized dimtypes parameter. Expected a dictionary, axis class, or axis instance. Got %s instead.'%type(dt)) assert len(axis) == len(oldaxis), "expected axis of length %s, ended up with axis of length %s"%(len(oldaxis),len(axis)) replacements[name] = axis return dataset.replace_axes(axisdict=replacements)
def __init__(self, var): # {{{ from pygeode.var import copy_meta import numpy as np self.var = var # At present data is packed into short integers following the packing # algorithm described in the NetCDF Operator documentation dtype = np.int16 min = var.nanmin() max = var.nanmax() self.scale = (max - min) / (2**16 - 2.) self.offset = 0.5 * (min + max) Var.__init__(self, var.axes, dtype=dtype) copy_meta(var, self) self.atts['packing_convention'] = 'NetCDF (16 bit)' self.atts['scale_factor'] = self.scale self.atts['add_offset'] = self.offset
def dims2axes (dataset): # {{{ from pygeode.axis import NamedAxis from pygeode.var import copy_meta # Loop over current set of generic "dimensions" replacements = {} for i,dim in enumerate(dataset.axes): # Do we have a Var with this name? # if dim.name in dataset: if any (var.name == dim.name for var in dataset.vars): # Get the var var = dataset[dim.name] if var.naxes != 1: continue # abort if we have > 1 dimension # Turn it into a proper axis axis = NamedAxis (name=var.name, values=var.get()) # need the values pre-loaded for axes copy_meta (var, axis) replacements[dim.name] = axis dataset = dataset.replace_axes(axisdict=replacements) # Remove the axes from the list of variables dataset = dataset.remove(*list(replacements.keys())) return dataset
def __init__(self,x,units='days',minfreq=None,maxfreq=None,nsamples=100): from pygeode.var import Var, copy_meta from pygeode.timeaxis import Time from pygeode.axis import Freq import numpy as np from math import log, exp, ceil assert x.hasaxis(Time), "no time axis found!" assert not x.hasaxis(Freq), "%s already has a frequency axis?"%repr(x) self.x = x self.taxis = taxis = x.getaxis(Time) self.T = T = len(taxis) self.dt = dt = taxis.delta(units) if minfreq is None: minfreq = 1./(T*dt) if maxfreq is None: maxfreq = 1./(2*dt) F1 = int(round(minfreq*T*dt)) F2 = int(round(maxfreq*T*dt)) assert nsamples > 1 stride = (F2-F1) / (nsamples-1) if stride == 0: stride = 1 F = np.arange(F2, F1-1, -stride)[::-1] if 0 in F: from pygeode.progress import PBar print 'Calculating mean' # constant s-transform value for n = 0 self.const = x.mean(Time).get(pbar=True) f = F / (T * dt) self.faxis = faxis = Freq(f, units) axes = list(x.axes) ti = x.whichaxis(Time) # Move time axis to the end, and include frequency axis axes = axes[:ti] + axes[ti+1:] + [faxis] + [taxis] Var.__init__(self, axes, dtype=complex) copy_meta(x, self) self.name = 'Strans('+(x.name or '??')+')'
def make_subgrid (var): import numpy as np from pygeode.axis import NamedAxis, YAxis from pygeode.var import Var, copy_meta # Skip variables with no grid coordinates. if not var.hasaxis('y'): return var y_ind = var.whichaxis('y') nsubgrids = len(np.where(var.y.values[:-1] > var.y.values[1:])[0]) + 1 subgrid = NamedAxis(range(nsubgrids), name='subgrid') yaxis = YAxis (var.y.values[:len(var.y)/nsubgrids], name=var.y.name) if isinstance(var, FSTD_Var): # Tweak the data_funcs to reshape the field. # Use nk to hold the subgrids. nk = nsubgrids nj = len(yaxis) ni = len(var.x) data_funcs = var.data_funcs.flatten() data_funcs = [lambda shape=(nk,nj,ni), f=df: f().reshape(shape) for df in data_funcs] data_funcs = np.array(data_funcs,dtype='O') var.data_funcs = data_funcs.reshape(var.data_funcs.shape) axes = list(var.axes) axes[var.whichaxis('k')] = subgrid axes[var.whichaxis('y')] = yaxis var.axes = tuple(axes) var.naxes = len(axes) var.shape = tuple(map(len,axes)) var.size = reduce(lambda x,y: x*y, var.shape, 1) return var # Handled pre-loaded fields if hasattr(var,'values'): shape = var.values.shape shape = shape[:y_ind] + (nsubgrids,-1) + shape[y_ind+1:] values = var.values.reshape(shape) axes = var.axes[:y_ind] + (subgrid,yaxis) + var.axes[y_ind+1:] newvar = Var(axes,values=values) copy_meta(var,newvar) return newvar # Skip derived fields print 'warning: unhandled case for %s'%var.name return var
def __init__(self,x,units='days',minfreq=None,maxfreq=None,nsamples=100): from pygeode.var import Var, copy_meta from pygeode.timeaxis import Time from pygeode.axis import Freq import numpy as np from math import log, exp, ceil assert x.hasaxis(Time), "no time axis found!" assert not x.hasaxis(Freq), "%s already has a frequency axis?"%repr(x) self.x = x self.taxis = taxis = x.getaxis(Time) self.T = T = len(taxis) self.dt = dt = taxis.delta(units) if minfreq is None: minfreq = 1./(T*dt) if maxfreq is None: maxfreq = 1./(2*dt) F1 = int(round(minfreq*T*dt)) F2 = int(round(maxfreq*T*dt)) assert nsamples > 1 stride = (F2-F1) // (nsamples-1) if stride == 0: stride = 1 F = np.arange(F2, F1-1, -stride)[::-1] if 0 in F: from pygeode.progress import PBar print('Calculating mean') # constant s-transform value for n = 0 self.const = x.mean(Time).get(pbar=True) f = F / (T * dt) self.faxis = faxis = Freq(f, units) axes = list(x.axes) ti = x.whichaxis(Time) # Move time axis to the end, and include frequency axis axes = axes[:ti] + axes[ti+1:] + [faxis] + [taxis] Var.__init__(self, axes, dtype=complex) copy_meta(x, self) self.name = 'Strans('+(x.name or '??')+')'
def __init__ (self, var, *iaxes, **kwargs): from pygeode.var import Var, copy_meta # Get the axes to be squeezed if len(iaxes) == 1 and isinstance(iaxes[0],(list,tuple)): iaxes = iaxes[0] if len(iaxes) == 0: iaxes = [i for i,a in enumerate(var.axes) if len(a) == 1] # Only remove degenerate axes iaxes = [var.whichaxis(a) for a in iaxes] iaxes = [i for i in iaxes if len(var.axes[i]) == 1] # Slice the var along some axes (passed by keyword argument)? if len(kwargs) > 0: for k,v in kwargs.items(): assert var.hasaxis(k), "unknown axis '%s'"%k a = var.whichaxis(k) if a not in iaxes: iaxes.append(a) assert isinstance(v,(int,float)), "expected a numerical value for keyword '%s' - received %s instead"%(k,type(v)) var = var(**kwargs) # Do the slicing first, before doing this wrapper self.var = var Var.__init__(self,[a for i,a in enumerate(var.axes) if i not in iaxes], var.dtype) copy_meta (var, self)
def __init__(self, var, yaxis, daxis): from pygeode.var import copy_meta, Var yaxis = var.whichaxis(yaxis) daxis = var.whichaxis(daxis) assert (yaxis < daxis) # need a certain order years = var.getaxis(yaxis) days = var.getaxis(daxis) # Generate the joined axis taxis = _jointime(years, days) axes = list(var.axes) axes = axes[:daxis] + axes[daxis+1:] axes[yaxis] = taxis Var.__init__(self, axes=axes, dtype=var.dtype) copy_meta(var,self) self.yaxis = yaxis self.daxis = daxis self.var = var
def dims2axes(dataset): # {{{ from pygeode.axis import NamedAxis from pygeode.var import copy_meta # Loop over current set of generic "dimensions" replacements = {} for i, dim in enumerate(dataset.axes): # Do we have a Var with this name? # if dim.name in dataset: if any(var.name == dim.name for var in dataset.vars): # Get the var var = dataset[dim.name] if var.naxes != 1: continue # abort if we have > 1 dimension # Turn it into a proper axis axis = NamedAxis( name=var.name, values=var.get()) # need the values pre-loaded for axes copy_meta(var, axis) replacements[dim.name] = axis dataset = dataset.replace_axes(axisdict=replacements) # Remove the axes from the list of variables dataset = dataset.remove(*list(replacements.keys())) return dataset
def __init__(self, var, yaxis, daxis): # {{{ from pygeode.var import copy_meta, Var yaxis = var.whichaxis(yaxis) daxis = var.whichaxis(daxis) assert (yaxis < daxis) # need a certain order years = var.getaxis(yaxis) days = var.getaxis(daxis) # Generate the joined axis taxis = _jointime(years, days) axes = list(var.axes) axes = axes[:daxis] + axes[daxis + 1:] axes[yaxis] = taxis Var.__init__(self, axes=axes, dtype=var.dtype) copy_meta(var, self) self.yaxis = yaxis self.daxis = daxis self.var = var
def __init__(self, var, dtype): from pygeode.var import Var, copy_meta self.var = var Var.__init__(self, var.axes, dtype) copy_meta (var, self)
def __init__(self, var, alist): from pygeode.var import Var, copy_meta self.var = var Var.__init__(self, [var.axes[a] for a in alist], dtype=var.dtype) copy_meta(var, self)
def __init__(self, var, fill): from pygeode.var import Var, copy_meta self.var = var self._fill = fill Var.__init__(self, var.axes, var.dtype) copy_meta(var, self)
def __init__(self, var, dtype): from pygeode.var import Var, copy_meta self.var = var Var.__init__(self, var.axes, dtype) copy_meta(var, self)