# ----------------------------------------------------- # 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