mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-26 19:56:48 -06:00
Merge pull request #438 from MarekSpodBiedry/issue-428
Scatter charts of two unlabelled columns plot the first as X for one series (#428)
This commit is contained in:
@@ -421,6 +421,7 @@ fn select_data(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
with_chart(s, p, move |c| {
|
||||
if let Some((series, source, by_rows)) = rebuilt {
|
||||
c.series = series;
|
||||
super::insert::scatter_x_from_first(c.kind, &mut c.series);
|
||||
c.source = Some(source);
|
||||
c.by_rows = by_rows;
|
||||
}
|
||||
|
||||
@@ -573,6 +573,17 @@ pub fn series_from_range(sh: &Sheet, r: RangeRef, by_rows: bool) -> Vec<Series>
|
||||
out
|
||||
}
|
||||
|
||||
/// A scatter plot of a block without category labels takes its first column (or row) as the X
|
||||
/// values of the others, as Excel does: two plain columns make one series of points, not two (#428).
|
||||
pub fn scatter_x_from_first(kind: ChartKind, series: &mut Vec<Series>) {
|
||||
if matches!(kind, ChartKind::Scatter | ChartKind::ScatterLines) && series.len() > 1 && series[0].categories.is_none() {
|
||||
let x = series.remove(0).values;
|
||||
for se in series.iter_mut() {
|
||||
se.categories = Some(x.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Most cells a chart's source block may span (bounds the series it builds).
|
||||
const MAX_CHART_CELLS: u64 = 1_000_000;
|
||||
|
||||
@@ -661,10 +672,11 @@ pub fn build_chart(s: &Session, p: &Json) -> Result<(usize, Chart)> {
|
||||
let data_w = r.width();
|
||||
let by_rows = data_w > data_h + 1;
|
||||
let kind = chart_kind(&t, &sub);
|
||||
let series = series_from_range(sh, r, by_rows);
|
||||
let mut series = series_from_range(sh, r, by_rows);
|
||||
if series.is_empty() {
|
||||
return Err(EngineError::Other("Select data for the chart first.".into()));
|
||||
}
|
||||
scatter_x_from_first(kind, &mut series);
|
||||
let id = d.wb.next_object_id();
|
||||
let at = cell_param_on(s, p, "at", sheet)?.unwrap_or_else(|| CellRef::new(r.start.row, r.end.col + 2));
|
||||
let title = str_param(p, "title").map(str::to_string).or_else(|| {
|
||||
@@ -801,6 +813,7 @@ fn chart_switch(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
c.source.get_or_insert(src);
|
||||
c.by_rows = by_rows;
|
||||
c.series = series;
|
||||
scatter_x_from_first(c.kind, &mut c.series);
|
||||
}
|
||||
Ok(Json::Null)
|
||||
})
|
||||
|
||||
@@ -1554,6 +1554,31 @@ fn every_chart_kind_survives_xlsx() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scatter_of_two_columns_is_one_series_with_the_first_as_x() {
|
||||
let mut s = s();
|
||||
s.execute("range.setValues", json!({"range": "A1", "values": [["X", "Y"], [1, 10], [2, 20], [3, 30]]})).unwrap();
|
||||
s.execute("insert.chart", json!({"type": "scatter", "range": "A1:B4"})).unwrap();
|
||||
let c = s.doc().unwrap().wb.active().unwrap().charts[0].clone();
|
||||
assert_eq!(c.series.len(), 1);
|
||||
assert_eq!(c.series[0].values, "Sheet1!$B$2:$B$4");
|
||||
assert_eq!(c.series[0].categories.as_deref(), Some("Sheet1!$A$2:$A$4"));
|
||||
// Select Data on the scatter chart and Switch Row/Column rebuild the series the same way.
|
||||
s.execute("chart.selectData", json!({"range": "A2:B4"})).unwrap();
|
||||
let c = s.doc().unwrap().wb.active().unwrap().charts[0].clone();
|
||||
assert_eq!(c.series.len(), 1);
|
||||
assert_eq!(c.series[0].categories.as_deref(), Some("Sheet1!$A$2:$A$4"));
|
||||
s.execute("range.setValues", json!({"range": "D1", "values": [[1, 2, 3, 4], [10, 20, 30, 40]]})).unwrap();
|
||||
s.execute("chart.selectData", json!({"range": "D1:G2"})).unwrap();
|
||||
s.execute("chart.switchRowColumn", json!({})).unwrap();
|
||||
s.execute("chart.switchRowColumn", json!({})).unwrap();
|
||||
let c = s.doc().unwrap().wb.active().unwrap().charts[0].clone();
|
||||
assert!(c.by_rows);
|
||||
assert_eq!(c.series.len(), 1);
|
||||
assert_eq!(c.series[0].values, "Sheet1!$D$2:$G$2");
|
||||
assert_eq!(c.series[0].categories.as_deref(), Some("Sheet1!$D$1:$G$1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn whole_sheet_selection_stays_within_the_data() {
|
||||
// On an empty sheet with everything selected these filled or scanned every cell of the
|
||||
|
||||
Reference in New Issue
Block a user