You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by mi...@apache.org on 2018/12/05 19:10:40 UTC

[incubator-superset] branch 0.30 created (now 8b2b462)

This is an automated email from the ASF dual-hosted git repository.

michellet pushed a change to branch 0.30
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git.


      at 8b2b462  Use @superset-ui/number-format and @superset-ui/time-format for formatting.  (#6470)

This branch includes the following new commits:

     new 8b2b462  Use @superset-ui/number-format and @superset-ui/time-format for formatting.  (#6470)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[incubator-superset] 01/01: Use @superset-ui/number-format and @superset-ui/time-format for formatting. (#6470)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michellet pushed a commit to branch 0.30
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit 8b2b4621feada9a7f7ca8861278fc8fa25d624a1
Author: Krist Wongsuphasawat <kr...@gmail.com>
AuthorDate: Tue Dec 4 13:24:07 2018 -0800

    Use @superset-ui/number-format and @superset-ui/time-format for formatting.  (#6470)
    
    refactor: proxy all d3 number and time formatting calls
    (cherry picked from commit fcec748b62b333fbfbba23c6d49cdf98f7d6a280)
---
 superset/assets/package.json                       |   2 +
 .../assets/spec/javascripts/modules/dates_spec.js  |  52 +---------
 .../assets/spec/javascripts/modules/utils_spec.jsx |  52 ----------
 .../javascripts/visualizations/nvd3/utils_spec.js  |  26 ++++-
 .../src/explore/components/RowCountLabel.jsx       |   5 +-
 superset/assets/src/modules/dates.js               | 112 ---------------------
 superset/assets/src/modules/utils.js               |  64 ------------
 superset/assets/src/preamble.js                    |   4 +
 superset/assets/src/setup/setupFormatters.js       |  35 +++++++
 .../src/visualizations/BigNumber/BigNumber.jsx     |   4 +-
 .../src/visualizations/BigNumber/transformProps.js |   7 +-
 .../assets/src/visualizations/Calendar/Calendar.js |   8 +-
 superset/assets/src/visualizations/Chord/Chord.js  |   3 +-
 .../src/visualizations/CountryMap/CountryMap.js    |   4 +-
 .../assets/src/visualizations/Heatmap/Heatmap.js   |   5 +-
 .../src/visualizations/Partition/Partition.js      |   7 +-
 .../src/visualizations/PivotTable/PivotTable.js    |   5 +-
 superset/assets/src/visualizations/Rose/Rose.js    |   7 +-
 .../assets/src/visualizations/Sankey/Sankey.js     |   3 +-
 .../assets/src/visualizations/Sunburst/Sunburst.js |   5 +-
 superset/assets/src/visualizations/Table/Table.js  |  13 +--
 .../visualizations/TimeTable/FormattedNumber.jsx   |   4 +-
 .../src/visualizations/TimeTable/SparklineCell.jsx |   6 +-
 .../src/visualizations/TimeTable/TimeTable.jsx     |  10 +-
 .../assets/src/visualizations/Treemap/Treemap.js   |   3 +-
 .../assets/src/visualizations/WorldMap/WorldMap.js |   3 +-
 superset/assets/src/visualizations/nvd3/NVD3Vis.js |  27 ++---
 superset/assets/src/visualizations/nvd3/utils.js   |  15 ++-
 superset/assets/yarn.lock                          |  17 +++-
 29 files changed, 162 insertions(+), 346 deletions(-)

diff --git a/superset/assets/package.json b/superset/assets/package.json
index f1940c7..466ad3e 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -55,6 +55,8 @@
     "@superset-ui/color": "^0.7.0",
     "@superset-ui/connection": "^0.5.0",
     "@superset-ui/core": "^0.7.0",
+    "@superset-ui/number-format": "^0.7.2",
+    "@superset-ui/time-format": "^0.7.2",
     "@superset-ui/translation": "^0.7.0",
     "@vx/legend": "^0.0.170",
     "@vx/responsive": "0.0.172",
diff --git a/superset/assets/spec/javascripts/modules/dates_spec.js b/superset/assets/spec/javascripts/modules/dates_spec.js
index 3f39343..d9f97e7 100644
--- a/superset/assets/spec/javascripts/modules/dates_spec.js
+++ b/superset/assets/spec/javascripts/modules/dates_spec.js
@@ -1,60 +1,10 @@
 import {
-  tickMultiFormat,
-  formatDate,
-  formatDateVerbose,
   fDuration,
   now,
   epochTimeXHoursAgo,
   epochTimeXDaysAgo,
   epochTimeXYearsAgo,
- } from '../../../src/modules/dates';
-
-describe('tickMultiFormat', () => {
-  it('is a function', () => {
-    expect(typeof tickMultiFormat).toBe('function');
-  });
-});
-
-describe('formatDate', () => {
-  it('is a function', () => {
-    expect(typeof formatDate).toBe('function');
-  });
-
-  it('shows only year when 1st day of the year', () => {
-    expect(formatDate(new Date('2020-01-01'))).toBe('2020');
-  });
-
-  it('shows only month when 1st of month', () => {
-    expect(formatDate(new Date('2020-03-01'))).toBe('March');
-  });
-
-  it('does not show day of week when it is Sunday', () => {
-    expect(formatDate(new Date('2020-03-15'))).toBe('Mar 15');
-  });
-
-  it('shows weekday when it is not Sunday (and no ms/sec/min/hr)', () => {
-    expect(formatDate(new Date('2020-03-03'))).toBe('Tue 03');
-  });
-});
-
-describe('formatDateVerbose', () => {
-  it('is a function', () => {
-    expect(typeof formatDateVerbose).toBe('function');
-  });
-
-  it('shows only year when 1st day of the year', () => {
-    expect(formatDateVerbose(new Date('2020-01-01'))).toBe('2020');
-  });
-
-  it('shows month and year when 1st of month', () => {
-    expect(formatDateVerbose(new Date('2020-03-01'))).toBe('Mar 2020');
-  });
-
-  it('shows weekday when any day of the month', () => {
-    expect(formatDateVerbose(new Date('2020-03-03'))).toBe('Tue Mar 3');
-    expect(formatDateVerbose(new Date('2020-03-15'))).toBe('Sun Mar 15');
-  });
-});
+} from '../../../src/modules/dates';
 
 describe('fDuration', () => {
   it('is a function', () => {
diff --git a/superset/assets/spec/javascripts/modules/utils_spec.jsx b/superset/assets/spec/javascripts/modules/utils_spec.jsx
index ca16d86..79a2044 100644
--- a/superset/assets/spec/javascripts/modules/utils_spec.jsx
+++ b/superset/assets/spec/javascripts/modules/utils_spec.jsx
@@ -1,9 +1,5 @@
 import {
   formatSelectOptionsForRange,
-  d3format,
-  d3FormatPreset,
-  d3TimeFormatPreset,
-  defaultNumberFormatter,
   mainMetric,
   roundDecimal,
 } from '../../../src/modules/utils';
@@ -25,54 +21,6 @@ describe('utils', () => {
     });
   });
 
-  describe('d3format', () => {
-    it('returns a string formatted number as specified', () => {
-      expect(d3format('.3s', 1234)).toBe('1.23k');
-      expect(d3format('.3s', 1237)).toBe('1.24k');
-      expect(d3format('', 1237)).toBe('1.24k');
-      expect(d3format('.2efd2.ef.2.e', 1237)).toBe('1237 (Invalid format: .2efd2.ef.2.e)');
-    });
-  });
-
-  describe('d3FormatPreset', () => {
-    it('is a function', () => {
-      expect(typeof d3FormatPreset).toBe('function');
-    });
-    it('returns a working formatter', () => {
-      expect(d3FormatPreset('.3s')(3000000)).toBe('3.00M');
-    });
-  });
-
-  describe('d3TimeFormatPreset', () => {
-    it('is a function', () => {
-      expect(typeof d3TimeFormatPreset).toBe('function');
-    });
-    it('returns a working formatter', () => {
-      expect(d3FormatPreset('smart_date')(0)).toBe('1970');
-      expect(d3FormatPreset('%%GIBBERISH')(0)).toBe('0 (Invalid format: %%GIBBERISH)');
-    });
-  });
-
-  describe('defaultNumberFormatter', () => {
-    expect(defaultNumberFormatter(10)).toBe('10');
-    expect(defaultNumberFormatter(1)).toBe('1');
-    expect(defaultNumberFormatter(1.0)).toBe('1');
-    expect(defaultNumberFormatter(10.0)).toBe('10');
-    expect(defaultNumberFormatter(10001)).toBe('10.0k');
-    expect(defaultNumberFormatter(10100)).toBe('10.1k');
-    expect(defaultNumberFormatter(111000000)).toBe('111M');
-    expect(defaultNumberFormatter(0.23)).toBe('230m');
-
-    expect(defaultNumberFormatter(-10)).toBe('-10');
-    expect(defaultNumberFormatter(-1)).toBe('-1');
-    expect(defaultNumberFormatter(-1.0)).toBe('-1');
-    expect(defaultNumberFormatter(-10.0)).toBe('-10');
-    expect(defaultNumberFormatter(-10001)).toBe('-10.0k');
-    expect(defaultNumberFormatter(-10101)).toBe('-10.1k');
-    expect(defaultNumberFormatter(-111000000)).toBe('-111M');
-    expect(defaultNumberFormatter(-0.23)).toBe('-230m');
-  });
-
   describe('mainMetric', () => {
     it('is null when no options', () => {
       expect(mainMetric([])).toBeUndefined();
diff --git a/superset/assets/spec/javascripts/visualizations/nvd3/utils_spec.js b/superset/assets/spec/javascripts/visualizations/nvd3/utils_spec.js
index 43a824e..623be1f 100644
--- a/superset/assets/spec/javascripts/visualizations/nvd3/utils_spec.js
+++ b/superset/assets/spec/javascripts/visualizations/nvd3/utils_spec.js
@@ -1,11 +1,26 @@
-import { formatLabel, tryNumify } from '../../../../src/visualizations/nvd3/utils';
+import { getTimeOrNumberFormatter, formatLabel, tryNumify } from '../../../../src/visualizations/nvd3/utils';
 
 describe('nvd3/utils', () => {
-  const verboseMap = {
-    foo: 'Foo',
-    bar: 'Bar',
-  };
+  describe('getTimeOrNumberFormatter(format)', () => {
+    it('is a function', () => {
+      expect(typeof getTimeOrNumberFormatter).toBe('function');
+    });
+    it('returns a date formatter if format is smart_date', () => {
+      const time = new Date(Date.UTC(2018, 10, 21, 22, 11));
+      expect(getTimeOrNumberFormatter('smart_date')(time)).toBe('10:11');
+    });
+    it('returns a number formatter otherwise', () => {
+      expect(getTimeOrNumberFormatter('.3s')(3000000)).toBe('3.00M');
+      expect(getTimeOrNumberFormatter()(3000100)).toBe('3.00M');
+    });
+  });
+
   describe('formatLabel()', () => {
+    const verboseMap = {
+      foo: 'Foo',
+      bar: 'Bar',
+    };
+
     it('formats simple labels', () => {
       expect(formatLabel('foo')).toBe('foo');
       expect(formatLabel(['foo'])).toBe('foo');
@@ -22,6 +37,7 @@ describe('nvd3/utils', () => {
       expect(formatLabel(['foo', 'bar', 'baz', '2 hours offset'], verboseMap)).toBe('Foo, Bar, baz, 2 hours offset');
     });
   });
+
   describe('tryNumify()', () => {
     it('tryNumify works as expected', () => {
       expect(tryNumify(5)).toBe(5);
diff --git a/superset/assets/src/explore/components/RowCountLabel.jsx b/superset/assets/src/explore/components/RowCountLabel.jsx
index aea9bc4..2eeb80d 100644
--- a/superset/assets/src/explore/components/RowCountLabel.jsx
+++ b/superset/assets/src/explore/components/RowCountLabel.jsx
@@ -1,12 +1,11 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Label } from 'react-bootstrap';
+import { getNumberFormatter } from '@superset-ui/number-format';
 import { t } from '@superset-ui/translation';
 
-import { defaultNumberFormatter } from '../../modules/utils';
 import TooltipWrapper from '../../components/TooltipWrapper';
 
-
 const propTypes = {
   rowcount: PropTypes.number,
   limit: PropTypes.number,
@@ -21,7 +20,7 @@ const defaultProps = {
 export default function RowCountLabel({ rowcount, limit, suffix }) {
   const limitReached = rowcount === limit;
   const bsStyle = (limitReached || rowcount === 0) ? 'danger' : 'default';
-  const formattedRowCount = defaultNumberFormatter(rowcount);
+  const formattedRowCount = getNumberFormatter()(rowcount);
   const tooltip = (
     <span>
       {limitReached &&
diff --git a/superset/assets/src/modules/dates.js b/superset/assets/src/modules/dates.js
index 311340b..f5063b0 100644
--- a/superset/assets/src/modules/dates.js
+++ b/superset/assets/src/modules/dates.js
@@ -1,4 +1,3 @@
-import d3 from 'd3';
 import moment from 'moment';
 
 export function UTC(dttm) {
@@ -12,117 +11,6 @@ export function UTC(dttm) {
   );
 }
 
-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) {
-      return d.getMilliseconds();
-    },
-  ],
-  // If there are millisections, show  only them
-  [
-    ':%S',
-    function (d) {
-      return d.getSeconds();
-    },
-  ],
-  // If there are seconds, show only them
-  [
-    '%a %b %d, %I:%M %p',
-    function (d) {
-      return d.getMinutes() !== 0;
-    },
-  ],
-  // If there are non-zero minutes, show Date, Hour:Minute [AM/PM]
-  [
-    '%a %b %d, %I %p',
-    function (d) {
-      return d.getHours() !== 0;
-    },
-  ],
-  // If there are hours that are multiples of 3, show date and AM/PM
-  [
-    '%a %b %e',
-    function (d) {
-      return d.getDate() >= 10;
-    },
-  ],
-  // If not the first of the month: "Tue Mar 2"
-  [
-    '%a %b%e',
-    function (d) {
-      return d.getDate() > 1;
-    },
-  ],
-  // If >= 10th of the month, compensate for padding : "Sun Mar 15"
-  [
-    '%b %Y',
-    function (d) {
-      return d.getMonth() !== 0 && d.getDate() === 1;
-    },
-  ],
-  // If the first of the month: 'Mar 2020'
-  [
-    '%Y',
-    function () {
-      return true;
-    },
-  ],  // fall back on just year: '2020'
-]);
-export const formatDate = function (dttm) {
-  const d = UTC(new Date(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 formatDateVerbose;
-  }
-
-  const formatter = d3.time.format(format);
-  return (dttm) => {
-    const d = UTC(new Date(dttm));
-    return formatter(d);
-  };
-};
-
 export const fDuration = function (t1, t2, format = 'HH:mm:ss.SS') {
   const diffSec = t2 - t1;
   const duration = moment(new Date(diffSec));
diff --git a/superset/assets/src/modules/utils.js b/superset/assets/src/modules/utils.js
index 9fbd1c8..11d2eb3 100644
--- a/superset/assets/src/modules/utils.js
+++ b/superset/assets/src/modules/utils.js
@@ -1,70 +1,6 @@
 /* eslint camelcase: 0 */
 import $ from 'jquery';
-import { format as d3Format } from 'd3-format';
 import { select as d3Select } from 'd3-selection';
-import { timeFormat as d3TimeFormat } from 'd3-time-format';
-import { formatDate, UTC } from './dates';
-
-const siFormatter = d3Format('.3s');
-
-export function defaultNumberFormatter(n) {
-  let si = siFormatter(n);
-  // Removing trailing `.00` if any
-  if (si.slice(-1) < 'A') {
-    si = parseFloat(si).toString();
-  }
-  return si;
-}
-
-export function d3FormatPreset(format) {
-  // like d3Format, but with support for presets like 'smart_date'
-  if (format === 'smart_date') {
-    return formatDate;
-  }
-  if (format) {
-    try {
-      return d3Format(format);
-    } catch (e) {
-      // eslint-disable-next-line no-console
-      console.warn(e);
-      return value => `${value} (Invalid format: ${format})`;
-    }
-  }
-  return defaultNumberFormatter;
-}
-
-export const d3TimeFormatPreset = function (format) {
-  const effFormat = format || 'smart_date';
-  if (effFormat === 'smart_date') {
-    return formatDate;
-  }
-  const f = d3TimeFormat(effFormat);
-  return function (dttm) {
-    const d = UTC(new Date(dttm));
-    return f(d);
-  };
-};
-
-const formatters = {};
-
-export function d3format(format, number) {
-  format = format || '.3s';
-  // Formats a number and memoizes formatters to be reused
-  if (!(format in formatters)) {
-    try {
-      formatters[format] = d3Format(format);
-    } catch (e) {
-      // eslint-disable-next-line no-console
-      console.warn(e);
-      return `${number} (Invalid format: ${format})`;
-    }
-  }
-  try {
-    return formatters[format](number);
-  } catch (e) {
-    return `${number} (Invalid format: ${format})`;
-  }
-}
 
 /*
   Utility function that takes a d3 svg:text selection and a max width, and splits the
diff --git a/superset/assets/src/preamble.js b/superset/assets/src/preamble.js
index 9d80dc9..3e96e60 100644
--- a/superset/assets/src/preamble.js
+++ b/superset/assets/src/preamble.js
@@ -2,6 +2,7 @@ import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only';
 import { configure } from '@superset-ui/translation';
 import setupClient from './setup/setupClient';
 import setupColors from './setup/setupColors';
+import setupFormatters from './setup/setupFormatters';
 
 // Configure translation
 if (typeof window !== 'undefined') {
@@ -22,3 +23,6 @@ setupClient();
 
 // Setup color palettes
 setupColors();
+
+// Setup number formatters
+setupFormatters();
diff --git a/superset/assets/src/setup/setupFormatters.js b/superset/assets/src/setup/setupFormatters.js
new file mode 100644
index 0000000..dd1f39f
--- /dev/null
+++ b/superset/assets/src/setup/setupFormatters.js
@@ -0,0 +1,35 @@
+import { getNumberFormatter, getNumberFormatterRegistry, createSiAtMostNDigitFormatter, NumberFormats } from '@superset-ui/number-format';
+import { getTimeFormatterRegistry, smartDateFormatter, smartDateVerboseFormatter } from '@superset-ui/time-format';
+
+export default function setupFormatters() {
+  const defaultNumberFormatter = createSiAtMostNDigitFormatter({ n: 3 });
+
+  getNumberFormatterRegistry()
+    .registerValue(defaultNumberFormatter.id, defaultNumberFormatter)
+    .setDefaultKey(defaultNumberFormatter.id)
+    // Add shims for format strings that are deprecated or common typos.
+    // Temporary solution until performing a db migration to fix this.
+    .registerValue('+,', getNumberFormatter(NumberFormats.INTEGER_CHANGE))
+    .registerValue(',0', getNumberFormatter(',.4~f'))
+    .registerValue('.', getNumberFormatter('.4~f'))
+    .registerValue(',#', getNumberFormatter(',.4~f'))
+    .registerValue(',2f', getNumberFormatter(',.4~f'))
+    .registerValue(',g', getNumberFormatter(',.4~f'))
+    .registerValue('int', getNumberFormatter(NumberFormats.INTEGER))
+    .registerValue(',.', getNumberFormatter(',.4~f'))
+    .registerValue('.0%f', getNumberFormatter('.1%'))
+    .registerValue('.1%f', getNumberFormatter('.1%'))
+    .registerValue('.r', getNumberFormatter('.4~f'))
+    .registerValue(',0s', getNumberFormatter(',.4~f'))
+    .registerValue('%%%', getNumberFormatter('.0%'))
+    .registerValue(',0f', getNumberFormatter(',.4~f'))
+    .registerValue(',1', getNumberFormatter(',.4~f'))
+    .registerValue('$,0', getNumberFormatter('$,.4f'))
+    .registerValue('$,0f', getNumberFormatter('$,.4f'))
+    .registerValue('$,.f', getNumberFormatter('$,.4f'));
+
+  getTimeFormatterRegistry()
+    .registerValue('smart_date', smartDateFormatter)
+    .registerValue('smart_date_verbose', smartDateVerboseFormatter)
+    .setDefaultKey('smart_date');
+}
diff --git a/superset/assets/src/visualizations/BigNumber/BigNumber.jsx b/superset/assets/src/visualizations/BigNumber/BigNumber.jsx
index 9c80e04..b6c79e6 100644
--- a/superset/assets/src/visualizations/BigNumber/BigNumber.jsx
+++ b/superset/assets/src/visualizations/BigNumber/BigNumber.jsx
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
 import shortid from 'shortid';
 import { XYChart, AreaSeries, CrossHair, LinearGradient } from '@data-ui/xy-chart';
 import { BRAND_COLOR } from '@superset-ui/color';
-import { formatDateVerbose } from '../../modules/dates';
+import { smartDateVerboseFormatter } from '@superset-ui/time-format';
 import { computeMaxFontSize } from '../../modules/visUtils';
 
 import './BigNumber.css';
@@ -26,7 +26,7 @@ const PROPORTION = {
 export function renderTooltipFactory(formatValue) {
   return function renderTooltip({ datum }) { // eslint-disable-line
     const { x: rawDate, y: rawValue } = datum;
-    const formattedDate = formatDateVerbose(rawDate);
+    const formattedDate = smartDateVerboseFormatter(rawDate);
     const value = formatValue(rawValue);
 
     return (
diff --git a/superset/assets/src/visualizations/BigNumber/transformProps.js b/superset/assets/src/visualizations/BigNumber/transformProps.js
index 92a88f3..cb5dcc2 100644
--- a/superset/assets/src/visualizations/BigNumber/transformProps.js
+++ b/superset/assets/src/visualizations/BigNumber/transformProps.js
@@ -1,6 +1,5 @@
 import * as color from 'd3-color';
-import { format as d3Format } from 'd3-format';
-import { d3FormatPreset } from '../../modules/utils';
+import { getNumberFormatter, NumberFormats } from '@superset-ui/number-format';
 import { renderTooltipFactory } from './BigNumber';
 
 const TIME_COLUMN = '__timestamp';
@@ -43,7 +42,7 @@ export default function transformProps(chartProps) {
         const compareValue = sortedData[compareIndex][metricName];
         percentChange = compareValue === 0
           ? 0 : (bigNumber - compareValue) / Math.abs(compareValue);
-        const formatPercentChange = d3Format('+.1%');
+        const formatPercentChange = getNumberFormatter(NumberFormats.PERCENT_CHANGE_1_POINT);
         formattedSubheader = `${formatPercentChange(percentChange)} ${compareSuffix}`;
       }
     }
@@ -62,7 +61,7 @@ export default function transformProps(chartProps) {
     className = 'negative';
   }
 
-  const formatValue = d3FormatPreset(yAxisFormat);
+  const formatValue = getNumberFormatter(yAxisFormat);
 
   return {
     width,
diff --git a/superset/assets/src/visualizations/Calendar/Calendar.js b/superset/assets/src/visualizations/Calendar/Calendar.js
index 6b7aada..0dd3944 100644
--- a/superset/assets/src/visualizations/Calendar/Calendar.js
+++ b/superset/assets/src/visualizations/Calendar/Calendar.js
@@ -2,8 +2,10 @@ import PropTypes from 'prop-types';
 import { extent as d3Extent, range as d3Range } from 'd3-array';
 import { select as d3Select } from 'd3-selection';
 import { getSequentialSchemeRegistry } from '@superset-ui/color';
+import { getNumberFormatter } from '@superset-ui/number-format';
+import { getTimeFormatter } from '@superset-ui/time-format';
 import CalHeatMap from '../../../vendor/cal-heatmap/cal-heatmap';
-import { d3TimeFormatPreset, d3FormatPreset } from '../../modules/utils'; import { UTC } from '../../modules/dates';
+import { UTC } from '../../modules/dates';
 import '../../../vendor/cal-heatmap/cal-heatmap.css';
 import './Calendar.css';
 
@@ -53,8 +55,8 @@ function Calendar(element, props) {
     verboseMap,
   } = props;
 
-  const valueFormatter = d3FormatPreset(valueFormat);
-  const timeFormatter = d3TimeFormatPreset(timeFormat);
+  const valueFormatter = getNumberFormatter(valueFormat);
+  const timeFormatter = getTimeFormatter(timeFormat);
 
   const container = d3Select(element)
     .style('height', height);
diff --git a/superset/assets/src/visualizations/Chord/Chord.js b/superset/assets/src/visualizations/Chord/Chord.js
index 05d416e..84e399f 100644
--- a/superset/assets/src/visualizations/Chord/Chord.js
+++ b/superset/assets/src/visualizations/Chord/Chord.js
@@ -2,6 +2,7 @@
 import d3 from 'd3';
 import PropTypes from 'prop-types';
 import { CategoricalColorNamespace } from '@superset-ui/color';
+import { getNumberFormatter } from '@superset-ui/number-format';
 import './Chord.css';
 
 const propTypes = {
@@ -28,7 +29,7 @@ function Chord(element, props) {
 
   const div = d3.select(element);
   const { nodes, matrix } = data;
-  const f = d3.format(numberFormat);
+  const f = getNumberFormatter(numberFormat);
   const colorFn = CategoricalColorNamespace.getScale(colorScheme);
 
   const outerRadius = Math.min(width, height) / 2 - 10;
diff --git a/superset/assets/src/visualizations/CountryMap/CountryMap.js b/superset/assets/src/visualizations/CountryMap/CountryMap.js
index ff22bcf..830ff28 100644
--- a/superset/assets/src/visualizations/CountryMap/CountryMap.js
+++ b/superset/assets/src/visualizations/CountryMap/CountryMap.js
@@ -1,8 +1,8 @@
 import d3 from 'd3';
 import PropTypes from 'prop-types';
 import { extent as d3Extent } from 'd3-array';
-import { format as d3Format } from 'd3-format';
 import { getSequentialSchemeRegistry } from '@superset-ui/color';
+import { getNumberFormatter } from '@superset-ui/number-format';
 import './CountryMap.css';
 
 const propTypes = {
@@ -32,7 +32,7 @@ function CountryMap(element, props) {
   } = props;
 
   const container = element;
-  const format = d3Format(numberFormat);
+  const format = getNumberFormatter(numberFormat);
   const colorScale = getSequentialSchemeRegistry()
     .get(linearColorScheme)
     .createLinearScale(d3Extent(data, v => v.metric));
diff --git a/superset/assets/src/visualizations/Heatmap/Heatmap.js b/superset/assets/src/visualizations/Heatmap/Heatmap.js
index 4c8f6aa..3e7d7d7 100644
--- a/superset/assets/src/visualizations/Heatmap/Heatmap.js
+++ b/superset/assets/src/visualizations/Heatmap/Heatmap.js
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
 import 'd3-svg-legend';
 import d3tip from 'd3-tip';
 import { getSequentialSchemeRegistry } from '@superset-ui/color';
+import { getNumberFormatter, NumberFormats } from '@superset-ui/number-format';
 
 import '../../../stylesheets/d3tip.css';
 import './Heatmap.css';
@@ -85,7 +86,7 @@ function Heatmap(element, props) {
     bottom: 35,
     left: 35,
   };
-  const valueFormatter = d3.format(numberFormat);
+  const valueFormatter = getNumberFormatter(numberFormat);
 
   // Dynamically adjusts  based on max x / y category lengths
   function adjustMargins() {
@@ -152,7 +153,7 @@ function Heatmap(element, props) {
 
   const hmWidth = width - (margin.left + margin.right);
   const hmHeight = height - (margin.bottom + margin.top);
-  const fp = d3.format('.2%');
+  const fp = getNumberFormatter(NumberFormats.PERCENT);
 
   const xScale = ordScale('x', null, sortXAxis);
   const yScale = ordScale('y', null, sortYAxis);
diff --git a/superset/assets/src/visualizations/Partition/Partition.js b/superset/assets/src/visualizations/Partition/Partition.js
index 539c024..dbb2e42 100644
--- a/superset/assets/src/visualizations/Partition/Partition.js
+++ b/superset/assets/src/visualizations/Partition/Partition.js
@@ -3,7 +3,8 @@ import d3 from 'd3';
 import PropTypes from 'prop-types';
 import { hierarchy } from 'd3-hierarchy';
 import { CategoricalColorNamespace } from '@superset-ui/color';
-import { d3TimeFormatPreset } from '../../modules/utils';
+import { getNumberFormatter } from '@superset-ui/number-format';
+import { getTimeFormatter } from '@superset-ui/time-format';
 import './Partition.css';
 
 // Compute dx, dy, x, y for each node and
@@ -93,8 +94,8 @@ function Icicle(element, props) {
   // Chart options
   const chartType = timeSeriesOption;
   const hasTime = ['adv_anal', 'time_series'].indexOf(chartType) >= 0;
-  const format = d3.format(numberFormat);
-  const timeFormat = d3TimeFormatPreset(dateTimeFormat);
+  const format = getNumberFormatter(numberFormat);
+  const timeFormat = getTimeFormatter(dateTimeFormat);
   const colorFn = CategoricalColorNamespace.getScale(colorScheme);
 
   div.selectAll('*').remove();
diff --git a/superset/assets/src/visualizations/PivotTable/PivotTable.js b/superset/assets/src/visualizations/PivotTable/PivotTable.js
index 71d0cfa..b5326bc 100644
--- a/superset/assets/src/visualizations/PivotTable/PivotTable.js
+++ b/superset/assets/src/visualizations/PivotTable/PivotTable.js
@@ -2,7 +2,8 @@ import dt from 'datatables.net-bs';
 import 'datatables.net-bs/css/dataTables.bootstrap.css';
 import $ from 'jquery';
 import PropTypes from 'prop-types';
-import { d3format, fixDataTableBodyHeight } from '../../modules/utils';
+import { formatNumber } from '@superset-ui/number-format';
+import { fixDataTableBodyHeight } from '../../modules/utils';
 import './PivotTable.css';
 
 dt(window, $);
@@ -59,7 +60,7 @@ function PivotTable(element, props) {
       const format = columnFormats[metric] || numberFormat || '.3s';
       const tdText = $(this)[0].textContent;
       if (!Number.isNaN(tdText) && tdText !== '') {
-        $(this)[0].textContent = d3format(format, tdText);
+        $(this)[0].textContent = formatNumber(format, tdText);
         $(this).attr('data-sort', tdText);
       }
     });
diff --git a/superset/assets/src/visualizations/Rose/Rose.js b/superset/assets/src/visualizations/Rose/Rose.js
index 097c918..a99d03f 100644
--- a/superset/assets/src/visualizations/Rose/Rose.js
+++ b/superset/assets/src/visualizations/Rose/Rose.js
@@ -3,7 +3,8 @@ import d3 from 'd3';
 import PropTypes from 'prop-types';
 import nv from 'nvd3';
 import { CategoricalColorNamespace } from '@superset-ui/color';
-import { d3TimeFormatPreset } from '../../modules/utils';
+import { getNumberFormatter } from '@superset-ui/number-format';
+import { getTimeFormatter } from '@superset-ui/time-format';
 import './Rose.css';
 
 const propTypes = {
@@ -58,8 +59,8 @@ function Rose(element, props) {
     .sort((a, b) => a - b);
   const numGrains = times.length;
   const numGroups = datum[times[0]].length;
-  const format = d3.format(numberFormat);
-  const timeFormat = d3TimeFormatPreset(dateTimeFormat);
+  const format = getNumberFormatter(numberFormat);
+  const timeFormat = getTimeFormatter(dateTimeFormat);
   const colorFn = CategoricalColorNamespace.getScale(colorScheme);
 
   d3.select('.nvtooltip').remove();
diff --git a/superset/assets/src/visualizations/Sankey/Sankey.js b/superset/assets/src/visualizations/Sankey/Sankey.js
index f80d032..5e4c6eb 100644
--- a/superset/assets/src/visualizations/Sankey/Sankey.js
+++ b/superset/assets/src/visualizations/Sankey/Sankey.js
@@ -3,6 +3,7 @@ import d3 from 'd3';
 import PropTypes from 'prop-types';
 import { sankey as d3Sankey } from 'd3-sankey';
 import { CategoricalColorNamespace } from '@superset-ui/color';
+import { getNumberFormatter, NumberFormats } from '@superset-ui/number-format';
 import './Sankey.css';
 
 const propTypes = {
@@ -16,7 +17,7 @@ const propTypes = {
   colorScheme: PropTypes.string,
 };
 
-const formatNumber = d3.format(',.2f');
+const formatNumber = getNumberFormatter(NumberFormats.FLOAT);
 
 function Sankey(element, props) {
   const {
diff --git a/superset/assets/src/visualizations/Sunburst/Sunburst.js b/superset/assets/src/visualizations/Sunburst/Sunburst.js
index 29496a6..5e13c19 100644
--- a/superset/assets/src/visualizations/Sunburst/Sunburst.js
+++ b/superset/assets/src/visualizations/Sunburst/Sunburst.js
@@ -2,6 +2,7 @@
 import d3 from 'd3';
 import PropTypes from 'prop-types';
 import { CategoricalColorNamespace } from '@superset-ui/color';
+import { getNumberFormatter, NumberFormats } from '@superset-ui/number-format';
 import { wrapSvgText } from '../../modules/utils';
 import './Sunburst.css';
 
@@ -79,8 +80,8 @@ function Sunburst(element, props) {
     .innerRadius(d => Math.sqrt(d.y))
     .outerRadius(d => Math.sqrt(d.y + d.dy));
 
-  const formatNum = d3.format('.3s');
-  const formatPerc = d3.format('.3p');
+  const formatNum = getNumberFormatter(NumberFormats.SI_3_DIGIT);
+  const formatPerc = getNumberFormatter(NumberFormats.PERCENT_3_POINT);
 
   container.select('svg').remove();
 
diff --git a/superset/assets/src/visualizations/Table/Table.js b/superset/assets/src/visualizations/Table/Table.js
index 7056235..23cdc07 100644
--- a/superset/assets/src/visualizations/Table/Table.js
+++ b/superset/assets/src/visualizations/Table/Table.js
@@ -4,8 +4,9 @@ import PropTypes from 'prop-types';
 import dt from 'datatables.net-bs';
 import 'datatables.net-bs/css/dataTables.bootstrap.css';
 import dompurify from 'dompurify';
-import { format as d3Format } from 'd3-format';
-import { fixDataTableBodyHeight, d3TimeFormatPreset } from '../../modules/utils';
+import { getNumberFormatter, NumberFormats } from '@superset-ui/number-format';
+import { getTimeFormatter } from '@superset-ui/time-format';
+import { fixDataTableBodyHeight } from '../../modules/utils';
 import './Table.css';
 
 dt(window, $);
@@ -46,8 +47,8 @@ const propTypes = {
   ]),
 };
 
-const formatValue = d3Format(',.0d');
-const formatPercent = d3Format('.3p');
+const formatValue = getNumberFormatter(NumberFormats.INTEGER);
+const formatPercent = getNumberFormatter(NumberFormats.PERCENT_3_POINT);
 function NOOP() {}
 
 function TableVis(element, props) {
@@ -96,7 +97,7 @@ function TableVis(element, props) {
     }
   }
 
-  const tsFormatter = d3TimeFormatPreset(tableTimestampFormat);
+  const tsFormatter = getTimeFormatter(tableTimestampFormat);
 
   const div = d3.select(element);
   div.html('');
@@ -130,7 +131,7 @@ function TableVis(element, props) {
         html = `<span class="like-pre">${dompurify.sanitize(val)}</span>`;
       }
       if (isMetric) {
-        html = d3Format(format || '0.3s')(val);
+        html = getNumberFormatter(format)(val);
       }
       if (key[0] === '%') {
         html = formatPercent(val);
diff --git a/superset/assets/src/visualizations/TimeTable/FormattedNumber.jsx b/superset/assets/src/visualizations/TimeTable/FormattedNumber.jsx
index eabbb0e..a4751e5 100644
--- a/superset/assets/src/visualizations/TimeTable/FormattedNumber.jsx
+++ b/superset/assets/src/visualizations/TimeTable/FormattedNumber.jsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { d3format } from '../../modules/utils';
+import { formatNumber } from '@superset-ui/number-format';
 
 const propTypes = {
   num: PropTypes.number,
@@ -15,7 +15,7 @@ const defaultProps = {
 function FormattedNumber({ num, format }) {
   if (format) {
     return (
-      <span title={num}>{d3format(format, num)}</span>
+      <span title={num}>{formatNumber(format, num)}</span>
     );
   }
   return <span>{num}</span>;
diff --git a/superset/assets/src/visualizations/TimeTable/SparklineCell.jsx b/superset/assets/src/visualizations/TimeTable/SparklineCell.jsx
index 1a49e35..bc58c10 100644
--- a/superset/assets/src/visualizations/TimeTable/SparklineCell.jsx
+++ b/superset/assets/src/visualizations/TimeTable/SparklineCell.jsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Sparkline, LineSeries, PointSeries, HorizontalReferenceLine, VerticalReferenceLine, WithTooltip } from '@data-ui/sparkline';
-import { d3format } from '../../modules/utils';
+import { formatNumber } from '@superset-ui/number-format';
 import { getTextDimension } from '../../modules/visUtils';
 
 const propTypes = {
@@ -110,8 +110,8 @@ class SparklineCell extends React.Component {
         ? maxBound
         : data.reduce((acc, current) => Math.max(acc, current), data[0]);
 
-      minLabel = d3format(numberFormat, min);
-      maxLabel = d3format(numberFormat, max);
+      minLabel = formatNumber(numberFormat, min);
+      maxLabel = formatNumber(numberFormat, max);
       labelLength = Math.max(
         getSparklineTextWidth(minLabel),
         getSparklineTextWidth(maxLabel),
diff --git a/superset/assets/src/visualizations/TimeTable/TimeTable.jsx b/superset/assets/src/visualizations/TimeTable/TimeTable.jsx
index 38bf058..667b377 100644
--- a/superset/assets/src/visualizations/TimeTable/TimeTable.jsx
+++ b/superset/assets/src/visualizations/TimeTable/TimeTable.jsx
@@ -3,10 +3,10 @@ import PropTypes from 'prop-types';
 import Mustache from 'mustache';
 import { scaleLinear } from 'd3-scale';
 import { Table, Thead, Th, Tr, Td } from 'reactable';
+import { formatNumber } from '@superset-ui/number-format';
+import { formatTime } from '@superset-ui/time-format';
 
 import MetricOption from '../../components/MetricOption';
-import { formatDateThunk } from '../../modules/dates';
-import { d3format } from '../../modules/utils';
 import InfoTooltipWithTrigger from '../../components/InfoTooltipWithTrigger';
 import FormattedNumber from './FormattedNumber';
 import SparklineCell from './SparklineCell';
@@ -113,8 +113,6 @@ class TimeTable extends React.PureComponent {
       sparkData = entries.map(d => d[valueField]);
     }
 
-    const formatDate = formatDateThunk(column.dateFormat);
-
     return (
       <Td
         column={column.key}
@@ -131,8 +129,8 @@ class TimeTable extends React.PureComponent {
           showYAxis={column.showYAxis}
           renderTooltip={({ index }) => (
             <div>
-              <strong>{d3format(column.d3format, sparkData[index])}</strong>
-              <div>{formatDate(entries[index].time)}</div>
+              <strong>{formatNumber(column.d3format, sparkData[index])}</strong>
+              <div>{formatTime(column.dateFormat, entries[index].time)}</div>
             </div>
           )}
         />
diff --git a/superset/assets/src/visualizations/Treemap/Treemap.js b/superset/assets/src/visualizations/Treemap/Treemap.js
index 17669d6..7ac0e1b 100644
--- a/superset/assets/src/visualizations/Treemap/Treemap.js
+++ b/superset/assets/src/visualizations/Treemap/Treemap.js
@@ -2,6 +2,7 @@
 import d3 from 'd3';
 import PropTypes from 'prop-types';
 import { CategoricalColorNamespace } from '@superset-ui/color';
+import { getNumberFormatter } from '@superset-ui/number-format';
 import './Treemap.css';
 
 // Declare PropTypes for recursive data structures
@@ -67,7 +68,7 @@ function Treemap(element, props) {
     treemapRatio,
   } = props;
   const div = d3.select(element);
-  const formatNumber = d3.format(numberFormat);
+  const formatNumber = getNumberFormatter(numberFormat);
   const colorFn = CategoricalColorNamespace.getScale(colorScheme);
   const data = clone(rawData);
 
diff --git a/superset/assets/src/visualizations/WorldMap/WorldMap.js b/superset/assets/src/visualizations/WorldMap/WorldMap.js
index b2cb2c0..91f654b 100644
--- a/superset/assets/src/visualizations/WorldMap/WorldMap.js
+++ b/superset/assets/src/visualizations/WorldMap/WorldMap.js
@@ -1,6 +1,7 @@
 import d3 from 'd3';
 import PropTypes from 'prop-types';
 import Datamap from 'datamaps/dist/datamaps.world.min';
+import { getNumberFormatter } from '@superset-ui/number-format';
 import './WorldMap.css';
 
 const propTypes = {
@@ -17,7 +18,7 @@ const propTypes = {
   showBubbles: PropTypes.bool,
 };
 
-const formatter = d3.format('.3s');
+const formatter = getNumberFormatter();
 
 function WorldMap(element, props) {
   const {
diff --git a/superset/assets/src/visualizations/nvd3/NVD3Vis.js b/superset/assets/src/visualizations/nvd3/NVD3Vis.js
index 526406b..5fbfed0 100644
--- a/superset/assets/src/visualizations/nvd3/NVD3Vis.js
+++ b/superset/assets/src/visualizations/nvd3/NVD3Vis.js
@@ -6,11 +6,11 @@ import moment from 'moment';
 import PropTypes from 'prop-types';
 import { t } from '@superset-ui/translation';
 import { CategoricalColorNamespace } from '@superset-ui/color';
+import { getNumberFormatter, formatNumber, NumberFormats } from '@superset-ui/number-format';
+import { getTimeFormatter, smartDateVerboseFormatter } from '@superset-ui/time-format';
 import 'nvd3/build/nv.d3.min.css';
 
 import ANNOTATION_TYPES, { applyNativeColumns } from '../../modules/AnnotationTypes';
-import { formatDateVerbose } from '../../modules/dates';
-import { d3TimeFormatPreset, d3FormatPreset } from '../../modules/utils';
 import { isTruthy } from '../../utils/common';
 import {
   cleanColorInput,
@@ -20,6 +20,7 @@ import {
   generateMultiLineTooltipContent,
   generateRichLineTooltipContent,
   getMaxLabelSize,
+  getTimeOrNumberFormatter,
   hideTooltips,
   tipFactory,
   tryNumify,
@@ -175,7 +176,7 @@ const propTypes = {
 };
 
 const NOOP = () => {};
-const formatter = d3.format('.3s');
+const formatter = getNumberFormatter();
 
 function nvd3Vis(element, props) {
   const {
@@ -342,7 +343,7 @@ function nvd3Vis(element, props) {
         if (pieLabelType !== 'key_percent' && pieLabelType !== 'key_value') {
           chart.labelType(pieLabelType);
         } else if (pieLabelType === 'key_value') {
-          chart.labelType(d => `${d.data.x}: ${d3.format('.3s')(d.data.y)}`);
+          chart.labelType(d => `${d.data.x}: ${formatNumber(NumberFormats.SI, d.data.y)}`);
         }
 
         if (pieLabelType === 'percent' || pieLabelType === 'key_percent') {
@@ -377,8 +378,8 @@ function nvd3Vis(element, props) {
             xField,
             yField,
             sizeField,
-            xFormatter: d3FormatPreset(xAxisFormat),
-            yFormatter: d3FormatPreset(yAxisFormat),
+            xFormatter: getTimeOrNumberFormatter(xAxisFormat),
+            yFormatter: getTimeOrNumberFormatter(yAxisFormat),
             sizeFormatter: formatter,
           }));
         chart.pointRange([5, maxBubbleSize ** 2]);
@@ -458,11 +459,11 @@ function nvd3Vis(element, props) {
 
     let xAxisFormatter;
     if (isTimeSeries) {
-      xAxisFormatter = d3TimeFormatPreset(xAxisFormat);
+      xAxisFormatter = getTimeFormatter(xAxisFormat);
       // In tooltips, always use the verbose time format
-      chart.interactiveLayer.tooltip.headerFormatter(formatDateVerbose);
+      chart.interactiveLayer.tooltip.headerFormatter(smartDateVerboseFormatter);
     } else {
-      xAxisFormatter = d3FormatPreset(xAxisFormat);
+      xAxisFormatter = getTimeOrNumberFormatter(xAxisFormat);
     }
     if (chart.x2Axis && chart.x2Axis.tickFormat) {
       chart.x2Axis.tickFormat(xAxisFormatter);
@@ -472,11 +473,11 @@ function nvd3Vis(element, props) {
       chart.xAxis.tickFormat(xAxisFormatter);
     }
 
-    let yAxisFormatter = d3FormatPreset(yAxisFormat);
+    let yAxisFormatter = getTimeOrNumberFormatter(yAxisFormat);
     if (chart.yAxis && chart.yAxis.tickFormat) {
       if (contribution || comparisonType === 'percentage') {
         // When computing a "Percentage" or "Contribution" selected, we force a percentage format
-        yAxisFormatter = d3.format('.1%');
+        yAxisFormatter = getNumberFormatter(NumberFormats.PERCENT_1_POINT);
       }
       chart.yAxis.tickFormat(yAxisFormatter);
     }
@@ -519,8 +520,8 @@ function nvd3Vis(element, props) {
     }
 
     if (isVizTypes(['dual_line', 'line_multi'])) {
-      const yAxisFormatter1 = d3.format(yAxisFormat);
-      const yAxisFormatter2 = d3.format(yAxis2Format);
+      const yAxisFormatter1 = getNumberFormatter(yAxisFormat);
+      const yAxisFormatter2 = getNumberFormatter(yAxis2Format);
       chart.yAxis1.tickFormat(yAxisFormatter1);
       chart.yAxis2.tickFormat(yAxisFormatter2);
       const yAxisFormatters = data.map(datum => (
diff --git a/superset/assets/src/visualizations/nvd3/utils.js b/superset/assets/src/visualizations/nvd3/utils.js
index 52e0c3e..86ee61f 100644
--- a/superset/assets/src/visualizations/nvd3/utils.js
+++ b/superset/assets/src/visualizations/nvd3/utils.js
@@ -1,6 +1,8 @@
 import d3 from 'd3';
 import d3tip from 'd3-tip';
 import dompurify from 'dompurify';
+import { getNumberFormatter } from '@superset-ui/number-format';
+import { smartDateFormatter } from '@superset-ui/time-format';
 
 // Regexp for the label added to time shifted series
 // (1 hour offset, 2 days offset, etc.)
@@ -14,8 +16,19 @@ export function cleanColorInput(value) {
     .join(', ');
 }
 
+/**
+ * If format is smart_date, format date
+ * Otherwise, format number with the given format name
+ * @param {*} format
+ */
+export function getTimeOrNumberFormatter(format) {
+  return (format === 'smart_date')
+    ? smartDateFormatter
+    : getNumberFormatter(format);
+}
+
 export function drawBarValues(svg, data, stacked, axisFormat) {
-  const format = d3.format(axisFormat || '.3s');
+  const format = getNumberFormatter(axisFormat);
   const countSeriesDisplayed = data.length;
 
   const totalStackedValues = stacked && data.length !== 0 ?
diff --git a/superset/assets/yarn.lock b/superset/assets/yarn.lock
index dec3789..9cdccb9 100644
--- a/superset/assets/yarn.lock
+++ b/superset/assets/yarn.lock
@@ -432,6 +432,21 @@
   dependencies:
     lodash "^4.17.11"
 
+"@superset-ui/number-format@^0.7.2":
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/@superset-ui/number-format/-/number-format-0.7.2.tgz#c193181d4bdc6eb63a48996012fae7baac5ad802"
+  dependencies:
+    "@superset-ui/core" "^0.7.0"
+    d3-format "^1.3.2"
+
+"@superset-ui/time-format@^0.7.2":
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/@superset-ui/time-format/-/time-format-0.7.2.tgz#f5d21a8c46d76fc9603f2377f927ebf11593b4e1"
+  dependencies:
+    "@superset-ui/core" "^0.7.0"
+    d3-time "^1.0.10"
+    d3-time-format "^2.1.3"
+
 "@superset-ui/translation@^0.7.0":
   version "0.7.0"
   resolved "https://registry.yarnpkg.com/@superset-ui/translation/-/translation-0.7.0.tgz#8b9426a97d523df5aefe9242084264897efe252c"
@@ -3546,7 +3561,7 @@ d3-time-format@2, d3-time-format@^2.1.3:
   dependencies:
     d3-time "1"
 
-d3-time@1:
+d3-time@1, d3-time@^1.0.10:
   version "1.0.10"
   resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.10.tgz#8259dd71288d72eeacfd8de281c4bf5c7393053c"