From bf05b96b87e5a039c823cbb3b288ba00b33b0580 Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Thu, 9 Nov 2023 12:00:58 +0800 Subject: [PATCH 01/17] fix(ava/insight): modify the structure of insight mark --- .../strategy/augmentedMarks/changePoint.ts | 47 +++++++++++++++---- .../chart/strategy/augmentedMarks/index.ts | 6 +-- .../augmentedMarks/timeSeriesOutlier.ts | 20 +++++++- .../chart/strategy/augmentedMarks/trend.ts | 10 +++- packages/ava/src/insight/chart/types.ts | 18 ++++++- .../src/insight/pipeline/specificInsight.ts | 30 +++++------- packages/ava/src/insight/types.ts | 3 +- 7 files changed, 98 insertions(+), 36 deletions(-) diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/changePoint.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/changePoint.ts index 1feabb105..048663c18 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/changePoint.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/changePoint.ts @@ -1,4 +1,5 @@ -import { Mark } from '@antv/g2'; +import { Mark, PointMark, TextMark } from '@antv/g2'; +import { size } from 'lodash'; import { ChangePointInfo, InsightInfo } from '../../../types'; import { INSIGHT_COLOR_PLATTE } from '../../constants'; @@ -6,6 +7,17 @@ import { dataFormat } from '../../../../utils'; import { pointMarkStrategy } from '../commonMarks/pointMark'; import { textMarkStrategy } from '../commonMarks/textMark'; import { insight2ChartStrategy } from '../chart'; +import { ChangePointMark } from '../../types'; + +const CHANGE_POINT_TEXT_STYLE = { + dy: -20, + background: true, + backgroundRadius: 2, + connector: true, + startMarker: true, + startMarkerFill: '#2C3542', + startMarkerFillOpacity: 0.65, +}; export const changePointAugmentedMarksStrategy = (insight: InsightInfo): Mark[] => { const { patterns } = insight; @@ -15,19 +27,34 @@ export const changePointAugmentedMarksStrategy = (insight: InsightInfo `${pattern.x}, ${measure}: ${pattern.y}`, - style: { - dy: -20, - background: true, - backgroundRadius: 2, - connector: true, - startMarker: true, - startMarkerFill: '#2C3542', - startMarkerFillOpacity: 0.65, - }, + style: CHANGE_POINT_TEXT_STYLE, }); return [pointMark, textMark]; }; +export const getAugmentedChangePointMarks = (insight: InsightInfo): ChangePointMark[] => { + const { patterns } = insight; + const color = INSIGHT_COLOR_PLATTE.highlight; + + if (!size(patterns)) return []; + + const { measure } = patterns[0]; + const changePointMarks: ChangePointMark[] = []; + patterns.forEach((pattern) => { + const pointMark = pointMarkStrategy([pattern], { style: { fill: color } }) as PointMark; + const textMark = textMarkStrategy([pattern], { + formatter: dataFormat, + label: (pt) => `${pt.x}, ${measure}: ${pt.y}`, + style: CHANGE_POINT_TEXT_STYLE, + }) as TextMark; + changePointMarks.push({ + changePoint: [pointMark, textMark], + }); + }); + + return changePointMarks; +}; + export const changePointStrategy = (insight: InsightInfo): Mark[] => { const chart = insight2ChartStrategy(insight); const augmentedMarks = changePointAugmentedMarksStrategy(insight); diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/index.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/index.ts index a8edfb971..0e49554c7 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/index.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/index.ts @@ -1,8 +1,8 @@ -export { trendStrategy, trendAugmentedMarksStrategy } from './trend'; +export { trendStrategy, trendAugmentedMarksStrategy, getAugmentedTrendMarks } from './trend'; export { lowVarianceStrategy, lowVarianceAugmentedMarkStrategy } from './lowVariance'; export { categoryOutlierStrategy, categoryOutlierAugmentedMarksStrategy } from './categoryOutlier'; -export { changePointStrategy, changePointAugmentedMarksStrategy } from './changePoint'; +export { changePointStrategy, changePointAugmentedMarksStrategy, getAugmentedChangePointMarks } from './changePoint'; export { majorityStrategy } from './majority'; export { correlationStrategy } from './correlation'; export { homogeneousStrategy } from './homogeneous'; -export { timeSeriesOutlierStrategy } from './timeSeriesOutlier'; +export { timeSeriesOutlierStrategy, getAugmentedTimeSeriesOutlierMarks } from './timeSeriesOutlier'; diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/timeSeriesOutlier.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/timeSeriesOutlier.ts index 01e057363..39fabc31c 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/timeSeriesOutlier.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/timeSeriesOutlier.ts @@ -1,7 +1,7 @@ -import { Mark } from '@antv/g2'; +import { AreaMark, LineMark, Mark, PointMark } from '@antv/g2'; import { TimeSeriesOutlierInfo, InsightInfo } from '../../../types'; -import { AreaMarkData, LineMarkData } from '../../types'; +import { AreaMarkData, LineMarkData, TimeSeriesOutlierMark } from '../../types'; import { insight2ChartStrategy } from '../chart'; import { areaMarkStrategy, lineMarkStrategy, pointMarkStrategy } from '../commonMarks'; @@ -87,6 +87,22 @@ export const timeSeriesOutlierStrategyAugmentedMarksStrategy = ( return [intervalMark, baselineMark, outlierMark]; }; +export const getAugmentedTimeSeriesOutlierMarks = ( + insight: InsightInfo +): TimeSeriesOutlierMark[] => { + const originalMarks = timeSeriesOutlierStrategyAugmentedMarksStrategy(insight); + const lineMark = originalMarks.find((mark) => mark.type === 'line') as LineMark; + const areaMark = originalMarks.find((mark) => mark.type === 'area') as AreaMark; + const outlierMark = originalMarks.find((mark) => mark.type === 'point') as PointMark; + return [ + { + trendLine: lineMark ? [lineMark] : [], + anomalyArea: areaMark ? [areaMark] : [], + outliers: outlierMark ? [outlierMark] : [], + }, + ]; +}; + export const timeSeriesOutlierStrategy = (insight: InsightInfo): Mark[] => { // Should to support marks free combination const chartMark = insight2ChartStrategy(insight); diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts index 0dcdf8d83..a0c9c7f34 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts @@ -1,8 +1,9 @@ -import { Mark } from '@antv/g2'; +import { LineMark, Mark } from '@antv/g2'; import { lineMarkStrategy } from '../commonMarks'; import { insight2ChartStrategy } from '../chart'; import { InsightInfo, TrendInfo } from '../../../types'; +import { TrendMark } from '../../types'; export const trendAugmentedMarksStrategy = (insight: InsightInfo): Mark[] => { const { @@ -32,6 +33,13 @@ export const trendAugmentedMarksStrategy = (insight: InsightInfo): Ma return [regressionLineMark]; }; +export const getAugmentedTrendMarks = (insight: InsightInfo): TrendMark[] => { + const originalMarks = trendAugmentedMarksStrategy(insight); + return originalMarks.map((mark) => ({ + trendLine: [mark as LineMark], + })); +}; + export const trendStrategy = (insight: InsightInfo): Mark[] => { const chart = insight2ChartStrategy(insight); const augmentedMarks = trendAugmentedMarksStrategy(insight); diff --git a/packages/ava/src/insight/chart/types.ts b/packages/ava/src/insight/chart/types.ts index 113be300a..3ee5f2bf2 100644 --- a/packages/ava/src/insight/chart/types.ts +++ b/packages/ava/src/insight/chart/types.ts @@ -1,4 +1,4 @@ -import type { Mark } from '@antv/g2'; +import type { AreaMark, LineMark, Mark, PointMark, TextMark } from '@antv/g2'; import type { Datum } from '../types'; type LabelType = string | ((d: Datum) => string); @@ -42,3 +42,19 @@ export type AreaMarkConfig = { export type IntervalMarkConfig = { style?: Mark['style']; }; + +export type ChangePointMark = { + changePoint: (PointMark | TextMark)[]; +}; + +export type TrendMark = { + trendLine: LineMark[]; +}; + +export type TimeSeriesOutlierMark = { + trendLine: LineMark[]; + anomalyArea: AreaMark[]; + outliers?: PointMark[]; +}; + +export type AugmentedMarks = ChangePointMark[] | TrendMark[] | TimeSeriesOutlierMark[]; diff --git a/packages/ava/src/insight/pipeline/specificInsight.ts b/packages/ava/src/insight/pipeline/specificInsight.ts index 161cad4e8..8158a16f2 100644 --- a/packages/ava/src/insight/pipeline/specificInsight.ts +++ b/packages/ava/src/insight/pipeline/specificInsight.ts @@ -1,11 +1,13 @@ -import { G2Spec, Mark } from '@antv/g2'; -import { zipObject } from 'lodash'; - -import { changePointAugmentedMarksStrategy, generateInsightChartSpec, trendAugmentedMarksStrategy } from '../chart'; -import { timeSeriesOutlierStrategyAugmentedMarksStrategy } from '../chart/strategy/augmentedMarks/timeSeriesOutlier'; +import { + generateInsightChartSpec, + getAugmentedChangePointMarks, + getAugmentedTrendMarks, + getAugmentedTimeSeriesOutlierMarks, +} from '../chart'; import { IMPACT_SCORE_WEIGHT } from '../constant'; import { insightPatternsExtractor } from '../insights'; import { InsightInfo, PatternInfo, PatternInfo2InsightInfoProps, SpecificInsightProps } from '../types'; +import { AugmentedMarks } from '../chart/types'; export const patternInfo2InsightInfo = (props: PatternInfo2InsightInfoProps) => { const { dimensions, measures, data, patternInfos } = props; @@ -20,28 +22,20 @@ export const patternInfo2InsightInfo = (props: PatternInfo2InsightInfoProps) => }; }; -export const getAnnotationSpec = (insightInfo: InsightInfo): Record => { +export const getAnnotationSpec = (insightInfo: InsightInfo): AugmentedMarks => { const { type: insightType } = insightInfo.patterns[0]; const insightType2AugmentedMarks = { - trend: trendAugmentedMarksStrategy, - change_point: changePointAugmentedMarksStrategy, - time_series_outlier: timeSeriesOutlierStrategyAugmentedMarksStrategy, + trend: getAugmentedTrendMarks, + change_point: getAugmentedChangePointMarks, + time_series_outlier: getAugmentedTimeSeriesOutlierMarks, }; - const markList = insightType2AugmentedMarks[insightType]?.(insightInfo) as Mark[]; - const markMap = zipObject( - markList.map((mark) => mark.type as string), - markList - ); - return markMap; + return insightType2AugmentedMarks[insightType]?.(insightInfo); }; export const getSpecificInsight = (props: SpecificInsightProps): InsightInfo => { - // 计算patternInfo const patternInfos = insightPatternsExtractor(props); - // 获取insightInfo const insightInfo = patternInfo2InsightInfo({ ...props, patternInfos }); - // 获取annotationSpec const annotationSpec = getAnnotationSpec(insightInfo); const chartSpec = generateInsightChartSpec(insightInfo); diff --git a/packages/ava/src/insight/types.ts b/packages/ava/src/insight/types.ts index 0a42d8898..f77418926 100644 --- a/packages/ava/src/insight/types.ts +++ b/packages/ava/src/insight/types.ts @@ -1,6 +1,7 @@ import { PCorrTestParameter } from '../data/statistics/types'; import { PATTERN_TYPES, HOMOGENEOUS_PATTERN_TYPES } from './constant'; +import { AugmentedMarks } from './chart/types'; import type { G2Spec } from '@antv/g2'; import type { ParagraphSpec } from '../ntv/types'; @@ -81,7 +82,7 @@ export interface InsightVisualizationSpec { patternType: InsightType; chartSpec: G2Spec; /** augmented marks */ - annotationSpec?: Record; + annotationSpec?: AugmentedMarks; /** * @description explain insight by text * @default ParagraphSpec[] From 6651a5ec91e496e3d3980d3716b12279efa14021 Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Thu, 9 Nov 2023 12:04:22 +0800 Subject: [PATCH 02/17] fix(ava/insight): export getSpecificInsight method --- packages/ava/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ava/src/index.ts b/packages/ava/src/index.ts index 463a0e640..faf9a2f0e 100644 --- a/packages/ava/src/index.ts +++ b/packages/ava/src/index.ts @@ -93,7 +93,7 @@ export type { } from './data'; /* insight */ -export { getInsights, generateInsightVisualizationSpec, insightPatternsExtractor } from './insight'; +export { getInsights, generateInsightVisualizationSpec, insightPatternsExtractor, getSpecificInsight } from './insight'; export type { Datum, DomainType, From aecf8d65805d5850fd2e0e91683b79790561fe8f Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Thu, 9 Nov 2023 17:25:04 +0800 Subject: [PATCH 03/17] fix(ava/insight): transform augmented mraks strategy --- .../strategy/augmentedMarks/changePoint.ts | 42 +++++++------------ .../chart/strategy/augmentedMarks/index.ts | 6 +-- .../augmentedMarks/timeSeriesOutlier.ts | 23 +++------- .../chart/strategy/augmentedMarks/trend.ts | 19 ++++----- .../src/insight/pipeline/specificInsight.ts | 12 +++--- 5 files changed, 37 insertions(+), 65 deletions(-) diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/changePoint.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/changePoint.ts index 048663c18..da6ef4c36 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/changePoint.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/changePoint.ts @@ -1,5 +1,5 @@ import { Mark, PointMark, TextMark } from '@antv/g2'; -import { size } from 'lodash'; +import { flatten, size } from 'lodash'; import { ChangePointInfo, InsightInfo } from '../../../types'; import { INSIGHT_COLOR_PLATTE } from '../../constants'; @@ -9,30 +9,7 @@ import { textMarkStrategy } from '../commonMarks/textMark'; import { insight2ChartStrategy } from '../chart'; import { ChangePointMark } from '../../types'; -const CHANGE_POINT_TEXT_STYLE = { - dy: -20, - background: true, - backgroundRadius: 2, - connector: true, - startMarker: true, - startMarkerFill: '#2C3542', - startMarkerFillOpacity: 0.65, -}; - -export const changePointAugmentedMarksStrategy = (insight: InsightInfo): Mark[] => { - const { patterns } = insight; - const color = INSIGHT_COLOR_PLATTE.highlight; - const { measure } = patterns?.[0]; - const pointMark = pointMarkStrategy(patterns, { style: { fill: color } }); - const textMark = textMarkStrategy(patterns, { - formatter: dataFormat, - label: (pattern) => `${pattern.x}, ${measure}: ${pattern.y}`, - style: CHANGE_POINT_TEXT_STYLE, - }); - return [pointMark, textMark]; -}; - -export const getAugmentedChangePointMarks = (insight: InsightInfo): ChangePointMark[] => { +export const changePointAugmentedMarksStrategy = (insight: InsightInfo): ChangePointMark[] => { const { patterns } = insight; const color = INSIGHT_COLOR_PLATTE.highlight; @@ -45,7 +22,15 @@ export const getAugmentedChangePointMarks = (insight: InsightInfo `${pt.x}, ${measure}: ${pt.y}`, - style: CHANGE_POINT_TEXT_STYLE, + style: { + dy: -20, + background: true, + backgroundRadius: 2, + connector: true, + startMarker: true, + startMarkerFill: '#2C3542', + startMarkerFillOpacity: 0.65, + }, }) as TextMark; changePointMarks.push({ changePoint: [pointMark, textMark], @@ -57,6 +42,7 @@ export const getAugmentedChangePointMarks = (insight: InsightInfo): Mark[] => { const chart = insight2ChartStrategy(insight); - const augmentedMarks = changePointAugmentedMarksStrategy(insight); - return [chart, ...augmentedMarks]; + const changePointMarks = changePointAugmentedMarksStrategy(insight); + const marks = flatten(changePointMarks.map((changePointMark) => [...changePointMark.changePoint])); + return [chart, ...marks]; }; diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/index.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/index.ts index 0e49554c7..a8372f803 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/index.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/index.ts @@ -1,8 +1,8 @@ -export { trendStrategy, trendAugmentedMarksStrategy, getAugmentedTrendMarks } from './trend'; +export { trendStrategy, trendAugmentedMarksStrategy } from './trend'; export { lowVarianceStrategy, lowVarianceAugmentedMarkStrategy } from './lowVariance'; export { categoryOutlierStrategy, categoryOutlierAugmentedMarksStrategy } from './categoryOutlier'; -export { changePointStrategy, changePointAugmentedMarksStrategy, getAugmentedChangePointMarks } from './changePoint'; +export { changePointStrategy, changePointAugmentedMarksStrategy } from './changePoint'; export { majorityStrategy } from './majority'; export { correlationStrategy } from './correlation'; export { homogeneousStrategy } from './homogeneous'; -export { timeSeriesOutlierStrategy, getAugmentedTimeSeriesOutlierMarks } from './timeSeriesOutlier'; +export { timeSeriesOutlierStrategy, timeSeriesOutlierStrategyAugmentedMarksStrategy } from './timeSeriesOutlier'; diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/timeSeriesOutlier.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/timeSeriesOutlier.ts index 39fabc31c..a23c4b2e1 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/timeSeriesOutlier.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/timeSeriesOutlier.ts @@ -11,7 +11,7 @@ const OUTLIER = 'outlier'; export const timeSeriesOutlierStrategyAugmentedMarksStrategy = ( insight: InsightInfo -): Mark[] => { +): TimeSeriesOutlierMark[] => { const { data: chartData, dimensions: [{ fieldName: dimensionName }], @@ -84,21 +84,11 @@ export const timeSeriesOutlierStrategyAugmentedMarksStrategy = ( }, }); - return [intervalMark, baselineMark, outlierMark]; -}; - -export const getAugmentedTimeSeriesOutlierMarks = ( - insight: InsightInfo -): TimeSeriesOutlierMark[] => { - const originalMarks = timeSeriesOutlierStrategyAugmentedMarksStrategy(insight); - const lineMark = originalMarks.find((mark) => mark.type === 'line') as LineMark; - const areaMark = originalMarks.find((mark) => mark.type === 'area') as AreaMark; - const outlierMark = originalMarks.find((mark) => mark.type === 'point') as PointMark; return [ { - trendLine: lineMark ? [lineMark] : [], - anomalyArea: areaMark ? [areaMark] : [], - outliers: outlierMark ? [outlierMark] : [], + trendLine: [baselineMark as LineMark], + anomalyArea: [intervalMark as AreaMark], + outliers: [outlierMark as PointMark], }, ]; }; @@ -106,7 +96,6 @@ export const getAugmentedTimeSeriesOutlierMarks = ( export const timeSeriesOutlierStrategy = (insight: InsightInfo): Mark[] => { // Should to support marks free combination const chartMark = insight2ChartStrategy(insight); - const augmentedMarks = timeSeriesOutlierStrategyAugmentedMarksStrategy(insight)?.slice(); - augmentedMarks.splice(2, 0, chartMark); - return augmentedMarks; + const { trendLine, anomalyArea, outliers } = timeSeriesOutlierStrategyAugmentedMarksStrategy(insight)[0]; + return [...anomalyArea, ...trendLine, ...outliers, chartMark]; }; diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts index a0c9c7f34..114c0231c 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts @@ -5,7 +5,7 @@ import { insight2ChartStrategy } from '../chart'; import { InsightInfo, TrendInfo } from '../../../types'; import { TrendMark } from '../../types'; -export const trendAugmentedMarksStrategy = (insight: InsightInfo): Mark[] => { +export const trendAugmentedMarksStrategy = (insight: InsightInfo): TrendMark[] => { const { data: chartData, dimensions: [{ fieldName: dimensionName }], @@ -30,18 +30,15 @@ export const trendAugmentedMarksStrategy = (insight: InsightInfo): Ma const regressionLineMark = lineMarkStrategy({ points: lineData }, { label: `y=${m.toFixed(2)}x+${c.toFixed(2)}` }); - return [regressionLineMark]; -}; - -export const getAugmentedTrendMarks = (insight: InsightInfo): TrendMark[] => { - const originalMarks = trendAugmentedMarksStrategy(insight); - return originalMarks.map((mark) => ({ - trendLine: [mark as LineMark], - })); + return [ + { + trendLine: [regressionLineMark as LineMark], + }, + ]; }; export const trendStrategy = (insight: InsightInfo): Mark[] => { const chart = insight2ChartStrategy(insight); - const augmentedMarks = trendAugmentedMarksStrategy(insight); - return [chart, ...augmentedMarks]; + const trendMarks = trendAugmentedMarksStrategy(insight); + return [chart, ...trendMarks[0].trendLine]; }; diff --git a/packages/ava/src/insight/pipeline/specificInsight.ts b/packages/ava/src/insight/pipeline/specificInsight.ts index 8158a16f2..a1f80ba01 100644 --- a/packages/ava/src/insight/pipeline/specificInsight.ts +++ b/packages/ava/src/insight/pipeline/specificInsight.ts @@ -1,8 +1,8 @@ import { generateInsightChartSpec, - getAugmentedChangePointMarks, - getAugmentedTrendMarks, - getAugmentedTimeSeriesOutlierMarks, + changePointAugmentedMarksStrategy, + trendAugmentedMarksStrategy, + timeSeriesOutlierStrategyAugmentedMarksStrategy, } from '../chart'; import { IMPACT_SCORE_WEIGHT } from '../constant'; import { insightPatternsExtractor } from '../insights'; @@ -26,9 +26,9 @@ export const getAnnotationSpec = (insightInfo: InsightInfo): Augmen const { type: insightType } = insightInfo.patterns[0]; const insightType2AugmentedMarks = { - trend: getAugmentedTrendMarks, - change_point: getAugmentedChangePointMarks, - time_series_outlier: getAugmentedTimeSeriesOutlierMarks, + trend: trendAugmentedMarksStrategy, + change_point: changePointAugmentedMarksStrategy, + time_series_outlier: timeSeriesOutlierStrategyAugmentedMarksStrategy, }; return insightType2AugmentedMarks[insightType]?.(insightInfo); }; From f5ee7cb6851494ebff8b203cec343f93c1a05d18 Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Thu, 9 Nov 2023 18:29:51 +0800 Subject: [PATCH 04/17] fix(ava/insight): adjust mark order & null value protection --- .../chart/strategy/augmentedMarks/timeSeriesOutlier.ts | 8 ++++++-- .../src/insight/chart/strategy/augmentedMarks/trend.ts | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/timeSeriesOutlier.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/timeSeriesOutlier.ts index a23c4b2e1..395ff2c78 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/timeSeriesOutlier.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/timeSeriesOutlier.ts @@ -96,6 +96,10 @@ export const timeSeriesOutlierStrategyAugmentedMarksStrategy = ( export const timeSeriesOutlierStrategy = (insight: InsightInfo): Mark[] => { // Should to support marks free combination const chartMark = insight2ChartStrategy(insight); - const { trendLine, anomalyArea, outliers } = timeSeriesOutlierStrategyAugmentedMarksStrategy(insight)[0]; - return [...anomalyArea, ...trendLine, ...outliers, chartMark]; + const { + trendLine = [], + anomalyArea = [], + outliers = [], + } = timeSeriesOutlierStrategyAugmentedMarksStrategy(insight)[0] || {}; + return [...anomalyArea, ...trendLine, chartMark, ...outliers]; }; diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts index 114c0231c..b9fce2986 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts @@ -40,5 +40,5 @@ export const trendAugmentedMarksStrategy = (insight: InsightInfo): Tr export const trendStrategy = (insight: InsightInfo): Mark[] => { const chart = insight2ChartStrategy(insight); const trendMarks = trendAugmentedMarksStrategy(insight); - return [chart, ...trendMarks[0].trendLine]; + return [chart, ...(trendMarks[0]?.trendLine ?? [])]; }; From 8b9456224ff568c1e2a6315b9ad490e7ba842edb Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Fri, 10 Nov 2023 10:27:23 +0800 Subject: [PATCH 05/17] chore(ava): release 3.3.0-beta.0 --- packages/ava/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ava/package.json b/packages/ava/package.json index 24014e98d..be255b0df 100644 --- a/packages/ava/package.json +++ b/packages/ava/package.json @@ -1,6 +1,6 @@ { "name": "@antv/ava", - "version": "3.2.0", + "version": "3.3.0-beta.0", "description": "A framework for automated visual analytics.", "author": { "name": "AntV", From eb433a3a1416439c6a426fb4110791792a38c2ed Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Fri, 10 Nov 2023 11:54:09 +0800 Subject: [PATCH 06/17] fix(ava/insight): delete generateInsightAugmentedMarks method --- .../src/insight/chart/generator/insights.ts | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/packages/ava/src/insight/chart/generator/insights.ts b/packages/ava/src/insight/chart/generator/insights.ts index 35451f045..a797b7c0d 100644 --- a/packages/ava/src/insight/chart/generator/insights.ts +++ b/packages/ava/src/insight/chart/generator/insights.ts @@ -9,34 +9,8 @@ import { correlationStrategy, timeSeriesOutlierStrategy, trendStrategy, - trendAugmentedMarksStrategy, - categoryOutlierAugmentedMarksStrategy, - changePointAugmentedMarksStrategy, - lowVarianceAugmentedMarkStrategy, viewSpecStrategy, } from '../strategy'; -import { LineMarkConfig, PointMarkConfig, TextMarkConfig } from '../types'; - -// The generateInsightAugmentedMarks needs to be refactored, it's not exported now. -export function generateInsightAugmentedMarks( - insight: InsightInfo, - markStyleConfig?: TextMarkConfig | LineMarkConfig | PointMarkConfig -): G2Spec { - const { type: insightType } = insight?.patterns[0]; - - const insightType2Strategy: Record< - string, - (insight: InsightInfo, markStyleConfig?: TextMarkConfig | LineMarkConfig | PointMarkConfig) => Mark[] - > = { - trend: trendAugmentedMarksStrategy, - category_outlier: categoryOutlierAugmentedMarksStrategy, - change_point: changePointAugmentedMarksStrategy, - low_variance: lowVarianceAugmentedMarkStrategy, - }; - - const augmentedMarks = insightType2Strategy[insightType]?.(insight, markStyleConfig); - return augmentedMarks; -} export function generateInsightChartSpec(insight: InsightInfo): G2Spec { const { type: insightType } = insight.patterns[0]; From 09e37728cdad5ceff7108bf41204f06947205427 Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Fri, 10 Nov 2023 12:09:51 +0800 Subject: [PATCH 07/17] chore(ava): release 3.3.0-beta.1 --- packages/ava/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ava/package.json b/packages/ava/package.json index be255b0df..683f614f3 100644 --- a/packages/ava/package.json +++ b/packages/ava/package.json @@ -1,6 +1,6 @@ { "name": "@antv/ava", - "version": "3.3.0-beta.0", + "version": "3.3.0-beta.1", "description": "A framework for automated visual analytics.", "author": { "name": "AntV", From cc8bd3b6f8581e341eb7320d37014b04769f9f1f Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Fri, 10 Nov 2023 18:26:19 +0800 Subject: [PATCH 08/17] fix(ava/insight): modify output of getSpecificInsight method & export related types --- packages/ava/src/index.ts | 2 ++ packages/ava/src/insight/chart/index.ts | 1 + packages/ava/src/insight/index.ts | 1 + .../src/insight/pipeline/specificInsight.ts | 16 +++++++++++++--- packages/ava/src/insight/types.ts | 18 ++++++------------ 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/packages/ava/src/index.ts b/packages/ava/src/index.ts index faf9a2f0e..2ca0aa264 100644 --- a/packages/ava/src/index.ts +++ b/packages/ava/src/index.ts @@ -125,6 +125,8 @@ export type { CorrelationInfo, InsightsResult, InsightExtractorProps, + SpecificInsightProps, + AugmentedMarks, } from './insight'; /* NTV (Narrative Text Vis) */ diff --git a/packages/ava/src/insight/chart/index.ts b/packages/ava/src/insight/chart/index.ts index 78c4f070f..96e04d730 100644 --- a/packages/ava/src/insight/chart/index.ts +++ b/packages/ava/src/insight/chart/index.ts @@ -1,3 +1,4 @@ export * from './generator/homogeneous'; export * from './generator/insights'; export * from './strategy/augmentedMarks'; +export type { AugmentedMarks } from './types'; diff --git a/packages/ava/src/insight/index.ts b/packages/ava/src/insight/index.ts index 951056148..c95a9df2b 100644 --- a/packages/ava/src/insight/index.ts +++ b/packages/ava/src/insight/index.ts @@ -3,3 +3,4 @@ export { insightPatternsExtractor } from './insights'; export { generateInsightVisualizationSpec } from './pipeline/visualize'; export * from './types'; export { getSpecificInsight } from './pipeline/specificInsight'; +export type { AugmentedMarks } from './chart'; diff --git a/packages/ava/src/insight/pipeline/specificInsight.ts b/packages/ava/src/insight/pipeline/specificInsight.ts index a1f80ba01..a4911d26e 100644 --- a/packages/ava/src/insight/pipeline/specificInsight.ts +++ b/packages/ava/src/insight/pipeline/specificInsight.ts @@ -3,11 +3,18 @@ import { changePointAugmentedMarksStrategy, trendAugmentedMarksStrategy, timeSeriesOutlierStrategyAugmentedMarksStrategy, + AugmentedMarks, } from '../chart'; import { IMPACT_SCORE_WEIGHT } from '../constant'; import { insightPatternsExtractor } from '../insights'; -import { InsightInfo, PatternInfo, PatternInfo2InsightInfoProps, SpecificInsightProps } from '../types'; -import { AugmentedMarks } from '../chart/types'; +import { + InsightInfo, + PatternInfo, + PatternInfo2InsightInfoProps, + SpecificInsightProps, + SpecificInsightResult, +} from '../types'; +import generateInsightNarrative from '../narrative'; export const patternInfo2InsightInfo = (props: PatternInfo2InsightInfoProps) => { const { dimensions, measures, data, patternInfos } = props; @@ -33,11 +40,13 @@ export const getAnnotationSpec = (insightInfo: InsightInfo): Augmen return insightType2AugmentedMarks[insightType]?.(insightInfo); }; -export const getSpecificInsight = (props: SpecificInsightProps): InsightInfo => { +export const getSpecificInsight = (props: SpecificInsightProps): SpecificInsightResult => { + const { visualizationOptions } = props.options || {}; const patternInfos = insightPatternsExtractor(props); const insightInfo = patternInfo2InsightInfo({ ...props, patternInfos }); const annotationSpec = getAnnotationSpec(insightInfo); const chartSpec = generateInsightChartSpec(insightInfo); + const narrativeSpec = generateInsightNarrative(insightInfo, visualizationOptions); return { ...insightInfo, @@ -46,6 +55,7 @@ export const getSpecificInsight = (props: SpecificInsightProps): InsightInfo & { /** Whether to filter non-significant insights. The default is false. */ filterInsight?: boolean; - /** Key parameters in the algorithm for extracting insights */ - algorithmParameter?: AlgorithmParameter; /** Whether data length, type, etc. need to be verified. The default is false. */ dataValidation?: boolean; - /** Parameter used for data preprocessing during data validation */ - dataProcessInfo?: Extra; + visualizationOptions?: InsightVisualizationOptions; }; export type InsightExtractorProps = { @@ -287,13 +284,10 @@ export type InsightsResult = { homogeneousInsights?: InsightInfo[]; }; -export type SpecificInsightProps = { - data: Datum[]; - dimensions: Dimension[]; - measures: Measure[]; - insightType: InsightType; - /** 包括自定义的算法参数,是否进行数据校验等内容 */ - options?: InsightExtractorOptions; +export type SpecificInsightProps = InsightExtractorProps; + +export type SpecificInsightResult = InsightInfo & { + visualizationSpecs: Required[]; }; export type PatternInfo2InsightInfoProps = SpecificInsightProps & { From 5aed44318fa982ed07125a025c331419c4424d51 Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Fri, 10 Nov 2023 18:50:12 +0800 Subject: [PATCH 09/17] feat(ava/insight): add LowVarianceMark and CategoryOutlierMark --- .../augmentedMarks/categoryOutlier.ts | 32 ++++++++++++++----- .../strategy/augmentedMarks/changePoint.ts | 5 +-- .../strategy/augmentedMarks/lowVariance.ts | 15 ++++++--- packages/ava/src/insight/chart/types.ts | 17 ++++++++-- packages/ava/src/insight/chart/utils.ts | 8 +++++ 5 files changed, 60 insertions(+), 17 deletions(-) create mode 100644 packages/ava/src/insight/chart/utils.ts diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/categoryOutlier.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/categoryOutlier.ts index c1c64b55d..8cb1f9b47 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/categoryOutlier.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/categoryOutlier.ts @@ -1,23 +1,39 @@ import { Mark } from '@antv/g2'; +import { size } from 'lodash'; import { dataFormat } from '../../../../utils'; import { InsightInfo, CategoryOutlierInfo } from '../../../types'; import { BOLD_FONT_WEIGHT } from '../../constants'; import { insight2ChartStrategy } from '../chart'; import { textMarkStrategy, intervalMarkStrategy } from '../commonMarks'; +import { CategoryOutlierMark } from '../../types'; +import { augmentedMarks2Marks } from '../../utils'; -export const categoryOutlierAugmentedMarksStrategy = (insight: InsightInfo): Mark[] => { +export const categoryOutlierAugmentedMarksStrategy = ( + insight: InsightInfo +): CategoryOutlierMark[] => { const { patterns } = insight; - const rectMark = intervalMarkStrategy(patterns); - const textMark = textMarkStrategy(patterns, { - style: { fontWeight: BOLD_FONT_WEIGHT, dy: -8 }, - formatter: dataFormat, + + if (!size(patterns)) return []; + + const categoryOutlierMarks: CategoryOutlierMark[] = []; + patterns.forEach((pattern) => { + const rectMark = intervalMarkStrategy([pattern]); + const textMark = textMarkStrategy([pattern], { + style: { fontWeight: BOLD_FONT_WEIGHT, dy: -8 }, + formatter: dataFormat, + }); + categoryOutlierMarks.push({ + categoryOutlier: [rectMark, textMark], + }); }); - return [rectMark, textMark]; + + return categoryOutlierMarks; }; export const categoryOutlierStrategy = (insight: InsightInfo): Mark[] => { const chart = insight2ChartStrategy(insight); - const augmentedMarks = categoryOutlierAugmentedMarksStrategy(insight); - return [chart, ...augmentedMarks]; + const categoryOutlierMarks = categoryOutlierAugmentedMarksStrategy(insight); + const marks = augmentedMarks2Marks(categoryOutlierMarks); + return [chart, ...marks]; }; diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/changePoint.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/changePoint.ts index da6ef4c36..6dc7aba02 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/changePoint.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/changePoint.ts @@ -1,5 +1,5 @@ import { Mark, PointMark, TextMark } from '@antv/g2'; -import { flatten, size } from 'lodash'; +import { size } from 'lodash'; import { ChangePointInfo, InsightInfo } from '../../../types'; import { INSIGHT_COLOR_PLATTE } from '../../constants'; @@ -8,6 +8,7 @@ import { pointMarkStrategy } from '../commonMarks/pointMark'; import { textMarkStrategy } from '../commonMarks/textMark'; import { insight2ChartStrategy } from '../chart'; import { ChangePointMark } from '../../types'; +import { augmentedMarks2Marks } from '../../utils'; export const changePointAugmentedMarksStrategy = (insight: InsightInfo): ChangePointMark[] => { const { patterns } = insight; @@ -43,6 +44,6 @@ export const changePointAugmentedMarksStrategy = (insight: InsightInfo): Mark[] => { const chart = insight2ChartStrategy(insight); const changePointMarks = changePointAugmentedMarksStrategy(insight); - const marks = flatten(changePointMarks.map((changePointMark) => [...changePointMark.changePoint])); + const marks = augmentedMarks2Marks(changePointMarks); return [chart, ...marks]; }; diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/lowVariance.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/lowVariance.ts index 8932dd07c..1d6317c29 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/lowVariance.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/lowVariance.ts @@ -3,20 +3,25 @@ import { Mark } from '@antv/g2'; import { LowVarianceInfo, InsightInfo } from '../../../types'; import { lineMarkStrategy } from '../commonMarks'; import { insight2ChartStrategy } from '../chart'; +import { LowVarianceMark } from '../../types'; +import { augmentedMarks2Marks } from '../../utils'; -export const lowVarianceAugmentedMarkStrategy = (insight: InsightInfo): Mark[] => { +export const lowVarianceAugmentedMarkStrategy = (insight: InsightInfo): LowVarianceMark[] => { const { patterns } = insight; - const marks = []; + const marks: LowVarianceMark[] = []; patterns.forEach((pattern) => { const { mean } = pattern; const meanLineMark = lineMarkStrategy({ y: mean }, { label: `mean: ${mean}` }); - marks.push(meanLineMark); + marks.push({ + meanLine: [meanLineMark], + }); }); return marks; }; export const lowVarianceStrategy = (insight: InsightInfo): Mark[] => { const chartMark = insight2ChartStrategy(insight); - const augmentedMarks = lowVarianceAugmentedMarkStrategy(insight); - return [chartMark, ...augmentedMarks]; + const lowVarianceMarks = lowVarianceAugmentedMarkStrategy(insight); + const marks = augmentedMarks2Marks(lowVarianceMarks); + return [chartMark, ...marks]; }; diff --git a/packages/ava/src/insight/chart/types.ts b/packages/ava/src/insight/chart/types.ts index 3ee5f2bf2..9c2c85a12 100644 --- a/packages/ava/src/insight/chart/types.ts +++ b/packages/ava/src/insight/chart/types.ts @@ -1,4 +1,4 @@ -import type { AreaMark, LineMark, Mark, PointMark, TextMark } from '@antv/g2'; +import type { AreaMark, IntervalMark, LineMark, Mark, PointMark, TextMark } from '@antv/g2'; import type { Datum } from '../types'; type LabelType = string | ((d: Datum) => string); @@ -57,4 +57,17 @@ export type TimeSeriesOutlierMark = { outliers?: PointMark[]; }; -export type AugmentedMarks = ChangePointMark[] | TrendMark[] | TimeSeriesOutlierMark[]; +export type CategoryOutlierMark = { + categoryOutlier: (IntervalMark | TextMark)[]; +}; + +export type LowVarianceMark = { + meanLine: LineMark[]; +}; + +export type AugmentedMarks = + | ChangePointMark[] + | TrendMark[] + | TimeSeriesOutlierMark[] + | CategoryOutlierMark[] + | LowVarianceMark[]; diff --git a/packages/ava/src/insight/chart/utils.ts b/packages/ava/src/insight/chart/utils.ts new file mode 100644 index 000000000..1ae07fcd7 --- /dev/null +++ b/packages/ava/src/insight/chart/utils.ts @@ -0,0 +1,8 @@ +import { Mark } from '@antv/g2'; +import { flattenDeep, map } from 'lodash'; + +import { AugmentedMarks } from './types'; + +export const augmentedMarks2Marks = (augmentedMarks: AugmentedMarks): Mark[] => { + return flattenDeep(map(augmentedMarks, (augmentedMark) => Object.values(augmentedMark))); +}; From b5c357e102c8c692155aa225aab1fb69202ddef0 Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Mon, 13 Nov 2023 13:49:13 +0800 Subject: [PATCH 10/17] fix(ava/insight): export related types & remove score from SpecificInsightResult --- packages/ava/src/insight/chart/index.ts | 2 +- packages/ava/src/insight/pipeline/specificInsight.ts | 7 +++---- packages/ava/src/insight/types.ts | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/ava/src/insight/chart/index.ts b/packages/ava/src/insight/chart/index.ts index 96e04d730..a0ef8ed35 100644 --- a/packages/ava/src/insight/chart/index.ts +++ b/packages/ava/src/insight/chart/index.ts @@ -1,4 +1,4 @@ export * from './generator/homogeneous'; export * from './generator/insights'; export * from './strategy/augmentedMarks'; -export type { AugmentedMarks } from './types'; +export * from './types'; diff --git a/packages/ava/src/insight/pipeline/specificInsight.ts b/packages/ava/src/insight/pipeline/specificInsight.ts index a4911d26e..258c0358d 100644 --- a/packages/ava/src/insight/pipeline/specificInsight.ts +++ b/packages/ava/src/insight/pipeline/specificInsight.ts @@ -5,7 +5,6 @@ import { timeSeriesOutlierStrategyAugmentedMarksStrategy, AugmentedMarks, } from '../chart'; -import { IMPACT_SCORE_WEIGHT } from '../constant'; import { insightPatternsExtractor } from '../insights'; import { InsightInfo, @@ -16,16 +15,16 @@ import { } from '../types'; import generateInsightNarrative from '../narrative'; -export const patternInfo2InsightInfo = (props: PatternInfo2InsightInfoProps) => { +export const patternInfo2InsightInfo = ( + props: PatternInfo2InsightInfoProps +): Omit, 'score'> => { const { dimensions, measures, data, patternInfos } = props; - const score = patternInfos[0] ? patternInfos[0].significance * (1 - IMPACT_SCORE_WEIGHT) + IMPACT_SCORE_WEIGHT : 0; return { subspace: [], dimensions, measures, patterns: patternInfos, data, - score, }; }; diff --git a/packages/ava/src/insight/types.ts b/packages/ava/src/insight/types.ts index 230dc24eb..d4015c3c9 100644 --- a/packages/ava/src/insight/types.ts +++ b/packages/ava/src/insight/types.ts @@ -286,7 +286,7 @@ export type InsightsResult = { export type SpecificInsightProps = InsightExtractorProps; -export type SpecificInsightResult = InsightInfo & { +export type SpecificInsightResult = Omit, 'score'> & { visualizationSpecs: Required[]; }; From c70fffd874c28cdda5203033e9461f4f03c8702e Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Mon, 13 Nov 2023 15:19:46 +0800 Subject: [PATCH 11/17] chore(ava): release 3.3.0-beta.2 --- packages/ava/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ava/package.json b/packages/ava/package.json index 683f614f3..53d627e29 100644 --- a/packages/ava/package.json +++ b/packages/ava/package.json @@ -1,6 +1,6 @@ { "name": "@antv/ava", - "version": "3.3.0-beta.1", + "version": "3.3.0-beta.2", "description": "A framework for automated visual analytics.", "author": { "name": "AntV", From ac52002d397ccd3e4184807f4354b3889ce4e68c Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Mon, 13 Nov 2023 16:11:26 +0800 Subject: [PATCH 12/17] fix(ava/insight): add default value to visualizationOptions --- packages/ava/src/insight/pipeline/specificInsight.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ava/src/insight/pipeline/specificInsight.ts b/packages/ava/src/insight/pipeline/specificInsight.ts index 258c0358d..ebfa14bfe 100644 --- a/packages/ava/src/insight/pipeline/specificInsight.ts +++ b/packages/ava/src/insight/pipeline/specificInsight.ts @@ -40,7 +40,7 @@ export const getAnnotationSpec = (insightInfo: InsightInfo): Augmen }; export const getSpecificInsight = (props: SpecificInsightProps): SpecificInsightResult => { - const { visualizationOptions } = props.options || {}; + const { visualizationOptions = { lang: 'zh-CN' } } = props.options || {}; const patternInfos = insightPatternsExtractor(props); const insightInfo = patternInfo2InsightInfo({ ...props, patternInfos }); const annotationSpec = getAnnotationSpec(insightInfo); From a67e69b70abbe494c6e3b9749e2c337c1b03dac1 Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Mon, 13 Nov 2023 18:02:44 +0800 Subject: [PATCH 13/17] fix(ava/insight): only generate annotationSpec for valid patternInfo --- .../chart/strategy/commonMarks/pointMark.ts | 7 +- packages/ava/src/insight/insights/util.ts | 11 +++- .../src/insight/pipeline/specificInsight.ts | 66 +++++++++++++------ packages/ava/src/insight/types.ts | 4 +- 4 files changed, 62 insertions(+), 26 deletions(-) diff --git a/packages/ava/src/insight/chart/strategy/commonMarks/pointMark.ts b/packages/ava/src/insight/chart/strategy/commonMarks/pointMark.ts index 2aa72e32a..a412510a4 100644 --- a/packages/ava/src/insight/chart/strategy/commonMarks/pointMark.ts +++ b/packages/ava/src/insight/chart/strategy/commonMarks/pointMark.ts @@ -1,11 +1,16 @@ import { Mark } from '@antv/g2'; +import { isNil } from 'lodash'; import { PointPatternInfo } from '../../../types'; import { PointMarkConfig } from '../../types'; /** get mark for point patterns, the patterns should have same dimension and measure */ export const pointMarkStrategy = (patterns: PointPatternInfo[], config: PointMarkConfig): Mark => { - const data = patterns.map(({ x, y }) => ({ x, y })); + const data = []; + patterns.forEach(({ x, y }) => { + if (isNil(x) || isNil(y)) return; + data.push({ x, y }); + }); const pointMark: Mark = { type: 'point', diff --git a/packages/ava/src/insight/insights/util.ts b/packages/ava/src/insight/insights/util.ts index 6eeba82a2..a284925d0 100644 --- a/packages/ava/src/insight/insights/util.ts +++ b/packages/ava/src/insight/insights/util.ts @@ -1,4 +1,4 @@ -import { mean } from 'lodash'; +import { isNil, mean } from 'lodash'; import { standardDeviation, cdf, normalDistributionQuantile, max, min } from '../../data'; import { @@ -9,6 +9,7 @@ import { NoPatternInfo, PatternInfo, PreValidationProps, + TimeSeriesOutlierInfo, } from '../types'; import { dataToDataProps } from '../pipeline/preprocess'; import { NO_PATTERN_INFO, VERIFICATION_FAILURE_INFO } from '../constant'; @@ -49,8 +50,8 @@ export const getAlgorithmCommonInput = ({ dimensions, measures, }: InsightExtractorProps): AlgorithmStandardInput => { - const dimension = dimensions[0]?.fieldName; - const measure = measures[0]?.fieldName; + const dimension = dimensions?.[0]?.fieldName; + const measure = measures?.[0]?.fieldName; const values = data.map((item) => item?.[measure] as number); return { dimension, measure, values }; }; @@ -107,3 +108,7 @@ export const getNonSignificantInsight = ({ export const pickValidPattern = (infos: PatternInfo[] = []): PatternInfo[] => { return infos.filter((info) => info.significantInsight); }; + +export const pickValidTimeSeriesOutlierPatterns = (infos: TimeSeriesOutlierInfo[] = []): TimeSeriesOutlierInfo[] => { + return infos.filter((info) => ![info.baselines, info.thresholds, info.x].every(isNil)); +}; diff --git a/packages/ava/src/insight/pipeline/specificInsight.ts b/packages/ava/src/insight/pipeline/specificInsight.ts index ebfa14bfe..fa8189649 100644 --- a/packages/ava/src/insight/pipeline/specificInsight.ts +++ b/packages/ava/src/insight/pipeline/specificInsight.ts @@ -1,23 +1,28 @@ +import { size } from 'lodash'; + import { generateInsightChartSpec, changePointAugmentedMarksStrategy, trendAugmentedMarksStrategy, timeSeriesOutlierStrategyAugmentedMarksStrategy, AugmentedMarks, + lowVarianceAugmentedMarkStrategy, + categoryOutlierAugmentedMarksStrategy, } from '../chart'; import { insightPatternsExtractor } from '../insights'; import { InsightInfo, + InsightType, PatternInfo, PatternInfo2InsightInfoProps, SpecificInsightProps, SpecificInsightResult, + TimeSeriesOutlierInfo, } from '../types'; import generateInsightNarrative from '../narrative'; +import { pickValidPattern, pickValidTimeSeriesOutlierPatterns } from '../insights/util'; -export const patternInfo2InsightInfo = ( - props: PatternInfo2InsightInfoProps -): Omit, 'score'> => { +export const patternInfo2InsightInfo = (props: PatternInfo2InsightInfoProps): SpecificInsightResult => { const { dimensions, measures, data, patternInfos } = props; return { subspace: [], @@ -29,33 +34,54 @@ export const patternInfo2InsightInfo = ( }; export const getAnnotationSpec = (insightInfo: InsightInfo): AugmentedMarks => { - const { type: insightType } = insightInfo.patterns[0]; + const { type: insightType } = insightInfo.patterns[0] ?? {}; const insightType2AugmentedMarks = { trend: trendAugmentedMarksStrategy, change_point: changePointAugmentedMarksStrategy, time_series_outlier: timeSeriesOutlierStrategyAugmentedMarksStrategy, + low_variance: lowVarianceAugmentedMarkStrategy, + category_outlier: categoryOutlierAugmentedMarksStrategy, }; return insightType2AugmentedMarks[insightType]?.(insightInfo); }; +export const filterValidInsightInfoForAnnotationSpec = ({ + patternInfos = [], + insightType, +}: { + patternInfos: PatternInfo[]; + insightType: InsightType; +}) => { + if (insightType === 'time_series_outlier') + return pickValidTimeSeriesOutlierPatterns(patternInfos as TimeSeriesOutlierInfo[]); + return pickValidPattern(patternInfos); +}; + export const getSpecificInsight = (props: SpecificInsightProps): SpecificInsightResult => { - const { visualizationOptions = { lang: 'zh-CN' } } = props.options || {}; + const { options = {}, insightType } = props; + const { visualizationOptions = { lang: 'zh-CN' } } = options; const patternInfos = insightPatternsExtractor(props); - const insightInfo = patternInfo2InsightInfo({ ...props, patternInfos }); - const annotationSpec = getAnnotationSpec(insightInfo); - const chartSpec = generateInsightChartSpec(insightInfo); - const narrativeSpec = generateInsightNarrative(insightInfo, visualizationOptions); + const validPatternInfos = filterValidInsightInfoForAnnotationSpec({ patternInfos, insightType }); + const totalInsightInfo = patternInfo2InsightInfo({ ...props, patternInfos }); - return { - ...insightInfo, - visualizationSpecs: [ - { - annotationSpec, - chartSpec, - patternType: props.insightType, - narrativeSpec, - }, - ], - }; + if (size(validPatternInfos)) { + const validInsightInfo = patternInfo2InsightInfo({ ...props, patternInfos: validPatternInfos }); + const annotationSpec = getAnnotationSpec(validInsightInfo); + const chartSpec = generateInsightChartSpec(validInsightInfo); + const narrativeSpec = generateInsightNarrative(validInsightInfo, visualizationOptions); + return { + ...totalInsightInfo, + visualizationSpecs: [ + { + annotationSpec, + chartSpec, + patternType: props.insightType, + narrativeSpec, + }, + ], + }; + } + + return { ...totalInsightInfo }; }; diff --git a/packages/ava/src/insight/types.ts b/packages/ava/src/insight/types.ts index d4015c3c9..0f0b8577b 100644 --- a/packages/ava/src/insight/types.ts +++ b/packages/ava/src/insight/types.ts @@ -286,8 +286,8 @@ export type InsightsResult = { export type SpecificInsightProps = InsightExtractorProps; -export type SpecificInsightResult = Omit, 'score'> & { - visualizationSpecs: Required[]; +export type SpecificInsightResult = Omit, 'score' | 'visualizationSpecs'> & { + visualizationSpecs?: Required[]; }; export type PatternInfo2InsightInfoProps = SpecificInsightProps & { From 979f9ecf0d30b86da1bec4e504f40315f5c422f1 Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Tue, 14 Nov 2023 11:18:42 +0800 Subject: [PATCH 14/17] fix(ava/insight): generate chartSpec for all patternInfos --- .../src/insight/pipeline/specificInsight.ts | 23 ++++++++++++++++--- packages/ava/src/insight/types.ts | 4 +--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/packages/ava/src/insight/pipeline/specificInsight.ts b/packages/ava/src/insight/pipeline/specificInsight.ts index fa8189649..98ab6010a 100644 --- a/packages/ava/src/insight/pipeline/specificInsight.ts +++ b/packages/ava/src/insight/pipeline/specificInsight.ts @@ -1,4 +1,5 @@ import { size } from 'lodash'; +import { G2Spec } from '@antv/g2'; import { generateInsightChartSpec, @@ -21,8 +22,9 @@ import { } from '../types'; import generateInsightNarrative from '../narrative'; import { pickValidPattern, pickValidTimeSeriesOutlierPatterns } from '../insights/util'; +import { insight2ChartStrategy, viewSpecStrategy } from '../chart/strategy'; -export const patternInfo2InsightInfo = (props: PatternInfo2InsightInfoProps): SpecificInsightResult => { +export const patternInfo2InsightInfo = (props: PatternInfo2InsightInfoProps): InsightInfo => { const { dimensions, measures, data, patternInfos } = props; return { subspace: [], @@ -46,6 +48,11 @@ export const getAnnotationSpec = (insightInfo: InsightInfo): Augmen return insightType2AugmentedMarks[insightType]?.(insightInfo); }; +export const getChartSpecWithoutAugmentedMarks = (insightInfo: InsightInfo): G2Spec => { + const chartMark = insight2ChartStrategy(insightInfo); + return viewSpecStrategy([chartMark], insightInfo); +}; + export const filterValidInsightInfoForAnnotationSpec = ({ patternInfos = [], insightType, @@ -76,12 +83,22 @@ export const getSpecificInsight = (props: SpecificInsightProps): SpecificInsight { annotationSpec, chartSpec, - patternType: props.insightType, + patternType: insightType, narrativeSpec, }, ], }; } - return { ...totalInsightInfo }; + const chartSpec = getChartSpecWithoutAugmentedMarks(totalInsightInfo); + + return { + ...totalInsightInfo, + visualizationSpecs: [ + { + chartSpec, + patternType: insightType, + }, + ], + }; }; diff --git a/packages/ava/src/insight/types.ts b/packages/ava/src/insight/types.ts index 0f0b8577b..9f82d4a04 100644 --- a/packages/ava/src/insight/types.ts +++ b/packages/ava/src/insight/types.ts @@ -286,9 +286,7 @@ export type InsightsResult = { export type SpecificInsightProps = InsightExtractorProps; -export type SpecificInsightResult = Omit, 'score' | 'visualizationSpecs'> & { - visualizationSpecs?: Required[]; -}; +export type SpecificInsightResult = Required, 'score'>>; export type PatternInfo2InsightInfoProps = SpecificInsightProps & { patternInfos: PatternInfo[]; From 07e824ec5a1f6f65df88cb57d222baa72214a677 Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Tue, 14 Nov 2023 15:38:29 +0800 Subject: [PATCH 15/17] chore(ava): release 3.3.0-beta.3 --- packages/ava/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ava/package.json b/packages/ava/package.json index 53d627e29..261731967 100644 --- a/packages/ava/package.json +++ b/packages/ava/package.json @@ -1,6 +1,6 @@ { "name": "@antv/ava", - "version": "3.3.0-beta.2", + "version": "3.3.0-beta.3", "description": "A framework for automated visual analytics.", "author": { "name": "AntV", From 37b0e96ee226460522d5aa53d62d125f9ab52f7d Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Tue, 14 Nov 2023 18:31:53 +0800 Subject: [PATCH 16/17] fix(ava/insight): correct sign of regression line & format the mean in lowVarianceMark --- .../insight/chart/strategy/augmentedMarks/lowVariance.ts | 5 +++-- .../ava/src/insight/chart/strategy/augmentedMarks/trend.ts | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/lowVariance.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/lowVariance.ts index 1d6317c29..747525f98 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/lowVariance.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/lowVariance.ts @@ -1,17 +1,18 @@ -import { Mark } from '@antv/g2'; +import { LineMark, Mark } from '@antv/g2'; import { LowVarianceInfo, InsightInfo } from '../../../types'; import { lineMarkStrategy } from '../commonMarks'; import { insight2ChartStrategy } from '../chart'; import { LowVarianceMark } from '../../types'; import { augmentedMarks2Marks } from '../../utils'; +import { dataFormat } from '../../../../utils'; export const lowVarianceAugmentedMarkStrategy = (insight: InsightInfo): LowVarianceMark[] => { const { patterns } = insight; const marks: LowVarianceMark[] = []; patterns.forEach((pattern) => { const { mean } = pattern; - const meanLineMark = lineMarkStrategy({ y: mean }, { label: `mean: ${mean}` }); + const meanLineMark = lineMarkStrategy({ y: mean }, { label: `mean: ${dataFormat(mean)}` }) as LineMark; marks.push({ meanLine: [meanLineMark], }); diff --git a/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts b/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts index b9fce2986..338988e63 100644 --- a/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts +++ b/packages/ava/src/insight/chart/strategy/augmentedMarks/trend.ts @@ -4,6 +4,7 @@ import { lineMarkStrategy } from '../commonMarks'; import { insight2ChartStrategy } from '../chart'; import { InsightInfo, TrendInfo } from '../../../types'; import { TrendMark } from '../../types'; +import { dataFormat } from '../../../../utils'; export const trendAugmentedMarksStrategy = (insight: InsightInfo): TrendMark[] => { const { @@ -28,7 +29,10 @@ export const trendAugmentedMarksStrategy = (insight: InsightInfo): Tr const lineData = points.map((point) => ({ x: point[0], y: point[1] })); - const regressionLineMark = lineMarkStrategy({ points: lineData }, { label: `y=${m.toFixed(2)}x+${c.toFixed(2)}` }); + const regressionLineMark = lineMarkStrategy( + { points: lineData }, + { label: `y=${dataFormat(m)}x${c < 0 ? '' : '+'}${dataFormat(c)}` } + ); return [ { From c291bc7f3effb403bafb68eb235142c43278e9ed Mon Sep 17 00:00:00 2001 From: "laixingui.lxg" Date: Thu, 16 Nov 2023 14:05:59 +0800 Subject: [PATCH 17/17] chore(ava): release v3.3.0 --- packages/ava/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ava/package.json b/packages/ava/package.json index 261731967..eda3c81a1 100644 --- a/packages/ava/package.json +++ b/packages/ava/package.json @@ -1,6 +1,6 @@ { "name": "@antv/ava", - "version": "3.3.0-beta.3", + "version": "3.3.0", "description": "A framework for automated visual analytics.", "author": { "name": "AntV",