diff --git a/packages/vmind/__tests__/browser/src/constants/mockData.ts b/packages/vmind/__tests__/browser/src/constants/mockData.ts index 5cbf1e7..3eced4b 100644 --- a/packages/vmind/__tests__/browser/src/constants/mockData.ts +++ b/packages/vmind/__tests__/browser/src/constants/mockData.ts @@ -185,7 +185,7 @@ export const mockUserInput6 = { 比利时,欧洲,53840,2018 挪威,欧洲,48930,2018 `, - input: '帮我展示各国GDP排名变化' + input: '使用动态条形图帮我展示各国GDP排名变化' }; /* @@ -4766,7 +4766,7 @@ export const bubbleCirclePackingData = { 房地产业,73821.3 其他,279918.4 `, - input: '请使用气泡图帮我绘制' + input: '请使用气泡圈图帮我绘制' }; export const mapChartData = { @@ -5076,7 +5076,7 @@ analytics,cluster,HierarchicalCluster,,6714 analytics,cluster,MergeEdge,,743 analytics,optimization,AspectRatioBanker,,7074 flex,FlareVis,,,4116`, - input: '请使用矩形树图渲染数据' + input: '请使用矩形树图渲染数据的层次结构' }; export const gaugeChartData = { @@ -5398,7 +5398,7 @@ export const singleColumnLineCombinationChartData = { 2022-09-01,0.259653267575217,2.040817156148029,2.19857288799284,2.229208371156883 2022-09-02,1.398428414171018,0.071469482611002,0.9048807067534731,0.0022491420541680004 2022-09-03,1.7166677805176591,1.903668070163285,1.866568462888393,1.8648831840830011`, - input: '请使用四个折线的组合图展示不同类别的权重随着时间的变化' + input: '请使用四个独立的折线的组合图展示不同类别的权重随着时间的变化' }; export const singleColumnLineCombinationChartData1 = { @@ -5594,7 +5594,7 @@ east,1027,654,654,830 west,1027,159,2100,532 north,1027,28,1679,498 `, - input: '帮我使用四个柱图的组合展示不同区域各商品销售额' + input: '帮我使用四个不同柱图的组合展示四个区域上不同商品销售额' }; export const singleColumnBarCombinationChartData1 = { @@ -5779,7 +5779,7 @@ export const singleColumnBarCombinationChartData1 = { 2022-09-01,0.259653267575217,2.040817156148029,2.19857288799284,2.229208371156883 2022-09-02,1.398428414171018,0.071469482611002,0.9048807067534731,0.0022491420541680004 2022-09-03,1.7166677805176591,1.903668070163285,1.866568462888393,1.8648831840830011`, - input: '请使用组合图展示不同类别的权重随着时间的变化,用四个柱图。' + input: '请使用四个独立柱图的组合图展示前十天不同类别的权重随着时间的变化。' }; export const dynamicScatterPlotData = { @@ -9737,6 +9737,120 @@ Italy,10,2020`, input: '使用动态玫瑰图帮我展示各国GDP排名变化' }; +export const sequenceData = { + csv: `playName,time,eventType +Deandre Ayton,-2209017943000,start +Deandre Ayton,-2209017476000,end +Deandre Ayton,-2209016998000,start +Deandre Ayton,-2209016057000,end +Deandre Ayton,-2209015551000,start +Deandre Ayton,-2209015127000,end +Deandre Ayton,-2209015116000,start +Deandre Ayton,-2209015063000,end +Devin Booker,-2209017943000,start +Devin Booker,-2209017293000,end +Devin Booker,-2209016892000,start +Devin Booker,-2209015783000,end +Devin Booker,-2209015380000,start +Devin Booker,-2209015063000,end +Kyle Lowry,-2209017943000,start +Kyle Lowry,-2209017476000,end +Kyle Lowry,-2209017223000,start +Kyle Lowry,-2209016762000,end +Kyle Lowry,-2209016614000,start +Kyle Lowry,-2209016057000,end +Kyle Lowry,-2209015884000,start +Kyle Lowry,-2209015063000,end +Jae Crowder,-2209017943000,start +Jae Crowder,-2209017293000,end +Jae Crowder,-2209016998000,start +Jae Crowder,-2209016139000,end +Jae Crowder,-2209015651000,start +Jae Crowder,-2209015063000,end +Aron Baynes,-2209017943000,start +Aron Baynes,-2209017476000,end +Aron Baynes,-2209016503000,start +Aron Baynes,-2209016166000,end +Pascal Siakam,-2209016892000,start +Pascal Siakam,-2209015788000,end +Pascal Siakam,-2209015528000,start +Pascal Siakam,-2209015063000,end +Pascal Siakam,-2209017943000,start +Pascal Siakam,-2209017223000,end +Mikal Bridges,-2209017943000,start +Mikal Bridges,-2209017650000,end +Mikal Bridges,-2209016998000,start +Mikal Bridges,-2209016762000,end +Mikal Bridges,-2209016503000,start +Mikal Bridges,-2209016003000,end +Mikal Bridges,-2209015783000,start +Mikal Bridges,-2209015063000,end +Chris Paul,-2209017943000,start +Chris Paul,-2209017476000,end +Chris Paul,-2209016998000,start +Chris Paul,-2209016057000,end +Chris Paul,-2209015551000,start +Chris Paul,-2209015063000,end +OG Anunoby,-2209017943000,start +OG Anunoby,-2209017476000,end +OG Anunoby,-2209017223000,start +OG Anunoby,-2209016614000,end +OG Anunoby,-2209016503000,start +OG Anunoby,-2209016021000,end +OG Anunoby,-2209015788000,start +OG Anunoby,-2209015063000,end +Fred VanVleet,-2209016892000,start +Fred VanVleet,-2209015884000,end +Fred VanVleet,-2209015651000,start +Fred VanVleet,-2209015063000,end +Fred VanVleet,-2209017943000,start +Fred VanVleet,-2209017223000,end +Cameron Johnson,-2209017650000,start +Cameron Johnson,-2209016998000,end +Cameron Johnson,-2209016762000,start +Cameron Johnson,-2209016503000,end +Cameron Johnson,-2209016139000,start +Cameron Johnson,-2209015651000,end +Yuta Watanabe,-2209017476000,start +Yuta Watanabe,-2209016892000,end +Yuta Watanabe,-2209016021000,start +Yuta Watanabe,-2209015651000,end +Dario Saric,-2209017476000,start +Dario Saric,-2209016998000,end +Dario Saric,-2209016057000,start +Dario Saric,-2209015551000,end +Dario Saric,-2209015127000,start +Dario Saric,-2209015116000,end +Chris Boucher,-2209017476000,start +Chris Boucher,-2209016998000,end +Chris Boucher,-2209015962000,start +Chris Boucher,-2209015528000,end +Norman Powell,-2209017476000,start +Norman Powell,-2209017119000,end +Norman Powell,-2209016762000,start +Norman Powell,-2209016547000,end +Norman Powell,-2209016057000,start +Norman Powell,-2209015063000,end +Cameron Payne,-2209017476000,start +Cameron Payne,-2209016998000,end +Cameron Payne,-2209016057000,start +Cameron Payne,-2209015551000,end +Langston Galloway,-2209017293000,start +Langston Galloway,-2209016998000,end +Jevon Carter,-2209017293000,start +Jevon Carter,-2209016892000,end +Jevon Carter,-2209016003000,start +Jevon Carter,-2209015380000,end +Malachi Flynn,-2209017119000,start +Malachi Flynn,-2209016892000,end +Alex Len,-2209016998000,start +Alex Len,-2209016503000,end +Alex Len,-2209016166000,start +Alex Len,-2209015962000,end +DeAndre' Bembry,-2209016547000,start +DeAndre' Bembry,-2209015783000,end`, + input: '使用时序图帮我展示各运动员在比赛中的行动记录。' +}; export const mockUserTextInput0 = { text: `快手消失了。快手上市后,市值一度超过2000亿美元,现在只剩200多亿美元。去年快手的营收破了千亿,公司也赚钱了,但市场不买账了。 滴滴也不见了。滴滴去年营收接近2000亿元,并首次实现年度盈利,不过滴滴从美股退市后,一直没在港股上市,所以没有市值参考。`, diff --git a/packages/vmind/__tests__/browser/src/pages/ChartGeneration/DataInput.tsx b/packages/vmind/__tests__/browser/src/pages/ChartGeneration/DataInput.tsx index e744de0..7a4caab 100644 --- a/packages/vmind/__tests__/browser/src/pages/ChartGeneration/DataInput.tsx +++ b/packages/vmind/__tests__/browser/src/pages/ChartGeneration/DataInput.tsx @@ -56,7 +56,8 @@ import { singleColumnBarCombinationChartData, dynamicScatterPlotData, dynamicRoseData, - dynamicRoseData1 + dynamicRoseData1, + sequenceData } from '../../constants/mockData'; import VMind, { ArcoTheme, builtinThemeMap, BuiltinThemeType } from '../../../../../src/index'; import { Model } from '../../../../../src/index'; @@ -120,7 +121,8 @@ const demoDataList: { [key: string]: any } = { SingleColumnBarCommon1: singleColumnBarCombinationChartData1, dynamicScatterPlotData: dynamicScatterPlotData, dynamicRoseData: dynamicRoseData, - dynamicRoseData1: dynamicRoseData1 + dynamicRoseData1: dynamicRoseData1, + sequenceData: sequenceData }; const globalVariables = (import.meta as any).env; diff --git a/packages/vmind/src/applications/chartGeneration/constants.ts b/packages/vmind/src/applications/chartGeneration/constants.ts index d666f06..c1a29d4 100644 --- a/packages/vmind/src/applications/chartGeneration/constants.ts +++ b/packages/vmind/src/applications/chartGeneration/constants.ts @@ -5,9 +5,14 @@ export const SUPPORTED_CHART_LIST = Object.values(ChartType); export const COMBINATION_BASIC_CHART_LIST = Object.values(CombinationBasicChartType); export const COMBINATION_CHART_LIST = Object.values(CombinationChartType); -export const NEED_COLOR_FIELD_CHART_LIST = [ChartType.PieChart, ChartType.RoseChart, ChartType.LinearProgress]; +export const NEED_COLOR_FIELD_CHART_LIST = [ + ChartType.PieChart, + ChartType.RoseChart, + ChartType.LinearProgress, + ChartType.CircularProgress +]; -export const NEED_SIZE_FIELD_CHART_LIST = [ChartType.ScatterPlot, ChartType.BasicHeatMap, ChartType.LiquidChart]; +export const NEED_SIZE_FIELD_CHART_LIST = [ChartType.ScatterPlot, ChartType.BasicHeatMap]; export const NEED_COLOR_AND_SIZE_CHART_LIST = [ ChartType.WordCloud, @@ -16,8 +21,7 @@ export const NEED_COLOR_AND_SIZE_CHART_LIST = [ ChartType.VennChart, ChartType.Gauge, ChartType.SunburstChart, - ChartType.TreemapChart, - ChartType.CircularProgress + ChartType.TreemapChart ]; export const CARTESIAN_CHART_LIST = [ @@ -34,10 +38,11 @@ export const CARTESIAN_CHART_LIST = [ ChartType.BasicHeatMap ]; -export const DYNAMIC_CHART_LIST = [ +export const TIME_SERIES_CHART_LIST = [ ChartType.DynamicBarChart, ChartType.DynamicScatterPlotChart, - ChartType.DynamicRoseChart + ChartType.DynamicRoseChart, + ChartType.SequenceChart ]; export const DEFAULT_MAP_OPTION: BasemapOption = { diff --git a/packages/vmind/src/applications/chartGeneration/taskNodes/generateChartType/skylark/prompt/knowledge.ts b/packages/vmind/src/applications/chartGeneration/taskNodes/generateChartType/skylark/prompt/knowledge.ts index aced930..c82fed1 100644 --- a/packages/vmind/src/applications/chartGeneration/taskNodes/generateChartType/skylark/prompt/knowledge.ts +++ b/packages/vmind/src/applications/chartGeneration/taskNodes/generateChartType/skylark/prompt/knowledge.ts @@ -92,20 +92,18 @@ export const chartKnowledgeBase: ChartKnowledgeBase = { }, [ChartType.SunburstChart]: { knowledge: [ - 'Sunburst Charts are excellent for visualizing hierarchical data, allowing users to see relationships between categories and subcategories at varying levels of detail.', - 'The colors field for sunburst chart and treemap chart must be an array. The order of the elements in the array needs to be sorted from large to small according to the coverage described by the data field.' + 'Sunburst Charts are excellent for visualizing hierarchical data, allowing users to see relationships between categories and subcategories at varying levels of detail.' ] }, [ChartType.TreemapChart]: { knowledge: [ - 'Treemap Charts are effective for displaying large amounts of hierarchical data in a compact space, where areas represent the size of each category.', - 'The colors field for sunburst chart and treemap chart must be an array. The order of the elements in the array needs to be sorted from large to small according to the coverage described by the data field.' + 'Treemap Charts are effective for displaying large amounts of hierarchical data in a compact space, where areas represent the size of each category.' ] }, [ChartType.Gauge]: { knowledge: [ - 'Gauge Charts are useful for displaying performance metrics against a target, providing a quick visual summary at a glance.', - 'The gauge chart must contain two fields: size and color.' + 'Gauge Charts are useful for displaying performance metrics against a target.', + 'If you want to display a dashboard, use a Gauge Chart.' ] }, [ChartType.BasicHeatMap]: { @@ -115,8 +113,7 @@ export const chartKnowledgeBase: ChartKnowledgeBase = { }, [ChartType.VennChart]: { knowledge: [ - 'Venn Charts are useful for displaying the relationships between different groups, emphasizing similarities and differences visually.', - 'The color field of the Venn diagram requires an array of length 2. The field with subscript 0 maps to the sets, and the field with subscript 1 maps to the name.' + 'Venn Charts are useful for displaying the relationships between different groups, emphasizing similarities and differences visually.' ] }, [ChartType.SingleColumnCombinationChart]: { @@ -134,11 +131,20 @@ export const chartKnowledgeBase: ChartKnowledgeBase = { }, [ChartType.DynamicRoseChart]: { knowledge: [ - 'Dynamic Rose Chart is used to display cyclical or seasonal data over time, with values represented by the length of radial bars.', - 'Dynamic Rose Chart highlights changes in categorical data or periodic trends across multiple categories over time.' + 'Dynamic Rose Chart is used to display cyclical or seasonal data over time, with values represented by the length of radial bars.' ], constraints: [ 'Use Dynamic Rose Chart if you want to show cyclical data and observe changes in multiple categories over time.' ] + }, + [ChartType.SequenceChart]: { + knowledge: [ + 'Sequence Chart visualizes events in chronological order along a time axis.', + 'Sequence Chart is ideal for showing the progression of time-based events.' + ], + constraints: [ + 'Use Sequence Chart when the data contains a sequence of events that are ordered by time.', + 'Sequence Chart requires a continuous time field in the data for accurate rendering.' + ] } }; diff --git a/packages/vmind/src/applications/chartGeneration/taskNodes/generateFieldMap/skylark/prompt/knowledge.ts b/packages/vmind/src/applications/chartGeneration/taskNodes/generateFieldMap/skylark/prompt/knowledge.ts index bac963a..13a5df1 100644 --- a/packages/vmind/src/applications/chartGeneration/taskNodes/generateFieldMap/skylark/prompt/knowledge.ts +++ b/packages/vmind/src/applications/chartGeneration/taskNodes/generateFieldMap/skylark/prompt/knowledge.ts @@ -312,17 +312,16 @@ export const ChartFieldInfo: ChannelInfo = { size: 'field assigned to size channel' }, knowledge: [ - 'The color field for treemap chart must be an array. The order of the elements in the array needs to be sorted from large to small according to the coverage described by the data field.' + 'The color field must be an array sorted from large to small according to the coverage described by the data field.' ] }, [ChartType.Gauge.toUpperCase()]: { visualChannels: { - color: - 'color channel of gauge chart. Used to represent the current value against a range. Must be a string field.', + color: 'color channel of gauge chart. Must be a string field.', size: "size channel of gauge chart. Represents a numeric value indicating the current state. Can't be empty." }, responseDescription: { - color: 'field assigned to color channel', + color: 'field assigned to color channel. Often used to distinguish themes.', size: 'field assigned to size channel' }, knowledge: [ @@ -406,5 +405,23 @@ export const ChartFieldInfo: ChannelInfo = { 'All visual channels must reflect the structure of the data presented.', 'Dynamic Rose Chart is useful for visualizing cyclical patterns, where radius represents the magnitude, color distinguishes categories, and time drives the dynamic updates.' ] + }, + [ChartType.SequenceChart.toUpperCase()]: { + visualChannels: { + group: + "group channel of sequence chart. Represents the initiator of the timeline or event, showing which entity or individual is involved in each sequence. Can't be empty.", + time: "time channel of sequence chart. Represents the timeline or time series, displaying the chronological order of events. This is essential for showing when events occur. Often a numeric value. Can't be empty.", + color: + 'color channel of sequence chart. Differentiates the types or categories of events within the timeline. It is useful for distinguishing between different types of events in the sequence. For example: start or end' + }, + responseDescription: { + group: 'field assigned to group channel, representing the initiator of the timeline or event', + time: 'field assigned to time channel, typically used for time progression', + color: 'field assigned to color channel, representing event types' + }, + knowledge: [ + 'Sequence charts are ideal for displaying event sequences over time, where the time-axis represents time progression, the group-axis shows the initiator of the timeline, and color helps distinguish between event types.', + 'This chart is useful for visualizing workflows, event timelines, or sequences where time, initiators, and event types need to be clearly represented.' + ] } }; diff --git a/packages/vmind/src/applications/chartGeneration/taskNodes/generateFieldMap/skylark/prompt/template.ts b/packages/vmind/src/applications/chartGeneration/taskNodes/generateFieldMap/skylark/prompt/template.ts index 8325c59..f3fb48e 100644 --- a/packages/vmind/src/applications/chartGeneration/taskNodes/generateFieldMap/skylark/prompt/template.ts +++ b/packages/vmind/src/applications/chartGeneration/taskNodes/generateFieldMap/skylark/prompt/template.ts @@ -18,7 +18,7 @@ Your task is: 1. Filter out useful fields related to user's command. 2. Assign the useful fields to the available visual channels according to field name and type. 3. If the chart type is a combination chart, the above two steps need to be repeated for each sub-chart generation task of the combination chart. The number of mapping relationships of visual channels in the response needs to be consistent with the number of sub-charts generated. -4. The response is an array in YAML format without any additional descriptions. +4. The outermost structure of the response must be an array in YAML format without any additional descriptions. The YAML array must be generated strictly according to the corresponding format at the end of the prompt, and special attention should be paid to the length of the array and the meaning of the elements in the array. Available visual channels: ${availableChannels} diff --git a/packages/vmind/src/applications/chartGeneration/taskNodes/generateTypeAndFieldMap/GPT/prompt/knowledges.ts b/packages/vmind/src/applications/chartGeneration/taskNodes/generateTypeAndFieldMap/GPT/prompt/knowledges.ts index 87d866e..b2beef3 100644 --- a/packages/vmind/src/applications/chartGeneration/taskNodes/generateTypeAndFieldMap/GPT/prompt/knowledges.ts +++ b/packages/vmind/src/applications/chartGeneration/taskNodes/generateTypeAndFieldMap/GPT/prompt/knowledges.ts @@ -7,7 +7,7 @@ import { NEED_COLOR_FIELD_CHART_LIST, NEED_SIZE_FIELD_CHART_LIST, NEED_COLOR_AND_SIZE_CHART_LIST, - DYNAMIC_CHART_LIST + TIME_SERIES_CHART_LIST } from '../../../../constants'; const getColorKnowledge = (chartTypeList: ChartType[]) => { @@ -93,7 +93,7 @@ export const visualChannelInfoMap = { }, time: (chartTypeList: ChartType[]) => { return { - singleFieldInfo: `This is usually a date field and cannot be empty in all dynamic chart types. For example, ${DYNAMIC_CHART_LIST.join( + singleFieldInfo: `This is usually a date field and cannot be empty in all dynamic chart types. For example, ${TIME_SERIES_CHART_LIST.join( ',' )}.` }; @@ -115,6 +115,12 @@ export const visualChannelInfoMap = { singleFieldInfo: "the field mapped to the value channel. Only used in Sankey Chart. Can't be empty in Sankey Chart." }; + }, + group: (chartTypeList: ChartType[]) => { + return { + singleFieldInfo: + "the field mapped to the group channel. Only used in Sequence Chart. Can't be empty in Sequence Chart." + }; } }; export const chartKnowledgeDict: ChartKnowledge = { @@ -194,7 +200,7 @@ export const chartKnowledgeDict: ChartKnowledge = { }, [ChartType.LiquidChart]: { index: 14, - visualChannels: ['x', 'y'], + visualChannels: ['value'], examples: [], knowledge: [ 'Liquid chart is used to display a single value, with the value range typically from 0 to 1. The value usually represents progress, completion, or percentage, and is associated with only one field' @@ -210,7 +216,7 @@ export const chartKnowledgeDict: ChartKnowledge = { }, [ChartType.CircularProgress]: { index: 16, - visualChannels: ['x', 'y'], + visualChannels: ['color', 'value'], examples: [], knowledge: [ 'Circular progress chart is also used to display progress data, presented in a circular form, with the values on the numerical axis typically ranging from 0 to 1.' @@ -258,7 +264,7 @@ export const chartKnowledgeDict: ChartKnowledge = { index: 23, visualChannels: ['y', 'x', 'size'], examples: [], - knowledge: [] + knowledge: ['The three channels that need to be mapped in the Basic Heat Map are: x, y, size;'] }, [ChartType.VennChart]: { index: 24, @@ -279,7 +285,7 @@ export const chartKnowledgeDict: ChartKnowledge = { visualChannels: ['x', 'y', 'color', 'size', 'time'], examples: [], knowledge: [ - 'The five channels that need to be mapped in the dynamic scatter plot are: x, y, color, size, and time; the x, y, and size channels require numeric data fields; the time field must be mapped.' + 'The five channels that need to be mapped in the dynamic scatter plot are: x, y, color, size, and time; the x, y, and size channels require numeric data fields; the color channel is needed to distinguish different categories of scatter points; the time field must be mapped.' ] }, [ChartType.DynamicRoseChart]: { @@ -287,6 +293,15 @@ export const chartKnowledgeDict: ChartKnowledge = { visualChannels: ['color', 'radius', 'time'], examples: [], knowledge: ['The three channels that need to be mapped in the dynamic rose chart are: color, radius, and time;'] + }, + [ChartType.SequenceChart]: { + index: 30, + visualChannels: ['group', 'time', 'color'], + examples: [], + knowledge: [ + 'The three channels that need to be mapped in the sequence chart are: group, time, and color;', + 'The sequence chart is used to display information such as time nodes with a sequence.' + ] } }; diff --git a/packages/vmind/src/applications/chartGeneration/taskNodes/getChartSpec/VChart/chartPipeline.ts b/packages/vmind/src/applications/chartGeneration/taskNodes/getChartSpec/VChart/chartPipeline.ts index c8a31a6..cd6db20 100644 --- a/packages/vmind/src/applications/chartGeneration/taskNodes/getChartSpec/VChart/chartPipeline.ts +++ b/packages/vmind/src/applications/chartGeneration/taskNodes/getChartSpec/VChart/chartPipeline.ts @@ -88,7 +88,10 @@ import { dynamicScatterPlotTooltip, dynamicRoseAnimation, dynamicRoseField, - dynamicRoseDisplayConf + dynamicRoseDisplayConf, + sequenceChartData, + sequenceChartSeries, + sequenceChartAxes } from './transformers'; const pipelineBar = [ @@ -265,6 +268,7 @@ const pipelineDynamicRoseChart = [ customMark, theme ]; +const pipelineSequenceChart = [chartType, sequenceChartData, sequenceChartSeries, sequenceChartAxes, theme]; const pipelineMap: { [chartType: string]: any } = { [ChartType.BarChart.toUpperCase()]: pipelineBar, @@ -293,7 +297,8 @@ const pipelineMap: { [chartType: string]: any } = { [ChartType.VennChart.toUpperCase()]: pipelineVenn, [ChartType.SingleColumnCombinationChart.toUpperCase()]: pipelineSingleColumnCombinationChart, [ChartType.DynamicScatterPlotChart.toUpperCase()]: pipelineDynamicScatterPlotChart, - [ChartType.DynamicRoseChart.toUpperCase()]: pipelineDynamicRoseChart + [ChartType.DynamicRoseChart.toUpperCase()]: pipelineDynamicRoseChart, + [ChartType.SequenceChart.toUpperCase()]: pipelineSequenceChart }; export const beforePipe: Transformer = ( diff --git a/packages/vmind/src/applications/chartGeneration/taskNodes/getChartSpec/VChart/transformers.ts b/packages/vmind/src/applications/chartGeneration/taskNodes/getChartSpec/VChart/transformers.ts index 6c662ca..41caf32 100644 --- a/packages/vmind/src/applications/chartGeneration/taskNodes/getChartSpec/VChart/transformers.ts +++ b/packages/vmind/src/applications/chartGeneration/taskNodes/getChartSpec/VChart/transformers.ts @@ -20,8 +20,8 @@ import { import { getFieldByDataType } from '../../../../../common/utils/utils'; import { array, isArray } from '@visactor/vutils'; import { isValidDataset } from '../../../../../common/dataProcess'; -import type { VMindDataset } from '../../../../../common/typings'; -import { CombinationBasicChartType, ChartType, DataType } from '../../../../../common/typings'; +import type { DataItem, VMindDataset } from '../../../../../common/typings'; +import { ChartType, CombinationBasicChartType, DataType } from '../../../../../common/typings'; import { builtinThemeMap } from '../../../../../common/builtinTheme'; import { FOLD_NAME, FOLD_VALUE, COLOR_FIELD } from '@visactor/chart-advisor'; import { CARTESIAN_CHART_LIST } from '../../../constants'; @@ -59,7 +59,8 @@ const chartTypeMap: { [chartName: string]: string } = { [ChartType.VennChart.toUpperCase()]: 'venn', [ChartType.SingleColumnCombinationChart.toUpperCase()]: 'common', [ChartType.DynamicScatterPlotChart.toUpperCase()]: 'common', - [ChartType.DynamicRoseChart.toUpperCase()]: 'rose' + [ChartType.DynamicRoseChart.toUpperCase()]: 'rose', + [ChartType.SequenceChart.toUpperCase()]: 'sequence' }; export const chartType: Transformer = (context: Context) => { @@ -1303,7 +1304,7 @@ export const liquidField: Transformer = (context: C const { cells, dataset, spec } = context; const cell = getCell(cells); - spec.valueField = cell.value; + spec.valueField = (cell.value ?? cell.y ?? cell.size) as string; spec.indicatorSmartInvert = true; return { spec }; @@ -1386,7 +1387,7 @@ export const circularProgressField: Transformer = ( const cell = getCell(cells); spec.categoryField = cell.color; - spec.valueField = cell.value; + spec.valueField = (cell.value ?? cell.size) as string; spec.seriesField = cell.color; spec.radius = 0.8; @@ -1413,7 +1414,7 @@ export const indicator: Transformer = (context: Con if (!firstEntry) { return { spec }; } - const valueField = (cell.value ?? cell.y) as string; + const valueField = (cell.value ?? cell.y ?? cell.size) as string; const value = firstEntry[valueField]; const cat = firstEntry[cell.radius ?? cell.x]; @@ -2303,3 +2304,150 @@ export const dynamicRoseDisplayConf: Transformer = spec.startAngle = -90; return { spec }; }; + +export const sequenceChartData: Transformer = (context: Context) => { + const { cells, dataset, spec } = context; + const cell = getCell(cells); + const timeField = cell.time as string; + const groupField = cell.group; + const colorField = cell.color as string; + const dataMap: { [key: string]: DataItem[] } = {}; + dataset.forEach(data => { + dataMap[data[groupField]] + ? dataMap[data[groupField]].push({ ...data }) + : (dataMap[data[groupField]] = [{ ...data }]); + }); + const dataDot: { [key: string]: DataItem[] | string }[] = []; + const dataLink: { [key: string]: string | number }[] = []; + Object.keys(dataMap).forEach(key => { + const dotList = sortArray(dataMap[key], [{ field: timeField, order: SortOrder.ASC }]).map((data, index, array) => { + const newData = { ...data }; + newData.node_name = `${data[groupField]}_${Math.floor(index / 2).toString()}_${data[colorField]}_node`; + return newData; + }); + dataDot.push({ + [cell.group]: key, + dots: dotList + }); + dotList.forEach((dot, index, array) => { + if (index % 2 !== 0) { + dataLink.push({ + from: array[index - 1].node_name, + to: dot.node_name + }); + } + }); + }); + spec.data = [ + { id: 'dataDotSeries', values: dataDot }, + { id: 'dataLinkSeries', values: dataLink } + ]; + return { spec }; +}; + +export const sequenceChartSeries: Transformer = (context: Context) => { + const { cells, spec } = context; + const cell = getCell(cells); + + spec.series = [ + { + type: 'link', + dataId: 'dataLinkSeries', + dotSeriesIndex: 1, + fromField: 'from', + toField: 'to', + arrow: { + style: { + visible: false + } + } + }, + { + type: 'dot', + dataId: 'dataDotSeries', + xField: cell.time as string, + yField: cell.group, + dotTypeField: cell.color as string, + titleField: cell.group, + highLightSeriesGroup: '', + height: 500, + clipHeight: 800, + title: { + style: { + fill: 'rgba(46, 47, 50)' + } + }, + subTitle: { + style: { + fill: 'rgba(46, 47, 50)', + dy: 7 + } + }, + grid: { + style: { + visible: false + } + }, + symbol: { + style: { + visible: false + } + }, + tooltip: { + mark: { + title: { + key: 'event 信息', + value: 'event 信息' + }, + content: [ + { + hasShape: true, + shapeType: 'square', + key: (datum: any) => datum[cell.group] + }, + { + hasShape: false, + key: 'event_time_stamp', + value: (datum: any) => datum[cell.group as string] + } + ] + } + } + } + ]; + return { spec }; +}; +export const sequenceChartAxes: Transformer = (context: Context) => { + const { cells, spec, fieldInfo } = context; + const cell = getCell(cells); + + spec.axes = [ + { + orient: 'top', + type: 'time', + range: { + min: fieldInfo.filter(fieldInfo => { + return fieldInfo.fieldName === cell.time; + })[0].domain[0], + max: fieldInfo.filter(fieldInfo => { + return fieldInfo.fieldName === cell.time; + })[0].domain[1] + }, + layers: [ + { + tickStep: 28800, + timeFormat: '%Y%m%d' + }, + { + tickStep: 28800, + timeFormat: '%H:%M' + } + ] + } + ]; + spec.appendPadding = { + left: 80, + right: 80 + }; + return { spec }; +}; diff --git a/packages/vmind/src/applications/chartGeneration/types.ts b/packages/vmind/src/applications/chartGeneration/types.ts index 5103fed..8cfa657 100644 --- a/packages/vmind/src/applications/chartGeneration/types.ts +++ b/packages/vmind/src/applications/chartGeneration/types.ts @@ -11,4 +11,5 @@ export type Cell = { target?: string; value?: string; category?: string; + group?: string; }; diff --git a/packages/vmind/src/common/typings/index.ts b/packages/vmind/src/common/typings/index.ts index c5f5bfd..0700a3d 100644 --- a/packages/vmind/src/common/typings/index.ts +++ b/packages/vmind/src/common/typings/index.ts @@ -86,7 +86,8 @@ export enum ChartType { VennChart = 'Venn Chart', SingleColumnCombinationChart = 'Single Column Combination Chart', DynamicScatterPlotChart = 'Dynamic Scatter Plot Chart', - DynamicRoseChart = 'Dynamic Rose Chart' + DynamicRoseChart = 'Dynamic Rose Chart', + SequenceChart = 'Sequence Chart' } export enum CombinationChartType {