Skip to content
This repository has been archived by the owner on Dec 10, 2021. It is now read-only.

Commit

Permalink
feat: implement ECharts pie chart (#772)
Browse files Browse the repository at this point in the history
  • Loading branch information
villebro authored Sep 10, 2020
1 parent e258fe0 commit 3a8b403
Show file tree
Hide file tree
Showing 16 changed files with 385 additions and 82 deletions.
2 changes: 1 addition & 1 deletion plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default {
{
label: t('Query'),
expanded: true,
controlSetRows: [['metric'], ['adhoc_filters'], ['groupby'], ['row_limit']],
controlSetRows: [['groupby'], ['metric'], ['adhoc_filters'], ['row_limit']],
},
{
label: t('Chart Options'),
Expand Down
4 changes: 2 additions & 2 deletions plugins/plugin-chart-echarts/src/Pie/EchartsPie.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
* under the License.
*/
import React from 'react';
import { EchartsPieProps } from './types';
import { EchartsProps } from '../types';
import Echart from '../components/Echart';

export default function EchartsPie({ height, width, echartOptions }: EchartsPieProps) {
export default function EchartsPie({ height, width, echartOptions }: EchartsProps) {
return <Echart height={height} width={width} echartOptions={echartOptions} />;
}
89 changes: 85 additions & 4 deletions plugins/plugin-chart-echarts/src/Pie/controlPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,98 @@
* under the License.
*/
import { t, validateNonEmpty } from '@superset-ui/core';
import { ControlPanelConfig } from '@superset-ui/chart-controls';
import { ControlPanelConfig, D3_FORMAT_OPTIONS } from '@superset-ui/chart-controls';

const config: ControlPanelConfig = {
controlPanelSections: [
{
label: t('Query'),
expanded: true,
controlSetRows: [['groupby'], ['metrics'], ['adhoc_filters'], ['row_limit', null]],
controlSetRows: [['groupby'], ['metric'], ['adhoc_filters'], ['row_limit', null]],
},
{
label: t('Chart Options'),
expanded: true,
controlSetRows: [
[
{
name: 'pie_label_type',
config: {
type: 'SelectControl',
label: t('Label Type'),
default: 'key',
renderTrigger: true,
choices: [
['key', 'Category Name'],
['value', 'Value'],
['percent', 'Percentage'],
['key_value', 'Category and Value'],
['key_percent', 'Category and Percentage'],
['key_value_percent', 'Category, Value and Percentage'],
],
description: t('What should be shown on the label?'),
},
},
{
name: 'number_format',
config: {
type: 'SelectControl',
freeForm: true,
label: t('Number format'),
renderTrigger: true,
default: 'SMART_NUMBER',
choices: D3_FORMAT_OPTIONS,
description: `${t('D3 format syntax: https://github.com/d3/d3-format')} ${t(
'Only applies when "Label Type" is set to show values.',
)}`,
},
},
],
[
{
name: 'donut',
config: {
type: 'CheckboxControl',
label: t('Donut'),
default: false,
renderTrigger: true,
description: t('Do you want a donut or a pie?'),
},
},
{
name: 'show_legend',
config: {
type: 'CheckboxControl',
label: t('Legend'),
renderTrigger: true,
default: true,
description: t('Whether to display a legend for the chart'),
},
},
],
[
{
name: 'show_labels',
config: {
type: 'CheckboxControl',
label: t('Show Labels'),
renderTrigger: true,
default: true,
description: t('Whether to display the labels.'),
},
},
{
name: 'labels_outside',
config: {
type: 'CheckboxControl',
label: t('Put labels outside'),
default: true,
renderTrigger: true,
description: t('Put the labels outside of the pie?'),
},
},
],
['color_scheme', 'label_colors'],
[
{
name: 'outerRadius',
Expand All @@ -40,10 +119,12 @@ const config: ControlPanelConfig = {
min: 10,
max: 100,
step: 1,
default: 70,
default: 80,
description: t('Outer edge of Pie chart'),
},
},
],
[
{
name: 'innerRadius',
config: {
Expand All @@ -53,7 +134,7 @@ const config: ControlPanelConfig = {
min: 0,
max: 100,
step: 1,
default: 50,
default: 40,
description: t('Inner radius of donut hole'),
},
},
Expand Down
Binary file modified plugins/plugin-chart-echarts/src/Pie/images/thumbnail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 5 additions & 7 deletions plugins/plugin-chart-echarts/src/Pie/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,6 @@ import controlPanel from './controlPanel';
import transformProps from './transformProps';
import thumbnail from './images/thumbnail.png';

const metadata = new ChartMetadata({
description: 'Pie chart using ECharts',
name: t('EchartsPie'),
thumbnail,
});

export default class EchartsPieChartPlugin extends ChartPlugin {
/**
* The constructor is used to pass relevant metadata and callbacks that get
Expand All @@ -44,7 +38,11 @@ export default class EchartsPieChartPlugin extends ChartPlugin {
buildQuery,
controlPanel,
loadChart: () => import('./EchartsPie'),
metadata,
metadata: new ChartMetadata({
description: 'Pie chart using ECharts',
name: t('ECharts Pie'),
thumbnail,
}),
transformProps,
});
}
Expand Down
129 changes: 97 additions & 32 deletions plugins/plugin-chart-echarts/src/Pie/transformProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,60 +16,126 @@
* specific language governing permissions and limitations
* under the License.
*/
import { ChartProps, DataRecord } from '@superset-ui/core';
import { EchartsPieProps } from './types';
import {
CategoricalColorNamespace,
ChartProps,
convertMetric,
DataRecord,
getNumberFormatter,
NumberFormats,
NumberFormatter,
} from '@superset-ui/core';
import { EchartsPieLabelType, PieChartFormData } from './types';
import { EchartsProps } from '../types';
import { extractGroupbyLabel } from '../utils/series';

export default function transformProps(chartProps: ChartProps): EchartsPieProps {
/*
TODO:
- add support for multiple groupby (requires post transform op)
- add support for ad-hoc metrics (currently only supports datasource metrics)
- add support for superset colors
- add support for control values in legacy pie chart
*/
const percentFormatter = getNumberFormatter(NumberFormats.PERCENT_2_POINT);

export function formatPieLabel({
params,
pieLabelType,
numberFormatter,
}: {
params: echarts.EChartOption.Tooltip.Format;
pieLabelType: EchartsPieLabelType;
numberFormatter: NumberFormatter;
}): string {
const { name = '', value, percent } = params;
const formattedValue = numberFormatter(value as number);
const formattedPercent = percentFormatter((percent as number) / 100);
if (pieLabelType === 'key') return name;
if (pieLabelType === 'value') return formattedValue;
if (pieLabelType === 'percent') return formattedPercent;
if (pieLabelType === 'key_value') return `${name}: ${formattedValue}`;
if (pieLabelType === 'key_value_percent')
return `${name}: ${formattedValue} (${formattedPercent})`;
if (pieLabelType === 'key_percent') return `${name}: ${formattedPercent}`;
return name;
}

export default function transformProps(chartProps: ChartProps): EchartsProps {
const { width, height, formData, queryData } = chartProps;
const data: DataRecord[] = queryData.data || [];

const { innerRadius = 50, outerRadius = 70, groupby = [], metrics = [] } = formData;
const {
colorScheme,
donut = false,
groupby,
innerRadius = 40,
labelsOutside = true,
metric,
numberFormat,
outerRadius = 80,
pieLabelType = 'value',
showLabels = true,
showLegend = false,
} = formData as PieChartFormData;
const { label: metricLabel } = convertMetric(metric);

const keys = Array.from(new Set(data.map(datum => datum[groupby[0]])));
const keys = data.map(datum => extractGroupbyLabel(datum, groupby));
const colorFn = CategoricalColorNamespace.getScale(colorScheme as string);
const numberFormatter = getNumberFormatter(numberFormat);

const transformedData = data.map(datum => {
const name = extractGroupbyLabel(datum, groupby);
return {
value: datum[metrics[0]],
name: datum[groupby[0]],
value: datum[metricLabel],
name,
itemStyle: {
color: colorFn(name),
},
};
});

const echartOptions = {
const formatter = (params: { name: string; value: number; percent: number }) =>
formatPieLabel({ params, numberFormatter, pieLabelType });

const echartOptions: echarts.EChartOption<echarts.EChartOption.SeriesPie> = {
tooltip: {
confine: true,
trigger: 'item',
formatter: '{b}: {c} ({d}%)',
},
legend: {
orient: 'vertical',
left: 10,
data: keys,
formatter: params => {
return formatPieLabel({
params: params as echarts.EChartOption.Tooltip.Format,
numberFormatter,
pieLabelType: 'key_value_percent',
});
},
},
legend: showLegend
? {
orient: 'horizontal',
left: 10,
data: keys,
}
: undefined,
series: [
{
type: 'pie',
radius: [`${innerRadius}%`, `${outerRadius}%`],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center',
},
radius: [`${donut ? innerRadius : 0}%`, `${outerRadius}%`],
avoidLabelOverlap: true,
labelLine: labelsOutside ? { show: true } : { show: false },
label: labelsOutside
? {
formatter,
position: 'outer',
show: showLabels,
alignTo: 'none',
bleedMargin: 5,
}
: {
formatter,
position: 'inner',
show: showLabels,
},
emphasis: {
label: {
show: true,
fontSize: '30',
fontSize: 30,
fontWeight: 'bold',
},
},
labelLine: {
show: false,
},
// @ts-ignore
data: transformedData,
},
],
Expand All @@ -78,7 +144,6 @@ export default function transformProps(chartProps: ChartProps): EchartsPieProps
return {
width,
height,
// @ts-ignore
echartOptions,
};
}
32 changes: 15 additions & 17 deletions plugins/plugin-chart-echarts/src/Pie/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,24 @@
* under the License.
*/
import { QueryFormData } from '@superset-ui/core';
import { EchartsProps } from '../types';

export type PieChartFormData = QueryFormData & {
groupby?: string[];
metrics?: string[];
groupby: string[];
metric: string;
outerRadius?: number;
innerRadius?: number;
colorScheme?: string;
donut?: boolean;
showLegend?: boolean;
showLabels?: boolean;
labelsOutside?: boolean;
numberFormat?: string;
};

export type EchartsPieProps = EchartsProps & {
formData: PieChartFormData;
area: number;
colorScheme: string;
contributionMode?: string;
zoomable?: boolean;
seriesType: string;
logAxis: boolean;
stack: boolean;
markerEnabled: boolean;
markerSize: number;
minorSplitLine: boolean;
opacity: number;
};
export type EchartsPieLabelType =
| 'key'
| 'value'
| 'percent'
| 'key_value'
| 'key_percent'
| 'key_value_percent';
2 changes: 1 addition & 1 deletion plugins/plugin-chart-echarts/src/Timeseries/buildQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default function buildQuery(formData: QueryFormData) {
return [
{
...baseQueryObject,
// Time series charts need to set the `is_timeseries` flag to true
groupby: formData.series,
is_timeseries: true,
post_processing: [
{
Expand Down
Loading

0 comments on commit 3a8b403

Please sign in to comment.