diff --git a/superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js b/superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js
index 5b90e4b4b3845..e679441187a10 100644
--- a/superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js
+++ b/superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js
@@ -33,7 +33,7 @@ const metadata = new ChartMetadata({
{ url: example1, description: t('Demographics') },
{ url: example2, description: t('Survey Responses') },
],
- name: t('Sankey Diagram'),
+ name: t('Sankey Diagram (legacy)'),
tags: [
t('Categorical'),
t('Directional'),
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/Sankey.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/Sankey.tsx
new file mode 100644
index 0000000000000..b01da214c3704
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/Sankey.tsx
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ */
+import { SankeyTransformedProps } from './types';
+import Echart from '../components/Echart';
+
+export default function Sankey(props: SankeyTransformedProps) {
+ const { height, width, echartOptions, refs } = props;
+
+ return (
+
+ );
+}
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/buildQuery.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/buildQuery.ts
new file mode 100644
index 0000000000000..0ec7ec85bf0f8
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/buildQuery.ts
@@ -0,0 +1,32 @@
+/**
+ * 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.
+ */
+import { buildQueryContext } from '@superset-ui/core';
+import { SankeyFormData } from './types';
+
+export default function buildQuery(formData: SankeyFormData) {
+ const { metric, sort_by_metric, source, target } = formData;
+ const groupby = [source, target];
+ return buildQueryContext(formData, baseQueryObject => [
+ {
+ ...baseQueryObject,
+ groupby,
+ ...(sort_by_metric && { orderby: [[metric, false]] }),
+ },
+ ]);
+}
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/controlPanel.tsx
new file mode 100644
index 0000000000000..05a7ac57cf610
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/controlPanel.tsx
@@ -0,0 +1,75 @@
+/**
+ * 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.
+ */
+import { t, validateNonEmpty } from '@superset-ui/core';
+import {
+ ControlPanelConfig,
+ dndGroupByControl,
+} from '@superset-ui/chart-controls';
+
+const config: ControlPanelConfig = {
+ controlPanelSections: [
+ {
+ label: t('Query'),
+ expanded: true,
+ controlSetRows: [
+ [
+ {
+ name: 'source',
+ config: {
+ ...dndGroupByControl,
+ label: t('Source'),
+ multi: false,
+ description: t(
+ 'The column to be used as the source of the edge.',
+ ),
+ validators: [validateNonEmpty],
+ freeForm: false,
+ },
+ },
+ ],
+ [
+ {
+ name: 'target',
+ config: {
+ ...dndGroupByControl,
+ label: t('Target'),
+ multi: false,
+ description: t(
+ 'The column to be used as the target of the edge.',
+ ),
+ validators: [validateNonEmpty],
+ freeForm: false,
+ },
+ },
+ ],
+ ['metric'],
+ ['adhoc_filters'],
+ ['row_limit'],
+ ['sort_by_metric'],
+ ],
+ },
+ {
+ label: t('Chart Options'),
+ expanded: true,
+ controlSetRows: [['color_scheme']],
+ },
+ ],
+};
+
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/images/example1.png b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/images/example1.png
new file mode 100644
index 0000000000000..ff5ca93400974
Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/images/example1.png differ
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/images/example2.png b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/images/example2.png
new file mode 100644
index 0000000000000..9ae0754bb42dd
Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/images/example2.png differ
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/images/thumbnail.png b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/images/thumbnail.png
new file mode 100644
index 0000000000000..6f18b45f08fe3
Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/images/thumbnail.png differ
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/index.ts
new file mode 100644
index 0000000000000..77348bdab7176
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/index.ts
@@ -0,0 +1,66 @@
+/**
+ * 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
+ * regardin
+ * g 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.
+ */
+import { Behavior, ChartMetadata, ChartPlugin, t } from '@superset-ui/core';
+import buildQuery from './buildQuery';
+import controlPanel from './controlPanel';
+import transformProps from './transformProps';
+import thumbnail from './images/thumbnail.png';
+import example1 from './images/example1.png';
+import example2 from './images/example2.png';
+import { SankeyChartProps, SankeyFormData } from './types';
+
+export default class EchartsSankeyChartPlugin extends ChartPlugin<
+ SankeyFormData,
+ SankeyChartProps
+> {
+ /**
+ * The constructor is used to pass relevant metadata and callbacks that get
+ * registered in respective registries that are used throughout the library
+ * and application. A more thorough description of each property is given in
+ * the respective imported file.
+ *
+ * It is worth noting that `buildQuery` and is optional, and only needed for
+ * advanced visualizations that require either post processing operations
+ * (pivoting, rolling aggregations, sorting etc) or submitting multiple queries.
+ */
+ constructor() {
+ super({
+ buildQuery,
+ controlPanel,
+ loadChart: () => import('./Sankey'),
+ metadata: new ChartMetadata({
+ behaviors: [Behavior.InteractiveChart],
+ credits: ['https://echarts.apache.org'],
+ category: t('Flow'),
+ description: t(
+ `The Sankey chart visually tracks the movement and transformation of values across
+ system stages. Nodes represent stages, connected by links depicting value flow. Node
+ height corresponds to the visualized metric, providing a clear representation of
+ value distribution and transformation.`,
+ ),
+ exampleGallery: [{ url: example1 }, { url: example2 }],
+ name: t('Sankey Chart'),
+ tags: [t('Directional'), t('Distribution'), t('Flow')],
+ thumbnail,
+ }),
+ transformProps,
+ });
+ }
+}
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/transformProps.ts
new file mode 100644
index 0000000000000..96be18c8988ba
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/transformProps.ts
@@ -0,0 +1,125 @@
+/**
+ * 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.
+ */
+import { EChartsOption, SankeySeriesOption } from 'echarts';
+import { CallbackDataParams } from 'echarts/types/src/util/types';
+import {
+ CategoricalColorNamespace,
+ NumberFormats,
+ getColumnLabel,
+ getMetricLabel,
+ getNumberFormatter,
+ tooltipHtml,
+} from '@superset-ui/core';
+import { SankeyChartProps, SankeyTransformedProps } from './types';
+import { Refs } from '../types';
+import { getDefaultTooltip } from '../utils/tooltip';
+import { getPercentFormatter } from '../utils/formatters';
+
+type Link = { source: string; target: string; value: number };
+
+export default function transformProps(
+ chartProps: SankeyChartProps,
+): SankeyTransformedProps {
+ const refs: Refs = {};
+ const { formData, height, hooks, queriesData, width } = chartProps;
+ const { onLegendStateChanged } = hooks;
+ const { colorScheme, metric, source, target } = formData;
+ const { data } = queriesData[0];
+ const colorFn = CategoricalColorNamespace.getScale(colorScheme);
+ const metricLabel = getMetricLabel(metric);
+ const valueFormatter = getNumberFormatter(NumberFormats.FLOAT_2_POINT);
+ const percentFormatter = getPercentFormatter(NumberFormats.PERCENT_2_POINT);
+
+ const links: Link[] = [];
+ const set = new Set();
+ data.forEach(datum => {
+ const sourceName = String(datum[getColumnLabel(source)]);
+ const targetName = String(datum[getColumnLabel(target)]);
+ const value = datum[metricLabel] as number;
+ set.add(sourceName);
+ set.add(targetName);
+ links.push({
+ source: sourceName,
+ target: targetName,
+ value,
+ });
+ });
+
+ const seriesData: NonNullable = Array.from(
+ set,
+ ).map(name => ({
+ name,
+ itemStyle: {
+ color: colorFn(name),
+ },
+ }));
+
+ // stores a map with the total values for each node considering the links
+ const nodeValues = new Map();
+ links.forEach(link => {
+ const { source, target, value } = link;
+ const sourceValue = nodeValues.get(source) || 0;
+ const targetValue = nodeValues.get(target) || 0;
+ nodeValues.set(source, sourceValue + value);
+ nodeValues.set(target, targetValue + value);
+ });
+
+ const tooltipFormatter = (params: CallbackDataParams) => {
+ const { name, data } = params;
+ const value = params.value as number;
+ const rows = [[metricLabel, valueFormatter.format(value)]];
+ const { source, target } = data as Link;
+ if (source && target) {
+ rows.push([
+ `% (${source})`,
+ percentFormatter.format(value / nodeValues.get(source)!),
+ ]);
+ rows.push([
+ `% (${target})`,
+ percentFormatter.format(value / nodeValues.get(target)!),
+ ]);
+ }
+ return tooltipHtml(rows, name);
+ };
+
+ const echartOptions: EChartsOption = {
+ series: {
+ animation: false,
+ data: seriesData,
+ lineStyle: {
+ color: 'source',
+ },
+ links,
+ type: 'sankey',
+ },
+ tooltip: {
+ ...getDefaultTooltip(refs),
+ formatter: tooltipFormatter,
+ },
+ };
+
+ return {
+ refs,
+ formData,
+ width,
+ height,
+ echartOptions,
+ onLegendStateChanged,
+ };
+}
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/types.ts
new file mode 100644
index 0000000000000..323bd1612ca80
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/types.ts
@@ -0,0 +1,37 @@
+/**
+ * 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.
+ */
+import {
+ QueryFormColumn,
+ QueryFormData,
+ QueryFormMetric,
+} from '@superset-ui/core';
+import { BaseChartProps, BaseTransformedProps } from '../types';
+
+export type SankeyFormData = QueryFormData & {
+ colorScheme: string;
+ metric: QueryFormMetric;
+ source: QueryFormColumn;
+ target: QueryFormColumn;
+};
+
+export interface SankeyChartProps extends BaseChartProps {
+ formData: SankeyFormData;
+}
+
+export type SankeyTransformedProps = BaseTransformedProps & {};
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/index.ts
index 36290ec450300..5c3c3e4c7f1f7 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/index.ts
@@ -41,6 +41,7 @@ export {
} from './BigNumber';
export { default as EchartsSunburstChartPlugin } from './Sunburst';
export { default as EchartsBubbleChartPlugin } from './Bubble';
+export { default as EchartsSankeyChartPlugin } from './Sankey';
export { default as EchartsWaterfallChartPlugin } from './Waterfall';
export { default as BoxPlotTransformProps } from './BoxPlot/transformProps';
@@ -58,6 +59,7 @@ export { default as SunburstTransformProps } from './Sunburst/transformProps';
export { default as BubbleTransformProps } from './Bubble/transformProps';
export { default as WaterfallTransformProps } from './Waterfall/transformProps';
export { default as HistogramTransformProps } from './Histogram/transformProps';
+export { default as SankeyTransformProps } from './Sankey/transformProps';
export { DEFAULT_FORM_DATA as TimeseriesDefaultFormData } from './Timeseries/constants';
diff --git a/superset-frontend/src/visualizations/presets/MainPreset.js b/superset-frontend/src/visualizations/presets/MainPreset.js
index 196f18b8d6e84..72dc9151c3b8c 100644
--- a/superset-frontend/src/visualizations/presets/MainPreset.js
+++ b/superset-frontend/src/visualizations/presets/MainPreset.js
@@ -61,6 +61,7 @@ import {
EchartsHistogramChartPlugin,
EchartsRadarChartPlugin,
EchartsFunnelChartPlugin,
+ EchartsSankeyChartPlugin,
EchartsTreemapChartPlugin,
EchartsMixedTimeseriesChartPlugin,
EchartsTreeChartPlugin,
@@ -112,6 +113,7 @@ export default class MainPreset extends Preset {
new DistBarChartPlugin().configure({ key: 'dist_bar' }),
new EventFlowChartPlugin().configure({ key: 'event_flow' }),
new EchartsFunnelChartPlugin().configure({ key: 'funnel' }),
+ new EchartsSankeyChartPlugin().configure({ key: 'sankey_v2' }),
new EchartsTreemapChartPlugin().configure({ key: 'treemap_v2' }),
new EchartsGaugeChartPlugin().configure({ key: 'gauge_chart' }),
new EchartsGraphChartPlugin().configure({ key: 'graph_chart' }),
diff --git a/superset/cli/viz_migrations.py b/superset/cli/viz_migrations.py
index 9714969073099..6b6ba1a7046d9 100644
--- a/superset/cli/viz_migrations.py
+++ b/superset/cli/viz_migrations.py
@@ -33,6 +33,7 @@ class VizType(str, Enum):
HISTOGRAM = "histogram"
LINE = "line"
PIVOT_TABLE = "pivot_table"
+ SANKEY = "sankey"
SUNBURST = "sunburst"
TREEMAP = "treemap"
@@ -89,6 +90,7 @@ def migrate(viz_type: VizType, is_downgrade: bool = False) -> None:
MigrateHistogramChart,
MigrateLineChart,
MigratePivotTable,
+ MigrateSankey,
MigrateSunburst,
MigrateTreeMap,
)
@@ -103,6 +105,7 @@ def migrate(viz_type: VizType, is_downgrade: bool = False) -> None:
VizType.HISTOGRAM: MigrateHistogramChart,
VizType.LINE: MigrateLineChart,
VizType.PIVOT_TABLE: MigratePivotTable,
+ VizType.SANKEY: MigrateSankey,
VizType.SUNBURST: MigrateSunburst,
VizType.TREEMAP: MigrateTreeMap,
}
diff --git a/superset/examples/configs/charts/Featured Charts/Sankey.yaml b/superset/examples/configs/charts/Featured Charts/Sankey.yaml
new file mode 100644
index 0000000000000..8540f5f6499ee
--- /dev/null
+++ b/superset/examples/configs/charts/Featured Charts/Sankey.yaml
@@ -0,0 +1,41 @@
+# 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.
+slice_name: Sankey
+description: null
+certified_by: null
+certification_details: null
+viz_type: sankey_v2
+params:
+ datasource: 22__table
+ viz_type: sankey_v2
+ source: product_line
+ target: deal_size
+ metric: count
+ adhoc_filters:
+ - clause: WHERE
+ subject: order_date
+ operator: TEMPORAL_RANGE
+ comparator: No filter
+ expressionType: SIMPLE
+ row_limit: 10000
+ color_scheme: supersetColors
+ extra_form_data: {}
+ dashboards: []
+cache_timeout: null
+uuid: fead4d46-ecb9-4fd9-8b9c-420629269c02
+version: 1.0.0
+dataset_uuid: e8623bb9-5e00-f531-506a-19607f5f8005
diff --git a/superset/examples/configs/dashboards/Featured_Charts.yaml b/superset/examples/configs/dashboards/Featured_Charts.yaml
index 2d0e0c4f1b296..598db88ad6185 100644
--- a/superset/examples/configs/dashboards/Featured_Charts.yaml
+++ b/superset/examples/configs/dashboards/Featured_Charts.yaml
@@ -49,7 +49,7 @@ position:
parents:
- ROOT_ID
- GRID_ID
- - ROW-Jq9auQfs6-
+ - ROW-3XARWMYOfz
type: CHART
CHART-3tEC_8e-uS:
children: []
@@ -147,7 +147,7 @@ position:
parents:
- ROOT_ID
- GRID_ID
- - ROW-3XARWMYOfz
+ - ROW-ux6j1ePT8I
type: CHART
CHART-EpsTnvUMuW:
children: []
@@ -273,7 +273,7 @@ position:
parents:
- ROOT_ID
- GRID_ID
- - ROW-ux6j1ePT8I
+ - ROW-we3i1eOT75
type: CHART
CHART-gfrGP3BD76:
children: []
@@ -289,6 +289,20 @@ position:
- GRID_ID
- ROW-W7YILGiS0-
type: CHART
+ CHART-Yi0u5d9otw:
+ children: []
+ id: CHART-Yi0u5d9otw
+ meta:
+ chartId: 359
+ height: 50
+ sliceName: Sankey
+ uuid: fead4d46-ecb9-4fd9-8b9c-420629269c02
+ width: 4
+ parents:
+ - ROOT_ID
+ - GRID_ID
+ - ROW-Jq9auQfs6-
+ type: CHART
CHART-j2o9aZo4HY:
children: []
id: CHART-j2o9aZo4HY
@@ -370,6 +384,7 @@ position:
- ROW-Jq9auQfs6-
- ROW-3XARWMYOfz
- ROW-ux6j1ePT8I
+ - ROW-we3i1eOT75
id: GRID_ID
parents:
- ROOT_ID
@@ -386,9 +401,9 @@ position:
type: ROOT
ROW-3XARWMYOfz:
children:
+ - CHART-33vjmwrGX1
- CHART-3tEC_8e-uS
- CHART-A4qrvR24Ne
- - CHART-DqaJJ8Fse6
id: ROW-3XARWMYOfz
meta:
background: BACKGROUND_TRANSPARENT
@@ -400,7 +415,7 @@ position:
children:
- CHART-qZh51tuuRH
- CHART-j2o9aZo4HY
- - CHART-33vjmwrGX1
+ - CHART-Yi0u5d9otw
id: ROW-Jq9auQfs6-
meta:
background: BACKGROUND_TRANSPARENT
@@ -470,9 +485,9 @@ position:
type: ROW
ROW-ux6j1ePT8I:
children:
+ - CHART-DqaJJ8Fse6
- CHART-XwFZukVv8E
- CHART-KE7lk61Tbt
- - CHART-aAhaxRYu_t
id: ROW-ux6j1ePT8I
meta:
background: BACKGROUND_TRANSPARENT
@@ -480,6 +495,16 @@ position:
- ROOT_ID
- GRID_ID
type: ROW
+ ROW-we3i1eOT75:
+ children:
+ - CHART-aAhaxRYu_t
+ id: ROW-we3i1eOT75
+ meta:
+ background: BACKGROUND_TRANSPARENT
+ parents:
+ - ROOT_ID
+ - GRID_ID
+ type: ROW
metadata:
color_scheme: supersetAndPresetColors
refresh_frequency: 0
diff --git a/superset/migrations/shared/migrate_viz/processors.py b/superset/migrations/shared/migrate_viz/processors.py
index ef5a1c6bd6094..99c545d98fa98 100644
--- a/superset/migrations/shared/migrate_viz/processors.py
+++ b/superset/migrations/shared/migrate_viz/processors.py
@@ -303,3 +303,15 @@ def _pre_action(self) -> None:
groupby = self.data.get("groupby")
if not groupby:
self.data["groupby"] = []
+
+
+class MigrateSankey(MigrateViz):
+ source_viz_type = "sankey"
+ target_viz_type = "sankey_v2"
+ remove_keys = {"groupby"}
+
+ def _pre_action(self) -> None:
+ groupby = self.data.get("groupby")
+ if groupby and len(groupby) > 1:
+ self.data["source"] = groupby[0]
+ self.data["target"] = groupby[1]