feat(bubble): migrate saved bubble charts to bubble_v2 and drop the legacy plugin (#41728)

Co-authored-by: Claude Code <noreply@anthropic.com>
This commit is contained in:
Evan Rusackas
2026-07-03 00:36:38 -07:00
committed by rusackas
parent 8948b5af94
commit 2cd9873540
18 changed files with 63 additions and 752 deletions

View File

@@ -1,140 +0,0 @@
/**
* 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 } from '@apache-superset/core/translation';
import {
ControlPanelConfig,
formatSelectOptions,
D3_FORMAT_OPTIONS,
getStandardizedControls,
} from '@superset-ui/chart-controls';
import {
showLegend,
xAxisLabel,
yAxisLabel,
bottomMargin,
xTicksLayout,
xAxisFormat,
yLogScale,
xAxisShowMinmax,
yAxisShowMinmax,
leftMargin,
yAxisBounds,
} from '../NVD3Controls';
const config: ControlPanelConfig = {
controlPanelSections: [
{
label: t('Query'),
expanded: true,
controlSetRows: [
['series'],
['entity'],
['x'],
['y'],
['adhoc_filters'],
['size'],
[
{
name: 'max_bubble_size',
config: {
type: 'SelectControl',
freeForm: true,
label: t('Max Bubble Size'),
default: '25',
choices: formatSelectOptions([
'5',
'10',
'15',
'25',
'50',
'75',
'100',
]),
},
},
],
['limit', null],
],
},
{
label: t('Chart Options'),
expanded: true,
tabOverride: 'customize',
controlSetRows: [['color_scheme'], [showLegend, null]],
},
{
label: t('X Axis'),
expanded: true,
tabOverride: 'customize',
controlSetRows: [
[xAxisLabel, leftMargin],
[
{
name: xAxisFormat.name,
config: {
...xAxisFormat.config,
default: 'SMART_NUMBER',
choices: D3_FORMAT_OPTIONS,
},
},
xTicksLayout,
],
[
{
name: 'x_log_scale',
config: {
type: 'CheckboxControl',
label: t('X Log Scale'),
default: false,
renderTrigger: true,
description: t('Use a log scale for the X-axis'),
},
},
xAxisShowMinmax,
],
],
},
{
label: t('Y Axis'),
expanded: true,
tabOverride: 'customize',
controlSetRows: [
[yAxisLabel, bottomMargin],
['y_axis_format', null],
[yLogScale, yAxisShowMinmax],
[yAxisBounds],
],
},
],
controlOverrides: {
color_scheme: {
renderTrigger: false,
},
},
formDataOverrides: formData => ({
...formData,
series: getStandardizedControls().shiftColumn(),
entity: getStandardizedControls().shiftColumn(),
x: getStandardizedControls().shiftMetric(),
y: getStandardizedControls().shiftMetric(),
size: getStandardizedControls().shiftMetric(),
}),
};
export default config;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -1,63 +0,0 @@
/**
* 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 } from '@apache-superset/core/translation';
import { ChartMetadata, ChartPlugin, ChartLabel } from '@superset-ui/core';
import transformProps from '../transformProps';
import example from './images/example.jpg';
import exampleDark from './images/example-dark.jpg';
import thumbnail from './images/thumbnail.png';
import thumbnailDark from './images/thumbnail-dark.png';
import controlPanel from './controlPanel';
const metadata = new ChartMetadata({
category: t('Correlation'),
credits: ['http://nvd3.org'],
description: t(
'Visualizes a metric across three dimensions of data in a single chart (X axis, Y axis, and bubble size). Bubbles from the same group can be showcased using bubble color.',
),
exampleGallery: [{ url: example, urlDark: exampleDark }],
label: ChartLabel.Deprecated,
name: t('Bubble Chart (legacy)'),
tags: [
t('Multi-Dimensions'),
t('Comparison'),
t('Legacy'),
t('Scatter'),
t('Time'),
t('Trend'),
t('nvd3'),
],
thumbnail,
thumbnailDark,
useLegacyApi: true,
});
/**
* @deprecated in version 4.0.
*/
export default class BubbleChartPlugin extends ChartPlugin {
constructor() {
super({
loadChart: () => import('../ReactNVD3'),
metadata,
transformProps,
controlPanel,
});
}
}

View File

@@ -1,103 +0,0 @@
/*
* 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 { SuperChart, VizType } from '@superset-ui/core';
import { BubbleChartPlugin } from '@superset-ui/legacy-preset-chart-nvd3';
import { dummyDatasource, withResizableChartDemo } from '@storybook-shared';
import data from './data';
new BubbleChartPlugin().configure({ key: VizType.LegacyBubble }).register();
export default {
title: 'Legacy Chart Plugins/legacy-preset-chart-nvd3/Bubble',
decorators: [withResizableChartDemo],
args: {
colorScheme: 'd3Category10',
maxBubbleSize: 50,
showLegend: true,
xLogScale: false,
yLogScale: false,
},
argTypes: {
colorScheme: {
control: 'select',
options: [
'supersetColors',
'd3Category10',
'bnbColors',
'googleCategory20c',
],
},
maxBubbleSize: {
control: { type: 'range', min: 10, max: 100, step: 5 },
},
showLegend: { control: 'boolean' },
xLogScale: { control: 'boolean' },
yLogScale: { control: 'boolean' },
},
};
export const Basic = ({
colorScheme,
maxBubbleSize,
showLegend,
xLogScale,
yLogScale,
width,
height,
}: {
colorScheme: string;
maxBubbleSize: number;
showLegend: boolean;
xLogScale: boolean;
yLogScale: boolean;
width: number;
height: number;
}) => (
<SuperChart
chartType={VizType.LegacyBubble}
width={width}
height={height}
datasource={dummyDatasource}
queriesData={[{ data }]}
formData={{
annotation_data: {},
bottom_margin: 'auto',
color_scheme: colorScheme,
entity: 'country_name',
left_margin: 'auto',
max_bubble_size: String(maxBubbleSize),
series: 'region',
show_legend: showLegend,
size: 'sum__SP_POP_TOTL',
viz_type: VizType.LegacyBubble,
x: 'sum__SP_RUR_TOTL_ZS',
x_axis_format: '.3s',
x_axis_label: 'Rural Population %',
x_axis_showminmax: false,
x_log_scale: xLogScale,
x_ticks_layout: 'auto',
y: 'sum__SP_DYN_LE00_IN',
y_axis_format: '.3s',
y_axis_label: 'Life Expectancy',
y_axis_showminmax: false,
y_log_scale: yLogScale,
}}
/>
);

View File

@@ -1,357 +0,0 @@
/*
* 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 */
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',
},
],
},
];

