from typing import List, Tuple from .charts_ticks_tick_step import tick_spec from .math_round_float import round_float def nice_ticks(start: float, stop: float, count: int) -> List[float]: """Ticks at round values between start and stop, as d3.ticks, each one exact operation on a whole number (i * step or i / divisor), so 0.1 steps give 0.3 and not 0.30000000000000004.""" mul, div = tick_spec(start, stop, count) if start == stop: return [float(start) + 0.0] reverse = stop < start lo = float(stop if reverse else start) hi = float(start if reverse else stop) i1, i2 = _indexes(lo, hi, mul, div) if i2 < i1 and count == 1: # No multiple of the step for one tick falls inside; d3 retries with two. mul, div = tick_spec(start, stop, 2) i1, i2 = _indexes(lo, hi, mul, div) ticks = [] i = i1 while i <= i2: ticks.append((i / div if div > 1 else i * mul) + 0.0) i += 1 if reverse: ticks.reverse() return ticks def _indexes(lo: float, hi: float, mul: float, div: float) -> Tuple[float, float]: if div > 1: i1 = round_float(lo * div, 0) i2 = round_float(hi * div, 0) if i1 / div < lo: i1 += 1 if i2 / div > hi: i2 -= 1 return i1, i2 i1 = round_float(lo / mul, 0) i2 = round_float(hi / mul, 0) if i1 * mul < lo: i1 += 1 if i2 * mul > hi: i2 -= 1 return i1, i2