Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New time_pivot visualization #3941

Merged
merged 3 commits into from
Dec 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions superset/assets/javascripts/explore/components/Control.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const propTypes = {
label: PropTypes.string.isRequired,
choices: PropTypes.arrayOf(PropTypes.array),
description: PropTypes.string,
tooltipOnClick: PropTypes.func,
places: PropTypes.number,
validators: PropTypes.array,
validationErrors: PropTypes.array,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const propTypes = {
leftNode: PropTypes.node,
onClick: PropTypes.func,
hovered: PropTypes.bool,
tooltipOnClick: PropTypes.func,
};

const defaultProps = {
Expand All @@ -32,6 +33,7 @@ export default class ControlHeader extends React.Component {
label={t('description')}
tooltip={this.props.description}
placement="top"
onClick={this.props.tooltipOnClick}
/>
{' '}
</span>
Expand Down
24 changes: 24 additions & 0 deletions superset/assets/javascripts/explore/stores/controls.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,30 @@ export const controls = {
'to find in the [country] column'),
},

freq: {
type: 'SelectControl',
label: t('Frequency'),
default: 'W-MON',
freeForm: true,
clearable: false,
choices: [
['AS', 'Year (freq=AS)'],
['52W-MON', '52 weeks starting Monday (freq=52W-MON)'],
['W-SUN', '1 week starting Sunday (freq=W-SUN)'],
['W-MON', '1 week starting Monday (freq=W-MON)'],
['D', 'Day (freq=D)'],
['4W-MON', '4 weeks (freq=4W-MON)'],
],
description: t(
`The periodicity over which to pivot time. Users can provide
"Pandas" offset alias.
Click on the info bubble for more details on accepted "freq" expressions.`),
tooltipOnClick: () => {
window.open(
'https://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases');
},
},

groupby: groupByControl,
dimension: {
...groupByControl,
Expand Down
44 changes: 44 additions & 0 deletions superset/assets/javascripts/explore/stores/visTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,50 @@ export const visTypes = {
},
},

time_pivot: {
label: t('Time Series - Periodicity Pivot'),
showOnExplore: true,
requiresTime: true,
controlPanelSections: [
{
label: t('Query'),
expanded: true,
controlSetRows: [
['metric', 'freq'],
],
},
{
label: t('Chart Options'),
expanded: true,
controlSetRows: [
['show_legend', 'line_interpolation'],
['color_picker', null],
],
},
{
label: t('X Axis'),
controlSetRows: [
['x_axis_label', 'bottom_margin'],
['x_axis_showminmax', 'x_axis_format'],
],
},
{
label: t('Y Axis'),
controlSetRows: [
['y_axis_label', 'left_margin'],
['y_axis_showminmax', 'y_log_scale'],
['y_axis_format', 'y_axis_bounds'],
],
},
],
controlOverrides: {
x_axis_format: {
choices: D3_TIME_FORMAT_OPTIONS,
default: 'smart_date',
},
},
},

dual_line: {
label: t('Dual Axis Line Chart'),
requiresTime: true,
Expand Down
1 change: 1 addition & 0 deletions superset/assets/javascripts/modules/colors.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import d3 from 'd3';

export const brandColor = '#00A699';
export const colorPrimary = { r: 0, g: 122, b: 135, a: 1 };

// Color related utility functions go in this object
export const bnbColors = [
Expand Down
1 change: 1 addition & 0 deletions superset/assets/visualizations/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const vizMap = {
horizon: require('./horizon.js'),
iframe: require('./iframe.js'),
line: require('./nvd3_vis.js'),
time_pivot: require('./nvd3_vis.js'),
mapbox: require('./mapbox.jsx'),
markup: require('./markup.js'),
para: require('./parallel_coordinates.js'),
Expand Down
20 changes: 18 additions & 2 deletions superset/assets/visualizations/nvd3_vis.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,13 @@ function nvd3Vis(slice, payload) {
chart.xAxis.staggerLabels(false);
break;

case 'time_pivot':
chart = nv.models.lineChart();
chart.xScale(d3.time.scale.utc());
chart.interpolate(fd.line_interpolation);
chart.xAxis.staggerLabels(false);
break;

case 'dual_line':
chart = nv.models.multiChart();
chart.interpolate('linear');
Expand Down Expand Up @@ -337,7 +344,7 @@ function nvd3Vis(slice, payload) {
chart.xScale(d3.scale.log());
}
const isTimeSeries = [
'line', 'dual_line', 'area', 'compare', 'bar'].indexOf(vizType) >= 0;
'line', 'dual_line', 'area', 'compare', 'bar', 'time_pivot'].indexOf(vizType) >= 0;
// if x axis format is a date format, rotate label 90 degrees
if (isTimeSeries) {
chart.xAxis.rotateLabels(45);
Expand Down Expand Up @@ -375,7 +382,16 @@ function nvd3Vis(slice, payload) {
setAxisShowMaxMin(chart.yAxis, fd.y_axis_showminmax);
setAxisShowMaxMin(chart.y2Axis, fd.y_axis_showminmax);

if (vizType !== 'bullet') {
if (vizType === 'time_pivot') {
chart.color((d) => {
const c = fd.color_picker;
let alpha = 1;
if (d.rank > 0) {
alpha = d.perc * 0.5;
}
return `rgba(${c.r}, ${c.g}, ${c.b}, ${alpha})`;
});
} else if (vizType !== 'bullet') {
chart.color(d => getColorFromScheme(d[colorKey], fd.color_scheme));
}
if ((vizType === 'line' || vizType === 'area') && fd.rich_tooltip) {
Expand Down
61 changes: 56 additions & 5 deletions superset/viz.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from markdown import markdown
import numpy as np
import pandas as pd
from pandas.tseries.frequencies import to_offset
import simplejson as json
from six import PY3, string_types
from six.moves import reduce
Expand Down Expand Up @@ -947,14 +948,23 @@ def to_series(self, df, classed='', title_suffix=''):
elif title_suffix and isinstance(series_title, (list, tuple)):
series_title = series_title + (title_suffix,)

values = []
for ds in df.index:
if ds in ys:
d = {
'x': ds,
'y': ys[ds],
}
else:
d = {}
values.append(d)

d = {
'key': series_title,
'classed': classed,
'values': [
{'x': ds, 'y': ys[ds] if ds in ys else None}
for ds in df.index
],
'values': values,
}
if classed:
d['classed'] = classed
chart_data.append(d)
return chart_data

Expand Down Expand Up @@ -1136,6 +1146,47 @@ class NVD3TimeSeriesBarViz(NVD3TimeSeriesViz):
verbose_name = _('Time Series - Bar Chart')


class NVD3TimePivotViz(NVD3TimeSeriesViz):

"""Time Series - Periodicity Pivot"""

viz_type = 'time_pivot'
sort_series = True
verbose_name = _('Time Series - Period Pivot')

def query_obj(self):
d = super(NVD3TimePivotViz, self).query_obj()
d['metrics'] = [self.form_data.get('metric')]
return d

def get_data(self, df):
fd = self.form_data
df = self.process_data(df)
freq = to_offset(fd.get('freq'))
freq.normalize = True
df[DTTM_ALIAS] = df.index.map(freq.rollback)
df['ranked'] = df[DTTM_ALIAS].rank(method='dense', ascending=False) - 1
df.ranked = df.ranked.map(int)
df['series'] = '-' + df.ranked.map(str)
df['series'] = df['series'].str.replace('-0', 'current')
rank_lookup = {
row['series']: row['ranked']
for row in df.to_dict(orient='records')
}
max_ts = df[DTTM_ALIAS].max()
max_rank = df['ranked'].max()
df[DTTM_ALIAS] = df.index + (max_ts - df[DTTM_ALIAS])
df = df.pivot_table(
index=DTTM_ALIAS,
columns='series',
values=fd.get('metric'))
chart_data = self.to_series(df)
for serie in chart_data:
serie['rank'] = rank_lookup[serie['key']]
serie['perc'] = 1 - (serie['rank'] / (max_rank + 1))
return chart_data


class NVD3CompareTimeSeriesViz(NVD3TimeSeriesViz):

"""A line chart component where you can compare the % change over time"""
Expand Down