You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by cc...@apache.org on 2018/04/20 22:55:29 UTC
[incubator-superset] branch master updated: [formats] add better
defaults for time + number formatting (#4843)
This is an automated email from the ASF dual-hosted git repository.
ccwilliams pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push:
new 66fcf9b [formats] add better defaults for time + number formatting (#4843)
66fcf9b is described below
commit 66fcf9b687bdd6cc8a6039f002ed87193a16b365
Author: Chris Williams <wi...@users.noreply.github.com>
AuthorDate: Fri Apr 20 15:55:25 2018 -0700
[formats] add better defaults for time + number formatting (#4843)
* [formats] add better defaults for time + number formatting
* [formatDate] add tests for concise formatDate
* [nvd3] use verbose time format in tooltips
* [number format] improve number format description
* [formats] revert to .3s defaults, tweak number format preview
* [formats] default number vis to .3s
---
.../assets/spec/javascripts/modules/dates_spec.js | 29 ++++++++++++++--
.../assets/spec/javascripts/modules/utils_spec.jsx | 13 +++++--
superset/assets/src/explore/stores/controls.jsx | 18 +++++-----
superset/assets/src/modules/dates.js | 40 +++++++++++++++++++++-
superset/assets/src/visualizations/nvd3_vis.js | 35 ++++++++++++-------
superset/assets/src/visualizations/sunburst.js | 4 +--
superset/assets/src/visualizations/world_map.js | 6 ++--
7 files changed, 111 insertions(+), 34 deletions(-)
diff --git a/superset/assets/spec/javascripts/modules/dates_spec.js b/superset/assets/spec/javascripts/modules/dates_spec.js
index 94dbfa6..7101b1d 100644
--- a/superset/assets/spec/javascripts/modules/dates_spec.js
+++ b/superset/assets/spec/javascripts/modules/dates_spec.js
@@ -3,6 +3,7 @@ import { expect } from 'chai';
import {
tickMultiFormat,
formatDate,
+ formatDateVerbose,
fDuration,
now,
epochTimeXHoursAgo,
@@ -25,13 +26,35 @@ describe('formatDate', () => {
expect(formatDate(new Date('2020-01-01'))).to.equal('2020');
});
+ it('shows only month when 1st of month', () => {
+ expect(formatDate(new Date('2020-03-01'))).to.equal('March');
+ });
+
+ it('does not show day of week when it is Sunday', () => {
+ expect(formatDate(new Date('2020-03-15'))).to.equal('Mar 15');
+ });
+
+ it('shows weekday when it is not Sunday (and no ms/sec/min/hr)', () => {
+ expect(formatDate(new Date('2020-03-03'))).to.equal('Tue 03');
+ });
+});
+
+describe('formatDateVerbose', () => {
+ it('is a function', () => {
+ assert.isFunction(formatDateVerbose);
+ });
+
+ it('shows only year when 1st day of the year', () => {
+ expect(formatDateVerbose(new Date('2020-01-01'))).to.equal('2020');
+ });
+
it('shows month and year when 1st of month', () => {
- expect(formatDate(new Date('2020-03-01'))).to.equal('Mar 2020');
+ expect(formatDateVerbose(new Date('2020-03-01'))).to.equal('Mar 2020');
});
it('shows weekday when any day of the month', () => {
- expect(formatDate(new Date('2020-03-03'))).to.equal('Tue Mar 3');
- expect(formatDate(new Date('2020-03-15'))).to.equal('Sun Mar 15');
+ expect(formatDateVerbose(new Date('2020-03-03'))).to.equal('Tue Mar 3');
+ expect(formatDateVerbose(new Date('2020-03-15'))).to.equal('Sun Mar 15');
});
});
diff --git a/superset/assets/spec/javascripts/modules/utils_spec.jsx b/superset/assets/spec/javascripts/modules/utils_spec.jsx
index f219c6e..4a319af 100644
--- a/superset/assets/spec/javascripts/modules/utils_spec.jsx
+++ b/superset/assets/spec/javascripts/modules/utils_spec.jsx
@@ -1,8 +1,13 @@
import { it, describe } from 'mocha';
import { expect } from 'chai';
import {
- tryNumify, slugify, formatSelectOptionsForRange, d3format,
- d3FormatPreset, d3TimeFormatPreset, defaultNumberFormatter,
+ tryNumify,
+ slugify,
+ formatSelectOptionsForRange,
+ d3format,
+ d3FormatPreset,
+ d3TimeFormatPreset,
+ defaultNumberFormatter,
mainMetric,
} from '../../../src/modules/utils';
@@ -53,12 +58,13 @@ describe('utils', () => {
expect(d3FormatPreset('smart_date')(0)).to.equal('1970');
});
});
- describe('d3TimeFormatPreset', () => {
+ describe('defaultNumberFormatter', () => {
expect(defaultNumberFormatter(10)).to.equal('10');
expect(defaultNumberFormatter(1)).to.equal('1');
expect(defaultNumberFormatter(1.0)).to.equal('1');
expect(defaultNumberFormatter(10.0)).to.equal('10');
expect(defaultNumberFormatter(10001)).to.equal('10.0k');
+ expect(defaultNumberFormatter(10100)).to.equal('10.1k');
expect(defaultNumberFormatter(111000000)).to.equal('111M');
expect(defaultNumberFormatter(0.23)).to.equal('230m');
@@ -67,6 +73,7 @@ describe('utils', () => {
expect(defaultNumberFormatter(-1.0)).to.equal('-1');
expect(defaultNumberFormatter(-10.0)).to.equal('-10');
expect(defaultNumberFormatter(-10001)).to.equal('-10.0k');
+ expect(defaultNumberFormatter(-10101)).to.equal('-10.1k');
expect(defaultNumberFormatter(-111000000)).to.equal('-111M');
expect(defaultNumberFormatter(-0.23)).to.equal('-230m');
});
diff --git a/superset/assets/src/explore/stores/controls.jsx b/superset/assets/src/explore/stores/controls.jsx
index 0a64433..2dc7cf2 100644
--- a/superset/assets/src/explore/stores/controls.jsx
+++ b/superset/assets/src/explore/stores/controls.jsx
@@ -56,14 +56,14 @@ const D3_FORMAT_DOCS = 'D3 format syntax: https://github.com/d3/d3-format';
// input choices & options
const D3_FORMAT_OPTIONS = [
- ['.1s', '.1s | 12k'],
- ['.3s', '.3s | 12.3k'],
- ['.1%', '.1% | 12.3%'],
- ['.3%', '.3% | 1234543.210%'],
- ['.4r', '.4r | 12350'],
- ['.3f', '.3f | 12345.432'],
- ['+,', '+, | +12,345.4321'],
- ['$,.2f', '$,.2f | $12,345.43'],
+ ['.1s', '.1s (12345.432 => 10k)'],
+ ['.3s', '.3s (12345.432 => 12.3k)'],
+ [',.1%', ',.1% (12345.432 => 1,234,543.2%)'],
+ ['.3%', '.3% (12345.432 => 1234543.200%)'],
+ ['.4r', '.4r (12345.432 => 12350)'],
+ [',.3f', ',.3f (12345.432 => 12,345.432)'],
+ ['+,', '+, (12345.432 => +12,345.432)'],
+ ['$,.2f', '$,.2f (12345.432 => $12,345.43)'],
];
const ROW_LIMIT_OPTIONS = [10, 50, 100, 250, 500, 1000, 5000, 10000, 50000];
@@ -1537,7 +1537,7 @@ export const controls = {
type: 'CheckboxControl',
label: t('Rich Tooltip'),
renderTrigger: true,
- default: true,
+ default: false,
description: t('The rich tooltip shows a list of all series for that ' +
'point in time'),
},
diff --git a/superset/assets/src/modules/dates.js b/superset/assets/src/modules/dates.js
index 91fde25..f8d8684 100644
--- a/superset/assets/src/modules/dates.js
+++ b/superset/assets/src/modules/dates.js
@@ -12,7 +12,40 @@ export function UTC(dttm) {
dttm.getUTCSeconds(),
);
}
-export const tickMultiFormat = d3.time.format.multi([
+
+export const tickMultiFormat = (() => {
+ const formatMillisecond = d3.time.format('.%Lms');
+ const formatSecond = d3.time.format(':%Ss');
+ const formatMinute = d3.time.format('%I:%M');
+ const formatHour = d3.time.format('%I %p');
+ const formatDay = d3.time.format('%a %d');
+ const formatWeek = d3.time.format('%b %d');
+ const formatMonth = d3.time.format('%B');
+ const formatYear = d3.time.format('%Y');
+
+ return function tickMultiFormatConcise(date) {
+ let formatter;
+ if (d3.time.second(date) < date) {
+ formatter = formatMillisecond;
+ } else if (d3.time.minute(date) < date) {
+ formatter = formatSecond;
+ } else if (d3.time.hour(date) < date) {
+ formatter = formatMinute;
+ } else if (d3.time.day(date) < date) {
+ formatter = formatHour;
+ } else if (d3.time.month(date) < date) {
+ formatter = d3.time.week(date) < date ? formatDay : formatWeek;
+ } else if (d3.time.year(date) < date) {
+ formatter = formatMonth;
+ } else {
+ formatter = formatYear;
+ }
+
+ return formatter(date);
+ };
+})();
+
+export const tickMultiFormatVerbose = d3.time.format.multi([
[
'.%L',
function (d) {
@@ -74,6 +107,11 @@ export const formatDate = function (dttm) {
return tickMultiFormat(d);
};
+export const formatDateVerbose = function (dttm) {
+ const d = UTC(new Date(dttm));
+ return tickMultiFormatVerbose(d);
+};
+
export const formatDateThunk = function (format) {
if (!format) {
return formatDate;
diff --git a/superset/assets/src/visualizations/nvd3_vis.js b/superset/assets/src/visualizations/nvd3_vis.js
index bf87287..4a3faba 100644
--- a/superset/assets/src/visualizations/nvd3_vis.js
+++ b/superset/assets/src/visualizations/nvd3_vis.js
@@ -13,6 +13,7 @@ import AnnotationTypes, {
applyNativeColumns,
} from '../modules/AnnotationTypes';
import { customizeToolTip, d3TimeFormatPreset, d3FormatPreset, tryNumify } from '../modules/utils';
+import { formatDateVerbose } from '../modules/dates';
import { isTruthy } from '../utils/common';
import { t } from '../locales';
@@ -136,7 +137,7 @@ export default function nvd3Vis(slice, payload) {
};
const vizType = fd.viz_type;
- const f = d3.format('.3s');
+ const formatter = d3.format('.3s');
const reduceXTicks = fd.reduce_x_ticks || false;
let stacked = false;
let row;
@@ -156,8 +157,6 @@ export default function nvd3Vis(slice, payload) {
if (fd.x_ticks_layout === 'auto') {
if (['column', 'dist_bar'].indexOf(vizType) >= 0) {
xLabelRotation = 45;
- } else if (isTimeSeries) {
- staggerLabels = true;
}
} else if (fd.x_ticks_layout === 'staggered') {
staggerLabels = true;
@@ -187,8 +186,6 @@ export default function nvd3Vis(slice, payload) {
} else {
chart = nv.models.lineChart();
}
- // To alter the tooltip header
- // chart.interactiveLayer.tooltip.headerFormatter(function(){return '';});
chart.xScale(d3.time.scale.utc());
chart.interpolate(fd.line_interpolation);
break;
@@ -303,9 +300,9 @@ export default function nvd3Vis(slice, payload) {
`<tr><td style="color: ${p.color};">` +
`<strong>${p[fd.entity]}</strong> (${p.group})` +
'</td></tr>');
- s += row(fd.x, f(p.x));
- s += row(fd.y, f(p.y));
- s += row(fd.size, f(p.size));
+ s += row(fd.x, formatter(p.x));
+ s += row(fd.y, formatter(p.y));
+ s += row(fd.size, formatter(p.size));
s += '</table>';
return s;
});
@@ -375,6 +372,8 @@ export default function nvd3Vis(slice, payload) {
let xAxisFormatter = d3FormatPreset(fd.x_axis_format);
if (isTimeSeries) {
xAxisFormatter = d3TimeFormatPreset(fd.x_axis_format);
+ // In tooltips, always use the verbose time format
+ chart.interactiveLayer.tooltip.headerFormatter(formatDateVerbose);
}
if (chart.x2Axis && chart.x2Axis.tickFormat) {
chart.x2Axis.tickFormat(xAxisFormatter);
@@ -397,6 +396,13 @@ export default function nvd3Vis(slice, payload) {
chart.y2Axis.tickFormat(yAxisFormatter);
}
+ if (chart.yAxis) {
+ chart.yAxis.ticks(5);
+ }
+ if (chart.y2Axis) {
+ chart.y2Axis.ticks(5);
+ }
+
// Set showMaxMin for all axis
function setAxisShowMaxMin(axis, showminmax) {
@@ -404,10 +410,12 @@ export default function nvd3Vis(slice, payload) {
axis.showMaxMin(showminmax);
}
}
- setAxisShowMaxMin(chart.xAxis, fd.x_axis_showminmax);
- setAxisShowMaxMin(chart.x2Axis, fd.x_axis_showminmax);
- setAxisShowMaxMin(chart.yAxis, fd.y_axis_showminmax);
- setAxisShowMaxMin(chart.y2Axis, fd.y_axis_showminmax);
+
+ // If these are undefined, they register as truthy
+ setAxisShowMaxMin(chart.xAxis, fd.x_axis_showminmax || false);
+ setAxisShowMaxMin(chart.x2Axis, fd.x_axis_showminmax || false);
+ setAxisShowMaxMin(chart.yAxis, fd.y_axis_showminmax || false);
+ setAxisShowMaxMin(chart.y2Axis, fd.y_axis_showminmax || false);
if (vizType === 'time_pivot') {
chart.color((d) => {
@@ -425,10 +433,11 @@ export default function nvd3Vis(slice, payload) {
chart.useInteractiveGuideline(true);
if (vizType === 'line') {
// Custom sorted tooltip
+ // use a verbose formatter for times
chart.interactiveLayer.tooltip.contentGenerator((d) => {
let tooltip = '';
tooltip += "<table><thead><tr><td colspan='3'>"
- + `<strong class='x-value'>${xAxisFormatter(d.value)}</strong>`
+ + `<strong class='x-value'>${formatDateVerbose(d.value)}</strong>`
+ '</td></tr></thead><tbody>';
d.series.sort((a, b) => a.value >= b.value ? -1 : 1);
d.series.forEach((series) => {
diff --git a/superset/assets/src/visualizations/sunburst.js b/superset/assets/src/visualizations/sunburst.js
index 0c04622..0c9c2cc 100644
--- a/superset/assets/src/visualizations/sunburst.js
+++ b/superset/assets/src/visualizations/sunburst.js
@@ -43,8 +43,8 @@ function sunburstVis(slice, payload) {
return Math.sqrt(d.y + d.dy);
});
- const formatNum = d3.format('.3s');
- const formatPerc = d3.format('.3p');
+ const formatNum = d3.format('.1s');
+ const formatPerc = d3.format('.1p');
container.select('svg').remove();
diff --git a/superset/assets/src/visualizations/world_map.js b/superset/assets/src/visualizations/world_map.js
index a9ab714..e7c1047 100644
--- a/superset/assets/src/visualizations/world_map.js
+++ b/superset/assets/src/visualizations/world_map.js
@@ -39,7 +39,7 @@ function worldMapChart(slice, payload) {
mapData[d.country] = d;
});
- const f = d3.format('.3s');
+ const formatter = d3.format('.3s');
container.show();
@@ -58,7 +58,7 @@ function worldMapChart(slice, payload) {
highlightFillColor: '#005a63',
highlightBorderWidth: 1,
popupTemplate: (geo, d) => (
- `<div class="hoverinfo"><strong>${d.name}</strong><br>${f(d.m1)}</div>`
+ `<div class="hoverinfo"><strong>${d.name}</strong><br>${formatter(d.m1)}</div>`
),
},
bubblesConfig: {
@@ -68,7 +68,7 @@ function worldMapChart(slice, payload) {
popupOnHover: true,
radius: null,
popupTemplate: (geo, d) => (
- `<div class="hoverinfo"><strong>${d.name}</strong><br>${f(d.m2)}</div>`
+ `<div class="hoverinfo"><strong>${d.name}</strong><br>${formatter(d.m2)}</div>`
),
fillOpacity: 0.5,
animate: true,
--
To stop receiving notification emails like this one, please contact
ccwilliams@apache.org.