diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts index 998e93da22b..1ecf56f039a 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts @@ -243,6 +243,10 @@ export default function transformProps( const MetricDisplayNameA = getMetricDisplayName(metrics[0], verboseMap); const MetricDisplayNameB = getMetricDisplayName(metricsB[0], verboseMap); + const dataTypes = getColtypesMapping(queriesData[0]); + const xAxisDataType = dataTypes?.[xAxisLabel] ?? dataTypes?.[xAxisOrig]; + const xAxisType = getAxisType(stack, xAxisForceCategorical, xAxisDataType); + const [rawSeriesA, sortedTotalValuesA] = extractSeries(rebasedDataA, { fillNeighborValue: stack ? 0 : undefined, xAxis: xAxisLabel, @@ -250,6 +254,7 @@ export default function transformProps( sortSeriesAscending, stack, totalStackedValues, + xAxisType, }); const rebasedDataB = rebaseForecastDatum(data2, verboseMap); const { @@ -267,11 +272,8 @@ export default function transformProps( sortSeriesAscending: sortSeriesAscendingB, stack: Boolean(stackB), totalStackedValues: totalStackedValuesB, + xAxisType, }); - - const dataTypes = getColtypesMapping(queriesData[0]); - const xAxisDataType = dataTypes?.[xAxisLabel] ?? dataTypes?.[xAxisOrig]; - const xAxisType = getAxisType(stack, xAxisForceCategorical, xAxisDataType); const series: SeriesOption[] = []; const formatter = contributionMode ? getNumberFormatter(',.0%') diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts index d57256bad3a..fe2f294d2e7 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts @@ -233,6 +233,8 @@ export default function transformProps( ); const isMultiSeries = groupBy.length || metrics?.length > 1; + const xAxisDataType = dataTypes?.[xAxisLabel] ?? dataTypes?.[xAxisOrig]; + const xAxisType = getAxisType(stack, xAxisForceCategorical, xAxisDataType); const [rawSeries, sortedTotalValues, minPositiveValue] = extractSeries( rebasedData, @@ -247,6 +249,7 @@ export default function transformProps( sortSeriesAscending, xAxisSortSeries: isMultiSeries ? xAxisSort : undefined, xAxisSortSeriesAscending: isMultiSeries ? xAxisSortAsc : undefined, + xAxisType, }, ); const showValueIndexes = extractShowValueIndexes(rawSeries, { @@ -259,9 +262,6 @@ export default function transformProps( rawSeries.map(series => series.name as string), ); const isAreaExpand = stack === StackControlsValue.Expand; - const xAxisDataType = dataTypes?.[xAxisLabel] ?? dataTypes?.[xAxisOrig]; - - const xAxisType = getAxisType(stack, xAxisForceCategorical, xAxisDataType); const series: SeriesOption[] = []; const forcePercentFormatter = Boolean(contributionMode || isAreaExpand); diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts b/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts index 4e3a1bd74e2..e2fb9c2722a 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts @@ -272,6 +272,7 @@ export function extractSeries( sortSeriesAscending?: boolean; xAxisSortSeries?: SortSeriesType; xAxisSortSeriesAscending?: boolean; + xAxisType?: AxisType; } = {}, ): [SeriesOption[], number[], number | undefined] { const { @@ -286,11 +287,15 @@ export function extractSeries( sortSeriesAscending, xAxisSortSeries, xAxisSortSeriesAscending, + xAxisType, } = opts; if (data.length === 0) return [[], [], undefined]; const rows: DataRecord[] = data.map(datum => ({ ...datum, - [xAxis]: datum[xAxis], + [xAxis]: + datum[xAxis] === null && xAxisType === AxisType.Category + ? NULL_STRING + : datum[xAxis], })); const sortedSeries = sortAndFilterSeries( rows, diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts index 5f54c63f94d..9f8b0791193 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts @@ -493,6 +493,43 @@ describe('extractSeries', () => { ]); }); + it('should convert NULL x-values to NULL_STRING for categorical axis', () => { + const data = [ + { + browser: 'Firefox', + count: 5, + }, + { + browser: null, + count: 10, + }, + { + browser: 'Chrome', + count: 8, + }, + ]; + expect( + extractSeries(data, { + xAxis: 'browser', + xAxisType: AxisType.Category, + }), + ).toEqual([ + [ + { + id: 'count', + name: 'count', + data: [ + ['Firefox', 5], + [NULL_STRING, 10], + ['Chrome', 8], + ], + }, + ], + [], + 5, + ]); + }); + it('should do missing value imputation', () => { const data = [ {