Skip to content

Commit 437f70e

Browse files
authored
Merge pull request #5125 from plotly/new-d3-number-format
Add new formatting options by replacing `d3.format` method with more recent `d3-format` module
2 parents 06d4d2d + 32898a1 commit 437f70e

File tree

18 files changed

+335
-220
lines changed

18 files changed

+335
-220
lines changed

draftlogs/5615_add.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Add new formatting options by replacing `d3.format` method with more recent `d3-format` module [[#5615](https://github.com/plotly/plotly.js/pull/5615)]

package-lock.json

+15-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
]
6767
},
6868
"dependencies": {
69-
"@plotly/d3": "3.7.0",
69+
"@plotly/d3": "3.8.0",
7070
"@plotly/d3-sankey": "0.7.2",
7171
"@plotly/d3-sankey-circular": "0.33.1",
7272
"@plotly/point-cluster": "^3.1.9",
@@ -82,10 +82,12 @@
8282
"convex-hull": "^1.0.3",
8383
"country-regex": "^1.1.0",
8484
"d3-force": "^1.2.1",
85+
"d3-format": "^1.4.5",
8586
"d3-geo": "^1.12.1",
8687
"d3-geo-projection": "^2.9.0",
8788
"d3-hierarchy": "^1.1.9",
8889
"d3-interpolate": "^1.4.0",
90+
"d3-time": "^1.1.0",
8991
"d3-time-format": "^2.2.3",
9092
"delaunay-triangulate": "^1.1.6",
9193
"fast-isnumeric": "^1.1.4",

src/components/drawing/index.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
'use strict';
22

33
var d3 = require('@plotly/d3');
4+
var Lib = require('../../lib');
5+
var numberFormat = Lib.numberFormat;
46
var isNumeric = require('fast-isnumeric');
57
var tinycolor = require('tinycolor2');
68

79
var Registry = require('../../registry');
810
var Color = require('../color');
911
var Colorscale = require('../colorscale');
10-
var Lib = require('../../lib');
1112
var strTranslate = Lib.strTranslate;
1213
var svgTextUtils = require('../../lib/svg_text_utils');
1314

@@ -275,7 +276,7 @@ function makePointPath(symbolNumber, r) {
275276

276277
var HORZGRADIENT = {x1: 1, x2: 0, y1: 0, y2: 0};
277278
var VERTGRADIENT = {x1: 0, x2: 0, y1: 1, y2: 0};
278-
var stopFormatter = d3.format('~.1f');
279+
var stopFormatter = numberFormat('~f');
279280
var gradientInfo = {
280281
radial: {node: 'radialGradient'},
281282
radialreversed: {node: 'radialGradient', reversed: true},

src/components/rangeselector/get_update_object.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

3-
var d3 = require('@plotly/d3');
3+
var d3Time = require('d3-time');
4+
var titleCase = require('../../lib').titleCase;
45

56
module.exports = function getUpdateObject(axisLayout, buttonLayout) {
67
var axName = axisLayout._name;
@@ -22,18 +23,21 @@ function getXRange(axisLayout, buttonLayout) {
2223
var currentRange = axisLayout.range;
2324
var base = new Date(axisLayout.r2l(currentRange[1]));
2425
var step = buttonLayout.step;
26+
27+
var utcStep = d3Time['utc' + titleCase(step)];
28+
2529
var count = buttonLayout.count;
2630
var range0;
2731

2832
switch(buttonLayout.stepmode) {
2933
case 'backward':
30-
range0 = axisLayout.l2r(+d3.time[step].utc.offset(base, -count));
34+
range0 = axisLayout.l2r(+utcStep.offset(base, -count));
3135
break;
3236

3337
case 'todate':
34-
var base2 = d3.time[step].utc.offset(base, -count);
38+
var base2 = utcStep.offset(base, -count);
3539

36-
range0 = axisLayout.l2r(+d3.time[step].utc.ceil(base2));
40+
range0 = axisLayout.l2r(+utcStep.ceil(base2));
3741
break;
3842
}
3943

src/constants/docs.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

33
module.exports = {
4-
FORMAT_LINK: 'https://github.com/d3/d3-3.x-api-reference/blob/master/Formatting.md#d3_format',
4+
FORMAT_LINK: 'https://github.com/d3/d3-format/tree/v1.4.5#d3-format',
55
DATE_FORMAT_LINK: 'https://github.com/d3/d3-time-format/tree/v2.2.3#locale_format'
66
};

src/lib/index.js

+44-3
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,56 @@
22

33
var d3 = require('@plotly/d3');
44
var utcFormat = require('d3-time-format').utcFormat;
5+
var d3Format = require('d3-format').format;
56
var isNumeric = require('fast-isnumeric');
67

78
var numConstants = require('../constants/numerical');
89
var MAX_SAFE = numConstants.FP_SAFE;
910
var MIN_SAFE = -MAX_SAFE;
1011
var BADNUM = numConstants.BADNUM;
1112

12-
var lib = module.exports = {
13-
_numberFormat: d3.format // simply to test d3.format before switching to d3-format
13+
var lib = module.exports = {};
14+
15+
lib.adjustFormat = function adjustFormat(formatStr) {
16+
if(
17+
!formatStr ||
18+
/^\d[.]\df/.test(formatStr) ||
19+
/[.]\d%/.test(formatStr)
20+
) return formatStr;
21+
22+
if(formatStr === '0.f') return '~f';
23+
if(/^\d%/.test(formatStr)) return '~%';
24+
if(/^\ds/.test(formatStr)) return '~s';
25+
26+
// try adding tilde to the start of format in order to trim
27+
if(!(/^[~,.0$]/.test(formatStr)) && /[&fps]/.test(formatStr)) return '~' + formatStr;
28+
29+
return formatStr;
30+
};
31+
32+
var seenBadFormats = {};
33+
lib.warnBadFormat = function(f) {
34+
var key = String(f);
35+
if(!seenBadFormats[key]) {
36+
seenBadFormats[key] = 1;
37+
lib.warn('encountered bad format: "' + key + '"');
38+
}
39+
};
40+
41+
lib.noFormat = function(value) {
42+
return String(value);
43+
};
44+
45+
lib.numberFormat = function(formatStr) {
46+
var fn;
47+
try {
48+
fn = d3Format(lib.adjustFormat(formatStr));
49+
} catch(e) {
50+
lib.warnBadFormat(formatStr);
51+
return lib.noFormat;
52+
}
53+
54+
return fn;
1455
};
1556

1657
lib.nestedProperty = require('./nested_property');
@@ -1122,7 +1163,7 @@ function templateFormatString(string, labels, d3locale) {
11221163
if(format) {
11231164
var fmt;
11241165
if(format[0] === ':') {
1125-
fmt = d3locale ? d3locale.numberFormat : d3.format;
1166+
fmt = d3locale ? d3locale.numberFormat : lib.numberFormat;
11261167
value = fmt(format.replace(TEMPLATE_STRING_FORMAT_SEPARATOR, ''))(value);
11271168
}
11281169

src/plots/cartesian/dragbox.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
'use strict';
22

33
var d3 = require('@plotly/d3');
4+
var Lib = require('../../lib');
5+
var numberFormat = Lib.numberFormat;
46
var tinycolor = require('tinycolor2');
57
var supportsPassive = require('has-passive-events');
68

79
var Registry = require('../../registry');
8-
var Lib = require('../../lib');
910
var strTranslate = Lib.strTranslate;
1011
var svgTextUtils = require('../../lib/svg_text_utils');
1112
var Color = require('../../components/color');
@@ -1029,11 +1030,11 @@ function getEndText(ax, end) {
10291030
return initialVal;
10301031
} else if(ax.type === 'log') {
10311032
dig = Math.ceil(Math.max(0, -Math.log(diff) / Math.LN10)) + 3;
1032-
return d3.format('.' + dig + 'g')(Math.pow(10, initialVal));
1033+
return numberFormat('.' + dig + 'g')(Math.pow(10, initialVal));
10331034
} else { // linear numeric (or category... but just show numbers here)
10341035
dig = Math.floor(Math.log(Math.abs(initialVal)) / Math.LN10) -
10351036
Math.floor(Math.log(diff) / Math.LN10) + 4;
1036-
return d3.format('.' + String(dig) + 'g')(initialVal);
1037+
return numberFormat('.' + String(dig) + 'g')(initialVal);
10371038
}
10381039
}
10391040

src/plots/cartesian/set_convert.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
var d3 = require('@plotly/d3');
44
var utcFormat = require('d3-time-format').utcFormat;
5+
var Lib = require('../../lib');
6+
var numberFormat = Lib.numberFormat;
57
var isNumeric = require('fast-isnumeric');
68

7-
var Lib = require('../../lib');
89
var cleanNumber = Lib.cleanNumber;
910
var ms2DateTime = Lib.ms2DateTime;
1011
var dateTime2ms = Lib.dateTime2ms;
@@ -953,7 +954,7 @@ module.exports = function setConvert(ax, fullLayout) {
953954
// occasionally we need _numFormat to pass through
954955
// even though it won't be needed by this axis
955956
ax._separators = fullLayout.separators;
956-
ax._numFormat = locale ? locale.numberFormat : d3.format;
957+
ax._numFormat = locale ? locale.numberFormat : numberFormat;
957958

958959
// and for bar charts and box plots: reset forced minimum tick spacing
959960
delete ax._minDtick;

src/plots/geo/geo.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ function getProjection(geoLayout) {
643643

644644
var projName = constants.projNames[projType];
645645
// uppercase the first letter and add geo to the start of method name
646-
projName = 'geo' + projName.charAt(0).toUpperCase() + projName.slice(1);
646+
projName = 'geo' + Lib.titleCase(projName);
647647
var projFn = geo[projName] || geoProjection[projName];
648648
var projection = projFn();
649649

src/plots/plots.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
var d3 = require('@plotly/d3');
44
var timeFormatLocale = require('d3-time-format').timeFormatLocale;
5+
var formatLocale = require('d3-format').formatLocale;
56
var isNumeric = require('fast-isnumeric');
67

78
var Registry = require('../registry');
@@ -702,7 +703,18 @@ function getFormatter(formatObj, separators) {
702703
formatObj.thousands = separators.charAt(1);
703704

704705
return {
705-
numberFormat: d3.locale(formatObj).numberFormat,
706+
numberFormat: function(formatStr) {
707+
try {
708+
formatStr = formatLocale(formatObj).format(
709+
Lib.adjustFormat(formatStr)
710+
);
711+
} catch(e) {
712+
Lib.warnBadFormat(formatStr);
713+
return Lib.noFormat;
714+
}
715+
716+
return formatStr;
717+
},
706718
timeFormat: timeFormatLocale(formatObj).utcFormat
707719
};
708720
}

src/traces/parcoords/parcoords.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
'use strict';
22

33
var d3 = require('@plotly/d3');
4+
var Lib = require('../../lib');
5+
var numberFormat = Lib.numberFormat;
46
var rgba = require('color-rgba');
57

68
var Axes = require('../../plots/cartesian/axes');
7-
var Lib = require('../../lib');
89
var strRotate = Lib.strRotate;
910
var strTranslate = Lib.strTranslate;
1011
var svgTextUtils = require('../../lib/svg_text_utils');
@@ -79,7 +80,7 @@ function domainScale(height, padding, dimension, tickvals, ticktext) {
7980
var extent = dimensionExtent(dimension);
8081
if(tickvals) {
8182
return d3.scale.ordinal()
82-
.domain(tickvals.map(toText(d3.format(dimension.tickformat), ticktext)))
83+
.domain(tickvals.map(toText(numberFormat(dimension.tickformat), ticktext)))
8384
.range(tickvals
8485
.map(function(d) {
8586
var unitVal = (d - extent[0]) / (extent[1] - extent[0]);
@@ -266,7 +267,7 @@ function viewModel(state, callbacks, model) {
266267

267268
// ensure ticktext and tickvals have same length
268269
if(!Array.isArray(ticktext) || !ticktext.length) {
269-
ticktext = tickvals.map(d3.format(dimension.tickformat));
270+
ticktext = tickvals.map(numberFormat(dimension.tickformat));
270271
} else if(ticktext.length > tickvals.length) {
271272
ticktext = ticktext.slice(0, tickvals.length);
272273
} else if(tickvals.length > ticktext.length) {

src/traces/sankey/plot.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
'use strict';
22

33
var d3 = require('@plotly/d3');
4+
var Lib = require('../../lib');
5+
var numberFormat = Lib.numberFormat;
46
var render = require('./render');
57
var Fx = require('../../components/fx');
68
var Color = require('../../components/color');
7-
var Lib = require('../../lib');
89
var cn = require('./constants').cn;
910

1011
var _ = Lib._;
@@ -192,7 +193,7 @@ module.exports = function plot(gd, calcData) {
192193
link.fullData = link.trace;
193194
obj = d.link.trace.link;
194195
var hoverCenter = hoverCenterPosition(link);
195-
var hovertemplateLabels = {valueLabel: d3.format(d.valueFormat)(link.value) + d.valueSuffix};
196+
var hovertemplateLabels = {valueLabel: numberFormat(d.valueFormat)(link.value) + d.valueSuffix};
196197

197198
hoverItems.push({
198199
x: hoverCenter[0],
@@ -202,7 +203,7 @@ module.exports = function plot(gd, calcData) {
202203
link.label || '',
203204
sourceLabel + link.source.label,
204205
targetLabel + link.target.label,
205-
link.concentrationscale ? concentrationLabel + d3.format('%0.2f')(link.flow.labelConcentration) : ''
206+
link.concentrationscale ? concentrationLabel + numberFormat('%0.2f')(link.flow.labelConcentration) : ''
206207
].filter(renderableValuePresent).join('<br>'),
207208
color: castHoverOption(obj, 'bgcolor') || Color.addOpacity(link.color, 1),
208209
borderColor: castHoverOption(obj, 'bordercolor'),
@@ -281,7 +282,7 @@ module.exports = function plot(gd, calcData) {
281282
var hoverCenterX1 = boundingBox.right + 2 - rootBBox.left;
282283
var hoverCenterY = boundingBox.top + boundingBox.height / 4 - rootBBox.top;
283284

284-
var hovertemplateLabels = {valueLabel: d3.format(d.valueFormat)(d.node.value) + d.valueSuffix};
285+
var hovertemplateLabels = {valueLabel: numberFormat(d.valueFormat)(d.node.value) + d.valueSuffix};
285286
d.node.fullData = d.node.trace;
286287

287288
gd._fullLayout._calcInverseTransform(gd);
@@ -292,7 +293,7 @@ module.exports = function plot(gd, calcData) {
292293
x0: scaleX * hoverCenterX0,
293294
x1: scaleX * hoverCenterX1,
294295
y: scaleY * hoverCenterY,
295-
name: d3.format(d.valueFormat)(d.node.value) + d.valueSuffix,
296+
name: numberFormat(d.valueFormat)(d.node.value) + d.valueSuffix,
296297
text: [
297298
d.node.label,
298299
incomingLabel + d.node.targetLinks.length,

src/traces/table/plot.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
var c = require('./constants');
44
var d3 = require('@plotly/d3');
5+
var Lib = require('../../lib');
6+
var numberFormat = Lib.numberFormat;
57
var gup = require('../../lib/gup');
68
var Drawing = require('../../components/drawing');
79
var svgUtil = require('../../lib/svg_text_utils');
@@ -528,7 +530,7 @@ function populateCellText(cellText, tableControlView, allColumnBlock, gd) {
528530
var suffix = latex ? '' : gridPick(d.calcdata.cells.suffix, col, row) || '';
529531
var format = latex ? null : gridPick(d.calcdata.cells.format, col, row) || null;
530532

531-
var prefixSuffixedText = prefix + (format ? d3.format(format)(d.value) : d.value) + suffix;
533+
var prefixSuffixedText = prefix + (format ? numberFormat(format)(d.value) : d.value) + suffix;
532534

533535
var hasWrapSplitCharacter;
534536
d.wrappingNeeded = !d.wrapped && !userBrokenText && !latex && (hasWrapSplitCharacter = hasWrapCharacter(prefixSuffixedText));
1.11 KB
Loading

test/image/baselines/tick-percent.png

-880 Bytes
Loading

0 commit comments

Comments
 (0)