Skip to content

Commit e446743

Browse files
authored
Merge pull request #5563 from plotly/xy-hoverformat
Add (x|y|z)hoverformat to a number of cartesian and gl3d traces
2 parents e3b8709 + aeba545 commit e446743

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+514
-51
lines changed

src/components/fx/hover.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1609,11 +1609,11 @@ function cleanPoint(d, hovermode) {
16091609

16101610
// and convert the x and y label values into formatted text
16111611
if(d.xLabelVal !== undefined) {
1612-
d.xLabel = ('xLabel' in d) ? d.xLabel : Axes.hoverLabelText(d.xa, d.xLabelVal);
1612+
d.xLabel = ('xLabel' in d) ? d.xLabel : Axes.hoverLabelText(d.xa, d.xLabelVal, trace.xhoverformat);
16131613
d.xVal = d.xa.c2d(d.xLabelVal);
16141614
}
16151615
if(d.yLabelVal !== undefined) {
1616-
d.yLabel = ('yLabel' in d) ? d.yLabel : Axes.hoverLabelText(d.ya, d.yLabelVal);
1616+
d.yLabel = ('yLabel' in d) ? d.yLabel : Axes.hoverLabelText(d.ya, d.yLabelVal, trace.yhoverformat);
16171617
d.yVal = d.ya.c2d(d.yLabelVal);
16181618
}
16191619

src/plots/cartesian/axes.js

+14-7
Original file line numberDiff line numberDiff line change
@@ -1361,16 +1361,23 @@ axes.tickText = function(ax, x, hover, noSuffixPrefix) {
13611361
* log axes (where negative values can't be displayed but can appear in hover text)
13621362
*
13631363
* @param {object} ax: the axis to format text for
1364-
* @param {number} val: calcdata value to format
1365-
* @param {Optional(number)} val2: a second value to display
1364+
* @param {number or array of numbers} values: calcdata value(s) to format
1365+
* @param {Optional(string)} hoverformat: trace (x|y)hoverformat to override axis.hoverformat
13661366
*
13671367
* @returns {string} `val` formatted as a string appropriate to this axis, or
1368-
* `val` and `val2` as a range (ie '<val> - <val2>') if `val2` is provided and
1369-
* it's different from `val`.
1368+
* first value and second value as a range (ie '<val1> - <val2>') if the second value is provided and
1369+
* it's different from the first value.
13701370
*/
1371-
axes.hoverLabelText = function(ax, val, val2) {
1372-
if(val2 !== BADNUM && val2 !== val) {
1373-
return axes.hoverLabelText(ax, val) + ' - ' + axes.hoverLabelText(ax, val2);
1371+
axes.hoverLabelText = function(ax, values, hoverformat) {
1372+
if(hoverformat) ax = Lib.extendFlat({}, ax, {hoverformat: hoverformat});
1373+
1374+
var val = Array.isArray(values) ? values[0] : values;
1375+
var val2 = Array.isArray(values) ? values[1] : undefined;
1376+
if(val2 !== undefined && val2 !== val) {
1377+
return (
1378+
axes.hoverLabelText(ax, val, hoverformat) + ' - ' +
1379+
axes.hoverLabelText(ax, val2, hoverformat)
1380+
);
13741381
}
13751382

13761383
var logOffScale = (ax.type === 'log' && val <= 0);

src/plots/cartesian/layout_attributes.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ var dash = require('../../components/drawing/attributes').dash;
66
var extendFlat = require('../../lib/extend').extendFlat;
77
var templatedArray = require('../../plot_api/plot_template').templatedArray;
88

9-
var FORMAT_LINK = require('../../constants/docs').FORMAT_LINK;
10-
var DATE_FORMAT_LINK = require('../../constants/docs').DATE_FORMAT_LINK;
9+
var docs = require('../../constants/docs');
10+
var FORMAT_LINK = docs.FORMAT_LINK;
11+
var DATE_FORMAT_LINK = docs.DATE_FORMAT_LINK;
12+
1113
var ONEDAY = require('../../constants/numerical').ONEDAY;
1214
var constants = require('./constants');
1315
var HOUR = constants.HOUR_PATTERN;

src/plots/gl3d/scene.js

+14-10
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,14 @@ proto.render = function() {
322322
if(trace.setContourLevels) trace.setContourLevels();
323323
}
324324

325-
function formatter(axisName, val) {
326-
var axis = scene.fullSceneLayout[axisName];
325+
function formatter(axLetter, val, hoverformat) {
326+
var ax = scene.fullSceneLayout[axLetter + 'axis'];
327327

328-
return Axes.tickText(axis, axis.d2l(val), 'hover').text;
328+
if(ax.type !== 'log') {
329+
val = ax.d2l(val);
330+
}
331+
332+
return Axes.hoverLabelText(ax, val, hoverformat);
329333
}
330334

331335
var oldEventData;
@@ -337,9 +341,9 @@ proto.render = function() {
337341
var ptNumber = selection.index;
338342

339343
var labels = {
340-
xLabel: formatter('xaxis', selection.traceCoordinate[0]),
341-
yLabel: formatter('yaxis', selection.traceCoordinate[1]),
342-
zLabel: formatter('zaxis', selection.traceCoordinate[2])
344+
xLabel: formatter('x', selection.traceCoordinate[0], trace.xhoverformat),
345+
yLabel: formatter('y', selection.traceCoordinate[1], trace.yhoverformat),
346+
zLabel: formatter('z', selection.traceCoordinate[2], trace.zhoverformat)
343347
};
344348

345349
var hoverinfo = Fx.castHoverinfo(traceNow, scene.fullLayout, ptNumber);
@@ -358,17 +362,17 @@ proto.render = function() {
358362
var vectorTx = [];
359363

360364
if(trace.type === 'cone' || trace.type === 'streamtube') {
361-
labels.uLabel = formatter('xaxis', selection.traceCoordinate[3]);
365+
labels.uLabel = formatter('x', selection.traceCoordinate[3], trace.uhoverformat);
362366
if(isHoverinfoAll || hoverinfoParts.indexOf('u') !== -1) {
363367
vectorTx.push('u: ' + labels.uLabel);
364368
}
365369

366-
labels.vLabel = formatter('yaxis', selection.traceCoordinate[4]);
370+
labels.vLabel = formatter('y', selection.traceCoordinate[4], trace.vhoverformat);
367371
if(isHoverinfoAll || hoverinfoParts.indexOf('v') !== -1) {
368372
vectorTx.push('v: ' + labels.vLabel);
369373
}
370374

371-
labels.wLabel = formatter('zaxis', selection.traceCoordinate[5]);
375+
labels.wLabel = formatter('z', selection.traceCoordinate[5], trace.whoverformat);
372376
if(isHoverinfoAll || hoverinfoParts.indexOf('w') !== -1) {
373377
vectorTx.push('w: ' + labels.wLabel);
374378
}
@@ -388,7 +392,7 @@ proto.render = function() {
388392
}
389393
tx = vectorTx.join('<br>');
390394
} else if(trace.type === 'isosurface' || trace.type === 'volume') {
391-
labels.valueLabel = Axes.tickText(scene._mockAxis, scene._mockAxis.d2l(selection.traceCoordinate[3]), 'hover').text;
395+
labels.valueLabel = Axes.hoverLabelText(scene._mockAxis, scene._mockAxis.d2l(selection.traceCoordinate[3]), trace.valuehoverformat);
392396
vectorTx.push('value: ' + labels.valueLabel);
393397
if(selection.textLabel) {
394398
vectorTx.push(selection.textLabel);

src/plots/hoverformat_attributes.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
var docs = require('../constants/docs');
4+
var FORMAT_LINK = docs.FORMAT_LINK;
5+
var DATE_FORMAT_LINK = docs.DATE_FORMAT_LINK;
6+
7+
module.exports = function axisHoverFormat(x, noDates) {
8+
return {
9+
valType: 'string',
10+
dflt: '',
11+
editType: 'none',
12+
description: [
13+
'Sets the hover text formatting rule for `' + x + '`',
14+
' using d3 formatting mini-languages which are very similar to those in Python.',
15+
'See: ' + FORMAT_LINK + (
16+
noDates ?
17+
'' :
18+
' And for dates see: ' + DATE_FORMAT_LINK
19+
),
20+
'By default the values are formatted using ' + (
21+
noDates ?
22+
'generic number format' :
23+
('`' + x + 'axis.hoverformat`')
24+
) + '.',
25+
].join(' ')
26+
};
27+
};

src/plots/template_attributes.js

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

3-
var FORMAT_LINK = require('../constants/docs').FORMAT_LINK;
4-
var DATE_FORMAT_LINK = require('../constants/docs').DATE_FORMAT_LINK;
3+
var docs = require('../constants/docs');
4+
var FORMAT_LINK = docs.FORMAT_LINK;
5+
var DATE_FORMAT_LINK = docs.DATE_FORMAT_LINK;
56

67
var templateFormatStringDescription = [
78
'Variables are inserted using %{variable}, for example "y: %{y}".',

src/traces/bar/attributes.js

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

33
var scatterAttrs = require('../scatter/attributes');
4+
var axisHoverFormat = require('../../plots/hoverformat_attributes');
45
var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
56
var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs;
67
var colorScaleAttrs = require('../../components/colorscale/attributes');
@@ -104,6 +105,8 @@ module.exports = {
104105
yperiod0: scatterAttrs.yperiod0,
105106
xperiodalignment: scatterAttrs.xperiodalignment,
106107
yperiodalignment: scatterAttrs.yperiodalignment,
108+
xhoverformat: axisHoverFormat('x'),
109+
yhoverformat: axisHoverFormat('y'),
107110

108111
text: scatterAttrs.text,
109112
texttemplate: texttemplateAttrs({editType: 'plot'}, {

src/traces/bar/defaults.js

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
2424
}
2525

2626
handlePeriodDefaults(traceIn, traceOut, layout, coerce);
27+
coerce('xhoverformat');
28+
coerce('yhoverformat');
2729

2830
coerce('orientation', (traceOut.x && !traceOut.y) ? 'h' : 'v');
2931
coerce('base');

src/traces/bar/hover.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,9 @@ function hoverOnBars(pointData, xval, yval, hovermode) {
170170
var hasPeriod = di.orig_p !== undefined;
171171
pointData[posLetter + 'LabelVal'] = hasPeriod ? di.orig_p : di.p;
172172

173-
pointData.labelLabel = hoverLabelText(pa, pointData[posLetter + 'LabelVal']);
174-
pointData.valueLabel = hoverLabelText(sa, pointData[sizeLetter + 'LabelVal']);
175-
pointData.baseLabel = hoverLabelText(sa, di.b);
173+
pointData.labelLabel = hoverLabelText(pa, pointData[posLetter + 'LabelVal'], trace[posLetter + 'hoverformat']);
174+
pointData.valueLabel = hoverLabelText(sa, pointData[sizeLetter + 'LabelVal'], trace[sizeLetter + 'hoverformat']);
175+
pointData.baseLabel = hoverLabelText(sa, di.b, trace[sizeLetter + 'hoverformat']);
176176

177177
// spikelines always want "closest" distance regardless of hovermode
178178
pointData.spikeDistance = (thisBarSizeFn(di) + thisBarPositionFn(di)) / 2;

src/traces/box/attributes.js

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var scatterAttrs = require('../scatter/attributes');
44
var barAttrs = require('../bar/attributes');
55
var colorAttrs = require('../../components/color/attributes');
6+
var axisHoverFormat = require('../../plots/hoverformat_attributes');
67
var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
78
var extendFlat = require('../../lib/extend').extendFlat;
89

@@ -70,6 +71,8 @@ module.exports = {
7071
yperiod0: scatterAttrs.yperiod0,
7172
xperiodalignment: scatterAttrs.xperiodalignment,
7273
yperiodalignment: scatterAttrs.yperiodalignment,
74+
xhoverformat: axisHoverFormat('x'),
75+
yhoverformat: axisHoverFormat('y'),
7376

7477
name: {
7578
valType: 'string',

src/traces/box/defaults.js

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
1717
if(traceOut.visible === false) return;
1818

1919
handlePeriodDefaults(traceIn, traceOut, layout, coerce);
20+
coerce('xhoverformat');
21+
coerce('yhoverformat');
2022

2123
var hasPreCompStats = traceOut._hasPreCompStats;
2224

src/traces/box/hover.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) {
166166
pointData2.attr = attr;
167167
pointData2[vLetter + '0'] = pointData2[vLetter + '1'] = valPx;
168168
pointData2[vLetter + 'LabelVal'] = val;
169-
pointData2[vLetter + 'Label'] = (t.labels ? t.labels[attr] + ' ' : '') + Axes.hoverLabelText(vAxis, val);
169+
pointData2[vLetter + 'Label'] = (t.labels ? t.labels[attr] + ' ' : '') + Axes.hoverLabelText(vAxis, val, trace[vLetter + 'hoverformat']);
170170

171171
// Note: introduced to be able to distinguish a
172172
// clicked point from a box during click-to-select

src/traces/candlestick/attributes.js

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

33
var extendFlat = require('../../lib').extendFlat;
4+
var axisHoverFormat = require('../../plots/hoverformat_attributes');
45
var OHLCattrs = require('../ohlc/attributes');
56
var boxAttrs = require('../box/attributes');
67

@@ -21,6 +22,8 @@ module.exports = {
2122
xperiod: OHLCattrs.xperiod,
2223
xperiod0: OHLCattrs.xperiod0,
2324
xperiodalignment: OHLCattrs.xperiodalignment,
25+
xhoverformat: axisHoverFormat('x'),
26+
yhoverformat: axisHoverFormat('y'),
2427

2528
x: OHLCattrs.x,
2629
open: OHLCattrs.open,
@@ -46,6 +49,7 @@ module.exports = {
4649

4750
text: OHLCattrs.text,
4851
hovertext: OHLCattrs.hovertext,
52+
4953
whiskerwidth: extendFlat({}, boxAttrs.whiskerwidth, { dflt: 0 }),
5054

5155
hoverlabel: OHLCattrs.hoverlabel,

src/traces/candlestick/defaults.js

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
1818
}
1919

2020
handlePeriodDefaults(traceIn, traceOut, layout, coerce, {x: true});
21+
coerce('xhoverformat');
22+
coerce('yhoverformat');
2123

2224
coerce('line.width');
2325

src/traces/carpet/axis_attributes.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ var colorAttrs = require('../../components/color/attributes');
55
var axesAttrs = require('../../plots/cartesian/layout_attributes');
66
var overrideAll = require('../../plot_api/edit_types').overrideAll;
77

8-
var FORMAT_LINK = require('../../constants/docs').FORMAT_LINK;
9-
var DATE_FORMAT_LINK = require('../../constants/docs').TIME_FORMAT_LINK;
8+
var docs = require('../../constants/docs');
9+
var FORMAT_LINK = docs.FORMAT_LINK;
10+
var DATE_FORMAT_LINK = docs.DATE_FORMAT_LINK;
1011

1112
module.exports = {
1213
color: {

src/traces/cone/attributes.js

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

33
var colorScaleAttrs = require('../../components/colorscale/attributes');
4+
var axisHoverFormat = require('../../plots/hoverformat_attributes');
45
var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
56
var mesh3dAttrs = require('../mesh3d/attributes');
67
var baseAttrs = require('../../plots/attributes');
@@ -152,6 +153,13 @@ var attrs = {
152153
},
153154

154155
hovertemplate: hovertemplateAttrs({editType: 'calc'}, {keys: ['norm']}),
156+
uhoverformat: axisHoverFormat('u', 1),
157+
vhoverformat: axisHoverFormat('v', 1),
158+
whoverformat: axisHoverFormat('w', 1),
159+
xhoverformat: axisHoverFormat('x'),
160+
yhoverformat: axisHoverFormat('y'),
161+
zhoverformat: axisHoverFormat('z'),
162+
155163
showlegend: extendFlat({}, baseAttrs.showlegend, {dflt: false})
156164
};
157165

src/traces/cone/defaults.js

+6
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
4545
coerce('text');
4646
coerce('hovertext');
4747
coerce('hovertemplate');
48+
coerce('uhoverformat');
49+
coerce('vhoverformat');
50+
coerce('whoverformat');
51+
coerce('xhoverformat');
52+
coerce('yhoverformat');
53+
coerce('zhoverformat');
4854

4955
// disable 1D transforms (for now)
5056
traceOut._length = null;

src/traces/contour/attributes.js

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

33
var heatmapAttrs = require('../heatmap/attributes');
44
var scatterAttrs = require('../scatter/attributes');
5+
var axisHoverFormat = require('../../plots/hoverformat_attributes');
56
var colorScaleAttrs = require('../../components/colorscale/attributes');
67
var dash = require('../../components/drawing/attributes').dash;
78
var fontAttrs = require('../../plots/font_attributes');
@@ -36,7 +37,9 @@ module.exports = extendFlat({
3637
transpose: heatmapAttrs.transpose,
3738
xtype: heatmapAttrs.xtype,
3839
ytype: heatmapAttrs.ytype,
39-
zhoverformat: heatmapAttrs.zhoverformat,
40+
xhoverformat: axisHoverFormat('x'),
41+
yhoverformat: axisHoverFormat('y'),
42+
zhoverformat: axisHoverFormat('z', 1),
4043
hovertemplate: heatmapAttrs.hovertemplate,
4144
hoverongaps: heatmapAttrs.hoverongaps,
4245
connectgaps: extendFlat({}, heatmapAttrs.connectgaps, {

src/traces/contour/defaults.js

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
2626
}
2727

2828
handlePeriodDefaults(traceIn, traceOut, layout, coerce);
29+
coerce('xhoverformat');
30+
coerce('yhoverformat');
2931

3032
coerce('text');
3133
coerce('hovertext');

src/traces/funnel/attributes.js

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var barAttrs = require('../bar/attributes');
44
var lineAttrs = require('../scatter/attributes').line;
55
var baseAttrs = require('../../plots/attributes');
6+
var axisHoverFormat = require('../../plots/hoverformat_attributes');
67
var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
78
var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs;
89
var constants = require('./constants');
@@ -23,6 +24,8 @@ module.exports = {
2324
yperiod0: barAttrs.yperiod0,
2425
xperiodalignment: barAttrs.xperiodalignment,
2526
yperiodalignment: barAttrs.yperiodalignment,
27+
xhoverformat: axisHoverFormat('x'),
28+
yhoverformat: axisHoverFormat('y'),
2629

2730
hovertext: barAttrs.hovertext,
2831
hovertemplate: hovertemplateAttrs({}, {

src/traces/funnel/defaults.js

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
2121
}
2222

2323
handlePeriodDefaults(traceIn, traceOut, layout, coerce);
24+
coerce('xhoverformat');
25+
coerce('yhoverformat');
2426

2527
coerce('orientation', (traceOut.y && !traceOut.x) ? 'v' : 'h');
2628
coerce('offset');

src/traces/heatmap/attributes.js

+5-11
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
var scatterAttrs = require('../scatter/attributes');
44
var baseAttrs = require('../../plots/attributes');
5+
var axisHoverFormat = require('../../plots/hoverformat_attributes');
56
var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
67
var colorScaleAttrs = require('../../components/colorscale/attributes');
7-
var FORMAT_LINK = require('../../constants/docs').FORMAT_LINK;
88

99
var extendFlat = require('../../lib/extend').extendFlat;
1010

@@ -111,16 +111,10 @@ module.exports = extendFlat({
111111
editType: 'plot',
112112
description: 'Sets the vertical gap (in pixels) between bricks.'
113113
},
114-
zhoverformat: {
115-
valType: 'string',
116-
dflt: '',
117-
editType: 'none',
118-
description: [
119-
'Sets the hover text formatting rule using d3 formatting mini-languages',
120-
'which are very similar to those in Python. See:',
121-
FORMAT_LINK
122-
].join(' ')
123-
},
114+
xhoverformat: axisHoverFormat('x'),
115+
yhoverformat: axisHoverFormat('y'),
116+
zhoverformat: axisHoverFormat('z', 1),
117+
124118
hovertemplate: hovertemplateAttrs(),
125119
showlegend: extendFlat({}, baseAttrs.showlegend, {dflt: false})
126120
}, {

0 commit comments

Comments
 (0)