superset-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From GitBox <...@apache.org>
Subject [GitHub] mistercrunch closed pull request #3941: New time_pivot visualization
Date Thu, 01 Jan 1970 00:00:00 GMT
mistercrunch closed pull request #3941: New time_pivot visualization
URL: https://github.com/apache/incubator-superset/pull/3941
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/superset/assets/images/viz_thumbnails/time_pivot.png b/superset/assets/images/viz_thumbnails/time_pivot.png
new file mode 100644
index 0000000000..149f3dae5d
Binary files /dev/null and b/superset/assets/images/viz_thumbnails/time_pivot.png differ
diff --git a/superset/assets/javascripts/explore/components/Control.jsx b/superset/assets/javascripts/explore/components/Control.jsx
index e458807633..25d69a5be4 100644
--- a/superset/assets/javascripts/explore/components/Control.jsx
+++ b/superset/assets/javascripts/explore/components/Control.jsx
@@ -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,
diff --git a/superset/assets/javascripts/explore/components/ControlHeader.jsx b/superset/assets/javascripts/explore/components/ControlHeader.jsx
index d2e0a6efd7..bc474a6885 100644
--- a/superset/assets/javascripts/explore/components/ControlHeader.jsx
+++ b/superset/assets/javascripts/explore/components/ControlHeader.jsx
@@ -13,6 +13,7 @@ const propTypes = {
   leftNode: PropTypes.node,
   onClick: PropTypes.func,
   hovered: PropTypes.bool,
+  tooltipOnClick: PropTypes.func,
 };
 
 const defaultProps = {
@@ -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>
diff --git a/superset/assets/javascripts/explore/stores/controls.jsx b/superset/assets/javascripts/explore/stores/controls.jsx
index 325c878692..7069ff7b32 100644
--- a/superset/assets/javascripts/explore/stores/controls.jsx
+++ b/superset/assets/javascripts/explore/stores/controls.jsx
@@ -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,
diff --git a/superset/assets/javascripts/explore/stores/visTypes.js b/superset/assets/javascripts/explore/stores/visTypes.js
index 15aa82eaf2..8967b1db07 100644
--- a/superset/assets/javascripts/explore/stores/visTypes.js
+++ b/superset/assets/javascripts/explore/stores/visTypes.js
@@ -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,
diff --git a/superset/assets/javascripts/modules/colors.js b/superset/assets/javascripts/modules/colors.js
index 03c3bb2ed4..f182e9744f 100644
--- a/superset/assets/javascripts/modules/colors.js
+++ b/superset/assets/javascripts/modules/colors.js
@@ -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 = [
diff --git a/superset/assets/visualizations/main.js b/superset/assets/visualizations/main.js
index 2afc57b617..9976614048 100644
--- a/superset/assets/visualizations/main.js
+++ b/superset/assets/visualizations/main.js
@@ -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'),
diff --git a/superset/assets/visualizations/nvd3_vis.js b/superset/assets/visualizations/nvd3_vis.js
index bbef132c94..f1b6c11cde 100644
--- a/superset/assets/visualizations/nvd3_vis.js
+++ b/superset/assets/visualizations/nvd3_vis.js
@@ -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');
@@ -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);
@@ -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) {
diff --git a/superset/viz.py b/superset/viz.py
index 6b369bedb7..e3c1737026 100644
--- a/superset/viz.py
+++ b/superset/viz.py
@@ -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
@@ -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
 
@@ -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"""


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

Mime
View raw message