pipeline.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import type { Advice, AdviseParams, AdvisorConfig, ChartKnowledgeBase, Datum, FieldInfo } from '@antv/ava';
  2. import { Advisor, CkbConfig, DataFrame } from '@antv/ava';
  3. import { size } from 'lodash';
  4. import type { CustomAdvisorConfig, RuleConfig, Specification } from '../types';
  5. export type CustomRecommendConfig = {
  6. customCKB?: Partial<AdvisorConfig['ckbCfg']>;
  7. customRule?: Partial<AdvisorConfig['ruleCfg']>;
  8. };
  9. export const customizeAdvisor = (props: CustomAdvisorConfig): Advisor => {
  10. const { charts, scopeOfCharts: CKBCfg, ruleConfig: ruleCfg } = props;
  11. const customCKB: ChartKnowledgeBase = {};
  12. charts?.forEach(chart => {
  13. /** 若用户自定义的图表 id 与内置图表 id 相同,内置图表将被覆盖 */
  14. if (!chart.chartKnowledge.toSpec) {
  15. chart.chartKnowledge.toSpec = (_: any, dataProps: any) => {
  16. return { dataProps } as Specification;
  17. };
  18. } else {
  19. const oriFunc = chart.chartKnowledge.toSpec;
  20. chart.chartKnowledge.toSpec = (data: any, dataProps: any) => {
  21. return {
  22. ...oriFunc(data, dataProps),
  23. dataProps: dataProps,
  24. } as Specification;
  25. };
  26. }
  27. customCKB[chart.chartType] = chart.chartKnowledge;
  28. });
  29. // 步骤一:如果有 exclude 项,先从给到的 CKB 中剔除部分选定的图表类型
  30. if (CKBCfg?.exclude) {
  31. CKBCfg.exclude.forEach((chartType: string) => {
  32. if (Object.keys(customCKB).includes(chartType)) {
  33. delete customCKB[chartType];
  34. }
  35. });
  36. }
  37. // 步骤二:如果有 include 项,则从当前(剔除后的)CKB中,只保留 include 中的图表类型。
  38. if (CKBCfg?.include) {
  39. const include = CKBCfg.include;
  40. Object.keys(customCKB).forEach((chartType: string) => {
  41. if (!include.includes(chartType)) {
  42. delete customCKB[chartType];
  43. }
  44. });
  45. }
  46. const CKBConfig: CkbConfig = {
  47. ...CKBCfg,
  48. custom: customCKB,
  49. };
  50. const ruleConfig: RuleConfig = {
  51. ...ruleCfg,
  52. };
  53. const myAdvisor = new Advisor({
  54. ckbCfg: CKBConfig,
  55. ruleCfg: ruleConfig,
  56. });
  57. return myAdvisor;
  58. };
  59. /** 主推荐流程 */
  60. export const getVisAdvices = (props: {
  61. data: Datum[];
  62. myChartAdvisor: Advisor;
  63. dataMetaMap?: Record<string, FieldInfo>;
  64. }): Advice[] => {
  65. const { data, dataMetaMap, myChartAdvisor } = props;
  66. /**
  67. * 若输入中有信息能够获取列的类型( Interval, Nominal, Time ),则将这个 信息传给 Advisor
  68. * 主要是读取 levelOfMeasureMents 这个字段,即 dataMetaMap[item].levelOfMeasurements
  69. */
  70. const customDataProps = dataMetaMap
  71. ? Object.keys(dataMetaMap).map(item => {
  72. return { name: item, ...dataMetaMap[item] };
  73. })
  74. : null;
  75. // 可根据需要选择是否使用全部 fields 进行推荐
  76. const useAllFields = false;
  77. // 挑选出维值不只有一个的字段
  78. const allFieldsInfo = new DataFrame(data).info();
  79. const selectedFields =
  80. size(allFieldsInfo) > 2
  81. ? allFieldsInfo?.filter(field => {
  82. if (field.recommendation === 'string' || field.recommendation === 'date') {
  83. return field.distinct && field.distinct > 1;
  84. }
  85. return true;
  86. })
  87. : allFieldsInfo;
  88. const allAdvices = myChartAdvisor?.adviseWithLog({
  89. data,
  90. dataProps: customDataProps as AdviseParams['dataProps'],
  91. // 不传 fields 参数,内部默认使用全部 fields,否则使用业务选择的字段
  92. fields: useAllFields ? undefined : selectedFields?.map(field => field.name),
  93. });
  94. return allAdvices?.advices ?? [];
  95. };