Skip to content

Commit 8afce43

Browse files
authored
feat: blind sorting option for vislib (#813)
1 parent 7af65c8 commit 8afce43

3 files changed

Lines changed: 124 additions & 54 deletions

File tree

src/chart_types/xy_chart/state/selectors/compute_series_domains.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export const computeSeriesDomainsSelector = createCachedSelector(
3838
customYDomainsByGroupId,
3939
deselectedDataSeries,
4040
settingsSpec.xDomain,
41+
// @ts-ignore blind sort option for vislib
42+
settingsSpec.enableVislibSeriesSort,
4143
);
4244
return domains;
4345
},

src/chart_types/xy_chart/state/utils/utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ function getLastValues(formattedDataSeries: {
192192
* @param customYDomainsByGroupId custom Y domains grouped by GroupId
193193
* @param customXDomain if specified in <Settings />, the custom X domain
194194
* @param deselectedDataSeries is optional; if not supplied,
195+
* @param customXDomain is optional; if not supplied,
196+
* @param enableVislibSeriesSort is optional; if not specified in <Settings />,
195197
* then all series will be factored into computations. Otherwise, selectedDataSeries
196198
* is used to restrict the computation for just the selected series
197199
* @returns `SeriesDomainsAndData`
@@ -202,10 +204,12 @@ export function computeSeriesDomains(
202204
customYDomainsByGroupId: Map<GroupId, YDomainRange> = new Map(),
203205
deselectedDataSeries: SeriesIdentifier[] = [],
204206
customXDomain?: DomainRange | Domain,
207+
enableVislibSeriesSort?: boolean,
205208
): SeriesDomainsAndData {
206209
const { dataSeriesBySpecId, xValues, seriesCollection, fallbackScale } = getDataSeriesBySpecId(
207210
seriesSpecs,
208211
deselectedDataSeries,
212+
enableVislibSeriesSort,
209213
);
210214

211215
// compute the x domain merging any custom domain

src/chart_types/xy_chart/utils/series.ts

Lines changed: 118 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -111,76 +111,138 @@ export function getSeriesIndex(series: SeriesIdentifier[], target: SeriesIdentif
111111
* `y` values and `mark` values are casted to number or null.
112112
* @internal
113113
*/
114-
export function splitSeriesDataByAccessors({
115-
id: specId,
116-
data,
117-
xAccessor,
118-
yAccessors,
119-
y0Accessors,
120-
markSizeAccessor,
121-
splitSeriesAccessors = [],
122-
}: Pick<
123-
BasicSeriesSpec,
124-
'id' | 'data' | 'xAccessor' | 'yAccessors' | 'y0Accessors' | 'splitSeriesAccessors' | 'markSizeAccessor'
125-
>): {
114+
export function splitSeriesDataByAccessors(
115+
{
116+
id: specId,
117+
data,
118+
xAccessor,
119+
yAccessors,
120+
y0Accessors,
121+
markSizeAccessor,
122+
splitSeriesAccessors = [],
123+
}: Pick<
124+
BasicSeriesSpec,
125+
'id' | 'data' | 'xAccessor' | 'yAccessors' | 'y0Accessors' | 'splitSeriesAccessors' | 'markSizeAccessor'
126+
>,
127+
enableVislibSeriesSort = false,
128+
): {
126129
dataSeries: Map<SeriesKey, DataSeries>;
127130
xValues: Array<string | number>;
128131
} {
129132
const dataSeries = new Map<SeriesKey, DataSeries>();
130133
const xValues: Array<string | number> = [];
131134
const nonNumericValues: any[] = [];
132135

133-
data.forEach((datum) => {
134-
const splitAccessors = getSplitAccessors(datum, splitSeriesAccessors);
135-
// if splitSeriesAccessors are defined we should have at least one split value to include datum
136-
if (splitSeriesAccessors.length > 0 && splitAccessors.size < 1) {
137-
return;
138-
}
139-
140-
// skip if the datum is not an object or null
141-
if (typeof datum !== 'object' || datum === null) {
142-
return null;
143-
}
136+
if (enableVislibSeriesSort) {
137+
/*
138+
* This logic is mostly duplicated from below but is a temporary fix before
139+
* https://github.com/elastic/elastic-charts/issues/795 is completed to allow sorting
140+
* The difference from below is that it loops through all the yAsccessors before the data.
141+
*/
142+
yAccessors.forEach((accessor, index) => {
143+
data.forEach((datum) => {
144+
const splitAccessors = getSplitAccessors(datum, splitSeriesAccessors);
145+
// if splitSeriesAccessors are defined we should have at least one split value to include datum
146+
if (splitSeriesAccessors.length > 0 && splitAccessors.size < 1) {
147+
return;
148+
}
144149

145-
const x = getAccessorValue(datum, xAccessor);
150+
// skip if the datum is not an object or null
151+
if (typeof datum !== 'object' || datum === null) {
152+
return;
153+
}
146154

147-
// skip if the x value is not a string or a number
148-
if (typeof x !== 'string' && typeof x !== 'number') {
149-
return null;
150-
}
155+
const x = getAccessorValue(datum, xAccessor);
151156

152-
xValues.push(x);
157+
// skip if the x value is not a string or a number
158+
if (typeof x !== 'string' && typeof x !== 'number') {
159+
return;
160+
}
153161

154-
yAccessors.forEach((accessor, index) => {
155-
const cleanedDatum = extractYandMarkFromDatum(
156-
datum,
157-
accessor,
158-
nonNumericValues,
159-
y0Accessors && y0Accessors[index],
160-
markSizeAccessor,
161-
);
162-
const seriesKeys = [...splitAccessors.values(), accessor];
163-
const seriesKey = getSeriesKey({
164-
specId,
165-
yAccessor: accessor,
166-
splitAccessors,
167-
});
168-
const newDatum = { x, ...cleanedDatum };
169-
const series = dataSeries.get(seriesKey);
170-
if (series) {
171-
series.data.push(newDatum);
172-
} else {
173-
dataSeries.set(seriesKey, {
162+
xValues.push(x);
163+
164+
const cleanedDatum = extractYandMarkFromDatum(
165+
datum,
166+
accessor,
167+
nonNumericValues,
168+
y0Accessors && y0Accessors[index],
169+
markSizeAccessor,
170+
);
171+
const seriesKeys = [...splitAccessors.values(), accessor];
172+
const seriesKey = getSeriesKey({
174173
specId,
175174
yAccessor: accessor,
176175
splitAccessors,
177-
data: [newDatum],
178-
key: seriesKey,
179-
seriesKeys,
180176
});
177+
const newDatum = { x, ...cleanedDatum };
178+
const series = dataSeries.get(seriesKey);
179+
if (series) {
180+
series.data.push(newDatum);
181+
} else {
182+
dataSeries.set(seriesKey, {
183+
specId,
184+
yAccessor: accessor,
185+
splitAccessors,
186+
data: [newDatum],
187+
key: seriesKey,
188+
seriesKeys,
189+
});
190+
}
191+
});
192+
});
193+
} else {
194+
data.forEach((datum) => {
195+
const splitAccessors = getSplitAccessors(datum, splitSeriesAccessors);
196+
// if splitSeriesAccessors are defined we should have at least one split value to include datum
197+
if (splitSeriesAccessors.length > 0 && splitAccessors.size < 1) {
198+
return;
199+
}
200+
201+
// skip if the datum is not an object or null
202+
if (typeof datum !== 'object' || datum === null) {
203+
return;
204+
}
205+
206+
const x = getAccessorValue(datum, xAccessor);
207+
208+
// skip if the x value is not a string or a number
209+
if (typeof x !== 'string' && typeof x !== 'number') {
210+
return;
181211
}
212+
213+
xValues.push(x);
214+
215+
yAccessors.forEach((accessor, index) => {
216+
const cleanedDatum = extractYandMarkFromDatum(
217+
datum,
218+
accessor,
219+
nonNumericValues,
220+
y0Accessors && y0Accessors[index],
221+
markSizeAccessor,
222+
);
223+
const seriesKeys = [...splitAccessors.values(), accessor];
224+
const seriesKey = getSeriesKey({
225+
specId,
226+
yAccessor: accessor,
227+
splitAccessors,
228+
});
229+
const newDatum = { x, ...cleanedDatum };
230+
const series = dataSeries.get(seriesKey);
231+
if (series) {
232+
series.data.push(newDatum);
233+
} else {
234+
dataSeries.set(seriesKey, {
235+
specId,
236+
yAccessor: accessor,
237+
splitAccessors,
238+
data: [newDatum],
239+
key: seriesKey,
240+
seriesKeys,
241+
});
242+
}
243+
});
182244
});
183-
});
245+
}
184246

185247
if (nonNumericValues.length > 0) {
186248
Logger.warn(
@@ -350,11 +412,13 @@ function getDataSeriesBySpecGroup(
350412
*
351413
* @param seriesSpecs the map for all the series spec
352414
* @param deselectedDataSeries the array of deselected/hidden data series
415+
* @param enableVislibSeriesSort is optional; if not specified in <Settings />,
353416
* @internal
354417
*/
355418
export function getDataSeriesBySpecId(
356419
seriesSpecs: BasicSeriesSpec[],
357420
deselectedDataSeries: SeriesIdentifier[] = [],
421+
enableVislibSeriesSort?: boolean,
358422
): {
359423
dataSeriesBySpecId: Map<SpecId, DataSeries[]>;
360424
seriesCollection: Map<SeriesKey, SeriesCollectionValue>;
@@ -377,7 +441,7 @@ export function getDataSeriesBySpecId(
377441
isOrdinalScale = true;
378442
}
379443

380-
const { dataSeries, xValues } = splitSeriesDataByAccessors(spec);
444+
const { dataSeries, xValues } = splitSeriesDataByAccessors(spec, enableVislibSeriesSort);
381445

382446
// filter deleselected dataseries
383447
let filteredDataSeries: DataSeries[] = [...dataSeries.values()];

0 commit comments

Comments
 (0)