294 lines
8.4 KiB
Python

# -----------------------------------------------------
# Author: Yaqiang Wang
# Date: 2018-7-18
# Purpose: MeteoInfo index module
# Note: Jython
# -----------------------------------------------------
from org.meteoinfo.dataframe import Index as MIIndex
from org.meteoinfo.dataframe import DateTimeIndex as MIDateTimeIndex
from java.time import LocalDateTime
import datetime
import numbers
import mipylib.numeric as np
import mipylib.miutil as miutil
import series
class Index(object):
@staticmethod
def factory(data=None, name='Index', index=None):
"""
Factory method
"""
if index is None:
if isinstance(data[0], (LocalDateTime, 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, np.NDArray):
data = data.aslist()
self.data = data
self._index = MIIndex.factory(data)
else:
self._index = index
self.data = list(self._index.getData())
self._index.setName(name)
@property
def name(self):
return self._index.getName()
@name.setter
def name(self, value):
self._index.setName(value)
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 np.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, series.Series):
key = key.values
if isinstance(key, np.NDArray) and key.dtype == np.dtype.bool:
r = self._index.filterIndices(key.asarray())
return list(r)
else:
if isinstance(key, np.NDArray):
r = self._index.getIndices(key.asarray())
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_indexer(self, key):
"""
Compute indexer and mask for new index given the current index.
:param key: Index.
:return: (*array*) Integers from 0 to n - 1 indicating that the index at these positions matches
the corresponding target values. Missing values in the target are marked by -1.
"""
if isinstance(key, np.NDArray):
r = self._index.getIndices(key.asarray())
else:
r = self._index.getIndices(key)
return list(r[2])
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, name='Index', start=None, end=None, periods=None, freq='D', index=None):
if index is None:
if not data is None:
if isinstance(data, np.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.getData()))
else:
self._index = index
self.data = miutil.pydate(list(self._index.getData()))
self._index.setName(name)
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, np.NDArray) and key.dtype.kind == 'b':
r = self._index.filterIndices(key.asarray())
return list(r)
elif isinstance(key, datetime.datetime):
key = miutil.jdatetime(key)
elif isinstance(key, (list, tuple, np.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