Skip to content

Commit 7745825

Browse files
committed
fix(plugin-charts): refuse a numeric axis no row can scale (objectui#7195)
A cartesian tile whose numeric axis has rows but no value Recharts can build a scale from drew an empty frame and said nothing. It now renders the data-chart-error placeholder with code no-numeric-value, naming the bound key and the row count, keyed on the whole dataset so the mixed boolean tile keeps drawing. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D486C1axmXnrkJMNUfz2eb
1 parent cd7b728 commit 7745825

4 files changed

Lines changed: 561 additions & 14 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
'@object-ui/plugin-charts': patch
3+
---
4+
5+
A cartesian chart whose numeric axis has rows but nothing to build a scale from now says so
6+
instead of drawing an empty frame (objectui#7195). The tile renders the existing
7+
`data-chart-error` placeholder with the new code `no-numeric-value` and a sentence naming the
8+
bound key and the row count: "none of the N rows has a numeric value for KEY".
9+
10+
The answer is keyed on the whole dataset, not on the value's type. A boolean beside one real
11+
number still draws (Recharts builds the scale from the number and places the booleans on it), so
12+
that mixed chart keeps drawing with no note. What now refuses, each of which drew zero marks
13+
before:
14+
15+
- scatter, when every row's x (or y, or both) is a boolean, or a boolean mixed only with values
16+
that cannot be placed. That last shape used to carry a footnote implying one point was drawn;
17+
- bar / column / horizontal-bar / line / area / combo, when no row gives any bound series a
18+
value the axis can scale: every value boolean, `null` or an unparseable string. For a stacked
19+
series `null` counts as nothing too.
20+
21+
What keeps drawing, unchanged: numeric strings, `''` (placed at zero), `Date` values, booleans
22+
in a STACKED series (the stack reads them as numbers), a series that is all boolean beside a
23+
numeric one, and a dual-axis chart with one live axis. A series key that no row carries at all
24+
is not covered by this change. Rows with no placeable pair still get scatter's
25+
`no-plottable-points`, a multi-series scatter still gets `scatter-multi-series`, and
26+
`missing-category-key` / `no-plottable-series` still take precedence over this one.

‎packages/plugin-charts/src/AdvancedChartImpl.degeneratePosition.test.tsx‎

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -223,32 +223,41 @@ describe('objectui#7171 — a POSITIONAL chart legitimately plots zero and negat
223223
expect(noteOf(container)).toBeNull();
224224
});
225225

226-
it('a BOOLEAN coordinate is measured-and-DECLINED, because whether it places depends on its neighbours', () => {
226+
it('a BOOLEAN coordinate: the all-boolean tile is refused (objectui#7195), the mixed tile still draws', () => {
227227
// The trap this card was fenced against, hit in a new place. An all-boolean
228228
// x drew 0 of 2 marks in the browser sweep and looked exactly like a
229229
// sibling of `null` — and pinning it as unplaceable turned RED here, which
230230
// is how the mixed reading was found: Recharts needs one real number to
231231
// build the scale and then coerces the booleans onto it.
232+
//
233+
// The REVERSE CONTROL, kept green: a boolean beside a number DOES place, so
234+
// `isPlottableCoord` still accepts it and neither this card's note nor
235+
// objectui#7195's refusal may fire — a sentence over three visible points
236+
// saying they are not there is false about the picture.
232237
const { container: mixed } = renderScatter([
233238
{ xm: 10, ym: 40 },
234239
{ xm: true, ym: 25 },
235240
{ xm: false, ym: 60 },
236241
]);
237242
expect(marksOf(mixed), 'a boolean beside a number DOES place').toBe(3);
238-
// So the predicate must accept it: a footnote reading "2 of 3 rows are not
239-
// drawn" over three visible points is a false sentence about the picture,
240-
// which is worse than the silence this card is about.
241243
expect(noteOf(mixed)).toBeNull();
242244
expect(refusalOf(mixed)).toBeNull();
245+
expect(mixed.querySelector('[data-chart-error="no-numeric-value"]')).toBeNull();
243246
cleanup();
244247

245-
// The cost of that choice, stated rather than hidden: with EVERY row
246-
// boolean there is no scale to coerce onto, nothing draws, and this card's
247-
// answer stays silent — exactly as it is today. A narrow hole, not a
248-
// regression, and its real answer belongs upstream.
248+
// With EVERY row boolean there is no scale to coerce onto and nothing
249+
// draws. objectui#7195 (ruled A) answers that on the WHOLE dataset — no
250+
// row carries a numeric value for `xm` — which is true here and cannot be
251+
// true of the mixed tile above. Its own code, not this card's: the rows
252+
// DO pass `isPlottableCoord`, so `no-plottable-points` stays silent.
249253
const { container: allBool } = renderScatter([{ xm: true, ym: 40 }, { xm: false, ym: 25 }]);
250254
expect(marksOf(allBool)).toBe(0);
251255
expect(refusalOf(allBool)).toBeNull();
256+
expect(noteOf(allBool)).toBeNull();
257+
expect(plotOf(allBool)).toBeNull();
258+
const refusal = allBool.querySelector('[data-chart-error="no-numeric-value"]');
259+
expect(refusal).not.toBeNull();
260+
expect(refusal!.textContent).toContain('none of the 2 rows has a numeric value for xm');
252261
});
253262

254263
it('a constant x with a varying y still draws every mark', () => {

0 commit comments

Comments
 (0)