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 40ce5323e702e..6e1d0186efc05 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts @@ -53,14 +53,15 @@ import { DEFAULT_FORM_DATA } from './constants'; import { ForecastSeriesEnum, ForecastValue, Refs } from '../types'; import { parseYAxisBound } from '../utils/controls'; import { + calculateLowerLogTick, currentSeries, dedupSeries, + extractDataTotalValues, extractSeries, + extractShowValueIndexes, getAxisType, getColtypesMapping, getLegendProps, - extractDataTotalValues, - extractShowValueIndexes, } from '../utils/series'; import { extractAnnotationLabels, @@ -199,20 +200,23 @@ export default function transformProps( const isMultiSeries = groupby.length || metrics.length > 1; - const [rawSeries, sortedTotalValues] = extractSeries(rebasedData, { - fillNeighborValue: stack && !forecastEnabled ? 0 : undefined, - xAxis: xAxisLabel, - extraMetricLabels, - stack, - totalStackedValues, - isHorizontal, - sortSeriesType, - sortSeriesAscending, - xAxisSortSeries: isMultiSeries ? xAxisSortSeries : undefined, - xAxisSortSeriesAscending: isMultiSeries - ? xAxisSortSeriesAscending - : undefined, - }); + const [rawSeries, sortedTotalValues, minPositiveValue] = extractSeries( + rebasedData, + { + fillNeighborValue: stack && !forecastEnabled ? 0 : undefined, + xAxis: xAxisLabel, + extraMetricLabels, + stack, + totalStackedValues, + isHorizontal, + sortSeriesType, + sortSeriesAscending, + xAxisSortSeries: isMultiSeries ? xAxisSortSeries : undefined, + xAxisSortSeriesAscending: isMultiSeries + ? xAxisSortSeriesAscending + : undefined, + }, + ); const showValueIndexes = extractShowValueIndexes(rawSeries, { stack, onlyTotal, @@ -358,6 +362,8 @@ export default function transformProps( if ((contributionMode === 'row' || isAreaExpand) && stack) { if (min === undefined) min = 0; if (max === undefined) max = 1; + } else if (logAxis && min === undefined && minPositiveValue !== undefined) { + min = calculateLowerLogTick(minPositiveValue); } const tooltipFormatter = 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 6247813742b26..5235e168d9f93 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts @@ -247,7 +247,7 @@ export function extractSeries( xAxisSortSeries?: SortSeriesType; xAxisSortSeriesAscending?: boolean; } = {}, -): [SeriesOption[], number[]] { +): [SeriesOption[], number[], number | undefined] { const { fillNeighborValue, xAxis = DTTM_ALIAS, @@ -261,7 +261,7 @@ export function extractSeries( xAxisSortSeries, xAxisSortSeriesAscending, } = opts; - if (data.length === 0) return [[], []]; + if (data.length === 0) return [[], [], undefined]; const rows: DataRecord[] = data.map(datum => ({ ...datum, [xAxis]: datum[xAxis], @@ -287,18 +287,27 @@ export function extractSeries( totalStackedValue: totalStackedValues[idx], })); + let minPositiveValue: number | undefined; const finalSeries = sortedSeries.map(name => ({ id: name, name, data: sortedRows .map(({ row, totalStackedValue }, idx) => { + const currentValue = row[name]; + if ( + typeof currentValue === 'number' && + currentValue > 0 && + (minPositiveValue === undefined || minPositiveValue > currentValue) + ) { + minPositiveValue = currentValue; + } const isNextToDefinedValue = isDefined(rows[idx - 1]?.[name]) || isDefined(rows[idx + 1]?.[name]); const isFillNeighborValue = - !isDefined(row[name]) && + !isDefined(currentValue) && isNextToDefinedValue && fillNeighborValue !== undefined; - let value: DataRecordValue | undefined = row[name]; + let value: DataRecordValue | undefined = currentValue; if (isFillNeighborValue) { value = fillNeighborValue; } else if ( @@ -315,6 +324,7 @@ export function extractSeries( return [ finalSeries, sortedRows.map(({ totalStackedValue }) => totalStackedValue), + minPositiveValue, ]; } @@ -518,3 +528,8 @@ export function getOverMaxHiddenFormatter( id: NumberFormats.OVER_MAX_HIDDEN, }); } + +export function calculateLowerLogTick(minPositiveValue: number) { + const logBase10 = Math.floor(Math.log10(minPositiveValue)); + return Math.pow(10, logBase10); +} 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 c2de493c51a72..75faee93e59cd 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 @@ -25,6 +25,7 @@ import { supersetTheme as theme, } from '@superset-ui/core'; import { + calculateLowerLogTick, dedupSeries, extractGroupbyLabel, extractSeries, @@ -321,6 +322,7 @@ describe('extractSeries', () => { }, ], totalStackedValues, + 1, ]); }); @@ -366,6 +368,7 @@ describe('extractSeries', () => { }, ], totalStackedValues, + 1, ]); }); @@ -435,6 +438,7 @@ describe('extractSeries', () => { }, ], totalStackedValues, + 1, ]); }); }); @@ -857,3 +861,12 @@ describe('getOverMaxHiddenFormatter', () => { expect(formatter.format(50000)).toEqual('50000'); }); }); + +test('calculateLowerLogTick', () => { + expect(calculateLowerLogTick(1000000)).toEqual(1000000); + expect(calculateLowerLogTick(456)).toEqual(100); + expect(calculateLowerLogTick(100)).toEqual(100); + expect(calculateLowerLogTick(99)).toEqual(10); + expect(calculateLowerLogTick(2)).toEqual(1); + expect(calculateLowerLogTick(0.005)).toEqual(0.001); +});