impl/python/time_tick_interval.py
1,411 bytes · the Python implementation · view raw
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from .charts_ticks_tick_step import tick_step ← tickStep, another function of this group · built into the same file, even by a slim install
from .charts_ticks_types import TimeTickInterval
from .dates_add_days import epoch_day_from_iso ← from dates.add-days ^1.0.0 · built alongside by fune
# d3-scale's calendar ladder, from a day up, with the lengths in days it
# compares against: a month counts as 30, a quarter as 90, a year as 365.
_LADDER = [
("day", 1, 1),
("day", 2, 2),
("week", 1, 7),
("month", 1, 30),
("quarter", 1, 90),
("year", 1, 365),
]
def time_tick_interval(start: str, stop: str, count: int) -> TimeTickInterval:
"""The calendar interval for about count ticks between two dates, as d3's
time scale picks it: the nearest rung of the ladder by ratio, or whole
years in steps of 1, 2 or 5 x 10^k beyond a year."""
if isinstance(count, bool) or not isinstance(count, int) or count < 1:
raise ValueError(f"count must be a whole number of at least 1, got {count}")
span = abs(epoch_day_from_iso(stop) - epoch_day_from_iso(start))
target = span / count
i = 0
while i < len(_LADDER) and _LADDER[i][2] <= target:
i += 1
if i == len(_LADDER):
return TimeTickInterval(interval="year", step=max(1, int(tick_step(0, span / 365, count))))
if i == 0:
return TimeTickInterval(interval="day", step=1)
pick = _LADDER[i - 1] if target / _LADDER[i - 1][2] < _LADDER[i][2] / target else _LADDER[i]
return TimeTickInterval(interval=pick[0], step=pick[1])