def use_dynamic_x(ax: Axes, data: DataFrame | Series) -> bool: freq = _get_index_freq(data.index) ax_freq = _get_ax_freq(ax) if freq is None: # convert irregular if axes has freq info freq = ax_freq else: # do not use tsplot if irregular was plotted first if (ax_freq is None) and (len(ax.get_lines()) > 0): return False if freq is None: return False freq_str = _get_period_alias(freq) if freq_str is None: return False # FIXME: hack this for 0.10.1, creating more technical debt...sigh if isinstance(data.index, ABCDatetimeIndex): # error: "BaseOffset" has no attribute "_period_dtype_code" base = to_offset(freq_str)._period_dtype_code # type: ignore[attr-defined] x = data.index if base <= FreqGroup.FR_DAY.value: return x[:1].is_normalized period = Period(x[0], freq_str) assert isinstance(period, Period) return period.to_timestamp().tz_localize(x.tz) == x[0] return True
def _parsed_string_to_bounds(self, reso: str, parsed: datetime): if reso not in ["year", "month", "quarter", "day", "hour", "minute", "second"]: raise KeyError(reso) grp = resolution.Resolution.get_freq_group(reso) iv = Period(parsed, freq=(grp, 1)) return (iv.asfreq(self.freq, how="start"), iv.asfreq(self.freq, how="end"))
def test_get_to_timestamp_base(freqstr, exp_freqstr): off = to_offset(freqstr) per = Period._from_ordinal(1, off) exp_code = to_offset(exp_freqstr)._period_dtype_code result_code = per._get_to_timestamp_base() assert result_code == exp_code
def _use_dynamic_x(ax, data: "FrameOrSeriesUnion") -> bool: freq = _get_index_freq(data.index) ax_freq = _get_ax_freq(ax) if freq is None: # convert irregular if axes has freq info freq = ax_freq else: # do not use tsplot if irregular was plotted first if (ax_freq is None) and (len(ax.get_lines()) > 0): return False if freq is None: return False freq = _get_period_alias(freq) if freq is None: return False # FIXME: hack this for 0.10.1, creating more technical debt...sigh if isinstance(data.index, ABCDatetimeIndex): base = to_offset(freq)._period_dtype_code x = data.index if base <= FreqGroup.FR_DAY: return x[:1].is_normalized return Period(x[0], freq).to_timestamp().tz_localize(x.tz) == x[0] return True
def _cast_partial_indexing_scalar(self, label): try: key = Period(label, freq=self.freq) except ValueError as err: # we cannot construct the Period raise KeyError(label) from err return key
def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default): """ If label is a string or a datetime, cast it to Period.ordinal according to resolution. Parameters ---------- label : object side : {'left', 'right'} kind : {'loc', 'getitem'}, or None Returns ------- bound : Period or object Notes ----- Value of `side` parameter should be validated in caller. """ assert kind in ["loc", "getitem", None, lib.no_default] self._deprecated_arg(kind, "kind", "_maybe_cast_slice_bound") if isinstance(label, datetime): return Period(label, freq=self.freq) elif isinstance(label, str): try: parsed, reso_str = parse_time_string(label, self.freq) except ValueError as err: # string cannot be parsed as datetime-like raise self._invalid_indexer("slice", label) from err reso = Resolution.from_attrname(reso_str) lower, upper = self._parsed_string_to_bounds(reso, parsed) return lower if side == "left" else upper elif not isinstance(label, self._data._recognized_scalars): raise self._invalid_indexer("slice", label) return label
def _maybe_cast_slice_bound(self, label, side: str, kind: str): """ If label is a string or a datetime, cast it to Period.ordinal according to resolution. Parameters ---------- label : object side : {'left', 'right'} kind : {'loc', 'getitem'} Returns ------- bound : Period or object Notes ----- Value of `side` parameter should be validated in caller. """ assert kind in ["loc", "getitem"] if isinstance(label, datetime): return Period(label, freq=self.freq) elif isinstance(label, str): try: parsed, reso = parse_time_string(label, self.freq) reso = Resolution.from_attrname(reso) bounds = self._parsed_string_to_bounds(reso, parsed) return bounds[0 if side == "left" else 1] except ValueError as err: # string cannot be parsed as datetime-like # TODO: we need tests for this case raise KeyError(label) from err elif is_integer(label) or is_float(label): self._invalid_indexer("slice", label) return label
def _parsed_string_to_bounds(self, reso: Resolution, parsed: datetime): grp = reso.freq_group iv = Period(parsed, freq=grp) return (iv.asfreq(self.freq, how="start"), iv.asfreq(self.freq, how="end"))
def get_loc(self, key, method=None, tolerance=None): """ Get integer location for requested label. Parameters ---------- key : Period, NaT, str, or datetime String or datetime key must be parsable as Period. Returns ------- loc : int or ndarray[int64] Raises ------ KeyError Key is not present in the index. TypeError If key is listlike or otherwise not hashable. """ orig_key = key if not is_scalar(key): raise InvalidIndexError(key) if isinstance(key, str): try: loc = self._get_string_slice(key) return loc except (TypeError, ValueError): pass try: asdt, reso = parse_time_string(key, self.freq) except (ValueError, DateParseError) as err: # A string with invalid format raise KeyError(f"Cannot interpret '{key}' as period") from err reso = Resolution.from_attrname(reso) grp = reso.freq_group freqn = self.dtype.freq_group # _get_string_slice will handle cases where grp < freqn assert grp >= freqn # BusinessDay is a bit strange. It has a *lower* code, but we never parse # a string as "BusinessDay" resolution, just Day. if grp == freqn or ( reso == Resolution.RESO_DAY and self.dtype.freq.name == "B" ): key = Period(asdt, freq=self.freq) loc = self.get_loc(key, method=method, tolerance=tolerance) return loc elif method is None: raise KeyError(key) else: key = asdt elif is_integer(key): # Period constructor will cast to string, which we dont want raise KeyError(key) try: key = Period(key, freq=self.freq) except ValueError as err: # we cannot construct the Period raise KeyError(orig_key) from err try: return Index.get_loc(self, key, method, tolerance) except KeyError as err: raise KeyError(orig_key) from err
def get_loc(self, key, method=None, tolerance=None): """ Get integer location for requested label. Parameters ---------- key : Period, NaT, str, or datetime String or datetime key must be parsable as Period. Returns ------- loc : int or ndarray[int64] Raises ------ KeyError Key is not present in the index. TypeError If key is listlike or otherwise not hashable. """ orig_key = key self._check_indexing_error(key) if is_valid_na_for_dtype(key, self.dtype): key = NaT elif isinstance(key, str): try: parsed, reso = self._parse_with_reso(key) except ValueError as err: # A string with invalid format raise KeyError(f"Cannot interpret '{key}' as period") from err if self._can_partial_date_slice(reso): try: return self._partial_date_slice(reso, parsed) except KeyError as err: # TODO: pass if method is not None, like DTI does? raise KeyError(key) from err if reso == self.dtype.resolution: # the reso < self.dtype.resolution case goes through _get_string_slice key = Period(parsed, freq=self.freq) loc = self.get_loc(key, method=method, tolerance=tolerance) # Recursing instead of falling through matters for the exception # message in test_get_loc3 (though not clear if that really matters) return loc elif method is None: raise KeyError(key) else: key = Period(parsed, freq=self.freq) elif isinstance(key, Period): sfreq = self.freq kfreq = key.freq if not (sfreq.n == kfreq.n and sfreq._period_dtype_code == kfreq._period_dtype_code): # GH#42247 For the subset of DateOffsets that can be Period freqs, # checking these two attributes is sufficient to check equality, # and much more performant than `self.freq == key.freq` raise KeyError(key) elif isinstance(key, datetime): try: key = Period(key, freq=self.freq) except ValueError as err: # we cannot construct the Period raise KeyError(orig_key) from err else: # in particular integer, which Period constructor would cast to string raise KeyError(key) try: return Index.get_loc(self, key, method, tolerance) except KeyError as err: raise KeyError(orig_key) from err
def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default): if isinstance(label, datetime): label = Period(label, freq=self.freq) return super()._maybe_cast_slice_bound(label, side, kind=kind)
def _format_coord(freq, t, y): time_period = Period(ordinal=int(t), freq=freq) return f"t = {time_period} y = {y:8f}"
def get_loc(self, key, method=None, tolerance=None): """ Get integer location for requested label. Parameters ---------- key : Period, NaT, str, or datetime String or datetime key must be parsable as Period. Returns ------- loc : int or ndarray[int64] Raises ------ KeyError Key is not present in the index. TypeError If key is listlike or otherwise not hashable. """ orig_key = key if not is_scalar(key): raise InvalidIndexError(key) if is_valid_na_for_dtype(key, self.dtype): key = NaT elif isinstance(key, str): try: loc = self._get_string_slice(key) return loc except (TypeError, ValueError): pass try: asdt, reso_str = parse_time_string(key, self.freq) except (ValueError, DateParseError) as err: # A string with invalid format raise KeyError(f"Cannot interpret '{key}' as period") from err reso = Resolution.from_attrname(reso_str) grp = reso.freq_group.value freqn = self.dtype.freq_group_code # _get_string_slice will handle cases where grp < freqn assert grp >= freqn # BusinessDay is a bit strange. It has a *lower* code, but we never parse # a string as "BusinessDay" resolution, just Day. if grp == freqn or (reso == Resolution.RESO_DAY and self.dtype.freq.name == "B"): key = Period(asdt, freq=self.freq) loc = self.get_loc(key, method=method, tolerance=tolerance) return loc elif method is None: raise KeyError(key) else: key = asdt elif isinstance(key, Period): sfreq = self.freq kfreq = key.freq if not (sfreq.n == kfreq.n and sfreq._period_dtype_code == kfreq._period_dtype_code): # GH#42247 For the subset of DateOffsets that can be Period freqs, # checking these two attributes is sufficient to check equality, # and much more performant than `self.freq == key.freq` raise KeyError(key) elif isinstance(key, datetime): try: key = Period(key, freq=self.freq) except ValueError as err: # we cannot construct the Period raise KeyError(orig_key) from err else: # in particular integer, which Period constructor would cast to string raise KeyError(key) try: key = Period(key, freq=self.freq) except ValueError as err: # we cannot construct the Period raise KeyError(orig_key) from err try: return Index.get_loc(self, key, method, tolerance) except KeyError as err: raise KeyError(orig_key) from err
def get_loc(self, key, method=None, tolerance=None): """ Get integer location for requested label. Parameters ---------- key : Period, NaT, str, or datetime String or datetime key must be parsable as Period. Returns ------- loc : int or ndarray[int64] Raises ------ KeyError Key is not present in the index. TypeError If key is listlike or otherwise not hashable. """ orig_key = key if not is_scalar(key): raise InvalidIndexError(key) if isinstance(key, str): try: loc = self._get_string_slice(key) return loc except (TypeError, ValueError): pass try: asdt, reso = parse_time_string(key, self.freq) except DateParseError as err: # A string with invalid format raise KeyError(f"Cannot interpret '{key}' as period") from err grp = get_freq_group(reso) freqn = get_freq_group(self.freq) # _get_string_slice will handle cases where grp < freqn assert grp >= freqn if grp == freqn: key = Period(asdt, freq=self.freq) loc = self.get_loc(key, method=method, tolerance=tolerance) return loc elif method is None: raise KeyError(key) else: key = asdt elif is_integer(key): # Period constructor will cast to string, which we dont want raise KeyError(key) try: key = Period(key, freq=self.freq) except ValueError as err: # we cannot construct the Period raise KeyError(orig_key) from err try: return Index.get_loc(self, key, method, tolerance) except KeyError as err: raise KeyError(orig_key) from err
def _parsed_string_to_bounds(self, reso: Resolution, parsed: datetime): iv = Period(parsed, freq=reso.attr_abbrev) return (iv.asfreq(self.freq, how="start"), iv.asfreq(self.freq, how="end"))