///|
// The subsecond interval table used by Matplotlib's AutoDateLocator.
fn microsecond_interval(target : Double) -> Int32 {
for
interval in [
1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000,
100000, 200000, 500000, 1000000,
] {
if Double::from_int(interval) >= target {
return interval
}
}
1000000
}
///|
// Source: Matplotlib v3.11.2 dates.MicrosecondLocator and ticker.MultipleLocator.
// The locator first floors the UTC ordinal and scales the fractional day to
// integer microseconds. The requested fixed offset affects date formatting,
// but does not move this UTC grid's phase.
fn microsecond_ticks(
first : Double,
last : Double,
interval : Int32,
) -> Array[Double] {
microsecond_ticks_unclipped(first, last, Double::from_int(interval)).filter(
supported_ordinal,
) catch {
_ => []
}
}
///|
fn microsecond_multiple_ticks(
lower : Double,
upper : Double,
step : Double,
) -> Array[Double] raise DateError {
@tick_grid.ticks(lower, upper, step) catch {
_ =>
raise DateError::InvalidDate(
message="microsecond grid alignment or count is not finite",
)
}
}
///|
// Keep origin from the original first endpoint. MultipleLocator sorts only
// after origin subtraction; reversed direct bounds can round differently.
fn microsecond_ticks_unclipped(
first : Double,
last : Double,
interval : Double,
) -> Array[Double] raise DateError {
let origin = first.floor()
let lower = (first - origin) * 86_400_000_000.0
let upper = (last - origin) * 86_400_000_000.0
microsecond_multiple_ticks(lower, upper, interval).map(value => {
value / 86_400_000_000.0 + origin
})
}