diff --git a/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/constants.ts b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/constants.ts
new file mode 100644
index 000000000..70083c631
--- /dev/null
+++ b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/constants.ts
@@ -0,0 +1,2 @@
+export const SCATTER_PLOT_PLUGIN_TYPE = 'v2-scatter-plot';
+export const SCATTER_PLOT_PLUGIN_LEGACY_TYPE = 'v2-scatter-plot/legacy';
diff --git a/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/data/data.js b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/data/data.js
new file mode 100644
index 000000000..e9aff588c
--- /dev/null
+++ b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/data/data.js
@@ -0,0 +1,178 @@
+/* eslint-disable sort-keys, no-magic-numbers */
+export default [
+ {
+ country_name: 'China',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 1344130000,
+ sum__SP_RUR_TOTL_ZS: 49.427,
+ sum__SP_DYN_LE00_IN: 75.042,
+ },
+ {
+ country_name: 'Indonesia',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 244808254,
+ sum__SP_RUR_TOTL_ZS: 49.288,
+ sum__SP_DYN_LE00_IN: 70.3915609756,
+ },
+ {
+ country_name: 'Japan',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 127817277,
+ sum__SP_RUR_TOTL_ZS: 8.752,
+ sum__SP_DYN_LE00_IN: 82.5912195122,
+ },
+ {
+ country_name: 'Philippines',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 94501233,
+ sum__SP_RUR_TOTL_ZS: 54.983,
+ sum__SP_DYN_LE00_IN: 68.3914878049,
+ },
+ {
+ country_name: 'Vietnam',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 87840000,
+ sum__SP_RUR_TOTL_ZS: 68.971,
+ sum__SP_DYN_LE00_IN: 75.457902439,
+ },
+ {
+ country_name: 'Thailand',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 66902958,
+ sum__SP_RUR_TOTL_ZS: 54.606,
+ sum__SP_DYN_LE00_IN: 74.008902439,
+ },
+ {
+ country_name: 'Myanmar',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 52125411,
+ sum__SP_RUR_TOTL_ZS: 68.065,
+ sum__SP_DYN_LE00_IN: 64.7612439024,
+ },
+ {
+ country_name: 'India',
+ region: 'South Asia',
+ sum__SP_POP_TOTL: 1247446011,
+ sum__SP_RUR_TOTL_ZS: 68.724,
+ sum__SP_DYN_LE00_IN: 65.9584878049,
+ },
+ {
+ country_name: 'Pakistan',
+ region: 'South Asia',
+ sum__SP_POP_TOTL: 173669648,
+ sum__SP_RUR_TOTL_ZS: 62.993,
+ sum__SP_DYN_LE00_IN: 66.2838780488,
+ },
+ {
+ country_name: 'Bangladesh',
+ region: 'South Asia',
+ sum__SP_POP_TOTL: 153405612,
+ sum__SP_RUR_TOTL_ZS: 68.775,
+ sum__SP_DYN_LE00_IN: 69.891804878,
+ },
+ {
+ country_name: 'United States',
+ region: 'North America',
+ sum__SP_POP_TOTL: 311721632,
+ sum__SP_RUR_TOTL_ZS: 19.06,
+ sum__SP_DYN_LE00_IN: 78.6414634146,
+ },
+ {
+ country_name: 'Brazil',
+ region: 'Latin America & Caribbean',
+ sum__SP_POP_TOTL: 200517584,
+ sum__SP_RUR_TOTL_ZS: 15.377,
+ sum__SP_DYN_LE00_IN: 73.3473658537,
+ },
+ {
+ country_name: 'Mexico',
+ region: 'Latin America & Caribbean',
+ sum__SP_POP_TOTL: 120365271,
+ sum__SP_RUR_TOTL_ZS: 21.882,
+ sum__SP_DYN_LE00_IN: 76.9141707317,
+ },
+ {
+ country_name: 'Nigeria',
+ region: 'Sub-Saharan Africa',
+ sum__SP_POP_TOTL: 163770669,
+ sum__SP_RUR_TOTL_ZS: 55.638,
+ sum__SP_DYN_LE00_IN: 51.7102439024,
+ },
+ {
+ country_name: 'Ethiopia',
+ region: 'Sub-Saharan Africa',
+ sum__SP_POP_TOTL: 89858696,
+ sum__SP_RUR_TOTL_ZS: 82.265,
+ sum__SP_DYN_LE00_IN: 62.2528536585,
+ },
+ {
+ country_name: 'Congo, Dem. Rep.',
+ region: 'Sub-Saharan Africa',
+ sum__SP_POP_TOTL: 68087376,
+ sum__SP_RUR_TOTL_ZS: 59.558,
+ sum__SP_DYN_LE00_IN: 49.3007073171,
+ },
+ {
+ country_name: 'South Africa',
+ region: 'Sub-Saharan Africa',
+ sum__SP_POP_TOTL: 51553479,
+ sum__SP_RUR_TOTL_ZS: 37.254,
+ sum__SP_DYN_LE00_IN: 55.2956585366,
+ },
+ {
+ country_name: 'Russian Federation',
+ region: 'Europe & Central Asia',
+ sum__SP_POP_TOTL: 142960868,
+ sum__SP_RUR_TOTL_ZS: 26.268,
+ sum__SP_DYN_LE00_IN: 69.6585365854,
+ },
+ {
+ country_name: 'Germany',
+ region: 'Europe & Central Asia',
+ sum__SP_POP_TOTL: 81797673,
+ sum__SP_RUR_TOTL_ZS: 25.512,
+ sum__SP_DYN_LE00_IN: 80.7414634146,
+ },
+ {
+ country_name: 'Turkey',
+ region: 'Europe & Central Asia',
+ sum__SP_POP_TOTL: 73199372,
+ sum__SP_RUR_TOTL_ZS: 28.718,
+ sum__SP_DYN_LE00_IN: 74.5404878049,
+ },
+ {
+ country_name: 'France',
+ region: 'Europe & Central Asia',
+ sum__SP_POP_TOTL: 65342776,
+ sum__SP_RUR_TOTL_ZS: 21.416,
+ sum__SP_DYN_LE00_IN: 82.1146341463,
+ },
+ {
+ country_name: 'United Kingdom',
+ region: 'Europe & Central Asia',
+ sum__SP_POP_TOTL: 63258918,
+ sum__SP_RUR_TOTL_ZS: 18.43,
+ sum__SP_DYN_LE00_IN: 80.9512195122,
+ },
+ {
+ country_name: 'Italy',
+ region: 'Europe & Central Asia',
+ sum__SP_POP_TOTL: 59379449,
+ sum__SP_RUR_TOTL_ZS: 31.556,
+ sum__SP_DYN_LE00_IN: 82.187804878,
+ },
+ {
+ country_name: 'Egypt, Arab Rep.',
+ region: 'Middle East & North Africa',
+ sum__SP_POP_TOTL: 83787634,
+ sum__SP_RUR_TOTL_ZS: 57,
+ sum__SP_DYN_LE00_IN: 70.6785609756,
+ },
+ {
+ country_name: 'Iran, Islamic Rep.',
+ region: 'Middle East & North Africa',
+ sum__SP_POP_TOTL: 75184322,
+ sum__SP_RUR_TOTL_ZS: 28.8,
+ sum__SP_DYN_LE00_IN: 73.4493170732,
+ },
+];
diff --git a/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/data/legacyData.js b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/data/legacyData.js
new file mode 100644
index 000000000..37a26d3ec
--- /dev/null
+++ b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/data/legacyData.js
@@ -0,0 +1,338 @@
+/* eslint-disable sort-keys, no-magic-numbers */
+export default [
+ {
+ key: 'East Asia & Pacific',
+ values: [
+ {
+ country_name: 'China',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 1344130000.0,
+ sum__SP_RUR_TOTL_ZS: 49.427,
+ sum__SP_DYN_LE00_IN: 75.042,
+ x: 49.427,
+ y: 75.042,
+ size: 1344130000.0,
+ shape: 'circle',
+ group: 'East Asia & Pacific',
+ },
+ {
+ country_name: 'Indonesia',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 244808254.0,
+ sum__SP_RUR_TOTL_ZS: 49.288,
+ sum__SP_DYN_LE00_IN: 70.3915609756,
+ x: 49.288,
+ y: 70.3915609756,
+ size: 244808254.0,
+ shape: 'circle',
+ group: 'East Asia & Pacific',
+ },
+ {
+ country_name: 'Japan',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 127817277.0,
+ sum__SP_RUR_TOTL_ZS: 8.752,
+ sum__SP_DYN_LE00_IN: 82.5912195122,
+ x: 8.752,
+ y: 82.5912195122,
+ size: 127817277.0,
+ shape: 'circle',
+ group: 'East Asia & Pacific',
+ },
+ {
+ country_name: 'Philippines',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 94501233.0,
+ sum__SP_RUR_TOTL_ZS: 54.983,
+ sum__SP_DYN_LE00_IN: 68.3914878049,
+ x: 54.983,
+ y: 68.3914878049,
+ size: 94501233.0,
+ shape: 'circle',
+ group: 'East Asia & Pacific',
+ },
+ {
+ country_name: 'Vietnam',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 87840000.0,
+ sum__SP_RUR_TOTL_ZS: 68.971,
+ sum__SP_DYN_LE00_IN: 75.457902439,
+ x: 68.971,
+ y: 75.457902439,
+ size: 87840000.0,
+ shape: 'circle',
+ group: 'East Asia & Pacific',
+ },
+ {
+ country_name: 'Thailand',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 66902958.0,
+ sum__SP_RUR_TOTL_ZS: 54.606,
+ sum__SP_DYN_LE00_IN: 74.008902439,
+ x: 54.606,
+ y: 74.008902439,
+ size: 66902958.0,
+ shape: 'circle',
+ group: 'East Asia & Pacific',
+ },
+ {
+ country_name: 'Myanmar',
+ region: 'East Asia & Pacific',
+ sum__SP_POP_TOTL: 52125411.0,
+ sum__SP_RUR_TOTL_ZS: 68.065,
+ sum__SP_DYN_LE00_IN: 64.7612439024,
+ x: 68.065,
+ y: 64.7612439024,
+ size: 52125411.0,
+ shape: 'circle',
+ group: 'East Asia & Pacific',
+ },
+ ],
+ },
+ {
+ key: 'South Asia',
+ values: [
+ {
+ country_name: 'India',
+ region: 'South Asia',
+ sum__SP_POP_TOTL: 1247446011.0,
+ sum__SP_RUR_TOTL_ZS: 68.724,
+ sum__SP_DYN_LE00_IN: 65.9584878049,
+ x: 68.724,
+ y: 65.9584878049,
+ size: 1247446011.0,
+ shape: 'circle',
+ group: 'South Asia',
+ },
+ {
+ country_name: 'Pakistan',
+ region: 'South Asia',
+ sum__SP_POP_TOTL: 173669648.0,
+ sum__SP_RUR_TOTL_ZS: 62.993,
+ sum__SP_DYN_LE00_IN: 66.2838780488,
+ x: 62.993,
+ y: 66.2838780488,
+ size: 173669648.0,
+ shape: 'circle',
+ group: 'South Asia',
+ },
+ {
+ country_name: 'Bangladesh',
+ region: 'South Asia',
+ sum__SP_POP_TOTL: 153405612.0,
+ sum__SP_RUR_TOTL_ZS: 68.775,
+ sum__SP_DYN_LE00_IN: 69.891804878,
+ x: 68.775,
+ y: 69.891804878,
+ size: 153405612.0,
+ shape: 'circle',
+ group: 'South Asia',
+ },
+ ],
+ },
+ {
+ key: 'North America',
+ values: [
+ {
+ country_name: 'United States',
+ region: 'North America',
+ sum__SP_POP_TOTL: 311721632.0,
+ sum__SP_RUR_TOTL_ZS: 19.06,
+ sum__SP_DYN_LE00_IN: 78.6414634146,
+ x: 19.06,
+ y: 78.6414634146,
+ size: 311721632.0,
+ shape: 'circle',
+ group: 'North America',
+ },
+ ],
+ },
+ {
+ key: 'Latin America & Caribbean',
+ values: [
+ {
+ country_name: 'Brazil',
+ region: 'Latin America & Caribbean',
+ sum__SP_POP_TOTL: 200517584.0,
+ sum__SP_RUR_TOTL_ZS: 15.377,
+ sum__SP_DYN_LE00_IN: 73.3473658537,
+ x: 15.377,
+ y: 73.3473658537,
+ size: 200517584.0,
+ shape: 'circle',
+ group: 'Latin America & Caribbean',
+ },
+ {
+ country_name: 'Mexico',
+ region: 'Latin America & Caribbean',
+ sum__SP_POP_TOTL: 120365271.0,
+ sum__SP_RUR_TOTL_ZS: 21.882,
+ sum__SP_DYN_LE00_IN: 76.9141707317,
+ x: 21.882,
+ y: 76.9141707317,
+ size: 120365271.0,
+ shape: 'circle',
+ group: 'Latin America & Caribbean',
+ },
+ ],
+ },
+ {
+ key: 'Sub-Saharan Africa',
+ values: [
+ {
+ country_name: 'Nigeria',
+ region: 'Sub-Saharan Africa',
+ sum__SP_POP_TOTL: 163770669.0,
+ sum__SP_RUR_TOTL_ZS: 55.638,
+ sum__SP_DYN_LE00_IN: 51.7102439024,
+ x: 55.638,
+ y: 51.7102439024,
+ size: 163770669.0,
+ shape: 'circle',
+ group: 'Sub-Saharan Africa',
+ },
+ {
+ country_name: 'Ethiopia',
+ region: 'Sub-Saharan Africa',
+ sum__SP_POP_TOTL: 89858696.0,
+ sum__SP_RUR_TOTL_ZS: 82.265,
+ sum__SP_DYN_LE00_IN: 62.2528536585,
+ x: 82.265,
+ y: 62.2528536585,
+ size: 89858696.0,
+ shape: 'circle',
+ group: 'Sub-Saharan Africa',
+ },
+ {
+ country_name: 'Congo, Dem. Rep.',
+ region: 'Sub-Saharan Africa',
+ sum__SP_POP_TOTL: 68087376.0,
+ sum__SP_RUR_TOTL_ZS: 59.558,
+ sum__SP_DYN_LE00_IN: 49.3007073171,
+ x: 59.558,
+ y: 49.3007073171,
+ size: 68087376.0,
+ shape: 'circle',
+ group: 'Sub-Saharan Africa',
+ },
+ {
+ country_name: 'South Africa',
+ region: 'Sub-Saharan Africa',
+ sum__SP_POP_TOTL: 51553479.0,
+ sum__SP_RUR_TOTL_ZS: 37.254,
+ sum__SP_DYN_LE00_IN: 55.2956585366,
+ x: 37.254,
+ y: 55.2956585366,
+ size: 51553479.0,
+ shape: 'circle',
+ group: 'Sub-Saharan Africa',
+ },
+ ],
+ },
+ {
+ key: 'Europe & Central Asia',
+ values: [
+ {
+ country_name: 'Russian Federation',
+ region: 'Europe & Central Asia',
+ sum__SP_POP_TOTL: 142960868.0,
+ sum__SP_RUR_TOTL_ZS: 26.268,
+ sum__SP_DYN_LE00_IN: 69.6585365854,
+ x: 26.268,
+ y: 69.6585365854,
+ size: 142960868.0,
+ shape: 'circle',
+ group: 'Europe & Central Asia',
+ },
+ {
+ country_name: 'Germany',
+ region: 'Europe & Central Asia',
+ sum__SP_POP_TOTL: 81797673.0,
+ sum__SP_RUR_TOTL_ZS: 25.512,
+ sum__SP_DYN_LE00_IN: 80.7414634146,
+ x: 25.512,
+ y: 80.7414634146,
+ size: 81797673.0,
+ shape: 'circle',
+ group: 'Europe & Central Asia',
+ },
+ {
+ country_name: 'Turkey',
+ region: 'Europe & Central Asia',
+ sum__SP_POP_TOTL: 73199372.0,
+ sum__SP_RUR_TOTL_ZS: 28.718,
+ sum__SP_DYN_LE00_IN: 74.5404878049,
+ x: 28.718,
+ y: 74.5404878049,
+ size: 73199372.0,
+ shape: 'circle',
+ group: 'Europe & Central Asia',
+ },
+ {
+ country_name: 'France',
+ region: 'Europe & Central Asia',
+ sum__SP_POP_TOTL: 65342776.0,
+ sum__SP_RUR_TOTL_ZS: 21.416,
+ sum__SP_DYN_LE00_IN: 82.1146341463,
+ x: 21.416,
+ y: 82.1146341463,
+ size: 65342776.0,
+ shape: 'circle',
+ group: 'Europe & Central Asia',
+ },
+ {
+ country_name: 'United Kingdom',
+ region: 'Europe & Central Asia',
+ sum__SP_POP_TOTL: 63258918.0,
+ sum__SP_RUR_TOTL_ZS: 18.43,
+ sum__SP_DYN_LE00_IN: 80.9512195122,
+ x: 18.43,
+ y: 80.9512195122,
+ size: 63258918.0,
+ shape: 'circle',
+ group: 'Europe & Central Asia',
+ },
+ {
+ country_name: 'Italy',
+ region: 'Europe & Central Asia',
+ sum__SP_POP_TOTL: 59379449.0,
+ sum__SP_RUR_TOTL_ZS: 31.556,
+ sum__SP_DYN_LE00_IN: 82.187804878,
+ x: 31.556,
+ y: 82.187804878,
+ size: 59379449.0,
+ shape: 'circle',
+ group: 'Europe & Central Asia',
+ },
+ ],
+ },
+ {
+ key: 'Middle East & North Africa',
+ values: [
+ {
+ country_name: 'Egypt, Arab Rep.',
+ region: 'Middle East & North Africa',
+ sum__SP_POP_TOTL: 83787634.0,
+ sum__SP_RUR_TOTL_ZS: 57.0,
+ sum__SP_DYN_LE00_IN: 70.6785609756,
+ x: 57.0,
+ y: 70.6785609756,
+ size: 83787634.0,
+ shape: 'circle',
+ group: 'Middle East & North Africa',
+ },
+ {
+ country_name: 'Iran, Islamic Rep.',
+ region: 'Middle East & North Africa',
+ sum__SP_POP_TOTL: 75184322.0,
+ sum__SP_RUR_TOTL_ZS: 28.8,
+ sum__SP_DYN_LE00_IN: 73.4493170732,
+ x: 28.8,
+ y: 73.4493170732,
+ size: 75184322.0,
+ shape: 'circle',
+ group: 'Middle East & North Africa',
+ },
+ ],
+ },
+];
diff --git a/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/index.js b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/index.js
new file mode 100644
index 000000000..ce1aec40b
--- /dev/null
+++ b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/index.js
@@ -0,0 +1,13 @@
+import { ScatterPlotPlugin as LegacyScatterPlotPlugin } from '../../../../../superset-ui-preset-chart-xy/src/legacy';
+import { ScatterPlotPlugin } from '../../../../../superset-ui-preset-chart-xy/src';
+import BasicStories from './stories/basic';
+import BubbleStories from './stories/bubble';
+import LegacyStories from './stories/legacy';
+import { SCATTER_PLOT_PLUGIN_TYPE, SCATTER_PLOT_PLUGIN_LEGACY_TYPE } from './constants';
+
+new LegacyScatterPlotPlugin().configure({ key: SCATTER_PLOT_PLUGIN_LEGACY_TYPE }).register();
+new ScatterPlotPlugin().configure({ key: SCATTER_PLOT_PLUGIN_TYPE }).register();
+
+export default {
+ examples: [...BasicStories, ...BubbleStories, ...LegacyStories],
+};
diff --git a/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/stories/basic.jsx b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/stories/basic.jsx
new file mode 100644
index 000000000..ff9c12ec3
--- /dev/null
+++ b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/stories/basic.jsx
@@ -0,0 +1,59 @@
+/* eslint-disable no-magic-numbers, sort-keys */
+import * as React from 'react';
+import { SuperChart, ChartProps } from '@superset-ui/chart';
+import { radios } from '@storybook/addon-knobs';
+import data from '../data/data';
+import { SCATTER_PLOT_PLUGIN_TYPE } from '../constants';
+
+export default [
+ {
+ renderStory: () => [
+ ,
+ ],
+ storyName: 'Basic',
+ storyPath: 'preset-chart-xy|ScatterPlotPlugin',
+ },
+];
diff --git a/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/stories/bubble.jsx b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/stories/bubble.jsx
new file mode 100644
index 000000000..d4c98b0ff
--- /dev/null
+++ b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/stories/bubble.jsx
@@ -0,0 +1,67 @@
+/* eslint-disable no-magic-numbers, sort-keys */
+import * as React from 'react';
+import { SuperChart, ChartProps } from '@superset-ui/chart';
+import { radios } from '@storybook/addon-knobs';
+import data from '../data/data';
+import { SCATTER_PLOT_PLUGIN_TYPE } from '../constants';
+
+export default [
+ {
+ renderStory: () => [
+ ,
+ ],
+ storyName: 'Bubble',
+ storyPath: 'preset-chart-xy|ScatterPlotPlugin',
+ },
+];
diff --git a/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/stories/legacy.tsx b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/stories/legacy.tsx
new file mode 100644
index 000000000..6e6d51a0f
--- /dev/null
+++ b/packages/superset-ui-plugins-demo/storybook/stories/preset-chart-xy/ScatterPlot/stories/legacy.tsx
@@ -0,0 +1,49 @@
+/* eslint-disable no-magic-numbers */
+import * as React from 'react';
+import { SuperChart, ChartProps } from '@superset-ui/chart';
+import data from '../data/legacyData';
+import { SCATTER_PLOT_PLUGIN_LEGACY_TYPE } from '../constants';
+
+export default [
+ {
+ renderStory: () => [
+ ,
+ ],
+ storyName: 'Use Legacy API shim',
+ storyPath: 'preset-chart-xy|ScatterPlotPlugin',
+ },
+];
diff --git a/packages/superset-ui-preset-chart-xy/src/BoxPlot/BoxPlot.tsx b/packages/superset-ui-preset-chart-xy/src/BoxPlot/BoxPlot.tsx
index 58676abfb..089f40d2e 100644
--- a/packages/superset-ui-preset-chart-xy/src/BoxPlot/BoxPlot.tsx
+++ b/packages/superset-ui-preset-chart-xy/src/BoxPlot/BoxPlot.tsx
@@ -1,21 +1,3 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
/* eslint-disable sort-keys, no-magic-numbers, complexity */
import React from 'react';
import { BoxPlotSeries, XYChart } from '@data-ui/xy-chart';
@@ -28,6 +10,7 @@ import WithLegend from '../components/WithLegend';
import ChartLegend from '../components/legend/ChartLegend';
import Encoder, { ChannelTypes, Encoding, Outputs } from './Encoder';
import { Dataset, PlainObject } from '../encodeable/types/Data';
+import { PartialSpec } from '../encodeable/types/Specification';
chartTheme.gridStyles.stroke = '#f1f3f5';
@@ -44,10 +27,10 @@ type Props = {
width: string | number;
height: string | number;
margin?: Margin;
- encoding: Encoding;
data: Dataset;
theme?: ChartTheme;
-} & Readonly;
+} & PartialSpec &
+ Readonly;
export default class BoxPlot extends React.PureComponent {
static defaultProps = defaultProps;
@@ -59,24 +42,26 @@ export default class BoxPlot extends React.PureComponent {
super(props);
const createEncoder = createSelector(
- (enc: Encoding) => enc,
- (enc: Encoding) => new Encoder({ encoding: enc }),
+ (p: PartialSpec) => p.encoding,
+ p => p.commonEncoding,
+ p => p.options,
+ (encoding, commonEncoding, options) => new Encoder({ encoding, commonEncoding, options }),
);
this.createEncoder = () => {
- this.encoder = createEncoder(this.props.encoding);
+ this.encoder = createEncoder(this.props);
};
- this.encoder = createEncoder(this.props.encoding);
+ this.encoder = createEncoder(this.props);
this.renderChart = this.renderChart.bind(this);
}
renderChart(dim: Dimension) {
const { width, height } = dim;
- const { data, encoding, margin, theme } = this.props;
+ const { data, margin, theme } = this.props;
const { channels } = this.encoder;
- const isHorizontal = encoding.y.type === 'nominal';
+ const isHorizontal = channels.y.definition.type === 'nominal';
const children = [
{
stroke={(datum: PlainObject) => channels.color.encode(datum)}
strokeWidth={1}
widthRatio={0.6}
- horizontal={encoding.y.type === 'nominal'}
+ horizontal={channels.y.definition.type === 'nominal'}
/>,
];
diff --git a/packages/superset-ui-preset-chart-xy/src/BoxPlot/createTooltip.tsx b/packages/superset-ui-preset-chart-xy/src/BoxPlot/createTooltip.tsx
index b3efd5070..23c0633cd 100644
--- a/packages/superset-ui-preset-chart-xy/src/BoxPlot/createTooltip.tsx
+++ b/packages/superset-ui-preset-chart-xy/src/BoxPlot/createTooltip.tsx
@@ -11,21 +11,24 @@ export default function createBoxPlotTooltip(encoder: Encoder) {
return function BoxPlotTooltip({ datum, color }: { datum: BoxPlotDataRow; color: string }) {
const { label, min, max, median, firstQuartile, thirdQuartile, outliers } = datum;
+ const formatValue =
+ channels.y.definition.type === 'nominal' ? channels.x.formatValue : channels.y.formatValue;
+
const data = [];
if (isDefined(min)) {
- data.push({ key: 'Min', valueColumn: channels.y.formatValue(min) });
+ data.push({ key: 'Min', valueColumn: formatValue(min) });
}
if (isDefined(max)) {
- data.push({ key: 'Max', valueColumn: channels.y.formatValue(max) });
+ data.push({ key: 'Max', valueColumn: formatValue(max) });
}
if (isDefined(median)) {
- data.push({ key: 'Median', valueColumn: channels.y.formatValue(median) });
+ data.push({ key: 'Median', valueColumn: formatValue(median) });
}
if (isDefined(firstQuartile)) {
- data.push({ key: '1st Quartile', valueColumn: channels.y.formatValue(firstQuartile) });
+ data.push({ key: '1st Quartile', valueColumn: formatValue(firstQuartile) });
}
if (isDefined(thirdQuartile)) {
- data.push({ key: '3rd Quartile', valueColumn: channels.y.formatValue(thirdQuartile) });
+ data.push({ key: '3rd Quartile', valueColumn: formatValue(thirdQuartile) });
}
if (isDefined(outliers) && outliers.length > 0) {
data.push({ key: '# Outliers', valueColumn: outliers.length });
diff --git a/packages/superset-ui-preset-chart-xy/src/Line/Line.tsx b/packages/superset-ui-preset-chart-xy/src/Line/Line.tsx
index 69accd8dc..8bcd81b81 100644
--- a/packages/superset-ui-preset-chart-xy/src/Line/Line.tsx
+++ b/packages/superset-ui-preset-chart-xy/src/Line/Line.tsx
@@ -19,6 +19,7 @@ import WithLegend from '../components/WithLegend';
import Encoder, { ChannelTypes, Encoding, Outputs } from './Encoder';
import { Dataset, PlainObject } from '../encodeable/types/Data';
import ChartLegend from '../components/legend/ChartLegend';
+import { PartialSpec } from '../encodeable/types/Specification';
chartTheme.gridStyles.stroke = '#f1f3f5';
@@ -35,10 +36,10 @@ type Props = {
width: string | number;
height: string | number;
margin?: Margin;
- encoding: Encoding;
data: Dataset;
theme?: ChartTheme;
-} & Readonly;
+} & PartialSpec &
+ Readonly;
export interface Series {
key: string;
@@ -67,15 +68,17 @@ class LineChart extends PureComponent {
super(props);
const createEncoder = createSelector(
- (enc: Encoding) => enc,
- (enc: Encoding) => new Encoder({ encoding: enc }),
+ (p: PartialSpec) => p.encoding,
+ p => p.commonEncoding,
+ p => p.options,
+ (encoding, commonEncoding, options) => new Encoder({ encoding, commonEncoding, options }),
);
this.createEncoder = () => {
- this.encoder = createEncoder(this.props.encoding);
+ this.encoder = createEncoder(this.props);
};
- this.encoder = createEncoder(this.props.encoding);
+ this.encoder = createEncoder(this.props);
this.renderChart = this.renderChart.bind(this);
}
diff --git a/packages/superset-ui-preset-chart-xy/src/ScatterPlot/Encoder.ts b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/Encoder.ts
new file mode 100644
index 000000000..bbda94638
--- /dev/null
+++ b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/Encoder.ts
@@ -0,0 +1,48 @@
+import AbstractEncoder from '../encodeable/AbstractEncoder';
+import { PartialSpec } from '../encodeable/types/Specification';
+import { EncodingFromChannelsAndOutputs } from '../encodeable/types/Channel';
+
+/**
+ * Define channel types
+ */
+const channelTypes = {
+ fill: 'Color',
+ size: 'Numeric',
+ stroke: 'Color',
+ x: 'X',
+ y: 'Y',
+} as const;
+
+export type ChannelTypes = typeof channelTypes;
+
+/**
+ * Define output type for each channel
+ */
+export interface Outputs {
+ fill: string;
+ size: number;
+ stroke: string;
+ x: number | null;
+ y: number | null;
+}
+
+/**
+ * Derive encoding config
+ */
+export type Encoding = EncodingFromChannelsAndOutputs;
+
+export default class Encoder extends AbstractEncoder {
+ static readonly DEFAULT_ENCODINGS: Encoding = {
+ fill: { value: '#222' },
+ size: { value: 5 },
+ stroke: { value: 'none' },
+ x: { field: 'x', type: 'quantitative' },
+ y: { field: 'y', type: 'quantitative' },
+ };
+
+ static readonly CHANNEL_OPTIONS = {};
+
+ constructor(spec: PartialSpec) {
+ super(channelTypes, spec, Encoder.DEFAULT_ENCODINGS, Encoder.CHANNEL_OPTIONS);
+ }
+}
diff --git a/packages/superset-ui-preset-chart-xy/src/ScatterPlot/ScatterPlot.tsx b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/ScatterPlot.tsx
new file mode 100644
index 000000000..1ba6316f4
--- /dev/null
+++ b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/ScatterPlot.tsx
@@ -0,0 +1,150 @@
+/* eslint-disable sort-keys, no-magic-numbers, complexity */
+import React, { PureComponent } from 'react';
+import { XYChart, PointSeries } from '@data-ui/xy-chart';
+import { chartTheme, ChartTheme } from '@data-ui/theme';
+import { Margin, Dimension } from '@superset-ui/dimension';
+import { extent as d3Extent } from 'd3-array';
+import { createSelector } from 'reselect';
+import createTooltip from './createTooltip';
+import XYChartLayout from '../utils/XYChartLayout';
+import WithLegend from '../components/WithLegend';
+import Encoder, { ChannelTypes, Encoding, Outputs } from './Encoder';
+import { Dataset, PlainObject } from '../encodeable/types/Data';
+import ChartLegend from '../components/legend/ChartLegend';
+import { PartialSpec } from '../encodeable/types/Specification';
+
+chartTheme.gridStyles.stroke = '#f1f3f5';
+
+const DEFAULT_MARGIN = { top: 20, right: 20, left: 20, bottom: 20 };
+
+const defaultProps = {
+ className: '',
+ margin: DEFAULT_MARGIN,
+ theme: chartTheme,
+} as const;
+
+type Props = {
+ className?: string;
+ width: string | number;
+ height: string | number;
+ margin?: Margin;
+ data: Dataset;
+ theme?: ChartTheme;
+} & PartialSpec &
+ Readonly;
+
+export interface EncodedPoint {
+ x: Outputs['x'];
+ y: Outputs['y'];
+ size: Outputs['size'];
+ fill: Outputs['fill'];
+ stroke: Outputs['stroke'];
+ data: PlainObject;
+}
+
+export default class ScatterPlot extends PureComponent {
+ static defaultProps = defaultProps;
+
+ encoder: Encoder;
+ private createEncoder: () => void;
+
+ constructor(props: Props) {
+ super(props);
+
+ const createEncoder = createSelector(
+ (p: PartialSpec) => p.encoding,
+ p => p.commonEncoding,
+ p => p.options,
+ (encoding, commonEncoding, options) => new Encoder({ encoding, commonEncoding, options }),
+ );
+
+ this.createEncoder = () => {
+ this.encoder = createEncoder(this.props);
+ };
+
+ this.encoder = createEncoder(this.props);
+ this.renderChart = this.renderChart.bind(this);
+ }
+
+ renderChart(dim: Dimension) {
+ const { width, height } = dim;
+ const { data, margin, theme } = this.props;
+ const { channels } = this.encoder;
+
+ if (typeof channels.size.scale !== 'undefined') {
+ const domain = d3Extent(data, d => channels.size.get(d));
+ const [min, max] = domain;
+ const adjustedDomain = [Math.min(min || 0, 0), Math.max(max || 1, 1)];
+ channels.size.scale.setDomain(adjustedDomain);
+ }
+
+ const encodedData = data.map(d => ({
+ x: channels.x.get(d),
+ y: channels.y.get(d),
+ size: channels.size.encode(d),
+ fill: channels.fill.encode(d),
+ stroke: channels.stroke.encode(d),
+ data: d,
+ }));
+
+ const children = [
+ d.fill}
+ fillOpacity={0.5}
+ stroke={(d: EncodedPoint) => d.stroke}
+ size={(d: EncodedPoint) => d.size}
+ />,
+ ];
+
+ const layout = new XYChartLayout({
+ width,
+ height,
+ margin: { ...DEFAULT_MARGIN, ...margin },
+ theme,
+ xEncoder: channels.x,
+ yEncoder: channels.y,
+ children,
+ });
+
+ return layout.renderChartWithFrame((chartDim: Dimension) => (
+
+ {children}
+ {layout.renderXAxis()}
+ {layout.renderYAxis()}
+
+ ));
+ }
+
+ render() {
+ const { className, data, width, height } = this.props;
+
+ this.createEncoder();
+ const renderLegend = this.encoder.hasLegend()
+ ? // eslint-disable-next-line react/jsx-props-no-multi-spaces
+ () => data={data} encoder={this.encoder} />
+ : undefined;
+
+ return (
+
+ );
+ }
+}
diff --git a/packages/superset-ui-preset-chart-xy/src/ScatterPlot/createMetadata.ts b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/createMetadata.ts
new file mode 100644
index 000000000..29a790802
--- /dev/null
+++ b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/createMetadata.ts
@@ -0,0 +1,12 @@
+import { t } from '@superset-ui/translation';
+import { ChartMetadata } from '@superset-ui/chart';
+import thumbnail from './images/thumbnail.png';
+
+export default function createMetadata(useLegacyApi = false) {
+ return new ChartMetadata({
+ description: '',
+ name: t('Scatter Plot'),
+ thumbnail,
+ useLegacyApi,
+ });
+}
diff --git a/packages/superset-ui-preset-chart-xy/src/ScatterPlot/createTooltip.tsx b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/createTooltip.tsx
new file mode 100644
index 000000000..aabb41f00
--- /dev/null
+++ b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/createTooltip.tsx
@@ -0,0 +1,57 @@
+/* eslint-disable no-magic-numbers */
+
+import React from 'react';
+import TooltipFrame from '../components/tooltip/TooltipFrame';
+import TooltipTable from '../components/tooltip/TooltipTable';
+import Encoder from './Encoder';
+import { isFieldDef } from '../encodeable/types/ChannelDef';
+import { EncodedPoint } from './ScatterPlot';
+
+export default function createTooltip(encoder: Encoder) {
+ function Tooltip({ datum }: { datum: EncodedPoint }) {
+ const { channels, commonChannels } = encoder;
+ const { x, y, size, fill, stroke } = channels;
+
+ const tooltipRows = [
+ { key: 'x', keyColumn: x.getTitle(), valueColumn: x.format(datum.data) },
+ { key: 'y', keyColumn: y.getTitle(), valueColumn: y.format(datum.data) },
+ ];
+
+ if (isFieldDef(fill.definition)) {
+ tooltipRows.push({
+ key: 'fill',
+ keyColumn: fill.getTitle(),
+ valueColumn: fill.format(datum.data),
+ });
+ }
+ if (isFieldDef(stroke.definition)) {
+ tooltipRows.push({
+ key: 'stroke',
+ keyColumn: stroke.getTitle(),
+ valueColumn: stroke.format(datum.data),
+ });
+ }
+ if (isFieldDef(size.definition)) {
+ tooltipRows.push({
+ key: 'size',
+ keyColumn: size.getTitle(),
+ valueColumn: size.format(datum.data),
+ });
+ }
+ commonChannels.group.forEach(g => {
+ tooltipRows.push({
+ key: `${g.name}`,
+ keyColumn: g.getTitle(),
+ valueColumn: g.format(datum.data),
+ });
+ });
+
+ return (
+
+
+
+ );
+ }
+
+ return Tooltip;
+}
diff --git a/packages/superset-ui-preset-chart-xy/src/ScatterPlot/images/thumbnail.png b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/images/thumbnail.png
new file mode 100644
index 000000000..ecb8dd566
Binary files /dev/null and b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/images/thumbnail.png differ
diff --git a/packages/superset-ui-preset-chart-xy/src/ScatterPlot/images/thumbnailLarge.png b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/images/thumbnailLarge.png
new file mode 100644
index 000000000..ecb8dd566
Binary files /dev/null and b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/images/thumbnailLarge.png differ
diff --git a/packages/superset-ui-preset-chart-xy/src/ScatterPlot/index.ts b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/index.ts
new file mode 100644
index 000000000..08a9615de
--- /dev/null
+++ b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/index.ts
@@ -0,0 +1,13 @@
+import { ChartPlugin } from '@superset-ui/chart';
+import createMetadata from './createMetadata';
+import transformProps from './transformProps';
+
+export default class LineChartPlugin extends ChartPlugin {
+ constructor() {
+ super({
+ loadChart: () => import('./ScatterPlot'),
+ metadata: createMetadata(),
+ transformProps,
+ });
+ }
+}
diff --git a/packages/superset-ui-preset-chart-xy/src/ScatterPlot/legacy/index.ts b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/legacy/index.ts
new file mode 100644
index 000000000..571dbef72
--- /dev/null
+++ b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/legacy/index.ts
@@ -0,0 +1,13 @@
+import { ChartPlugin } from '@superset-ui/chart';
+import createMetadata from '../createMetadata';
+import transformProps from './transformProps';
+
+export default class LineChartPlugin extends ChartPlugin {
+ constructor() {
+ super({
+ loadChart: () => import('../ScatterPlot'),
+ metadata: createMetadata(true),
+ transformProps,
+ });
+ }
+}
diff --git a/packages/superset-ui-preset-chart-xy/src/ScatterPlot/legacy/transformProps.ts b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/legacy/transformProps.ts
new file mode 100644
index 000000000..8c2cc418b
--- /dev/null
+++ b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/legacy/transformProps.ts
@@ -0,0 +1,96 @@
+/* eslint-disable sort-keys */
+import { ChartProps } from '@superset-ui/chart';
+import { flatMap } from 'lodash';
+
+interface DataRow {
+ key: string[];
+ values: {
+ [key: string]: any;
+ }[];
+}
+
+export default function transformProps(chartProps: ChartProps) {
+ const { width, height, formData, payload } = chartProps;
+ const {
+ colorScheme,
+ entity,
+ maxBubbleSize,
+ series,
+ showLegend,
+ size,
+ x,
+ xAxisFormat,
+ xAxisLabel,
+ // TODO: These fields are not supported yet
+ // xAxisShowminmax,
+ // xLogScale,
+ y,
+ yAxisLabel,
+ yAxisFormat,
+ // TODO: These fields are not supported yet
+ // yAxisShowminmax,
+ // yLogScale,
+ } = formData;
+ const data = payload.data as DataRow[];
+
+ return {
+ data: flatMap(
+ data.map((row: DataRow) =>
+ row.values.map(v => ({
+ [x]: v[x],
+ [y]: v[y],
+ [series]: v[series],
+ [size]: v[size],
+ [entity]: v[entity],
+ })),
+ ),
+ ),
+ width,
+ height,
+ encoding: {
+ x: {
+ field: x,
+ type: 'quantitive',
+ format: xAxisFormat,
+ scale: {
+ type: 'linear',
+ },
+ axis: {
+ orient: 'bottom',
+ title: xAxisLabel,
+ },
+ },
+ y: {
+ field: y,
+ type: 'quantitative',
+ format: yAxisFormat,
+ scale: {
+ type: 'linear',
+ },
+ axis: {
+ orient: 'left',
+ title: yAxisLabel,
+ },
+ },
+ size: {
+ field: size,
+ type: 'quantitative',
+ scale: {
+ type: 'linear',
+ range: [0, maxBubbleSize],
+ },
+ },
+ fill: {
+ field: series,
+ type: 'nominal',
+ scale: {
+ scheme: colorScheme,
+ },
+ legend: showLegend,
+ },
+ },
+ commonEncoding: {
+ group: [{ field: entity }],
+ },
+ };
+}
diff --git a/packages/superset-ui-preset-chart-xy/src/ScatterPlot/transformProps.ts b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/transformProps.ts
new file mode 100644
index 000000000..94f2c864e
--- /dev/null
+++ b/packages/superset-ui-preset-chart-xy/src/ScatterPlot/transformProps.ts
@@ -0,0 +1,18 @@
+import { ChartProps } from '@superset-ui/chart';
+
+/* eslint-disable sort-keys */
+
+export default function transformProps(chartProps: ChartProps) {
+ const { width, height, formData, payload } = chartProps;
+ const { encoding, commonEncoding, margin } = formData;
+ const { data } = payload;
+
+ return {
+ data,
+ width,
+ height,
+ encoding,
+ commonEncoding,
+ margin,
+ };
+}
diff --git a/packages/superset-ui-preset-chart-xy/src/encodeable/AbstractEncoder.ts b/packages/superset-ui-preset-chart-xy/src/encodeable/AbstractEncoder.ts
index cd9f95394..4a290a362 100644
--- a/packages/superset-ui-preset-chart-xy/src/encodeable/AbstractEncoder.ts
+++ b/packages/superset-ui-preset-chart-xy/src/encodeable/AbstractEncoder.ts
@@ -7,7 +7,7 @@ import {
ChannelInput,
} from './types/Channel';
import { FullSpec, BaseOptions, PartialSpec } from './types/Specification';
-import { isFieldDef, isTypedFieldDef } from './types/ChannelDef';
+import { isFieldDef, isTypedFieldDef, FieldDef } from './types/ChannelDef';
import ChannelEncoder from './ChannelEncoder';
import { Dataset } from './types/Data';
@@ -28,6 +28,11 @@ export default abstract class AbstractEncoder<
readonly [k in keyof ChannelTypes]: ChannelEncoder
};
+ readonly commonChannels: {
+ group: ChannelEncoder[];
+ tooltip: ChannelEncoder[];
+ };
+
readonly legends: {
[key: string]: (keyof ChannelTypes)[];
};
@@ -67,6 +72,25 @@ export default abstract class AbstractEncoder<
return all;
}, {}) as Channels;
+ this.commonChannels = {
+ group: this.spec.commonEncoding.group.map(
+ (def, i) =>
+ new ChannelEncoder({
+ definition: def,
+ name: `group${i}`,
+ type: 'Text',
+ }),
+ ),
+ tooltip: this.spec.commonEncoding.tooltip.map(
+ (def, i) =>
+ new ChannelEncoder({
+ definition: def,
+ name: `tooltip${i}`,
+ type: 'Text',
+ }),
+ ),
+ };
+
// Group the channels that use the same field together
// so they can share the same legend.
this.legends = {};
@@ -94,9 +118,14 @@ export default abstract class AbstractEncoder<
return spec as FullSpec;
}
- const { encoding, ...rest } = spec;
+ const { encoding, commonEncoding = {}, ...rest } = spec;
+ const { group = [], tooltip = [] } = commonEncoding;
return {
+ commonEncoding: {
+ group,
+ tooltip,
+ },
...rest,
encoding: {
...defaultEncoding,
diff --git a/packages/superset-ui-preset-chart-xy/src/encodeable/AxisAgent.ts b/packages/superset-ui-preset-chart-xy/src/encodeable/AxisAgent.ts
index 94c1737c3..ffc15404f 100644
--- a/packages/superset-ui-preset-chart-xy/src/encodeable/AxisAgent.ts
+++ b/packages/superset-ui-preset-chart-xy/src/encodeable/AxisAgent.ts
@@ -142,7 +142,7 @@ export default class AxisAgent, Output extends Va
if (this.channelEncoder.isX()) {
if (strategyForLabelOverlap === 'flat') {
- const labelHeight = labelDimensions[0].height;
+ const labelHeight = labelDimensions.length > 0 ? labelDimensions[0].height : 0;
labelOffset = labelHeight + labelPadding;
requiredMargin += labelHeight;
} else if (strategyForLabelOverlap === 'rotate') {
diff --git a/packages/superset-ui-preset-chart-xy/src/encodeable/types/Specification.ts b/packages/superset-ui-preset-chart-xy/src/encodeable/types/Specification.ts
index 7631de62e..f8d7427d0 100644
--- a/packages/superset-ui-preset-chart-xy/src/encodeable/types/Specification.ts
+++ b/packages/superset-ui-preset-chart-xy/src/encodeable/types/Specification.ts
@@ -1,13 +1,23 @@
+import { FieldDef } from './ChannelDef';
+
export interface BaseOptions {
namespace?: string;
}
export interface PartialSpec {
encoding: Partial;
+ commonEncoding?: Partial<{
+ group: FieldDef[];
+ tooltip: FieldDef[];
+ }>;
options?: Options;
}
export interface FullSpec {
encoding: Encoding;
+ commonEncoding: {
+ group: FieldDef[];
+ tooltip: FieldDef[];
+ };
options?: Options;
}
diff --git a/packages/superset-ui-preset-chart-xy/src/index.ts b/packages/superset-ui-preset-chart-xy/src/index.ts
index 498637196..3932d61ae 100644
--- a/packages/superset-ui-preset-chart-xy/src/index.ts
+++ b/packages/superset-ui-preset-chart-xy/src/index.ts
@@ -1,2 +1,3 @@
export { default as BoxPlotChartPlugin } from './BoxPlot';
+export { default as ScatterPlotPlugin } from './ScatterPlot';
export { default as LineChartPlugin } from './Line';
diff --git a/packages/superset-ui-preset-chart-xy/src/legacy.ts b/packages/superset-ui-preset-chart-xy/src/legacy.ts
index c0403f479..24c83c6d3 100644
--- a/packages/superset-ui-preset-chart-xy/src/legacy.ts
+++ b/packages/superset-ui-preset-chart-xy/src/legacy.ts
@@ -1,2 +1,3 @@
export { default as BoxPlotChartPlugin } from './BoxPlot/legacy';
+export { default as ScatterPlotPlugin } from './ScatterPlot/legacy';
export { default as LineChartPlugin } from './Line/legacy';
diff --git a/packages/superset-ui-preset-chart-xy/types/@data-ui/xy-chart/index.d.ts b/packages/superset-ui-preset-chart-xy/types/@data-ui/xy-chart/index.d.ts
index 504be9e51..308a07385 100644
--- a/packages/superset-ui-preset-chart-xy/types/@data-ui/xy-chart/index.d.ts
+++ b/packages/superset-ui-preset-chart-xy/types/@data-ui/xy-chart/index.d.ts
@@ -33,6 +33,7 @@ declare module '@data-ui/xy-chart' {
export class CrossHair extends React.PureComponent {}
export class LinearGradient extends React.PureComponent {}
export class LineSeries extends React.PureComponent {}
+ export class PointSeries extends React.PureComponent {}
export class WithTooltip extends React.PureComponent {}
export class XYChart extends React.PureComponent {}
export class XAxis extends React.PureComponent {}