from copy import deepcopy
from re import match as re_match
from itertools import izip
from operator import __and__ as operator_and
from operator import __or__ as operator_or
from numpy import ndarray as numpy_ndarray
from numpy import vectorize as numpy_vectorize
from .cfdatetime import Datetime, dt
from .functions import inspect as cf_inspect
from .functions import equals as cf_equals
from .functions import equivalent as cf_equivalent
from .data.data import Data
# ====================================================================
#
# Query object
#
# ====================================================================
[docs]class Query(object):
'''Store a query operation.
The query operation is an operator with a right hand side operand. For
example, an operator could be "strictly less than" and a right hand
side operand could 3.
Such a query (such as "is strictly less than 3?") may be evaluated for
an arbitrary left hand side operand, *x* (such as "is *x* strictly
less than 3?").
The result of the query is dependent on the object type of left hand
side operand, *x*. For example, if *x* is an integer then evaluating
"is *x* strictly less than 3?" will result in a boolean; but if *x* is
a `numpy` array then "is *x* strictly less than 3?" will likely
produce a numpy array of booleans.
The query is evaluated with its `evaluate` method or equivalently with
the ``==`` operator:
>>> q = cf.Query('lt', 3)
>>> q.evaluate(2)
True
>>> 2 == q
True
>>> q == 2
True
>>> 4 == q
False
The inverse of the query may be evaluated with the ``!=`` operator:
>>> q = cf.Query('wi', [3, 5])
>>> q.evaluate(4)
True
>>> 4 == q
True
>>> 4 != q
False
>>> q != 6
True
The following operators are supported:
============= ========================================================= ============
operator Description Constructor
============= ========================================================= ============
``'lt'`` Is *x* strictly less than a value? `cf.lt`
``'le'`` Is *x* less than or equal to a value? `cf.le`
``'gt'`` Is *x* strictly greater than a value? `cf.gt`
``'ge'`` Is *x* greater than or equal to a value? `cf.ge`
``'eq'`` Is *x* equal to a value? `cf.eq`
``'ne'`` Is *x* not equal to a value? `cf.ne`
``'wi'`` Is *x* within a given range of values (range bounds `cf.wi`
included)?
``'wo'`` Is *x* without a given range of values (range bounds `cf.wo`
excluded)?
``'set'`` Is *x* equal to any member of a collection? `cf.set`
``'contain'`` If cells are defined, is value contained in a cell of `cf.contain`
*x*? otherwise is *x* equal to a value?
============= ========================================================= ============
For the ``'wi'``, ``'wo '`` and ``'set'`` operators, if the left hand
side operand supports broadcasting over its elements (such as a
`numpy` array or a `cf.Field` object) then each element is tested
independently. For example:
>>> q = cf.Query('wi', [3, 4])
>>> q == [2, 3, 4]
False
>>> print q == numpy.array([2, 3, 4])
[ False True True]
As a convenience, for each operator there is an identically named
constructor function which returns the appropriate `cf.Query`
object. For example:
>>> cf.lt(3)
<CF Query: lt 3>
**Compound queries**
Multiple queries may be logically combined with the bitwise ``&`` and
``|`` operators to form a new `cf.Query` object. For example:
>>> q = cf.ge(3)
>>> r = cf.lt(5)
>>> s = q & r
>>> s
>>> <CF Query: [(ge 3) & (lt 5)]>
>>> 4 == s
True
>>> t = q | r
>>> t
<CF Query: [(ge 3) | (lt 5)]>
>>> 2 == t
True
Compound queries may be combined further:
>>> u = s | cf.wi(1.5, 2.5)
>>> u
<CF Query: [[(ge 3) & (lt 5)] | (wi (1.5, 2.5))]>
>>> 2 == u
True
>>> u & t
<CF Query: [[[(ge 3) & (lt 5)] | (wi (1.5, 2.5))] & [(ge 3) | (lt 5)]]>
If any of the component queries are for left hand side operand
attributes, then these are retained in a compound query. For example:
>>> q = cf.ge(3)
>>> r = cf.lt(5, attr='bar')
>>> s = q & r
>>> s = e.addattr('foo')
>>> s
<CF Query: foo[(ge 3) & bar(lt 5)]>
In this example,
>>> x == s
is equivalent to
>>> (x.foo == cf.ge(3)) & (x.foo.bar == cf.lt(5))
**Attributes**
=============== ======================================================
Attribute Description
=============== ======================================================
`!attr` An attribute name such that this attribute of the
left hand side operand is compared, rather than the
operand itself. If there is more than one attribute
name then each is interpreted as an attribute of the
previous attribute.
`!operator` The query operation (such as ``'lt'``, for
example). Always `None` for compound queries.
`exact` If False then string values are treated as a regular
expressions as understood by the :py:obj:`re` module
and are evaluated using the :py:obj:`re.match`
method. Ignored for all operators except ``'eq'``,
``'ne'`` and ``'set'``.
=============== ======================================================
'''
[docs] def __init__(self, operator, value, units=None, exact=True, attr=None):
'''**Initialization**
:Parameters:
operator : str
The query operator.
value :
The right hand side of the query operation.
units : str or cf.Units, optional
The units of *value*. By default, the same units, if any, as
the left hand side of the query operation are assumed.
exact : bool, optional
If False then string values are treated as a regular
expressions as understood by the :py:obj:`re` module and are
evaluated using the :py:obj:`re.match` method. Ignored for
all operators except ``'eq'``, ``'ne'`` and ``'set'``.
attr : str, optional
Specify an attribute name such that this attribute of the left
hand side operand is compared, rather than the operand itself.
*Example:*
``cf.Query('ge', 2, attr='ndim')`` with return True when
evaluated for an array with two or more dimensions.
:Examples:
>>> cf.Query('le', 5.6)
<CF Query: (le 5.6)>
>>> cf.Query('gt', 5.6, 'metres')
<CF Query: (gt <CF Data: 5.6 metres>)>
>>> cf.Query('gt', cf.Data(5.6, 'metres'))
<CF Query: (gt <CF Data: 5.6 metres>)>
>>> cf.Query('wi', [2, 56])
<CF Query: (wi [2, 56])>
>>> cf.Query('set', [2, 56], 'seconds')
<CF Query: (set <CF Data: [2, 56] seconds>)>
>>> cf.Query('set', cf.Data([2, 56], 'seconds'))
<CF Query: (set <CF Data: [2, 56] seconds>)>
>>> cf.Query('eq', 'air_temperature')
<CF Query: (eq 'air_temperature')>
>>> cf.Query('eq', 'temperature', exact=False)
<CF Query: (eq 'temperature')>
>>> cf.Query('gt', 1, attr='ndim')
<CF Query: ndim(gt 1)>
'''
if units is not None:
value_units = getattr(value, 'Units', None)
if value_units is None:
value = Data(value, units)
elif not value_units.equivalent(units):
raise ValueError("sdfsdfsd99885109^^^^")
#--- End: if
self._operator = operator
self._value = value
self._exact = exact
self._compound = False
self._attr = () if not attr else (attr,)
self._bitwise_operator = None
self._NotImplemented_RHS_Data_op = True
#--- End: def
def __deepcopy__(self, memo):
'''
Used if copy.deepcopy is called on the variable.
'''
return self.copy()
#--- End: def
def __eq__(self, x):
'''
x.__eq__(y) <==> x==y <==> x.evaluate(y)
'''
return self._evaluate(x, ())
#--- End: def
def __ne__(self, x):
'''
x.__ne__(y) <==> x!=y <==> (x==y)==False
'''
return self._evaluate(x, ()) == False
#--- End: def
def __ge__(self, x):
raise TypeError("Unsupported operand type(s) for >=: '%s' and '%s'" %
(self.__class__.__name__, x.__class__.__name__))
#--- End: def
def __gt__(self, x):
raise TypeError("Unsupported operand type(s) for >: '%s' and '%s'" %
(self.__class__.__name__, x.__class__.__name__))
#--- End: def
def __le__(self, x):
raise TypeError("Unsupported operand type(s) for <=: '%s' and '%s'" %
(self.__class__.__name__, x.__class__.__name__))
#--- End: def
def __lt__(self, x):
raise TypeError("Unsupported operand type(s) for <: '%s' and '%s'" %
(self.__class__.__name__, x.__class__.__name__))
#--- End: def
def __and__(self, other):
'''
x.__and__(y) <==> x&y
'''
Q = type(self)
new = Q.__new__(Q)
new._operator = None
new._exact = True
new._compound = (self, other)
new._bitwise_operator = operator_and
new._attr = ()
new._NotImplemented_RHS_Data_op = True
return new
#--- End: def
def __iand__(self, other):
'''
x.__iand__(y) <==> x&=y
'''
return self & other
#--- End: def
def __or__(self, other):
'''
x.__or__(y) <==> x|y
'''
Q = type(self)
new = Q.__new__(Q)
new._operator = None
new._exact = True
new._compound = (self, other)
new._bitwise_operator = operator_or
new._attr = ()
new._NotImplemented_RHS_Data_op = True
return new
#--- End: def
def __ior__(self, other):
'''
x.__ior__(y) <==> x|=y
'''
return self | other
#--- End: def
def __repr__(self):
'''
x.__repr__() <==> repr(x)
'''
return '<CF %s: %s>' % (self.__class__.__name__, self)
#--- End: def
def __str__(self):
'''
x.__str__() <==> str(x)
'''
attr = '.'.join(self._attr)
if not self._compound:
if not self._exact:
out = '%s(%s match(%r))' % (attr, self._operator, self._value)
else:
out = '%s(%s %r)' % (attr, self._operator, self._value)
else:
bitwise_operator = repr(self._bitwise_operator)
if '__and__' in bitwise_operator:
bitwise_operator = '&'
elif '__or__' in bitwise_operator:
bitwise_operator = '|'
out = '%s[%s %s %s]' % (attr, self._compound[0], bitwise_operator,
self._compound[1])
#--- End: if
return out
#--- End: def
@property
def attr(self):
'''
:Examples:
>>> q = cf.Query('ge', 4)
>>> print q.attr
None
>>> q = cf.Query('le', 6, attr='year')
>>> q.attr
'year'
>>> q.addattr('foo')
>>> q.attr
'year'asdasdas
'''
return self._attr
#--- End: def
@property
def operator(self):
'''
:Examples:
>>> q = cf.Query('ge', 4)
>>> q.operator
'ge'
>>> q |= cf.Query('le', 6)
>>> print q.operator
None
'''
return self._operator
#--- End: def
@property
def exact(self):
'''
:Examples:
>>> q = cf.Query('eq', 'foo')
>>> q.exact
True
>>> q = cf.Query('eq', '.*foo', exact=False)
>>> q.exact
False
>>> q |= cf.Query('eq', 'bar')
>>> print q.exact
False
'''
return self._exact
#--- End: def
@property
def value(self):
'''
:Examples:
>>> q = cf.Query('ge', 4)
>>> q.value
4
>>> q |= cf.Query('le', 6)
>>> q.value
AttributeError: Compound query doesn't have attribute 'value'
'''
if not self._compound:
return self._value
raise AttributeError("Compound query doesn't have attribute 'value'")
#--- End: def
[docs] def addattr(self, attr):
'''Return a `cf.Query` object with a new left hand side operand
attribute to be used during evaluation.
If another attribute has previously been specified, then the new
attribute is considered to be an attribute of the existing attribute.
:Parameters:
attr : str
The attribute name.
:Returns:
out : cf.Query
The new query object.
:Examples:
>>> q = cf.eq(2001)
>>> q
<CF Query: (eq 2001)>
>>> q = q.addattr('year')
>>> q
<CF Query: year(eq 2001)>
>>> q = cf.lt(2)
>>> q = q.addattr('A')
>>> q = q.addattr('B')
>>> q
<CF Query: A.B(lt 2)>
>>> q = q.addattr('C')
>>> q
<CF Query: A.B.C(lt 2)>
'''
Q = type(self)
new = Q.__new__(Q)
new.__dict__ = self.__dict__.copy()
new._attr += (attr,)
new._NotImplemented_RHS_Data_op = True
return new
#--- End: def
[docs] def copy(self):
'''
Return a deep copy.
``q.copy()`` is equivalent to ``copy.deepcopy(q)``.
:Returns:
out :
The deep copy.
:Examples:
>>> r = q.copy()
'''
return self
#--- End: def
[docs] def dump(self, display=True):
'''
Return a string containing a full description of the instance.
:Parameters:
display : bool, optional
If False then return the description as a string. By default
the description is printed, i.e. ``q.dump()`` is equivalent to
``print q.dump(display=False)``.
:Returns:
out : None or str
A string containing the description.
:Examples:
'''
string = str(self)
if display:
print string
else:
return string
#--- End: def
[docs] def equals(self, other, traceback=False):
'''
'''
if self._compound:
if not other._compound:
return False
if self._bitwise_operator != other._bitwise_operator:
return False
if not self._compound[0].equals(other._compound[0]):
if not self._compound[0].equals(other._compound[1]):
return False
if not self._compound[1].equals(other._compound[0]):
return False
elif not self._compound[1].equals(other._compound[1]):
return False
elif other._compound:
return False
for attr in ('_NotImplemented_RHS_Data_op',
'_attr',
'_value',
'_operator',
'_exact'):
if not cf_equals(getattr(self, attr, None),
getattr(other, attr, None),
traceback=traceback):
return False
#--- End: for
return True
#--- End: def
[docs] def equivalent(self, other, traceback=False):
'''
'''
for attr, value in self.__dict__.iteritems():
if not cf_equivalent(value, getattr(other, attr),
traceback=traceback):
return False
#--- End: for
return True
#--- End: def
[docs] def evaluate(self, x):
'''
Evaluate the query operation for a given left hand side operand.
Note that for the query object ``q`` and any object, ``x``, ``x==q``
is equivalent to ``q.evaluate(x)`` and ``x!=q`` is equivalent to
``q.evaluate(x)==False``.
:Parameters:
x :
The object for the left hand side operand of the query.
:Returns:
out :
The result of the query. The nature of the result is dependent
on the object type of *x*.
:Examples:
>>> q = cf.Query('lt', 5.5)
>>> q.evaluate(6)
False
>>> q = cf.Query('wi', (1,2))
>>> array = numpy.arange(4)
>>> array
array([0, 1, 2, 3])
>>> q.evaluate(array)
array([False, True, True, False], dtype=bool)
'''
return self._evaluate(x, ())
#--- End: def
def _evaluate(self, x, parent_attr):
'''
Evaluate the query operation for a given object.
.. seealso:: `evaluate`
:Parameters:
x : object
See `evaluate`.
parent_attr : tuple
:Returns:
out :
See `evaluate`.
:Examples:
'''
compound = self._compound
attr = parent_attr + self._attr
if compound:
c = compound[0]._evaluate(x, attr)
d = compound[1]._evaluate(x, attr)
return self._bitwise_operator(c, d)
#--- End: if
# Still here?
# ------------------------------------------------------------
#
# ------------------------------------------------------------
for a in attr:
x = getattr(x, a)
operator = self._operator
value = self._value
if operator == 'eq':
if not self._exact:
if not isinstance(x, basestring):
raise ValueError("Can't re.match on non-string")
return bool(re_match(value, x))
else:
return x == value
#--- End: if
if operator == 'ne':
if not self._exact:
if not isinstance(x, basestring):
raise ValueError("Can't re.match on non-string")
return not re_match(value, x)
else:
return x != value
#--- End: if
if operator == 'lt':
_lt = getattr(x, '_query_lt', None)
if _lt is not None:
return _lt(value)
return x < value
#--- End: if
if operator == 'le':
_le = getattr(x, '_query_le', None)
if _le is not None:
return _le(value)
return x <= value
#--- End: if
if operator == 'gt':
_gt = getattr(x, '_query_gt', None)
if _gt is not None:
return _gt(value)
return x > value
#--- End: if
if operator == 'ge':
_ge = getattr(x, '_query_ge', None)
if _ge is not None:
return _ge(value)
return x >= value
#--- End: if
if operator == 'wi':
_wi = getattr(x, '_query_wi', None)
if _wi is not None:
return _wi(value[0], value[1])
return (x >= value[0]) & (x <= value[1])
#--- End: if
if operator == 'wo':
_wo = getattr(x, '_query_wo', None)
if _wo is not None:
return _wo(value[0], value[1])
return (x < value[0]) | (x > value[1])
#--- End: if
if operator == 'contain':
_contain = getattr(x, '_query_contain', None)
if _contain is not None:
return _contain(value)
else:
return x == value
#--- End: if
if operator == 'set':
_set = getattr(x, '_query_set', None)
if _set is not None:
return _set(value, self._exact)
i = iter(value)
v = i.next()
if not self._exact:
if not isinstance(x, basestring):
raise ValueError("Can't, as yet, regex on non string")
if re_match(v, x):
return True
for v in i:
if re_match(v, x):
return True
return False
else:
out = (x == v)
for v in i:
out |= (x == v)
return out
#--- End: if
#--- End: def
[docs] def inspect(self):
'''
Inspect the object for debugging.
.. seealso:: `cf.inspect`
:Returns:
None
'''
print cf_inspect(self)
#--- End: def
#--- End: class
[docs]def lt(value, units=None, attr=None):
'''Return a `cf.Query` object for a variable for being strictly less
than a value.
.. seealso:: `cf.contain`, `cf.eq`, `cf.ge`, `cf.gt`, `cf.ne`,
`cf.le`, `cf.set`, `cf.wi`, `cf.wo`
:Parameters:
value : object
The value which a variable is to be compared with.
units : str or cf.Units, optional
The units of *value*. By default, the same units as the
variable being tested are assumed, if applicable.
attr : str, optional
Return a query object for a variable's *attr* attribute.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> q = cf.lt(5)
>>> q
<CF Query: x lt 5>
>>> q.evaluate(4)
True
>>> q.evaluate(5)
False
'''
return Query('lt', value, units=units, attr=attr)
#--- End: def
[docs]def le(value, units=None, attr=None):
'''Return a `cf.Query` object for a variable for being less than or equal
to a value.
.. seealso:: `cf.contain`, `cf.eq`, `cf.ge`, `cf.gt`, `cf.ne`,
`cf.lt`, `cf.set`, `cf.wi`, `cf.wo`
:Parameters:
value : object
The value which a variable is to be compared with.
units : str or cf.Units, optional
The units of *value*. By default, the same units as the
variable being tested are assumed, if applicable.
attr : str, optional
Return a query object for a variable's *attr* attribute.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> q = cf.le(5)
>>> q
<CF Query: x le 5>
>>> q.evaluate(5)
True
>>> q.evaluate(6)
False
'''
return Query('le', value, units=units, attr=attr)
#--- End: def
[docs]def gt(value, units=None, attr=None):
'''Return a `cf.Query` object for a variable for being strictly greater
than a value.
.. seealso:: `cf.contain`, `cf.eq`, `cf.ge`, `cf.ne`, `cf.le`,
`cf.lt`, `cf.set`, `cf.wi`, `cf.wo`
:Parameters:
value : object
The value which a variable is to be compared with.
units : str or cf.Units, optional
The units of *value*. By default, the same units as the
variable being tested are assumed, if applicable.
attr : str, optional
Return a query object for a variable's *attr* attribute.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> q = cf.gt(5)
>>> q
<CF Query: x gt 5>
>>> q.evaluate(6)
True
>>> q.evaluate(5)
False
'''
return Query('gt', value, units=units, attr=attr)
#--- End: def
[docs]def ge(value, units=None, attr=None):
'''Return a `cf.Query` object for a variable for being greater than or
equal to a value.
.. seealso:: `cf.contain`, `cf.eq`, `cf.gt`, `cf.ne`, `cf.le`,
`cf.lt`, `cf.set`, `cf.wi`, `cf.wo`
:Parameters:
value :
The value which a variable is to be compared with.
units : str or cf.Units, optional
The units of *value*. By default, the same units as the
variable being tested are assumed, if applicable.
attr : str, optional
Return a query object for a variable's *attr* attribute.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> q = cf.ge(5)
>>> q
<CF Query: x ge 5>
>>> q.evaluate(5)
True
>>> q.evaluate(4)
False
>>> cf.ge(10, 'm')
<CF Query: (ge <CF Data: 10 m>)>
>>> cf.ge(100, cf.Units('kg'))
<CF Query: (ge <CF Data: 100 kg>)>
>>> cf.ge(2, attr='month')
<CF Query: month(ge 2)>
'''
return Query('ge', value, units=units, attr=attr)
#--- End: def
[docs]def eq(value, units=None, exact=True, attr=None):
'''Return a `cf.Query` object for a variable for being equal to a value.
.. seealso:: `cf.contain`, `cf.ge`, `cf.gt`, `cf.ne`, `cf.le`,
`cf.lt`, `cf.set`, `cf.wi`, `cf.wo`
:Parameters:
value
The value which a variable is to be compared with.
units : str or cf.Units, optional
The units of *value*. By default, the same units as the
variable being tested are assumed, if applicable.
exact : bool, optional
If False then string values are to be treated as regular
expressions understood by the :py:obj:`re` module and are
evaluated using the :py:obj:`re.match` method.
attr : str, optional
Return a query object for a variable's *attr* attribute.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> q = cf.eq(5)
>>> q
<CF Query: x eq 5>
>>> q.evaluate(5)
True
>>> q == 4
False
>>> q = cf.eq('air', exact=False)
>>> q == 'air_temperature'
True
>>> q = cf.eq('.*temp', exact=False)
>>> q == 'air_temperature'
True
'''
return Query('eq', value, units=units, exact=exact, attr=attr)
#--- End: def
[docs]def ne(value, units=None, exact=True, attr=None):
'''Return a `cf.Query` object for a variable for being equal to a value.
.. seealso:: `cf.contain`, `cf.eq`, `cf.ge`, `cf.gt`, `cf.le`,
`cf.lt`, `cf.set`, `cf.wi`, `cf.wo`
:Parameters:
value : object
The value which a variable is to be compared with.
units : str or cf.Units, optional
The units of *value*. By default, the same units as the
variable being tested are assumed, if applicable.
exact : bool, optional
If False then string values are to be treated as regular
expressions understood by the :py:obj:`re` module and are
evaluated using the :py:obj:`re.match` method.
attr : str, optional
Return a query object for a variable's *attr* attribute.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> q = cf.ne(5)
>>> q
<CF Query: x ne 5>
>>> q.evaluate(4)
True
>>> q.evaluate(5)
False
'''
return Query('ne', value, units=units, exact=exact, attr=attr)
#--- End: def
[docs]def wi(value0, value1, units=None, attr=None):
'''Return a `cf.Query` object for a variable being within a range.
``x == cf.wi(a, b)`` is equivalent to ``x == cf.ge(a) & cf.le(b)``.
``x == cf.wi(a, b, attr='foo')`` is equivalent to ``x.foo == cf.wi(a,
b)``.
.. seealso:: `cf.contain`, `cf.eq`, `cf.ge`, `cf.gt`, `cf.ne`,
`cf.le`, `cf.lt`, `cf.set`, `cf.wo`
:Parameters:
value0 : scalar object
The lower bound of the range which a variable is to be
compared with.
value1 : scalar object
The upper bound of the range which a variable is to be
compared with.
units : str or cf.Units, optional
If applicable, the units of *value0* and *value1*. By default,
the same units as the variable being tested are assumed.
attr : str, optional
Return a query object for a variable's *attr* attribute.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> q = cf.wi(5, 7)
>>> q
<CF Query: wi (5, 7)>
>>> q.evaluate(6)
True
>>> q.evaluate(4)
False
'''
return Query('wi', [value0, value1], units=units, attr=attr)
#--- End: def
[docs]def wo(value0, value1, units=None, attr=None):
'''Return a `cf.Query` object for a variable for being without a
range.
``x == cf.wo(a, b)`` is equivalent to ``x == cf.lt(a) | cf.gt(b)``.
.. seealso:: `cf.contain`, `cf.eq`, `cf.ge`, `cf.gt`, `cf.ne`,
`cf.le`, `cf.lt`, `cf.set`, `cf.wi`
:Parameters:
value0 : object
The lower bound of the range which a variable is to be
compared with.
value1 : object
The upper bound of the range which a variable is to be
compared with.
units : str or cf.Units, optional
If applicable, the units of *value0* and *value1*. By default,
the same units as the variable being tested are assumed.
attr : str, optional
Return a query object for a variable's *attr* attribute.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> q = cf.wo(5)
>>> q
<CF Query: x wo (5, 7)>
>>> q.evaluate(4)
True
>>> q.evaluate(6)
False
'''
return Query('wo', [value0, value1], units=units, attr=attr)
#--- End: def
[docs]def set(values, units=None, exact=True, attr=None):
'''Return a `cf.Query` object for a variable for being equal to any
member of a collection.
.. seealso:: `cf.contain`, `cf.eq`, `cf.ge`, `cf.gt`, `cf.ne`,
`cf.le`, `cf.lt`, `cf.wi`, `cf.wo`
:Parameters:
values : sequence
units : str or cf.Units, optional
The units of each element of *values*. By default, the same
units as the variable being tested are assumed, if applicable.
exact : bool, optional
If False then string values are to be treated as regular
expressions understood by the :py:obj:`re` module and are
evaluated using the :py:obj:`re.match` method.
attr : str, optional
Return a query object for a variable's *attr* attribute.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> c = cf.set([3, 5])
>>> c
<CF Query: set [3, 5]>
>>> c == 4
False
>>> c == 5
True
>>> print c == numpy.array([2, 3, 4, 5])
[False True False True]
'''
return Query('set', values, units=units, exact=exact, attr=attr)
#--- End: def
[docs]def contain(value, units=None, attr=None):
'''Return a `cf.Query` object for cells of a variable for containing a
value.
If cells are not defined then return a `cf.Query` object for a
variable for being equal to a value, i.e. this case is equivalent to
`cf.eq`.
.. versionadded:: 1.0
.. seealso:: `cf.eq`, `cf.ge`, `cf.gt`, `cf.ne`, `cf.le`, `cf.lt`,
`cf.set`, `cf.wi`, `cf.wo`
:Parameters:
value :
The value which a variable is to be compared with.
units : str or cf.Units, optional
The units of each element of *values*. By default, the same
units as the variable being tested are assumed, if applicable.
attr : str, optional
Return a query object for a variable's *attr* attribute.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> cf.contain(30, 'degrees_east')
<CF Query: (contain <CF Data: 30 degrees_east>)>
>>> cf.contain(cf.Data(10, 'km'))
<CF Query: (contain <CF Data: 10 km>)>
>>> c
<CF DimensionCoordinate: longitude(4) degrees_east>
>>> print c.bounds.array
[[ 0 90]
[ 90 180]
[180 270]
[270 360]]
>>> print (cf.contain(100) == c).array
[False True False False]
>>> print (cf.contain(9999) == c).array
[False False False False]
'''
return Query('contain', value, units=units, attr=attr)
#--- End: def
[docs]def year(value):
'''Return a `cf.Query` object for date-time years.
In this context, any object which has a `!year` attribute is
considered to be a date-time variable.
If *value* is a `cf.Query` object then ``cf.year(value)`` is
equivalent to ``value.addattr('year')``. Otherwise ``cf.year(value)``
is equivalent to ``cf.eq(value, attr='year')``.
.. seealso:: `cf.year`, `cf.month`, `cf.day`, `cf.hour`, `cf.minute`,
`cf.second`, `cf.dteq`, `cf.dtge`, `cf.dtgt`, `cf.dtne`,
`cf.dtle`, `cf.dtlt`
:Parameters:
value :
Either the value that the year is to be compared with, or a
`cf.Query` object for testing the year.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> d = cf.dt(2002, 6, 16)
>>> d == cf.year(2002)
True
>>> d == cf.year(cf.le(2003))
True
>>> d == cf.year(2001)
False
>>> d == cf.year(cf.wi(2003, 2006))
False
'''
if isinstance(value, Query):
return value.addattr('year')
else:
return Query('eq', value, attr='year')
#--- End: def
[docs]def month(value):
'''Return a `cf.Query` object for date-time months.
In this context, any object which has a `!month` attribute is
considered to be a date-time variable.
If *value* is a `cf.Query` object then ``cf.month(value)`` is
equivalent to ``value.addattr('month')``. Otherwise
``cf.month(value)`` is equivalent to ``cf.eq(value, attr='month')``.
.. seealso:: `cf.year`, `cf.day`, `cf.hour`, `cf.minute`, `cf.second`,
`cf.dteq`, `cf.dtge`, `cf.dtgt`, `cf.dtne`, `cf.dtle`,
`cf.dtlt`
:Parameters:
value :
Either the value that the month is to be compared with, or a
`cf.Query` object for testing the month.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> d = cf.dt(2002, 6, 16)
>>> d == cf.month(6)
True
>>> d == cf.month(cf.le(7))
True
>>> d == cf.month(7)
False
>>> d == cf.month(cf.wi(1, 6))
True
'''
if isinstance(value, Query):
return value.addattr('month')
else:
return Query('eq', value, attr='month')
#--- End: def
[docs]def day(value):
'''Return a `cf.Query` object for date-time days.
In this context, any object which has a `!day` attribute is considered
to be a date-time variable.
If *value* is a `cf.Query` object then ``cf.day(value)`` is
equivalent to ``value.addattr('day')``. Otherwise ``cf.day(value)`` is
equivalent to ``cf.eq(value, attr='day')``.
.. seealso:: `cf.year`, `cf.month`, `cf.hour`, `cf.minute`,
`cf.second`, `cf.dteq`, `cf.dtge`, `cf.dtgt`, `cf.dtne`,
`cf.dtle`, `cf.dtlt`
:Parameters:
value :
Either the value that the day is to be compared with, or a
`cf.Query` object for testing the day.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> d = cf.dt(2002, 6, 16)
>>> d == cf.day(16)
True
>>> d == cf.day(cf.le(19))
True
>>> d == cf.day(7)
False
>>> d == cf.day(cf.wi(1, 21))
True
'''
if isinstance(value, Query):
return value.addattr('day')
else:
return Query('eq', value, attr='day')
#--- End: def
[docs]def hour(value):
'''Return a `cf.Query` object for date-time hours.
In this context, any object which has a `!hour` attribute is
considered to be a date-time variable.
If *value* is a `cf.Query` object then ``cf.hour(value)`` is
equivalent to ``value.addattr('hour')``. Otherwise ``cf.hour(value)``
is equivalent to ``cf.eq(value, attr='hour')``.
.. seealso:: `cf.year`, `cf.month`, `cf.day`, `cf.minute`,
`cf.second`, `cf.dteq`, `cf.dtge`, `cf.dtgt`, `cf.dtne`,
`cf.dtle`, `cf.dtlt`
:Parameters:
value :
Either the value that the hour is to be compared with, or a
`cf.Query` object for testing the hour.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> d = cf.dt(2002, 6, 16, 18)
>>> d == cf.hour(18)
True
>>> d == cf.hour(cf.le(19))
True
>>> d == cf.hour(7)
False
>>> d == cf.hour(cf.wi(6, 23))
True
'''
if isinstance(value, Query):
return value.addattr('hour')
else:
return Query('eq', value, attr='hour')
#--- End: def
[docs]def minute(value):
'''
Return a `cf.Query` object for date-time minutes.
In this context, any object which has a `!minute` attribute is
considered to be a date-time variable.
If *value* is a `cf.Query` object then ``cf.minute(value)`` is
equivalent to ``value.addattr('minute')``. Otherwise
``cf.minute(value)`` is equivalent to ``cf.eq(value, attr='minute')``.
.. seealso:: `cf.year`, `cf.month`, `cf.day`, `cf.hour`, `cf.second`,
`cf.dteq`, `cf.dtge`, `cf.dtgt`, `cf.dtne`, `cf.dtle`,
`cf.dtlt`
:Parameters:
value :
Either the value that the minute is to be compared with, or a
`cf.Query` object for testing the minute.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> d = cf.dt(2002, 6, 16, 18, 30, 0)
>>> d == cf.minute(30)
True
>>> d == cf.minute(cf.le(45))
True
>>> d == cf.minute(7)
False
>>> d == cf.minute(cf.wi(15, 45))
True
'''
if isinstance(value, Query):
return value.addattr('minute')
else:
return Query('eq', value, attr='minute')
#--- End: def
[docs]def second(value):
'''
Return a `cf.Query` object for date-time seconds.
In this context, any object which has a `!second` attribute is
considered to be a date-time variable.
If *value* is a `cf.Query` object then ``cf.second(value)`` is
equivalent to ``value.addattr('second')``. Otherwise
``cf.second(value)`` is equivalent to ``cf.eq(value, attr='second')``.
.. seealso:: `cf.year`, `cf.month`, `cf.day`, `cf.hour`, `cf.minute`,
`cf.dteq`, `cf.dtge`, `cf.dtgt`, `cf.dtne`, `cf.dtle`,
`cf.dtlt`
:Parameters:
value :
Either the value that the second is to be compared with, or a
`cf.Query` object for testing the second.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> d = cf.dt(2002, 6, 16, 18, 30, 0)
>>> d == cf.second(0)
True
>>> d == cf.second(cf.le(30))
True
>>> d == cf.second(30)
False
>>> d == cf.second(cf.wi(0, 30))
True
'''
if isinstance(value, Query):
return value.addattr('second')
else:
return Query('eq', value, attr='second')
#--- End: def
[docs]def cellsize(value, units=None):
'''Return a `cf.Query` object for the cell size of a coordinate object.
In this context, a coordinate is any object which has a `!cellsize`
attribute.
If *value* is a `cf.Query` object then ``cf.cellsize(value)`` is
equivalent to ``value.addattr('cellsize')`` (see
`cf.Query.addattr`). Otherwise ``cf.cellsize(value)`` is equivalent to
``cf.eq(value, attr='cellsize')``.
.. seealso:: `cf.cellge`, `cf.cellgt`, `cf.celllt`, `cf.cellle`,
`cf.cellwi`, `cf.cellwo`, `cf.eq`
:Parameters:
value :
Either the value that the cell size is to be compared with, or a
`cf.Query` object for testing the cell size.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> cf.cellsize(cf.lt(5, 'km'))
<CF Query: cellsize(lt <CF Data: 5 km>)>
>>> cf.cellsize(5)
<CF Query: cellsize(eq 5)>
>>> cf.cellsize(cf.Data(5, 'km'))
<CF Query: cellsize(eq <CF Data: 5 km>)>
>>> cf.cellsize(cf.Data(5, 'km'))
<CF Query: cellsize(eq <CF Data: 5 km>)>
>>> cf.cellsize(5, units='km')
<CF Query: cellsize(eq <CF Data: 5 km>)>
'''
if isinstance(value, Query):
return value.addattr('cellsize')
else:
return Query('eq', value, units=units, attr='cellsize')
#--- End: def
[docs]def dtge(*args, **kwargs):
'''
Return a `cf.Query` object for a variable being not earlier
than a date-time.
``cf.dtge(*args, **kwargs)`` is equivalent to ``cf.ge(cf.dt(*args,
**kwargs))``.
.. seealso:: `cf.year`, `cf.month`, `cf.day`, `cf.hour`, `cf.minute`,
`cf.second`, `cf.dteq`, `cf.dtgt`, `cf.dtne`, `cf.dtle`,
`cf.dtlt`
:Parameters:
args, kwargs :
Positional and keyword arguments for defining a date-time. See
`cf.dt` for details.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> d = cf.dt(2002, 6, 16)
>>> d == cf.dtge(1990, 1, 1)
True
>>> d == cf.dtge(2002, 6, 16)
True
>>> d == cf.dtge('2100-1-1')
False
>>> d == cf.dtge('2001-1-1') & cf.dtle(2010, 12, 31)
True
The last example is equivalent to:
>>> d == cf.wi(cf.dt(2001, 1, 1), cf.dt('2010-12-31'))
True
'''
return Query('ge', dt(*args, **kwargs))
#--- End: def
[docs]def dtgt(*args, **kwargs):
'''
Return a `cf.Query` object for a variable being later than a
date-time.
``cf.dtgt(*args, **kwargs)`` is equivalent to ``cf.gt(cf.dt(*args,
**kwargs))``.
.. seealso:: `cf.year`, `cf.month`, `cf.day`, `cf.hour`, `cf.minute`,
`cf.second`, `cf.dteq`, `cf.dtge`, `cf.dtne`, `cf.dtle`,
`cf.dtlt`
:Parameters:
args, kwargs :
Positional and keyword arguments for defining a date-time. See
`cf.dt` for details.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> d = cf.dt(2002, 6, 16)
>>> d == cf.dtgt(1990, 1, 1)
True
>>> d == cf.dtgt(2002, 6, 16)
False
>>> d == cf.dtgt('2100-1-1')
False
>>> d == cf.dtgt('2001-1-1') & cf.dtle(2010, 12, 31)
True
The last example is equivalent to:
>>> d == cf.wi(cf.dt(2001, 1, 1), cf.dt('2010-12-31'))
True
'''
return Query('gt', dt(*args, **kwargs))
#--- End: def
[docs]def dtle(*args, **kwargs):
'''
Return a `cf.Query` object for a variable being not later than a
date-time.
``cf.dtle(*args, **kwargs)`` is equivalent to ``cf.le(cf.dt(*args,
**kwargs))``.
.. seealso:: `cf.year`, `cf.month`, `cf.day`, `cf.hour`, `cf.minute`,
`cf.second`, `cf.dteq`, `cf.dtge`, `cf.dtgt`, `cf.dtne`,
`cf.dtlt`
:Parameters:
args, kwargs :
Positional and keyword arguments for defining a date-time. See
`cf.dt` for details.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> d = cf.dt(2002, 6, 16)
>>> d == cf.dtle(1990, 1, 1)
True
>>> d == cf.dtle(2002, 6, 16)
True
>>> d == cf.dtle('2100-1-1')
False
>>> d == cf.dtle('2001-1-1') & cf.dtle(2010, 12, 31)
True
The last example is equivalent to:
>>> d == cf.wi(cf.dt(2001, 1, 1), cf.dt('2010-12-31'))
True
'''
return Query('le', dt(*args, **kwargs))
#--- End: def
[docs]def dtlt(*args, **kwargs):
'''
Return a `cf.Query` object for a variable being earlier than a
date-time.
``cf.dtlt(*args, **kwargs)`` is equivalent to ``cf.lt(cf.dt(*args,
**kwargs))``.
.. seealso:: `cf.year`, `cf.month`, `cf.day`, `cf.hour`, `cf.minute`,
`cf.second`, `cf.dteq`, `cf.dtge`, `cf.dtgt`, `cf.dtne`,
`cf.dtle`
:Parameters:
args, kwargs :
Positional and keyword arguments for defining a date-time. See
`cf.dt` for details.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> d = cf.dt(2002, 6, 16)
>>> d == cf.dtlt(1990, 1, 1)
True
>>> d == cf.dtlt(2002, 6, 16)
True
>>> d == cf.dtlt('2100-1-1')
False
>>> d == cf.dtlt('2001-1-1') & cf.dtlt(2010, 12, 31)
True
The last example is equivalent to:
>>> d == cf.wi(cf.dt(2001, 1, 1), cf.dt('2010-12-31'))
True
'''
return Query('lt', dt(*args, **kwargs))
#--- End: def
[docs]def dteq(*args, **kwargs):
'''
Return a `cf.Query` object for a variable being equal to a
date-time.
``cf.dteq(*args, **kwargs)`` is equivalent to ``cf.eq(cf.dt(*args,
**kwargs))``.
.. seealso:: `cf.year`, `cf.month`, `cf.day`, `cf.hour`, `cf.minute`,
`cf.second`, `cf.dtge`, `cf.dtgt`, `cf.dtne`, `cf.dtle`,
`cf.dtlt`
:Parameters:
args, kwargs :
Positional and keyword arguments for defining a date-time. See
`cf.dt` for details.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> d = cf.dt(2002, 6, 16)
>>> d == cf.dteq(1990, 1, 1)
True
>>> d == cf.dteq(2002, 6, 16)
True
>>> d == cf.dteq('2100-1-1')
False
>>> d == cf.dteq('2001-1-1') & cf.dteq(2010, 12, 31)
True
The last example is equivalent to:
>>> d == cf.wi(cf.dt(2001, 1, 1), cf.dt('2010-12-31'))
True
'''
return Query('eq', dt(*args, **kwargs))
#--- End: def
[docs]def dtne(*args, **kwargs):
'''
Return a `cf.Query` object for a variable being not equal to a
date-time.
``cf.dtne(*args, **kwargs)`` is equivalent to ``cf.ne(cf.dt(*args,
**kwargs))``.
.. seealso:: `cf.year`, `cf.month`, `cf.day`, `cf.hour`, `cf.minute`,
`cf.second`, `cf.dteq`, `cf.dtge`, `cf.dtgt`, `cf.dtle`,
`cf.dtlt`
:Parameters:
args, kwargs :
Positional and keyword arguments for defining a date-time. See
`cf.dt` for details.
:Returns:
out : cf.Query
The query object.
:Examples:
>>> d = cf.dt(2002, 6, 16)
>>> d == cf.dtne(1990, 1, 1)
True
>>> d == cf.dtne(2002, 6, 16)
True
>>> d == cf.dtne('2100-1-1')
False
>>> d == cf.dtne('2001-1-1') & cf.dtne(2010, 12, 31)
True
The last example is equivalent to:
>>> d == cf.wi(cf.dt(2001, 1, 1), cf.dt('2010-12-31'))
True
'''
return Query('ne', dt(*args, **kwargs))
#--- End: def
[docs]def cellwi(value0, value1, units=None):
'''Return a `cf.Query` object for coordinate cell bounds being within
a range.
In this context, a coordinate is any object which has `!lower_bounds`
and `!upper_bounds` attributes.
``cf.cellwi(value0, value1)`` is equivalent to ``cf.ge(value0,
attr='lower_bounds') & cf.le(value1, attr='upper_bounds')``.
.. versionadded:: 1.0
.. seealso:: `cf.cellge`, `cf.cellgt`, `cf.cellle`, `cf.celllt`,
`cf.cellsize`, `cf.cellwo`, `cf.wi`
:Parameters:
:Returns:
out : cf.Query
The query object.
:Examples:
'''
return (Query('ge', value0, units=units, attr='lower_bounds') &
Query('le', value1, units=units, attr='upper_bounds'))
#--- End: def
[docs]def cellwo(value0, value1, units=None):
'''Return a `cf.Query` object for coordinate cell bounds being
outside a range.
In this context, a coordinate is any object which has `!lower_bounds`
and `!upper_bounds` attributes.
``cf.cellwo(value0, value1)`` is equivalent to ``cf.lt(value0,
attr='lower_bounds') & cf.gt(value1, attr='upper_bounds')``.
.. versionadded:: 1.0
.. seealso:: `cf.cellge`, `cf.cellgt`, `cf.cellle`, `cf.celllt`,
`cf.cellsize`, `cf.cellwi`, `cf.wo`
:Parameters:
:Returns:
out : cf.Query
The query object.
:Examples:
'''
return (Query('lt', value0, units=units, attr='lower_bounds') &
Query('gt', value1, units=units, attr='upper_bounds'))
#--- End: def
[docs]def cellgt(value, units=None):
'''Return a `cf.Query` object for coordinate cell bounds being
strictly greater than a value.
In this context, a coordinate is any object which has a
`!lower_bounds` attribute.
``cf.cellgt(value)`` is equivalent to ``cf.gt(value,
attr='lower_bounds')``.
.. versionadded:: 1.0
.. seealso:: `cf.cellge`, `cf.cellle`, `cf.celllt`, `cf.cellsize`,
`cf.cellwi`,`cf.cellwo`, `cf.gt`
:Parameters:
:Returns:
out : cf.Query
The query object.
:Examples:
'''
return Query('gt', value, units=units, attr='lower_bounds')
#--- End: def
[docs]def cellge(value, units=None):
'''Return a `cf.Query` object for coordinate cell bounds being
greater than or equal to a value.
In this context, a coordinate is any object which has a
`!lower_bounds` attribute.
``cf.cellge(value)`` is equivalent to ``cf.ge(value,
attr='lower_bounds')``.
.. versionadded:: 1.0
.. seealso:: `cf.cellgt`, `cf.cellle`, `cf.celllt`, `cf.cellsize`,
`cf.cellwi`,`cf.cellwo`, `cf.gt`
:Parameters:
:Returns:
out : cf.Query
The query object.
:Examples:
'''
return Query('ge', value, units=units, attr='lower_bounds')
#--- End: def
[docs]def celllt(value, units=None):
'''Return a `cf.Query` object for coordinate cell bounds being
strictly less than a value.
In this context, a coordinate is any object which has a
`!upper_bounds` attribute.
``cf.celllt(value)`` is equivalent to ``cf.lt(value,
attr='upper_bounds')``.
.. versionadded:: 1.0
.. seealso:: `cf.cellge`, `cf.cellgt`, `cf.cellle`, `cf.cellsize`,
`cf.cellwi`,`cf.cellwo`, `cf.le`
:Parameters:
:Returns:
out : cf.Query
The query object.
:Examples:
'''
return Query('lt', value, units=units, attr='upper_bounds')
#--- End: def
[docs]def cellle(value, units=None):
'''Return a `cf.Query` object for coordinate cell bounds being
less than or equal to a value.
In this context, a coordinate is any object which has a
`!upper_bounds` attribute.
``cf.cellle(value)`` is equivalent to ``cf.le(value,
attr='upper_bounds')``.
.. versionadded:: 1.0
.. seealso:: `cf.cellge`, `cf.cellgt`, `cf.celllt`, `cf.cellsize`,
`cf.cellwi`,`cf.cellwo`, `cf.lt`
:Parameters:
:Returns:
out : cf.Query
The query object.
:Examples:
'''
return Query('le', value, units=units, attr='upper_bounds')
#--- End: def
[docs]def jja():
'''Return a `cf.Query` object for season June, July, August.
``cf.jja()`` is equivalent to ``cf.month(cf.wi(6, 8))``.
.. versionadded:: 1.0
.. seealso:: `cf.djf`, `cf.mam`, `cf.son`, `cf.seasons`, `cf.month`,
`cf.wi`
:Returns:
out : cf.Query
The query object.
:Examples:
>>> f
<CF Field: air_temperature(time(365), latitude(64), longitude(128)) K>
>>> f.subspace(time=cf.jja())
<CF Field: air_temperature(time(92), latitude(64), longitude(128)) K>
'''
return Query('wi', (6, 8), attr='month')
#--- End: def
[docs]def son():
'''Return a `cf.Query` object for season September, October,
November.
``cf.son()`` is equivalent to ``cf.month(cf.wi(9, 11))``.
.. versionadded:: 1.0
.. seealso:: `cf.djf`, `cf.mam`, `cf.jja`, `cf.seasons`, `cf.month`,
`cf.wi`
:Returns:
out : cf.Query
The query object.
:Examples:
>>> f
<CF Field: air_temperature(time(365), latitude(64), longitude(128)) K>
>>> f.subspace(time=cf.son())
<CF Field: air_temperature(time(91), latitude(64), longitude(128)) K>
'''
return Query('wi', (9, 11), attr='month')
#--- End: def
[docs]def djf():
'''Return a `cf.Query` object for season December, January, February.
``cf.djf()`` is equivalent to ``cf.month(cf.ge(12) | cf.le(2))``.
.. versionadded:: 1.0
.. seealso:: `cf.mam`, `cf.jja`, `cf.son`, `cf.seasons`, `cf.month`,
`cf.ge`, `cf.le`
:Returns:
out : cf.Query
The query object.
:Examples:
>>> f
<CF Field: air_temperature(time(365), latitude(64), longitude(128)) K>
>>> f.subspace(time=cf.djf())
<CF Field: air_temperature(time(90), latitude(64), longitude(128)) K>
'''
q = Query('ge', 12) | Query('le', 2)
return q.addattr('month')
#--- End: def
[docs]def mam():
'''Return a `cf.Query` object for the season March, April, May.
``cf.mam()`` is equivalent to ``cf.month(cf.wi(3, 5))``.
.. versionadded:: 1.0
.. seealso:: `cf.djf`, `cf.jja`, `cf.son`, `cf.seasons`, `cf.month`,
`cf.wi`
:Returns:
out : cf.Query
The query object.
:Examples:
>>> f
<CF Field: air_temperature(time(365), latitude(64), longitude(128)) K>
>>> f.subspace(time=cf.mam())
<CF Field: air_temperature(time(92), latitude(64), longitude(128)) K>
'''
return Query('wi', (3, 5), attr='month')
#--- End: def
[docs]def seasons(n=4, start=12):
'''Return a list `cf.Query` objects for all seasons in a year.
.. versionadded:: 1.0
.. seealso:: `cf.mam`, `cf.jja`, `cf.son`, `cf.djf`
:Parameters:
n : int, optional
The number of seasons in the year. By default there are four
seasons.
start : int, optional
The start month of the first season of the year. By default
this is 12 (December).
:Returns:
out : list of cf.Query
The query objects.
:Examples:
>>> cf.seasons()
[<CF Query: month[(ge 12) | (le 2)]>,
<CF Query: month(wi (3, 5))>,
<CF Query: month(wi (6, 8))>,
<CF Query: month(wi (9, 11))>]
>>> cf.seasons(4, 1)
[<CF Query: month(wi (1, 3))>,
<CF Query: month(wi (4, 6))>,
<CF Query: month(wi (7, 9))>,
<CF Query: month(wi (10, 12))>]
>>> cf.seasons(3, 6)
[<CF Query: month(wi (6, 9))>,
<CF Query: month[(ge 10) | (le 1)]>,
<CF Query: month(wi (2, 5))>]
>>> cf.seasons(3)
[<CF Query: month[(ge 12) | (le 3)]>,
<CF Query: month(wi (4, 7))>,
<CF Query: month(wi (8, 11))>]
>>> cf.seasons(3, 6)
[<CF Query: month(wi (6, 9))>,
<CF Query: month[(ge 10) | (le 1)]>,
<CF Query: month(wi (2, 5))>]
>>> cf.seasons(12)
[<CF Query: month(eq 12)>,
<CF Query: month(eq 1)>,
<CF Query: month(eq 2)>,
<CF Query: month(eq 3)>,
<CF Query: month(eq 4)>,
<CF Query: month(eq 5)>,
<CF Query: month(eq 6)>,
<CF Query: month(eq 7)>,
<CF Query: month(eq 8)>,
<CF Query: month(eq 9)>,
<CF Query: month(eq 10)>,
<CF Query: month(eq 11)>]
>>> cf.seasons(1, 4)
[<CF Query: month[(ge 4) | (le 3)]>]
'''
if 12 % n:
raise ValueError(
"Number of seasons must divide into 12. Got %s" % n)
if not 1 <= start <= 12 or int(start) != start:
raise ValueError(
"Start month must be integer between 1 and 12. Got %s" % start)
out = []
inc = int(12 / n)
start = int(start)
m0 = start
for i in range(int(n)):
m1 = ((m0 + inc) % 12) - 1
if not m1:
m1 = 12
elif m1 == -1:
m1 = 11
if m0 < m1:
q = Query('wi', (m0, m1))
elif m0 > m1:
q = Query('ge', m0) | Query('le', m1)
else:
q = Query('eq', m0)
out.append(q.addattr('month'))
m0 = m1 + 1
if m0 > 12:
m0 = 1
#--- End: for
return out
#--- End: def
# --------------------------------------------------------------------
# Vectorized
# --------------------------------------------------------------------
def _match(regex, x):
return bool(re_match(regex, x))
_array_match = numpy_vectorize(_match, otypes=[bool])