mod rendering;
mod scoring;
mod utils;
const MAX_SKIP_AMOUNT: i32 = 9;
const Q_VALUES: [f64; 6] = [1.0, 5.0, 2.0, 2.5, 4.0, 3.0];
pub fn float_axis_labels(
x_min: f64,
x_max: f64,
available_space: u32,
padding_left: u32,
vertical_direction: bool,
unit: &String,
) -> Result<String, String> {
if available_space == 0 {
return Err(String::from("Invalid arguments: available_space == 0."));
}
if x_max < x_min {
return Err(String::from("Invalid arguments: x_max < x_min."));
}
let base_exponent = (x_max - x_min).log10() as i64;
let preferred_nr_labels = crate::float_range::scoring::compute_preferred_number_of_labels(
available_space,
vertical_direction,
);
let mut best_score = -2.0;
let mut best_result = String::new();
let mut step_size: f64;
for exponent in [base_exponent, base_exponent - 1] {
let f = x_min / 10_f64.powf(exponent as f64 + 1.0);
let label_start = f.floor() * 10_f64.powf(exponent as f64 + 1.0);
for j in 1..(MAX_SKIP_AMOUNT + 1) {
for (ix, q) in Q_VALUES.iter().enumerate() {
let i = ix as i32;
step_size = q * (j as f64) * 10_f64.powf(exponent as f64);
let labels =
crate::float_range::utils::linspace(label_start, x_min, x_max, step_size);
if labels.len() < 2 {
continue;
}
let simplicity_score = crate::float_range::scoring::compute_simplicity_score(
&labels,
i,
j,
Q_VALUES.len(),
);
let coverage_score =
crate::float_range::scoring::compute_coverage_score(&labels, x_min, x_max);
let density_score = crate::float_range::scoring::compute_density_score(
&labels,
preferred_nr_labels,
);
let score_upper_bound = crate::float_range::scoring::upper_bound_on_overall_score(
simplicity_score,
coverage_score,
density_score,
);
if (!best_result.is_empty()) && (score_upper_bound < best_score) {
continue;
}
let (result, grid_overlap) = crate::float_range::rendering::render(
&labels,
x_min,
x_max,
available_space,
padding_left,
vertical_direction,
&unit,
);
let grid_alignment_score = 1.0 - ((grid_overlap as i32) as f64);
let score = crate::float_range::scoring::overall_score(
simplicity_score,
coverage_score,
density_score,
grid_alignment_score,
);
if score > best_score {
best_score = score;
best_result = result;
}
}
}
}
return Ok(best_result);
}