View File

@@ -47,7 +47,6 @@ import {
cleanColorInput,
computeYDomain,
drawBarValues,
generateBubbleTooltipContent,
generateCompareTooltipContent,
generateTimePivotTooltip,
generateTooltipClassName,
@@ -407,29 +406,6 @@ function nvd3Vis(element, props) {
chart.xAxis.showMaxMin(false);
break;
case VizType.LegacyBubble:
chart = nv.models.scatterChart();
chart.showDistX(false);
chart.showDistY(false);
chart.tooltip.contentGenerator(d =>
generateBubbleTooltipContent({
point: d.point,
entity,
xField,
yField,
sizeField,
xFormatter: getTimeOrNumberFormatter(xAxisFormat),
yFormatter: getTimeOrNumberFormatter(yAxisFormat),
sizeFormatter: formatter,
}),
);
chart.pointRange([5, maxBubbleSize ** 2]);
chart.pointDomain([
0,
d3.max(data, d => d3.max(d.values, v => v.size)),
]);
break;
case VizType.BoxPlot:
colorKey = 'label';
chart = nv.models.boxPlotChart();

View File

@@ -18,7 +18,6 @@
*/
export { default as NVD3ChartPreset } from './preset';
export { default as BubbleChartPlugin } from './Bubble';
export { default as BulletChartPlugin } from './Bullet';
export { default as CompareChartPlugin } from './Compare';
export { default as TimePivotChartPlugin } from './TimePivot';

View File

@@ -17,7 +17,6 @@
* under the License.
*/
import { Preset, VizType } from '@superset-ui/core';
import BubbleChartPlugin from './Bubble';
import BulletChartPlugin from './Bullet';
import CompareChartPlugin from './Compare';
import TimePivotChartPlugin from './TimePivot';
@@ -27,7 +26,6 @@ export default class NVD3ChartPreset extends Preset {
super({
name: 'NVD3 charts',
plugins: [
new BubbleChartPlugin().configure({ key: VizType.LegacyBubble }),
new BulletChartPlugin().configure({ key: VizType.Bullet }),
new CompareChartPlugin().configure({ key: VizType.Compare }),
new TimePivotChartPlugin().configure({ key: VizType.TimePivot }),

View File

@@ -34,7 +34,6 @@ import TableChartPlugin from '@superset-ui/plugin-chart-table';
import { WordCloudChartPlugin } from '@superset-ui/plugin-chart-word-cloud';
import WorldMapChartPlugin from '@superset-ui/legacy-plugin-chart-world-map';
import {
BubbleChartPlugin,
BulletChartPlugin,
CompareChartPlugin,
TimePivotChartPlugin,
@@ -114,7 +113,6 @@ export default class MainPreset extends Preset {
key: VizType.BigNumberTotal,
}),
new EchartsBoxPlotChartPlugin().configure({ key: VizType.BoxPlot }),
new BubbleChartPlugin().configure({ key: VizType.LegacyBubble }),
new BulletChartPlugin().configure({ key: VizType.Bullet }),
new CalendarChartPlugin().configure({ key: VizType.Calendar }),
new ChordChartPlugin().configure({ key: VizType.Chord }),

View File

@@ -222,16 +222,16 @@ def create_slices(tbl: BaseDatasource) -> list[Slice]:
),
Slice(
slice_name="Life Expectancy VS Rural %",
viz_type="bubble",
viz_type="bubble_v2",
datasource_type=DatasourceType.TABLE,
datasource_id=tbl.id,
params=get_slice_json(
defaults,
viz_type="bubble",
viz_type="bubble_v2",
since="2011-01-01",
until="2011-01-02",
series="region",
limit=0,
row_limit=0,
entity="country_name",
x="sum__SP_RUR_TOTL_ZS",
y="sum__SP_DYN_LE00_IN",

View File

@@ -0,0 +1,55 @@
# 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.
"""migrate_bubble_chart_to_echarts
Revision ID: d4e5f6a7b8c9
Revises: b4a3f2e1d0c9
Create Date: 2026-07-02 21:00:00.000000
"""
from alembic import op
from sqlalchemy import text
from sqlalchemy.dialects.mysql.base import MySQLDialect
from superset import db
from superset.migrations.shared.migrate_viz import MigrateBubbleChart
# revision identifiers, used by Alembic.
revision = "d4e5f6a7b8c9"
down_revision = "b4a3f2e1d0c9"
def upgrade():
bind = op.get_bind()
# Ensure `slice.params` and `slice.query_context` in MySQL is MEDIUMTEXT
# before migration, as the migration will save a duplicate form_data backup
# which may significantly increase the size of these fields.
if isinstance(bind.dialect, MySQLDialect):
# If the columns are already MEDIUMTEXT, this is a no-op
op.execute(text("ALTER TABLE slices MODIFY params MEDIUMTEXT"))
op.execute(text("ALTER TABLE slices MODIFY query_context MEDIUMTEXT"))
session = db.Session(bind=bind)
MigrateBubbleChart.upgrade(session)
def downgrade():
bind = op.get_bind()
session = db.Session(bind=bind)
MigrateBubbleChart.downgrade(session)

View File

@@ -27,7 +27,7 @@ import copy
import dataclasses
import logging
import math
from collections import defaultdict, OrderedDict
from collections import OrderedDict
from datetime import datetime, timedelta
from itertools import product
from typing import Any, cast, Optional, TYPE_CHECKING
@@ -884,58 +884,6 @@ class NVD3Viz(BaseViz):
is_timeseries = False
class BubbleViz(NVD3Viz):
"""Based on the NVD3 bubble chart"""
viz_type = "bubble"
verbose_name = _("Bubble Chart")
is_timeseries = False
@deprecated(deprecated_in="3.0")
def query_obj(self) -> QueryObjectDict:
query_obj = super().query_obj()
query_obj["groupby"] = [self.form_data.get("entity")]
if self.form_data.get("series"):
query_obj["groupby"].append(self.form_data.get("series"))
# dedup groupby if it happens to be the same
query_obj["groupby"] = self.dedup_columns(query_obj["groupby"])
# pylint: disable=attribute-defined-outside-init
self.x_metric = self.form_data["x"]
self.y_metric = self.form_data["y"]
self.z_metric = self.form_data["size"]
self.entity = self.form_data.get("entity")
self.series = self.form_data.get("series") or self.entity
query_obj["row_limit"] = self.form_data.get("limit")
query_obj["metrics"] = [self.z_metric, self.x_metric, self.y_metric]
if len(set(self.metric_labels)) < 3:
raise QueryObjectValidationError(_("Please use 3 different metric labels"))
if not all(query_obj["metrics"] + [self.entity]):
raise QueryObjectValidationError(_("Pick a metric for x, y and size"))
return query_obj
@deprecated(deprecated_in="3.0")
def get_data(self, df: pd.DataFrame) -> VizData:
if df.empty:
return None
df["x"] = df[[utils.get_metric_name(self.x_metric)]]
df["y"] = df[[utils.get_metric_name(self.y_metric)]]
df["size"] = df[[utils.get_metric_name(self.z_metric)]]
df["shape"] = "circle"
df["group"] = df[[get_column_name(self.series)]] # type: ignore
series: dict[Any, list[Any]] = defaultdict(list)
for row in df.to_dict(orient="records"):
series[row["group"]].append(row)
chart_data = []
for k, v in series.items():
chart_data.append({"key": k, "values": v})
return chart_data
class BulletViz(NVD3Viz):
"""Based on the NVD3 bullet chart"""

View File

@@ -123,7 +123,7 @@ class TestCore(SupersetTestCase):
@pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_viz_cache_key(self):
self.login(ADMIN_USERNAME)
slc = self.get_slice("Life Expectancy VS Rural %")
slc = self.get_slice("% Rural")
viz = slc.viz
qobj = viz.query_obj()
@@ -486,7 +486,7 @@ class TestCore(SupersetTestCase):
)
self.login(ADMIN_USERNAME)
slc = self.get_slice("Life Expectancy VS Rural %")
slc = self.get_slice("% Rural")
rv = self.client.post(
f"/explore_json/{slc.datasource_type}/{slc.datasource_id}/",
data={"form_data": json.dumps(slc.form_data)},
@@ -513,7 +513,7 @@ class TestCore(SupersetTestCase):
mock_get_df.side_effect = RuntimeError("boom")
self.login(ADMIN_USERNAME)
slc = self.get_slice("Life Expectancy VS Rural %")
slc = self.get_slice("% Rural")
rv = self.client.post(
f"/explore_json/{slc.datasource_type}/{slc.datasource_id}/",
data={"form_data": json.dumps(slc.form_data)},

View File

@@ -358,7 +358,7 @@ class TestUtils(SupersetTestCase):
def test_log_this(self) -> None:
# TODO: Add additional scenarios.
self.login(ADMIN_USERNAME)
slc = self.get_slice("Life Expectancy VS Rural %")
slc = self.get_slice("% Rural")
dashboard_id = 1
assert slc.viz is not None