diff --git a/superset/assets/spec/javascripts/visualizations/nvd3_viz_spec.jsx b/superset/assets/spec/javascripts/visualizations/nvd3_viz_spec.jsx index c9ed4d87063ed..f1b58f1763ed5 100644 --- a/superset/assets/spec/javascripts/visualizations/nvd3_viz_spec.jsx +++ b/superset/assets/spec/javascripts/visualizations/nvd3_viz_spec.jsx @@ -20,9 +20,9 @@ describe('nvd3 viz', () => { expect(formatLabel(['foo'], verboseMap)).to.equal('Foo'); expect(formatLabel(['foo', 'bar', 'baz'], verboseMap)).to.equal('Foo, Bar, baz'); }); - it('deals with --- properly', () => { - expect(formatLabel(['foo', '---'], verboseMap)).to.equal('Foo ---'); - expect(formatLabel(['foo', 'bar', 'baz', '---'], verboseMap)).to.equal('Foo, Bar, baz ---'); + it('deals with time shift properly', () => { + expect(formatLabel(['foo', '1 hour offset'], verboseMap)).to.equal('Foo, 1 hour offset'); + expect(formatLabel(['foo', 'bar', 'baz', '2 hours offset'], verboseMap)).to.equal('Foo, Bar, baz, 2 hours offset'); }); }); }); diff --git a/superset/assets/src/modules/colors.js b/superset/assets/src/modules/colors.js index ac206b0b172c6..8825a7ad4985e 100644 --- a/superset/assets/src/modules/colors.js +++ b/superset/assets/src/modules/colors.js @@ -1,4 +1,5 @@ import d3 from 'd3'; +import { TIME_SHIFT_PATTERN } from '../utils/common'; export const brandColor = '#00A699'; export const colorPrimary = { r: 0, g: 122, b: 135, a: 1 }; @@ -181,7 +182,7 @@ export const getColorFromScheme = (function () { const selectedScheme = scheme ? ALL_COLOR_SCHEMES[scheme] : ALL_COLOR_SCHEMES.bnbColors; let stringifyS = String(s).toLowerCase(); // next line is for superset series that should have the same color - stringifyS = stringifyS.replace(' ---', ''); + stringifyS = stringifyS.split(', ').filter(k => !TIME_SHIFT_PATTERN.test(k)).join(', '); if (forcedColor && !forcedColors[stringifyS]) { forcedColors[stringifyS] = forcedColor; diff --git a/superset/assets/src/utils/common.js b/superset/assets/src/utils/common.js index 093882aa903c0..c1a4eba94b570 100644 --- a/superset/assets/src/utils/common.js +++ b/superset/assets/src/utils/common.js @@ -13,6 +13,9 @@ export const DEFAULT_LONGITUDE = -122.405293; export const DEFAULT_LATITUDE = 37.772123; export const DEFAULT_ZOOM = 11; +// Regexp for the label added to time shifted series (1 hour offset, 2 days offset, etc.) +export const TIME_SHIFT_PATTERN = /\d+ \w+ offset/; + export function kmToPixels(kilometers, latitude, zoomLevel) { // Algorithm from: http://wiki.openstreetmap.org/wiki/Zoom_levels const latitudeRad = latitude * (Math.PI / 180); diff --git a/superset/assets/src/visualizations/nvd3_vis.css b/superset/assets/src/visualizations/nvd3_vis.css index fed0d013dc531..c6a8198d64f4c 100644 --- a/superset/assets/src/visualizations/nvd3_vis.css +++ b/superset/assets/src/visualizations/nvd3_vis.css @@ -64,3 +64,33 @@ g.opacityHigh path, line.opacityHigh { stroke-opacity: .8 } +g.time-shift-0 path, line.time-shift-0 { + stroke-dasharray: 5, 5; +} +g.time-shift-1 path, line.time-shift-1 { + stroke-dasharray: 1, 5; +} +g.time-shift-2 path, line.time-shift-2 { + stroke-dasharray: 10, 5; +} +g.time-shift-3 path, line.time-shift-3 { + stroke-dasharray: 5, 1; +} +g.time-shift-4 path, line.time-shift-4 { + stroke-dasharray: 5, 10; +} +g.time-shift-5 path, line.time-shift-5 { + stroke-dasharray: 0.9; +} +g.time-shift-6 path, line.time-shift-6 { + stroke-dasharray: 15, 10, 5; +} +g.time-shift-7 path, line.time-shift-7 { + stroke-dasharray: 15, 10, 5, 10; +} +g.time-shift-8 path, line.time-shift-8 { + stroke-dasharray: 15, 10, 5, 10, 15; +} +g.time-shift-9 path, line.time-shift-9 { + stroke-dasharray: 5, 5, 1, 5; +} diff --git a/superset/assets/src/visualizations/nvd3_vis.js b/superset/assets/src/visualizations/nvd3_vis.js index c2c74a0b7eb1f..7685c002d495b 100644 --- a/superset/assets/src/visualizations/nvd3_vis.js +++ b/superset/assets/src/visualizations/nvd3_vis.js @@ -15,7 +15,7 @@ import AnnotationTypes, { } from '../modules/AnnotationTypes'; import { customizeToolTip, d3TimeFormatPreset, d3FormatPreset, tryNumify } from '../modules/utils'; import { formatDateVerbose } from '../modules/dates'; -import { isTruthy } from '../utils/common'; +import { isTruthy, TIME_SHIFT_PATTERN } from '../utils/common'; import { t } from '../locales'; // CSS @@ -103,11 +103,8 @@ export function formatLabel(input, verboseMap = {}) { const verboseLkp = s => verboseMap[s] || s; let label; if (Array.isArray(input) && input.length) { - const verboseLabels = input.filter(s => s !== '---').map(verboseLkp); + const verboseLabels = input.map(l => TIME_SHIFT_PATTERN.test(l) ? l : verboseLkp(l)); label = verboseLabels.join(', '); - if (input.length > verboseLabels.length) { - label += ' ---'; - } } else { label = verboseLkp(input); } diff --git a/superset/viz.py b/superset/viz.py index bd34e7689ebdd..90f202480e411 100644 --- a/superset/viz.py +++ b/superset/viz.py @@ -1208,6 +1208,8 @@ def run_extra_queries(self): if not isinstance(time_compare, list): time_compare = [time_compare] + classes = ['time-shift-{}'.format(i) for i in range(10)] + i = 0 for option in time_compare: query_object = self.query_obj() delta = utils.parse_human_timedelta(option) @@ -1223,11 +1225,13 @@ def run_extra_queries(self): df2 = self.get_df_payload(query_object).get('df') if df2 is not None: + classed = classes[i % len(classes)] + i += 1 label = '{} offset'. format(option) df2[DTTM_ALIAS] += delta df2 = self.process_data(df2) self._extra_chart_data.extend(self.to_series( - df2, classed='superset', title_suffix=label)) + df2, classed=classed, title_suffix=label)) def get_data(self, df): df = self.process_data(df)