From 0834952de135eca98aed20c57bb6c97ec70186ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B8=83=E9=B1=BC?= <48511770+leffy-yan@users.noreply.github.com> Date: Thu, 16 Nov 2023 14:56:53 +0800 Subject: [PATCH] develop violin plot (#2176) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: violin plot * feat: 封装violin API * fix: delete useEffect * fix: delete .editor * fix: ignore .vscode * fix: delete .vscode & delete init * feat: ignore .vscode * fix: open api xField yField seriesField * fix: lint --------- Co-authored-by: zy371123 Co-authored-by: Joel Alan <31396322+lxfu1@users.noreply.github.com> --- .gitignore | 1 + packages/plots/src/components/index.ts | 3 ++ .../plots/src/components/violin/index.tsx | 12 +++++ packages/plots/src/core/base/index.ts | 2 - packages/plots/src/core/index.ts | 3 ++ .../plots/src/core/plots/violin/adaptor.ts | 49 ++++++++++++++++++ .../plots/src/core/plots/violin/index.tsx | 51 +++++++++++++++++++ packages/plots/src/core/plots/violin/type.ts | 5 ++ .../src/core/utils/delete-custom-keys.ts | 4 +- packages/plots/src/hooks/useChart.ts | 1 + site/examples/statistics/violin/demo/basic.js | 19 +++++++ .../statistics/violin/demo/density.js | 19 +++++++ .../examples/statistics/violin/demo/meta.json | 32 ++++++++++++ site/examples/statistics/violin/demo/polar.js | 19 +++++++ site/examples/statistics/violin/index.en.md | 4 ++ site/examples/statistics/violin/index.zh.md | 4 ++ 16 files changed, 224 insertions(+), 4 deletions(-) create mode 100644 packages/plots/src/components/violin/index.tsx create mode 100644 packages/plots/src/core/plots/violin/adaptor.ts create mode 100644 packages/plots/src/core/plots/violin/index.tsx create mode 100644 packages/plots/src/core/plots/violin/type.ts create mode 100644 site/examples/statistics/violin/demo/basic.js create mode 100644 site/examples/statistics/violin/demo/density.js create mode 100644 site/examples/statistics/violin/demo/meta.json create mode 100644 site/examples/statistics/violin/demo/polar.js create mode 100644 site/examples/statistics/violin/index.en.md create mode 100644 site/examples/statistics/violin/index.zh.md diff --git a/.gitignore b/.gitignore index 33f664b2b..b06fb9636 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ logs #ide .idea/ .eslintcache +.vscode/** # temp temp-gallery.md diff --git a/packages/plots/src/components/index.ts b/packages/plots/src/components/index.ts index 8a426386f..1044a9f7d 100644 --- a/packages/plots/src/components/index.ts +++ b/packages/plots/src/components/index.ts @@ -20,6 +20,7 @@ import Gauge from './gauge'; import Liquid from './liquid'; import WordCloud from './wordCloud'; import Treemap from './treemap'; +import Violin from './violin'; import BidirectionalBar from './bidirectional-bar'; export type { AreaConfig } from './area'; @@ -43,6 +44,7 @@ export type { GaugeConfig } from './gauge'; export type { LiquidConfig } from './liquid'; export type { WordCloudConfig } from './wordCloud'; export type { TreemapConfig } from './treemap'; +export type { ViolinConfig } from './violin'; export type { BidirectionalBarConfig } from './bidirectional-bar'; export { @@ -68,5 +70,6 @@ export { Liquid, WordCloud, Treemap, + Violin, BidirectionalBar, }; diff --git a/packages/plots/src/components/violin/index.tsx b/packages/plots/src/components/violin/index.tsx new file mode 100644 index 000000000..2cca323f2 --- /dev/null +++ b/packages/plots/src/components/violin/index.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { ViolinOptions } from '../../core'; +import { CommonConfig } from '../../interface'; +import { BaseChart } from '../base'; + +export type ViolinConfig = CommonConfig; + +const ViolinChart = (props: ViolinConfig) => { + return ; +} + +export default ViolinChart; \ No newline at end of file diff --git a/packages/plots/src/core/base/index.ts b/packages/plots/src/core/base/index.ts index 58429432a..d4cb6345f 100644 --- a/packages/plots/src/core/base/index.ts +++ b/packages/plots/src/core/base/index.ts @@ -54,7 +54,6 @@ export abstract class Plot extends EE { if (this.type === 'base' || this[SKIP_DEL_CUSTOM_SIGN]) { return { ...this.options, ...this.getChartOptions() }; } - return deleteCustomKeys(omit(this.options, CHART_OPTIONS), true); } @@ -106,7 +105,6 @@ export abstract class Plot extends EE { this.chart.render().then(() => { this.annotations(); }); - // 绑定 this.bindSizeSensor(); } diff --git a/packages/plots/src/core/index.ts b/packages/plots/src/core/index.ts index ee1d1929b..514ce3f7e 100644 --- a/packages/plots/src/core/index.ts +++ b/packages/plots/src/core/index.ts @@ -24,6 +24,7 @@ export type { GaugeOptions } from './plots/gauge'; export type { LiquidOptions } from './plots/liquid'; export type { WordCloudOptions } from './plots/wordCloud'; export type { TreemapOptions } from './plots/treemap'; +export type { ViolinOptions } from './plots/violin'; export type { BidirectionalBarOptions } from './plots/bidirectional-bar'; export * from './types'; @@ -53,6 +54,7 @@ import { Gauge } from './plots/gauge'; import { Liquid } from './plots/liquid'; import { WordCloud } from './plots/wordCloud'; import { Treemap } from './plots/treemap'; +import { Violin } from './plots/violin'; import { BidirectionalBar } from './plots/bidirectional-bar'; export const Plots = { @@ -82,5 +84,6 @@ export const Plots = { Liquid, WordCloud, Treemap, + Violin, BidirectionalBar, }; diff --git a/packages/plots/src/core/plots/violin/adaptor.ts b/packages/plots/src/core/plots/violin/adaptor.ts new file mode 100644 index 000000000..b928232f5 --- /dev/null +++ b/packages/plots/src/core/plots/violin/adaptor.ts @@ -0,0 +1,49 @@ +import { flow, transformOptions, set } from '../../utils'; +import { mark } from '../../components'; +import type { Adaptor } from '../../types'; +import type { ViolinOptions } from './type'; + +type Params = Adaptor; + +/** + * @param chart + * @param options + */ +export function adaptor(params: Params) { + /** + * 图表差异化处理 + */ + const customTransform = (params: Params) => { + const { options } = params; + const { xField, yField, seriesField, children } = options; + + const newChildren = children?.map((item) => { + return { + ...item, + xField, + yField, + seriesField, + colorField: seriesField, + data: item.type === 'density' ? { + transform: [ + { + type: 'kde', + field: yField, + groupBy: [xField, seriesField], + }, + ], + } : item.data, + } + }).filter((item) => options.violinType !== 'density' || item.type === 'density'); + set(options, 'children', newChildren); + // 默认‘normal’类型数据格式 + if (options.violinType === 'polar') { + set(options, 'coordinate', { type: 'polar'}) + } + // 底层不消费violinType字段。 + set(options, 'violinType', undefined); + return params; + } + + return flow(customTransform, transformOptions, mark)(params); +} diff --git a/packages/plots/src/core/plots/violin/index.tsx b/packages/plots/src/core/plots/violin/index.tsx new file mode 100644 index 000000000..4143d09ca --- /dev/null +++ b/packages/plots/src/core/plots/violin/index.tsx @@ -0,0 +1,51 @@ +import { Plot } from '../../base'; +import type { Adaptor } from '../../types'; +import { adaptor } from './adaptor'; +import { ViolinOptions } from './type'; + +export type { ViolinOptions }; + +export class Violin extends Plot { + /** 图表类型 */ + public type = 'violin'; + + /** + * 获取 折线图 默认配置项 + * 供外部使用 + */ + static getDefaultOptions(): Partial { + return { + type: 'view', + children: [ + { + type: 'density', + sizeField: 'size', + tooltip: false, + }, + { + type: 'boxplot', + shapeField: 'violin', + style: { + opacity: 0.5, + point: false, + }, + }, + ], + animate: { enter: { type: 'fadeIn' } }, + }; + } + + /** + * 获取 折线图 默认配置 + */ + protected getDefaultOptions() { + return Violin.getDefaultOptions(); + } + + /** + * 折线图适配器 + */ + protected getSchemaAdaptor(): (params: Adaptor) => void { + return adaptor; + } +} diff --git a/packages/plots/src/core/plots/violin/type.ts b/packages/plots/src/core/plots/violin/type.ts new file mode 100644 index 000000000..934b083f5 --- /dev/null +++ b/packages/plots/src/core/plots/violin/type.ts @@ -0,0 +1,5 @@ +import type { BaseOptions, Options } from '../../types/common'; + +export type ViolinOptions = Options & BaseOptions & { + violinType?: 'normal' | 'density' | 'polar' +}; diff --git a/packages/plots/src/core/utils/delete-custom-keys.ts b/packages/plots/src/core/utils/delete-custom-keys.ts index 4bac855cf..351fd9ebb 100644 --- a/packages/plots/src/core/utils/delete-custom-keys.ts +++ b/packages/plots/src/core/utils/delete-custom-keys.ts @@ -11,8 +11,8 @@ export const deleteCustomKeys = (options: O, isRender?: boole [...deleteKeys, ...COORDIANTE_OPTIONS].forEach((key) => { delete options[key]; }); - - options.children.forEach((child) => { + // 2023-11-09 对children为空情况做兼容。 + options.children?.forEach((child) => { Object.keys(child).forEach((key) => { if (deleteKeys.includes(key)) { delete child[key]; diff --git a/packages/plots/src/hooks/useChart.ts b/packages/plots/src/hooks/useChart.ts index 2fb6c4e88..395ae5b96 100644 --- a/packages/plots/src/hooks/useChart.ts +++ b/packages/plots/src/hooks/useChart.ts @@ -114,6 +114,7 @@ export default function useChart(ChartC }; }, []); + return { chart, container, diff --git a/site/examples/statistics/violin/demo/basic.js b/site/examples/statistics/violin/demo/basic.js new file mode 100644 index 000000000..b4e915ec1 --- /dev/null +++ b/site/examples/statistics/violin/demo/basic.js @@ -0,0 +1,19 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Violin } from '@ant-design/plots'; + +const DemoViolin = () => { + const config = { + violinType: 'normal', + data: { + type: 'fetch', + value: 'https://assets.antv.antgroup.com/g2/species.json', + }, + xField: 'x', + yField: 'y', + seriesField: 'species' + }; + return ; +}; + +ReactDOM.render(, document.getElementById('container')); diff --git a/site/examples/statistics/violin/demo/density.js b/site/examples/statistics/violin/demo/density.js new file mode 100644 index 000000000..7b4ca7a67 --- /dev/null +++ b/site/examples/statistics/violin/demo/density.js @@ -0,0 +1,19 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Violin } from '@ant-design/plots'; + +const DemoViolin = () => { + const config = { + violinType: 'density', + data: { + type: 'fetch', + value: 'https://assets.antv.antgroup.com/g2/species.json', + }, + xField: 'x', + yField: 'y', + seriesField: 'species' + }; + return ; +}; + +ReactDOM.render(, document.getElementById('container')); \ No newline at end of file diff --git a/site/examples/statistics/violin/demo/meta.json b/site/examples/statistics/violin/demo/meta.json new file mode 100644 index 000000000..13159b858 --- /dev/null +++ b/site/examples/statistics/violin/demo/meta.json @@ -0,0 +1,32 @@ +{ + "title": { + "zh": "中文分类", + "en": "Category" + }, + "demos": [ + { + "filename": "density.js", + "title": { + "zh": "和密度图", + "en": "Density plot" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_lwk8lu/afts/img/A*pctXQbGFiBIAAAAAAAAAAAAADma_AQ/original" + }, + { + "filename": "basic.js", + "title": { + "zh": "基础小提琴图", + "en": "Basic violin plot" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_lwk8lu/afts/img/A*vKc6SJjPY40AAAAAAAAAAAAADma_AQ/original" + }, + { + "filename": "polar.js", + "title": { + "zh": "极坐标小提琴图", + "en": "Polar violin plot" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_lwk8lu/afts/img/A*LLm1S5RBXGIAAAAAAAAAAAAADma_AQ/original" + } + ] +} diff --git a/site/examples/statistics/violin/demo/polar.js b/site/examples/statistics/violin/demo/polar.js new file mode 100644 index 000000000..283aa9b67 --- /dev/null +++ b/site/examples/statistics/violin/demo/polar.js @@ -0,0 +1,19 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Violin } from '@ant-design/plots'; + +const DemoViolin = () => { + const config = { + violinType: 'polar', + data: { + type: 'fetch', + value: 'https://assets.antv.antgroup.com/g2/species.json', + }, + xField: 'x', + yField: 'y', + seriesField: 'species' + }; + return ; +}; + +ReactDOM.render(, document.getElementById('container')); diff --git a/site/examples/statistics/violin/index.en.md b/site/examples/statistics/violin/index.en.md new file mode 100644 index 000000000..15e7a93a7 --- /dev/null +++ b/site/examples/statistics/violin/index.en.md @@ -0,0 +1,4 @@ +--- +title: Violin +order: 15 +--- \ No newline at end of file diff --git a/site/examples/statistics/violin/index.zh.md b/site/examples/statistics/violin/index.zh.md new file mode 100644 index 000000000..71ae5e3d1 --- /dev/null +++ b/site/examples/statistics/violin/index.zh.md @@ -0,0 +1,4 @@ +--- +title: 小提琴图 +order: 15 +--- \ No newline at end of file