mirror of
https://github.com/apache/superset.git
synced 2026-04-20 08:34:37 +00:00
* feat(plugin-chart-echarts): support non-timeseries x-axis * fix tests * change formula return type from Date to number * add x_axis test coverage * rename func and improve coverage * add x-axis control to bar chart * remove redundant console.log * fix description * make x-axis control mandatory * 🙃 * fix x-axis formatter * fix showValues * fix implicit rDTTM_ALIAS references in postProcessing * replace TIME_COLUMN with DTTM_ALIAS * fix remaining implicit indexes * fix: Disable filtering on wide result sets (#18021) * fix: handle null values in time-series table (#18039) * cleanup column_type_mappings (#17569) Signed-off-by: Đặng Minh Dũng <dungdm93@live.com> * important change to MakeFile (#18037) * add missing is_timeseries to pivot op Co-authored-by: Erik Ritter <erik.ritter@airbnb.com> Co-authored-by: Grace Guo <grace.guo@airbnb.com> Co-authored-by: Đặng Minh Dũng <dungdm93@live.com> Co-authored-by: AAfghahi <48933336+AAfghahi@users.noreply.github.com>
145 lines
4.8 KiB
TypeScript
145 lines
4.8 KiB
TypeScript
/**
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
import {
|
|
TimeseriesDataRecord,
|
|
NumberFormatter,
|
|
DTTM_ALIAS,
|
|
} from '@superset-ui/core';
|
|
import { CallbackDataParams, OptionName } from 'echarts/types/src/util/types';
|
|
import { TooltipMarker } from 'echarts/types/src/util/format';
|
|
import {
|
|
ForecastSeriesContext,
|
|
ForecastSeriesEnum,
|
|
ProphetValue,
|
|
} from '../types';
|
|
import { sanitizeHtml } from './series';
|
|
|
|
const seriesTypeRegex = new RegExp(
|
|
`(.+)(${ForecastSeriesEnum.ForecastLower}|${ForecastSeriesEnum.ForecastTrend}|${ForecastSeriesEnum.ForecastUpper})$`,
|
|
);
|
|
export const extractForecastSeriesContext = (
|
|
seriesName: OptionName,
|
|
): ForecastSeriesContext => {
|
|
const name = seriesName as string;
|
|
const regexMatch = seriesTypeRegex.exec(name);
|
|
if (!regexMatch) return { name, type: ForecastSeriesEnum.Observation };
|
|
return {
|
|
name: regexMatch[1],
|
|
type: regexMatch[2] as ForecastSeriesEnum,
|
|
};
|
|
};
|
|
|
|
export const extractForecastSeriesContexts = (
|
|
seriesNames: string[],
|
|
): { [key: string]: ForecastSeriesEnum[] } =>
|
|
seriesNames.reduce((agg, name) => {
|
|
const context = extractForecastSeriesContext(name);
|
|
const currentContexts = agg[context.name] || [];
|
|
currentContexts.push(context.type);
|
|
return { ...agg, [context.name]: currentContexts };
|
|
}, {} as { [key: string]: ForecastSeriesEnum[] });
|
|
|
|
export const extractProphetValuesFromTooltipParams = (
|
|
params: (CallbackDataParams & { seriesId: string })[],
|
|
): Record<string, ProphetValue> => {
|
|
const values: Record<string, ProphetValue> = {};
|
|
params.forEach(param => {
|
|
const { marker, seriesId, value } = param;
|
|
const context = extractForecastSeriesContext(seriesId);
|
|
const numericValue = (value as [Date, number])[1];
|
|
if (numericValue) {
|
|
if (!(context.name in values))
|
|
values[context.name] = {
|
|
marker: marker || '',
|
|
};
|
|
const prophetValues = values[context.name];
|
|
if (context.type === ForecastSeriesEnum.Observation)
|
|
prophetValues.observation = numericValue;
|
|
if (context.type === ForecastSeriesEnum.ForecastTrend)
|
|
prophetValues.forecastTrend = numericValue;
|
|
if (context.type === ForecastSeriesEnum.ForecastLower)
|
|
prophetValues.forecastLower = numericValue;
|
|
if (context.type === ForecastSeriesEnum.ForecastUpper)
|
|
prophetValues.forecastUpper = numericValue;
|
|
}
|
|
});
|
|
return values;
|
|
};
|
|
|
|
export const formatProphetTooltipSeries = ({
|
|
seriesName,
|
|
observation,
|
|
forecastTrend,
|
|
forecastLower,
|
|
forecastUpper,
|
|
marker,
|
|
formatter,
|
|
}: ProphetValue & {
|
|
seriesName: string;
|
|
marker: TooltipMarker;
|
|
formatter: NumberFormatter;
|
|
}): string => {
|
|
let row = `${marker}${sanitizeHtml(seriesName)}: `;
|
|
let isObservation = false;
|
|
if (observation) {
|
|
isObservation = true;
|
|
row += `${formatter(observation)}`;
|
|
}
|
|
if (forecastTrend) {
|
|
if (isObservation) row += ', ';
|
|
row += `ŷ = ${formatter(forecastTrend)}`;
|
|
}
|
|
if (forecastLower && forecastUpper)
|
|
// the lower bound needs to be added to the upper bound
|
|
row = `${row.trim()} (${formatter(forecastLower)}, ${formatter(
|
|
forecastLower + forecastUpper,
|
|
)})`;
|
|
return `${row.trim()}`;
|
|
};
|
|
|
|
export function rebaseTimeseriesDatum(
|
|
data: TimeseriesDataRecord[],
|
|
verboseMap: Record<string, string> = {},
|
|
) {
|
|
const keys = data.length > 0 ? Object.keys(data[0]) : [];
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
return data.map(row => {
|
|
const newRow: TimeseriesDataRecord = { [DTTM_ALIAS]: '' };
|
|
keys.forEach(key => {
|
|
const forecastContext = extractForecastSeriesContext(key);
|
|
const lowerKey = `${forecastContext.name}${ForecastSeriesEnum.ForecastLower}`;
|
|
let value = row[key] as number;
|
|
if (
|
|
forecastContext.type === ForecastSeriesEnum.ForecastUpper &&
|
|
keys.includes(lowerKey) &&
|
|
value !== null &&
|
|
row[lowerKey] !== null
|
|
) {
|
|
value -= row[lowerKey] as number;
|
|
}
|
|
const newKey =
|
|
key !== DTTM_ALIAS && verboseMap[key] ? verboseMap[key] : key;
|
|
newRow[newKey] = value;
|
|
});
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
return newRow;
|
|
});
|
|
}
|