2019-08-15 10:05:51 +08:00

261 lines
8.0 KiB
Python

#-----------------------------------------------------
# Author: Yaqiang Wang
# Date: 2018-7-18
# Purpose: MeteoInfo index module
# Note: Jython
#-----------------------------------------------------
from org.meteoinfo.data.dataframe import Index as MIIndex
from org.meteoinfo.data.dataframe import DateTimeIndex as MIDateTimeIndex
from org.joda.time import DateTime
import datetime
import numbers
from mipylib.numeric.core import NDArray
import mipylib.miutil as miutil
class Index(object):
@staticmethod
def factory(data=None, name='Index', index=None):
'''
Factory method
'''
if index is None:
if isinstance(data[0], (DateTime, datetime.datetime)):
return DateTimeIndex(data, name)
else:
return Index(data, name)
else:
if isinstance(index, MIDateTimeIndex):
return DateTimeIndex(index=index)
else:
return Index(index=index)
def __init__(self, data=None, name='Index', index=None):
'''
Index
:param data: (*array_like*) Index values
:param name: (*string*) Index name
'''
if index is None:
if isinstance(data, NDArray):
data = data.aslist()
self.data = data
self._index = MIIndex.factory(data)
self.name = name
else:
self._index = index
self.data = list(self._index.getData())
self.name = self._index.getName()
def __len__(self):
return self._index.size()
def __iter__(self):
"""
provide iteration over the values of the Index
"""
return iter(self._index)
def __str__(self):
return self.__repr__()
def __repr__(self):
return self._index.toString()
def __getitem__(self, k):
if isinstance(k, int):
return self.data[k]
else:
sidx = 0 if k.start is None else k.start
if sidx < 0:
sidx = self.__len__() + sidx
eidx = self.__len__() if k.stop is None else k.stop
if eidx < 0:
eidx = self.__len__() + eidx
step = 1 if k.step is None else k.step
r = self._index.subIndex(sidx, eidx, step)
return Index.factory(index=r)
def __eq__(self, other):
if isinstance(other, numbers.Number):
return NDArray(self._index.equal(other))
else:
return False
def index(self, v):
'''
Get index of a value.
:param v: (*object*) value
:returns: (*int*) Value index
'''
return self._index.indexOf(v)
def get_loc(self, key, outkeys=False):
'''
Get integer location, slice or boolean mask for requested label.
:param key: (*string or list*) Label.
:param outkeys: (*boolean*) If return location keys or not.
:returns: int if unique index, slice if monotonic index, else mask.
'''
if isinstance(key, NDArray) and key.dtype.toString() == 'boolean':
r = self._index.filterIndices(key.asarray())
return list(r)
else:
r = self._index.getIndices(key)
if outkeys:
return list(r[0]), list(r[1])
else:
return list(r[0])
def fill_keylist(self, rdata, rfdata):
return self._index.fillKeyList(rdata.asarray(), rfdata)
def get_format(self):
'''
Get value to string format.
:returns: (*string*) Format string.
'''
return self._index.getFormat()
def set_format(self, format):
'''
Set value to string format.
:param format: (*string*) Format string.
'''
self._index.setFormat(format)
############################################
class DateTimeIndex(Index):
def __init__(self, data=None, start=None, end=None, periods=None, freq='D', index=None):
if index is None:
if not data is None:
if isinstance(data, NDArray):
data = data.aslist()
self.data = data
if isinstance(data[0], datetime.datetime):
self._index = MIDateTimeIndex(miutil.jdate(data))
else:
self._index = MIDateTimeIndex(data)
else:
if start is None:
self._index = MIDateTimeIndex(periods, end, freq)
elif end is None:
self._index = MIDateTimeIndex(start, periods, freq)
else:
self._index = MIDateTimeIndex(start, end, freq)
self.data = miutil.pydate(list(self._index.getDateValues()))
else:
self._index = index
self.data = miutil.pydate(list(self._index.getDateValues()))
def index(self, v):
'''
Get index of a value.
:param v: (*datetime or string*) Date time value
:returns: (*int*) Value index
'''
if isinstance(v, datetime.datetime):
v = miutil.jdatetime(v)
else:
v = miutil.str2jdate(v)
return self._index.indexOf(v)
def get_loc(self, key, outkeys=False):
'''
Get integer location, slice or boolean mask for requested label.
:param key: (*string or list*) Label.
:param outkeys: (*boolean*) If return location keys or not.
:returns: int if unique index, slice if monotonic index, else mask.
'''
if isinstance(key, NDArray) and key.dtype.toString() == 'boolean':
r = self._index.filterIndices(key.asarray())
return list(r)
elif isinstance(key, datetime.datetime):
key = miutil.jdatetime(key)
elif isinstance(key, (list, tuple, NDArray)) and isinstance(key[0], datetime.datetime):
key = miutil.jdatetime(key)
r = self._index.getIndices(key)
if outkeys:
return list(r[0]), list(r[1])
else:
return list(r[0])
@property
def year(self):
'''
Get year index.
'''
r = self._index.getYear()
return Index(index=r)
@property
def month(self):
'''
Get month index.
'''
r = self._index.getMonth()
return Index(index=r)
@property
def day(self):
'''
Get day index.
'''
r = self._index.getDay()
return Index(index=r)
@property
def hour(self):
'''
Get hour index.
'''
r = self._index.getHOur()
return Index(index=r)
@property
def minute(self):
'''
Get minute index.
'''
r = self._index.getMinute()
return Index(index=r)
@property
def second(self):
'''
Get second index.
'''
r = self._index.getSecond()
return Index(index=r)
#############################################
def date_range(start=None, end=None, periods=None, freq='D'):
'''
Create DateTimeIndex by date range.
:param start: (*string or datetime*) Start date time.
:param end: (*string or datetime*) End date time.
:param periods: (*int*) Periods number.
:param freq: (*string*) Date time frequent value [ Y | M | D | H | m | S ].
:returns: (*DateTimeIndex*) DateTimeIndex
'''
r = DateTimeIndex(start=start, end=end, periods=periods, freq=freq)
return r