mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Chart builder: SelectControl pickers, channel chooser, per-type aggregates
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
isChannelTypeAllowed,
|
||||
isColumnAllowedOnChannel,
|
||||
supportsAggregate,
|
||||
validAggregateOps,
|
||||
supportsBin,
|
||||
supportsTimeUnit,
|
||||
supportsSort,
|
||||
@@ -840,12 +841,96 @@ describe('transforms — aggregate / bin / timeUnit', () => {
|
||||
|
||||
it('exposes the transform-applicability predicates by field type', () => {
|
||||
expect(supportsAggregate('quantitative')).toBe(true);
|
||||
expect(supportsAggregate('nominal')).toBe(false);
|
||||
// Every type now takes at least one aggregate (`distinct` applies to anything).
|
||||
expect(supportsAggregate('nominal')).toBe(true);
|
||||
expect(supportsBin('quantitative')).toBe(true);
|
||||
expect(supportsBin('temporal')).toBe(false);
|
||||
expect(supportsTimeUnit('temporal')).toBe(true);
|
||||
expect(supportsTimeUnit('quantitative')).toBe(false);
|
||||
});
|
||||
|
||||
it('offers per-type aggregate menus: arithmetic needs numbers, min/max an ordering, distinct anything', () => {
|
||||
expect(validAggregateOps('quantitative')).toEqual([
|
||||
'sum',
|
||||
'mean',
|
||||
'median',
|
||||
'min',
|
||||
'max',
|
||||
'distinct',
|
||||
]);
|
||||
expect(validAggregateOps('temporal')).toEqual(['min', 'max', 'distinct']);
|
||||
expect(validAggregateOps('ordinal')).toEqual(['min', 'max', 'distinct']);
|
||||
expect(validAggregateOps('nominal')).toEqual(['distinct']);
|
||||
});
|
||||
|
||||
it('emits a distinct-count of a categorical field as a quantitative measure', () => {
|
||||
const spec = buildChartSpec({
|
||||
datasetName: 'D',
|
||||
mark: 'bar',
|
||||
encodings: {
|
||||
x: { field: 'region', type: 'nominal' },
|
||||
y: { field: 'customer', type: 'nominal', aggregate: 'distinct' },
|
||||
},
|
||||
});
|
||||
const enc = spec.encoding as Record<string, Record<string, unknown>>;
|
||||
// The carried (nominal) type is for round-tripping; the emitted type is the
|
||||
// effective one — a count of unique values reads as a quantitative measure.
|
||||
expect(enc.y).toEqual({ field: 'customer', type: 'quantitative', aggregate: 'distinct' });
|
||||
});
|
||||
|
||||
it('keeps the field type on order-preserving aggregates (a temporal min is still temporal)', () => {
|
||||
const spec = buildChartSpec({
|
||||
datasetName: 'D',
|
||||
mark: 'point',
|
||||
encodings: {
|
||||
x: { field: 'region', type: 'nominal' },
|
||||
y: { field: 'orderDate', type: 'temporal', aggregate: 'min' },
|
||||
},
|
||||
});
|
||||
const enc = spec.encoding as Record<string, Record<string, unknown>>;
|
||||
expect(enc.y).toEqual({ field: 'orderDate', type: 'temporal', aggregate: 'min' });
|
||||
});
|
||||
|
||||
it('emits title as a bare string, the object form with a subtitle, nothing without a title', () => {
|
||||
const base: BuilderConfig = {
|
||||
datasetName: 'D',
|
||||
mark: 'bar',
|
||||
encodings: { x: { field: 'region', type: 'nominal' } },
|
||||
};
|
||||
expect(buildChartSpec({ ...base, title: 'Sales by region' }).title).toBe('Sales by region');
|
||||
expect(buildChartSpec({ ...base, title: 'Sales', subtitle: 'FY26' }).title).toEqual({
|
||||
text: 'Sales',
|
||||
subtitle: 'FY26',
|
||||
});
|
||||
// A subtitle alone is not emitted (VL has no standalone subtitle), nor is a
|
||||
// whitespace-only title.
|
||||
expect(buildChartSpec({ ...base, subtitle: 'orphan' }).title).toBeUndefined();
|
||||
expect(buildChartSpec({ ...base, title: ' ' }).title).toBeUndefined();
|
||||
});
|
||||
|
||||
it('prefers a user-written title as the generated snippet name', () => {
|
||||
expect(
|
||||
generateChartName({
|
||||
datasetName: 'D',
|
||||
mark: 'bar',
|
||||
title: 'Quarterly revenue',
|
||||
encodings: { x: { field: 'region', type: 'nominal' } },
|
||||
}),
|
||||
).toBe('Quarterly revenue');
|
||||
});
|
||||
|
||||
it('names a distinct-count chart with a "unique" phrase', () => {
|
||||
expect(
|
||||
generateChartName({
|
||||
datasetName: 'D',
|
||||
mark: 'bar',
|
||||
encodings: {
|
||||
x: { field: 'region', type: 'nominal' },
|
||||
y: { field: 'customer', type: 'nominal', aggregate: 'distinct' },
|
||||
},
|
||||
}),
|
||||
).toBe('Bar chart of unique customer by region');
|
||||
});
|
||||
});
|
||||
|
||||
describe('sort (ranking)', () => {
|
||||
|
||||
Reference in New Issue
Block a user