Skip to content

Commit

Permalink
feat(plugin-chart-echarts): add BoxPlot chart (#801)
Browse files Browse the repository at this point in the history
* feat(plugin-chart-echarts): add BoxPlot chart

* make headline stand out

* address comments
  • Loading branch information
villebro authored and zhaoyongjie committed Nov 26, 2021
1 parent f9c7d35 commit 88acb6b
Show file tree
Hide file tree
Showing 23 changed files with 841 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ const groupByControl: SharedControlConfig<'SelectControl', ColumnMeta> = {
clearable: true,
default: [],
includeTime: false,
description: t('One or many controls to group by'),
description: t('One or many columns to group by'),
optionRenderer: c => <ColumnOption showType column={c} />,
valueRenderer: c => <ColumnOption column={c} />,
valueKey: 'column_name',
Expand Down Expand Up @@ -220,7 +220,7 @@ const secondary_metric: SharedControlConfig<'MetricsControl'> = {
const columnsControl: typeof groupByControl = {
...groupByControl,
label: t('Columns'),
description: t('One or many controls to pivot as columns'),
description: t('One or many columns to pivot as columns'),
};

const druid_time_origin: SharedControlConfig<'SelectControl'> = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { SuperChart, getChartTransformPropsRegistry } from '@superset-ui/core';
import { select, withKnobs } from '@storybook/addon-knobs';
import { EchartsBoxPlotChartPlugin } from '@superset-ui/plugin-chart-echarts';
import transformProps from '@superset-ui/plugin-chart-echarts/lib/BoxPlot/transformProps';
import data from './data';

new EchartsBoxPlotChartPlugin().configure({ key: 'echarts-boxplot' }).register();

getChartTransformPropsRegistry().registerValue('echarts-boxplot', transformProps);

export default {
title: 'Chart Plugins|plugin-chart-echarts/BoxPlot',
decorators: [withKnobs],
};

export const BoxPlot = ({ width, height }) => {
return (
<SuperChart
chartType="echarts-boxplot"
width={width}
height={height}
queryData={{ data }}
formData={{
columns: [],
groupby: ['type', 'region'],
metrics: ['AVG(averageprice)'],
whiskerOptions: 'Tukey',
xTicksLayout: select('X Tick Layout', ['auto', 'flat', '45°', '90°', 'staggered'], '45°'),
yAxisFormat: 'SMART_NUMBER',
}}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
export default [
{
type: 'organic',
region: 'Charlotte',
'AVG(averageprice)__mean': 1.9405512820512825,
'AVG(averageprice)__median': 1.9025,
'AVG(averageprice)__high': 2.505,
'AVG(averageprice)__low': 1.4775,
'AVG(averageprice)__q1': 1.73875,
'AVG(averageprice)__q3': 2.105,
'AVG(averageprice)__count': 39,
'AVG(averageprice)__outliers': [2.735],
},
{
type: 'organic',
region: 'Hartford Springfield',
'AVG(averageprice)__mean': 2.231141025641026,
'AVG(averageprice)__median': 2.265,
'AVG(averageprice)__high': 2.595,
'AVG(averageprice)__low': 1.862,
'AVG(averageprice)__q1': 2.1285,
'AVG(averageprice)__q3': 2.32625,
'AVG(averageprice)__count': 39,
'AVG(averageprice)__outliers': [],
},
{
type: 'organic',
region: 'Jacksonville',
'AVG(averageprice)__mean': 1.829282051282052,
'AVG(averageprice)__median': 1.808,
'AVG(averageprice)__high': 2.255,
'AVG(averageprice)__low': 1.455,
'AVG(averageprice)__q1': 1.6945000000000001,
'AVG(averageprice)__q3': 1.9475,
'AVG(averageprice)__count': 39,
'AVG(averageprice)__outliers': [2.48, 2.406, 1.3075, 1.274],
},
{
type: 'organic',
region: 'NewYork',
'AVG(averageprice)__mean': 2.0531923076923073,
'AVG(averageprice)__median': 2.068,
'AVG(averageprice)__high': 2.348,
'AVG(averageprice)__low': 1.785,
'AVG(averageprice)__q1': 1.9725000000000001,
'AVG(averageprice)__q3': 2.125,
'AVG(averageprice)__count': 39,
'AVG(averageprice)__outliers': [2.3825, 2.38, 1.7075],
},
{
type: 'organic',
region: 'Northeast',
'AVG(averageprice)__mean': 1.8608333333333336,
'AVG(averageprice)__median': 1.868,
'AVG(averageprice)__high': 2.145,
'AVG(averageprice)__low': 1.5925,
'AVG(averageprice)__q1': 1.76375,
'AVG(averageprice)__q3': 1.96875,
'AVG(averageprice)__count': 39,
'AVG(averageprice)__outliers': [],
},
{
type: 'organic',
region: 'Orlando',
'AVG(averageprice)__mean': 1.7969999999999995,
'AVG(averageprice)__median': 1.8075,
'AVG(averageprice)__high': 2.1125,
'AVG(averageprice)__low': 1.306,
'AVG(averageprice)__q1': 1.6237499999999998,
'AVG(averageprice)__q3': 1.8697499999999998,
'AVG(averageprice)__count': 39,
'AVG(averageprice)__outliers': [2.3825, 2.358, 2.252],
},
{
type: 'organic',
region: 'Philadelphia',
'AVG(averageprice)__mean': 1.8673589743589747,
'AVG(averageprice)__median': 1.85,
'AVG(averageprice)__high': 2.2525,
'AVG(averageprice)__low': 1.56,
'AVG(averageprice)__q1': 1.7125,
'AVG(averageprice)__q3': 1.99575,
'AVG(averageprice)__count': 39,
'AVG(averageprice)__outliers': [],
},
{
type: 'organic',
region: 'Raleigh Greensboro',
'AVG(averageprice)__mean': 1.8851410256410257,
'AVG(averageprice)__median': 1.782,
'AVG(averageprice)__high': 2.402,
'AVG(averageprice)__low': 1.356,
'AVG(averageprice)__q1': 1.7000000000000002,
'AVG(averageprice)__q3': 2.0045,
'AVG(averageprice)__count': 39,
'AVG(averageprice)__outliers': [2.79, 2.6225, 2.5575, 2.5],
},
{
type: 'organic',
region: 'Sacramento',
'AVG(averageprice)__mean': 1.972871794871795,
'AVG(averageprice)__median': 1.9875,
'AVG(averageprice)__high': 2.655,
'AVG(averageprice)__low': 1.2925,
'AVG(averageprice)__q1': 1.74875,
'AVG(averageprice)__q3': 2.1465,
'AVG(averageprice)__count': 39,
'AVG(averageprice)__outliers': [],
},
{
type: 'organic',
region: 'San Francisco',
'AVG(averageprice)__mean': 2.213615384615385,
'AVG(averageprice)__median': 2.275,
'AVG(averageprice)__high': 2.9825,
'AVG(averageprice)__low': 1.2275,
'AVG(averageprice)__q1': 1.9675,
'AVG(averageprice)__q3': 2.541,
'AVG(averageprice)__count': 39,
'AVG(averageprice)__outliers': [],
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import { SuperChart, getChartTransformPropsRegistry } from '@superset-ui/core';
import { boolean, select, withKnobs } from '@storybook/addon-knobs';
import { EchartsPieChartPlugin } from '@superset-ui/plugin-chart-echarts';
import transformProps from '@superset-ui/plugin-chart-echarts/lib/Pie/transformProps';
import data from './data';

new EchartsPieChartPlugin().configure({ key: 'echarts-pie' }).register();

getChartTransformPropsRegistry().registerValue('echarts-pie', transformProps);

export default {
title: 'Chart Plugins|plugin-chart-echarts/Pie',
decorators: [withKnobs],
};

export const Pie = ({ width, height }) => {
return (
<SuperChart
chartType="echarts-pie"
width={width}
height={height}
queryData={{ data }}
formData={{
colorScheme: 'supersetColors',
groupby: ['Day'],
metric: 'SUM(AIR_TIME)',
numberFormat: 'SMART_NUMBER',
donut: boolean('Donut', false),
labelsOutside: boolean('Labels outside', true),
showLabels: boolean('Show labels', true),
showLegend: boolean('Show legend', false),
pieLabelType: select(
'Pie label type',
['key', 'value', 'percent', 'key_value', 'key_percent', 'key_value_percent'],
'key_value_percent',
),
}}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default [
{ Day: 'Friday', 'SUM(AIR_TIME)': 1943661 },
{ Day: 'Saturday', 'SUM(AIR_TIME)': 1798845 },
{ Day: 'Thursday', 'SUM(AIR_TIME)': 1626157 },
{ Day: 'Sunday', 'SUM(AIR_TIME)': 1048653 },
];
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ import { SuperChart, getChartTransformPropsRegistry } from '@superset-ui/core';
import { boolean, number, select, withKnobs } from '@storybook/addon-knobs';
import { EchartsTimeseriesChartPlugin } from '@superset-ui/plugin-chart-echarts';
import transformProps from '@superset-ui/plugin-chart-echarts/lib/Timeseries/transformProps';
import { withResizableChartDemo } from '../../../shared/components/ResizableChartDemo';
import data from './data';

new EchartsTimeseriesChartPlugin().configure({ key: 'echarts-timeseries' }).register();

getChartTransformPropsRegistry().registerValue('echarts-timeseries', transformProps);

export default {
title: 'Chart Plugins|plugin-chart-echarts',
decorators: [withKnobs, withResizableChartDemo],
title: 'Chart Plugins|plugin-chart-echarts/Timeseries',
decorators: [withKnobs],
};

export const Timeseries = ({ width, height }) => {
Expand All @@ -22,6 +21,7 @@ export const Timeseries = ({ width, height }) => {
forecastEnabled
? row
: {
// eslint-disable-next-line no-underscore-dangle
__timestamp: row.__timestamp,
Boston: row.Boston,
California: row.California,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable sort-keys */
export default [
{
__timestamp: 1419811200000,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* 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 React from 'react';
import { EchartsProps } from '../types';
import Echart from '../components/Echart';

export default function EchartsBoxPlot({ height, width, echartOptions }: EchartsProps) {
return <Echart height={height} width={width} echartOptions={echartOptions} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* 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, convertMetric } from '@superset-ui/core';
import { BoxPlotQueryFormData, BoxPlotQueryObjectType } from './types';

const PERCENTILE_REGEX = /(\d+)\/(\d+) percentiles/;

export default function buildQuery(formData: BoxPlotQueryFormData) {
const { whiskerOptions, columns, groupby, metrics: formDataMetrics } = formData;
// TODO: Refactor superset-ui-cre/query and remove QueryFormResidual types which are causing confusion
// @ts-ignore
const metrics = formDataMetrics.map(metric => convertMetric(metric).label);
return buildQueryContext(formData, baseQueryObject => {
let type: BoxPlotQueryObjectType;
let percentiles: [number, number] | undefined;
const percentileMatch = PERCENTILE_REGEX.exec(whiskerOptions as string);
const distributionColumns = columns || [];

if (whiskerOptions === 'Tukey') type = 'tukey';
else if (whiskerOptions === 'Min/max (no outliers)') type = 'min/max';
else if (percentileMatch) {
type = 'percentile';
percentiles = [parseInt(percentileMatch[1], 10), parseInt(percentileMatch[2], 10)];
} else {
throw new Error(`Unsupported whisker type: ${whiskerOptions}`);
}
console.log(formData);
return [
{
...baseQueryObject,
is_timeseries: distributionColumns.length === 0,
groupby: (groupby || []).concat(distributionColumns),
post_processing: [
{
operation: 'boxplot',
options: {
type,
percentiles,
groupby,
metrics,
},
},
],
},
];
});
}

0 comments on commit 88acb6b

Please sign in to comment.