mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-10 20:40:05 -06:00
address review: charge scatter Y and X values to the chart point budget as a pair
This commit is contained in:
@@ -246,7 +246,7 @@ pub fn resolve(wb: &Workbook, sheet: usize, chart: &Chart) -> ChartData {
|
||||
// One point budget for the whole chart, not one per series.
|
||||
let mut budget = MAX_CHART_POINTS;
|
||||
for (i, s) in chart.series.iter().take(MAX_SERIES).enumerate() {
|
||||
let values = nums(wb, sheet, &s.values, &mut budget);
|
||||
let mut values: Vec<Option<f64>> = eval_list_capped(wb, sheet, &s.values, budget).iter().map(to_num).collect();
|
||||
let name = s.name.as_deref().map(|n| series_name(wb, sheet, n)).filter(|n| !n.is_empty()).unwrap_or_else(|| format!("Series{}", i + 1));
|
||||
let color =
|
||||
s.color.as_ref().and_then(|c| c.resolve(&wb.theme)).map(|[r, g, b]| [r, g, b, 0xFF]).unwrap_or_else(|| series_color(&wb.theme, i));
|
||||
@@ -255,16 +255,23 @@ pub fn resolve(wb: &Workbook, sheet: usize, chart: &Chart) -> ChartData {
|
||||
// X values with text in them (labels) are ignored: the points are numbered 1..n.
|
||||
(Some(f), true) => {
|
||||
let xs = eval_list_capped(wb, sheet, f, budget);
|
||||
// Only X values that are kept are charged to the budget.
|
||||
if xs.iter().any(Value::is_text) {
|
||||
None
|
||||
} else {
|
||||
budget -= xs.len().min(budget);
|
||||
Some(xs.iter().map(to_num).collect())
|
||||
let mut xs: Vec<Option<f64>> = xs.iter().map(to_num).collect();
|
||||
// Y and X are kept as a pair: when both do not fit, each gets half, so a
|
||||
// series is never left with values and no X (which draws nothing).
|
||||
if values.len() + xs.len() > budget {
|
||||
values.truncate(budget / 2);
|
||||
xs.truncate(budget / 2);
|
||||
}
|
||||
budget -= xs.len();
|
||||
Some(xs)
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
budget -= values.len();
|
||||
if categories.is_none()
|
||||
&& let Some(f) = &s.categories
|
||||
{
|
||||
|
||||
@@ -1296,3 +1296,23 @@ fn rejected_text_x_values_are_not_charged_to_the_point_budget() {
|
||||
assert_eq!(d.series.len(), 40);
|
||||
assert!(d.series.iter().all(|s| s.values.len() == 100 && s.x.is_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scatter_values_are_kept_with_their_x_values_when_the_budget_runs_out() {
|
||||
// Y and X are charged as a pair: a series that gets values also gets X values, so it still draws.
|
||||
let mut wb = Workbook::new();
|
||||
let s = wb.sheet_mut(0).unwrap();
|
||||
for col in 0..2 {
|
||||
s.set_value(CellRef::new(0, col), Value::Number(1.0));
|
||||
s.set_value(CellRef::new(59_999, col), Value::Number(2.0));
|
||||
}
|
||||
let mut c = chart(ChartKind::Scatter);
|
||||
c.series = (0..40)
|
||||
.map(|_| Series { values: "Sheet1!$A$1:$A$60000".into(), categories: Some("Sheet1!$B$1:$B$60000".into()), ..Default::default() })
|
||||
.collect();
|
||||
let d = resolve(&wb, 0, &c);
|
||||
let total: usize = d.series.iter().map(|s| s.values.len() + s.x.as_ref().map_or(0, Vec::len)).sum();
|
||||
assert!(total <= crate::resolve::MAX_CHART_POINTS);
|
||||
assert!(d.series.iter().any(|s| s.values.len() < 60_000 && !s.values.is_empty()));
|
||||
assert!(d.series.iter().all(|s| s.values.is_empty() || s.x.as_ref().is_some_and(|x| x.len() == s.values.len())));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user