use super::*;
use crate::chart::chart_data::{XAxisTemporalKind, x_axis_label_at};
fn tick_labels(ticks: &[f64], numbers: &AxisNumbers, level: usize) -> Vec<String> {
let format = AxisFormat::new(ticks, numbers);
ticks
.iter()
.map(|&v| format.label(v, level).unwrap())
.collect()
}
fn preset(name: &str) -> AxisNumbers {
AxisNumbers {
format: crate::numfmt::NumberFormat::preset(name).unwrap(),
whole: false,
}
}
#[test]
fn log_axis_labels_write_each_tick_exactly() {
let ticks = [0.0, 1.0, 10.0, 100.0, 1e3, 1e4, 2e5, 1e6, 5e9];
let labels = |numbers: &AxisNumbers, level| {
let format = AxisFormat::log(&ticks, numbers);
ticks
.iter()
.map(|&v| format.label(v, level).unwrap())
.collect::<Vec<_>>()
};
assert_eq!(
labels(&preset("thousands"), 0),
[
"0",
"1",
"10",
"100",
"1,000",
"10,000",
"200,000",
"1,000,000",
"5,000,000,000"
]
);
assert_eq!(
labels(&AxisNumbers::default(), 1),
["0", "1", "10", "100", "1k", "10k", "200k", "1M", "5G"]
);
let short = [0.0, 0.25, 0.5, 0.75, 1.0];
let format = AxisFormat::log(&short, &AxisNumbers::default());
let written: Vec<_> = short.iter().map(|&v| format.label(v, 0).unwrap()).collect();
assert_eq!(written, ["0.00", "0.25", "0.50", "0.75", "1.00"]);
assert_eq!(
format.label(1.0, 1),
None,
"no shorter form under a thousand"
);
let huge = AxisFormat::log(&[1e15, 2e16, 1e18], &AxisNumbers::default());
assert_eq!(huge.label(2e16, 0).as_deref(), Some("2e16"));
}
#[test]
fn axis_labels_step_down_to_shorter_forms() {
let plain = AxisNumbers::default();
let ticks = [0.0, 12_345.0, 24_690.0];
assert_eq!(tick_labels(&ticks, &plain, 0), ["0", "12345", "24690"]);
assert_eq!(tick_labels(&ticks, &plain, 1), ["0", "12k", "25k"]);
let ticks = [-1500.0, 0.0, 1500.0];
assert_eq!(tick_labels(&ticks, &plain, 1), ["-1.5k", "0", "1.5k"]);
let ticks = [0.0, 1.5e9, 3e9];
assert_eq!(tick_labels(&ticks, &plain, 1), ["0", "1.5G", "3.0G"]);
let format = AxisFormat::new(&[0.0, 5.0], &plain);
assert_eq!(format.label(5.0, 1), None);
assert_eq!(format.label(5.0, 2), None);
let (lo, hi) = (18262.0, 20088.0);
let numbers = AxisFormat::new(&[], &plain);
let date =
|v, bounds, level| x_axis_label_at(v, XAxisTemporalKind::Date, bounds, level, &numbers);
let forms: Vec<_> = (0..).map_while(|level| date(hi, (lo, hi), level)).collect();
assert_eq!(forms, ["2024-12-31", "2024-12", "2024"]);
assert_eq!(date(lo, (lo, lo + 30.0), 1).as_deref(), Some("01-01"));
let us = 86_400.0 * 1e6;
let kind = XAxisTemporalKind::DatetimeUs;
let at = |v, bounds, level| x_axis_label_at(v, kind, bounds, level, &numbers);
let forms: Vec<_> = (0..)
.map_while(|level| at(lo * us, (lo * us, hi * us), level))
.collect();
assert_eq!(forms, ["2020-01-01 00:00", "2020-01-01", "2020-01", "2020"]);
let day = (lo * us, lo * us + 3600e6);
assert_eq!(at(lo * us + 3600e6, day, 1).as_deref(), Some("01:00"));
}
#[test]
fn an_axis_keeps_one_notation_and_precision() {
let plain = AxisNumbers::default();
let density = tick_labels(&[0.0, 0.00651, 0.01302], &plain, 0);
assert_eq!(density, ["0.0000", "0.0065", "0.0130"]);
let density = tick_labels(&[0.0, 0.00451, 0.00902], &plain, 0);
assert_eq!(density, ["0.00000", "0.00451", "0.00902"]);
let round = tick_labels(&[0.0, 0.006, 0.012], &plain, 0);
assert_eq!(round, ["0.000", "0.006", "0.012"]);
let round = tick_labels(&[0.0, 0.1 * 3.0, 0.6], &plain, 0);
assert_eq!(round, ["0.0", "0.3", "0.6"]);
let round = tick_labels(&[0.0, 20.0, 40.0, 60.0, 80.0], &plain, 0);
assert_eq!(round, ["0", "20", "40", "60", "80"]);
let round = tick_labels(&[0.0, 2_000.0, 4_000.0], &plain, 1);
assert_eq!(round, ["0", "2k", "4k"]);
let tiny = tick_labels(&[0.0, 2.5e-8, 5e-8], &plain, 0);
assert_eq!(tiny, ["0.00e0", "2.50e-8", "5.00e-8"]);
assert_eq!(
tick_labels(&[3.21, 50.17, 97.2], &plain, 0),
["3.2", "50.2", "97.2"]
);
let close = tick_labels(&[1000.1, 1000.2, 1000.3], &plain, 0);
assert_eq!(close, ["1000.1", "1000.2", "1000.3"]);
assert_eq!(tick_labels(&[-0.0001, 1.0], &plain, 0), ["0.00", "1.00"]);
let padded = [-0.5, 249.75, 500.0];
assert_eq!(tick_labels(&padded, &plain, 0), ["0", "250", "500"]);
let padded = [-500.0, 24_750.0, 50_000.0];
assert_eq!(tick_labels(&padded, &plain, 1), ["0", "25k", "50k"]);
assert_eq!(tick_labels(&[-0.0, 5e-8], &plain, 0), ["0.00e0", "5.00e-8"]);
let stepped = [-2e-8, 1.3e-24, 2e-8];
assert_eq!(
tick_labels(&stepped, &plain, 0),
["-2.00e-8", "0.00e0", "2.00e-8"]
);
let close = tick_labels(&[1.0, 1.000_000_1], &plain, 0);
assert_eq!(close, ["1.0000000e0", "1.0000001e0"]);
let nanoseconds = [1.727e18, 1.727_05e18, 1.7271e18];
let labels = tick_labels(&nanoseconds, &plain, 0);
assert_eq!(labels, ["1.72700e18", "1.72705e18", "1.72710e18"]);
assert_eq!(tick_labels(&nanoseconds, &plain, 1), labels);
let huge = [0.0, 5e15];
assert_eq!(tick_labels(&huge, &plain, 0), ["0.00e0", "5.00e15"]);
assert_eq!(tick_labels(&huge, &plain, 1), ["0e0", "5e15"]);
let huge = [1e15, 1.5e15, 2e15];
assert_eq!(
tick_labels(&huge, &plain, 1),
["1.0e15", "1.5e15", "2.0e15"]
);
let whole = AxisNumbers {
whole: true,
..preset("thousands")
};
assert_eq!(
tick_labels(&[0.0, 2161.0, 4322.0], &whole, 0),
["0", "2,161", "4,322"]
);
}
#[test]
fn axis_labels_take_the_table_number_style() {
let european = preset("european");
let ticks = [12_000.0, 12_300.0, 12_600.0];
assert_eq!(
tick_labels(&ticks, &european, 0),
["12.000", "12.300", "12.600"]
);
assert_eq!(
tick_labels(&ticks, &european, 1),
["12,0k", "12,3k", "12,6k"]
);
let ticks = [0.0, 0.25, 0.5];
assert_eq!(tick_labels(&ticks, &european, 0), ["0,00", "0,25", "0,50"]);
assert_eq!(
tick_labels(&[0.0, 5e-8], &european, 0),
["0,00e0", "5,00e-8"]
);
let thousands = preset("thousands");
let ticks = [0.0, 6172.4, 12345.0];
assert_eq!(tick_labels(&ticks, &thousands, 0), ["0", "6,172", "12,345"]);
let ticks = [0.0, 12_300.0];
assert_eq!(tick_labels(&ticks, &thousands, 1), ["0", "12k"]);
}