diff --git a/superset/assets/src/explore/controlPanels/LineBar.js b/superset/assets/src/explore/controlPanels/LineBar.js new file mode 100644 index 0000000000000..a41579d6ab1b7 --- /dev/null +++ b/superset/assets/src/explore/controlPanels/LineBar.js @@ -0,0 +1,73 @@ +/** + * 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 '@superset-ui/translation'; +import { annotations } from './sections'; +import { D3_TIME_FORMAT_OPTIONS } from '../controls'; + +export default { + requiresTime: true, + controlPanelSections: [ + { + label: t('Chart Options'), + expanded: true, + controlSetRows: [ + ['color_scheme'], + ['x_axis_format'], + ], + }, + { + label: t('Y Axis 1 (Bar)'), + expanded: true, + controlSetRows: [ + ['metric', 'y_axis_format'], + ], + }, + { + label: t('Y Axis 2 (Line)'), + expanded: true, + controlSetRows: [ + ['metric_2', 'y_axis_2_format'], + ], + }, + annotations, + ], + controlOverrides: { + metric: { + label: t('Left(Bar) Axis Metric'), + description: t('Choose a metric for left(Bar) axis'), + }, + y_axis_format: { + label: t('Left(Bar) Axis Format'), + }, + metric_2: { + label: t('Right(Line) Axis Metric'), + description: t('Choose a metric for right(Line) axis'), + }, + y_axis_2_format: { + label: t('Right(Line) Axis Format'), + }, + x_axis_format: { + choices: D3_TIME_FORMAT_OPTIONS, + default: 'smart_date', + }, + row_limit: { + default: 50000, + }, + }, +}; diff --git a/superset/assets/src/explore/controlPanels/index.js b/superset/assets/src/explore/controlPanels/index.js index e663f54afb83a..ce0bc257337d5 100644 --- a/superset/assets/src/explore/controlPanels/index.js +++ b/superset/assets/src/explore/controlPanels/index.js @@ -45,6 +45,7 @@ import Histogram from './Histogram'; import Horizon from './Horizon'; import Iframe from './Iframe'; import Line from './Line'; +import LineBar from './LineBar'; import LineMulti from './LineMulti'; import Mapbox from './Mapbox'; import Markup from './Markup'; @@ -95,6 +96,7 @@ export const controlPanelConfigs = extraOverrides({ horizon: Horizon, iframe: Iframe, line: Line, + line_bar: LineBar, line_multi: LineMulti, mapbox: Mapbox, markup: Markup, diff --git a/superset/assets/src/visualizations/presets/CommonChartPreset.js b/superset/assets/src/visualizations/presets/CommonChartPreset.js index a74f1ea28e52d..23db805d1e448 100644 --- a/superset/assets/src/visualizations/presets/CommonChartPreset.js +++ b/superset/assets/src/visualizations/presets/CommonChartPreset.js @@ -23,7 +23,7 @@ import { BigNumberChartPlugin, BigNumberTotalChartPlugin } from '@superset-ui/le // Make sure to import '@superset-ui/legacy-preset-chart-nvd3/lib' // Not '@superset-ui/legacy-preset-chart-nvd3', // which will point to '@superset-ui/legacy-preset-chart-nvd3/esm' by default -import { AreaChartPlugin, BarChartPlugin, BoxPlotChartPlugin, BubbleChartPlugin, DistBarChartPlugin, LineChartPlugin, PieChartPlugin } from '@superset-ui/legacy-preset-chart-nvd3/lib'; +import { AreaChartPlugin, BarChartPlugin, BoxPlotChartPlugin, BubbleChartPlugin, DistBarChartPlugin, LineChartPlugin, LineBarChartPlugin, PieChartPlugin } from '@superset-ui/legacy-preset-chart-nvd3/lib'; import HistogramChartPlugin from '@superset-ui/legacy-plugin-chart-histogram'; import PivotTableChartPlugin from '@superset-ui/legacy-plugin-chart-pivot-table'; import TableChartPlugin from '@superset-ui/legacy-plugin-chart-table'; @@ -46,6 +46,7 @@ export default class CommonChartPreset extends Preset { new FilterBoxChartPlugin().configure({ key: 'filter_box' }), new HistogramChartPlugin().configure({ key: 'histogram' }), new LineChartPlugin().configure({ key: 'line' }), + new LineBarChartPlugin().configure({ key: 'line_bar' }), new PieChartPlugin().configure({ key: 'pie' }), new PivotTableChartPlugin().configure({ key: 'pivot_table' }), new TableChartPlugin().configure({ key: 'table' }), diff --git a/superset/viz.py b/superset/viz.py index 786fad11da942..586afc3dc7b56 100644 --- a/superset/viz.py +++ b/superset/viz.py @@ -2757,6 +2757,81 @@ def get_data(self, df): return self.nest_values(levels) +class LineBarViz(NVD3Viz): + + """A simple line bar chart with dual axis""" + + viz_type = 'line_bar' + verbose_name = _('Time Series - Line Bar Chart') + sort_series = False + is_timeseries = True + + def query_obj(self): + d = super(LineBarViz, self).query_obj() + m1 = self.form_data.get('metric') + m2 = self.form_data.get('metric_2') + d['metrics'] = [m1, m2] + if not m1: + raise Exception(_('Pick a metric for left(bar) axis!')) + if not m2: + raise Exception(_('Pick a metric for right(line) axis!')) + if m1 == m2: + raise Exception(_('Please choose different metrics' + ' on left and right axis')) + return d + + def to_series(self, df, classed=''): + cols = [] + for col in df.columns: + if col == '': + cols.append('N/A') + elif col is None: + cols.append('NULL') + else: + cols.append(col) + df.columns = cols + series = df.to_dict('series') + chart_data = [] + metrics = [ + self.form_data.get('metric'), + self.form_data.get('metric_2'), + ] + for i, m in enumerate(metrics): + + ys = series[m['label']] + if df[m['label']].dtype.kind not in 'biufc': + continue + series_title = m['label'] + d = { + 'key': series_title, + 'classed': classed, + 'values': [ + {'x': ds, 'y': ys[ds] if ds in ys else None} + for ds in df.index + ], + 'yAxis': i + 1, + 'type': 'bar' if i == 0 else 'line', + } + chart_data.append(d) + return chart_data + + def get_data(self, df): + fd = self.form_data + df = df.fillna(0) + + if self.form_data.get('granularity') == 'all': + raise Exception(_('Pick a time granularity for your time series')) + + metric = utils.get_metric_name(fd.get('metric')) + metric_2 = utils.get_metric_name(fd.get('metric_2')) + df = df.pivot_table( + index=DTTM_ALIAS, + values=[metric, metric_2]) + + chart_data = self.to_series(df) + return chart_data + + viz_types = { o.viz_type: o for o in globals().values() if (