Skip to content

Commit

Permalink
Merge pull request #5563 from plotly/xy-hoverformat
Browse files Browse the repository at this point in the history
Add (x|y|z)hoverformat to a number of cartesian and gl3d traces
  • Loading branch information
archmoj authored Apr 9, 2021
2 parents e3b8709 + aeba545 commit e446743
Show file tree
Hide file tree
Showing 58 changed files with 514 additions and 51 deletions.
4 changes: 2 additions & 2 deletions src/components/fx/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -1609,11 +1609,11 @@ function cleanPoint(d, hovermode) {

// and convert the x and y label values into formatted text
if(d.xLabelVal !== undefined) {
d.xLabel = ('xLabel' in d) ? d.xLabel : Axes.hoverLabelText(d.xa, d.xLabelVal);
d.xLabel = ('xLabel' in d) ? d.xLabel : Axes.hoverLabelText(d.xa, d.xLabelVal, trace.xhoverformat);
d.xVal = d.xa.c2d(d.xLabelVal);
}
if(d.yLabelVal !== undefined) {
d.yLabel = ('yLabel' in d) ? d.yLabel : Axes.hoverLabelText(d.ya, d.yLabelVal);
d.yLabel = ('yLabel' in d) ? d.yLabel : Axes.hoverLabelText(d.ya, d.yLabelVal, trace.yhoverformat);
d.yVal = d.ya.c2d(d.yLabelVal);
}

Expand Down
21 changes: 14 additions & 7 deletions src/plots/cartesian/axes.js
Original file line number Diff line number Diff line change
Expand Up @@ -1361,16 +1361,23 @@ axes.tickText = function(ax, x, hover, noSuffixPrefix) {
* log axes (where negative values can't be displayed but can appear in hover text)
*
* @param {object} ax: the axis to format text for
* @param {number} val: calcdata value to format
* @param {Optional(number)} val2: a second value to display
* @param {number or array of numbers} values: calcdata value(s) to format
* @param {Optional(string)} hoverformat: trace (x|y)hoverformat to override axis.hoverformat
*
* @returns {string} `val` formatted as a string appropriate to this axis, or
* `val` and `val2` as a range (ie '<val> - <val2>') if `val2` is provided and
* it's different from `val`.
* first value and second value as a range (ie '<val1> - <val2>') if the second value is provided and
* it's different from the first value.
*/
axes.hoverLabelText = function(ax, val, val2) {
if(val2 !== BADNUM && val2 !== val) {
return axes.hoverLabelText(ax, val) + ' - ' + axes.hoverLabelText(ax, val2);
axes.hoverLabelText = function(ax, values, hoverformat) {
if(hoverformat) ax = Lib.extendFlat({}, ax, {hoverformat: hoverformat});

var val = Array.isArray(values) ? values[0] : values;
var val2 = Array.isArray(values) ? values[1] : undefined;
if(val2 !== undefined && val2 !== val) {
return (
axes.hoverLabelText(ax, val, hoverformat) + ' - ' +
axes.hoverLabelText(ax, val2, hoverformat)
);
}

var logOffScale = (ax.type === 'log' && val <= 0);
Expand Down
6 changes: 4 additions & 2 deletions src/plots/cartesian/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ var dash = require('../../components/drawing/attributes').dash;
var extendFlat = require('../../lib/extend').extendFlat;
var templatedArray = require('../../plot_api/plot_template').templatedArray;

var FORMAT_LINK = require('../../constants/docs').FORMAT_LINK;
var DATE_FORMAT_LINK = require('../../constants/docs').DATE_FORMAT_LINK;
var docs = require('../../constants/docs');
var FORMAT_LINK = docs.FORMAT_LINK;
var DATE_FORMAT_LINK = docs.DATE_FORMAT_LINK;

var ONEDAY = require('../../constants/numerical').ONEDAY;
var constants = require('./constants');
var HOUR = constants.HOUR_PATTERN;
Expand Down
24 changes: 14 additions & 10 deletions src/plots/gl3d/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,14 @@ proto.render = function() {
if(trace.setContourLevels) trace.setContourLevels();
}

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

return Axes.tickText(axis, axis.d2l(val), 'hover').text;
if(ax.type !== 'log') {
val = ax.d2l(val);
}

return Axes.hoverLabelText(ax, val, hoverformat);
}

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

var labels = {
xLabel: formatter('xaxis', selection.traceCoordinate[0]),
yLabel: formatter('yaxis', selection.traceCoordinate[1]),
zLabel: formatter('zaxis', selection.traceCoordinate[2])
xLabel: formatter('x', selection.traceCoordinate[0], trace.xhoverformat),
yLabel: formatter('y', selection.traceCoordinate[1], trace.yhoverformat),
zLabel: formatter('z', selection.traceCoordinate[2], trace.zhoverformat)
};

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

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

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

labels.wLabel = formatter('zaxis', selection.traceCoordinate[5]);
labels.wLabel = formatter('z', selection.traceCoordinate[5], trace.whoverformat);
if(isHoverinfoAll || hoverinfoParts.indexOf('w') !== -1) {
vectorTx.push('w: ' + labels.wLabel);
}
Expand All @@ -388,7 +392,7 @@ proto.render = function() {
}
tx = vectorTx.join('<br>');
} else if(trace.type === 'isosurface' || trace.type === 'volume') {
labels.valueLabel = Axes.tickText(scene._mockAxis, scene._mockAxis.d2l(selection.traceCoordinate[3]), 'hover').text;
labels.valueLabel = Axes.hoverLabelText(scene._mockAxis, scene._mockAxis.d2l(selection.traceCoordinate[3]), trace.valuehoverformat);
vectorTx.push('value: ' + labels.valueLabel);
if(selection.textLabel) {
vectorTx.push(selection.textLabel);
Expand Down
27 changes: 27 additions & 0 deletions src/plots/hoverformat_attributes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict';

var docs = require('../constants/docs');
var FORMAT_LINK = docs.FORMAT_LINK;
var DATE_FORMAT_LINK = docs.DATE_FORMAT_LINK;

module.exports = function axisHoverFormat(x, noDates) {
return {
valType: 'string',
dflt: '',
editType: 'none',
description: [
'Sets the hover text formatting rule for `' + x + '`',
' using d3 formatting mini-languages which are very similar to those in Python.',
'See: ' + FORMAT_LINK + (
noDates ?
'' :
' And for dates see: ' + DATE_FORMAT_LINK
),
'By default the values are formatted using ' + (
noDates ?
'generic number format' :
('`' + x + 'axis.hoverformat`')
) + '.',
].join(' ')
};
};
5 changes: 3 additions & 2 deletions src/plots/template_attributes.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
'use strict';

var FORMAT_LINK = require('../constants/docs').FORMAT_LINK;
var DATE_FORMAT_LINK = require('../constants/docs').DATE_FORMAT_LINK;
var docs = require('../constants/docs');
var FORMAT_LINK = docs.FORMAT_LINK;
var DATE_FORMAT_LINK = docs.DATE_FORMAT_LINK;

var templateFormatStringDescription = [
'Variables are inserted using %{variable}, for example "y: %{y}".',
Expand Down
3 changes: 3 additions & 0 deletions src/traces/bar/attributes.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

var scatterAttrs = require('../scatter/attributes');
var axisHoverFormat = require('../../plots/hoverformat_attributes');
var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs;
var colorScaleAttrs = require('../../components/colorscale/attributes');
Expand Down Expand Up @@ -104,6 +105,8 @@ module.exports = {
yperiod0: scatterAttrs.yperiod0,
xperiodalignment: scatterAttrs.xperiodalignment,
yperiodalignment: scatterAttrs.yperiodalignment,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),

text: scatterAttrs.text,
texttemplate: texttemplateAttrs({editType: 'plot'}, {
Expand Down
2 changes: 2 additions & 0 deletions src/traces/bar/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
}

handlePeriodDefaults(traceIn, traceOut, layout, coerce);
coerce('xhoverformat');
coerce('yhoverformat');

coerce('orientation', (traceOut.x && !traceOut.y) ? 'h' : 'v');
coerce('base');
Expand Down
6 changes: 3 additions & 3 deletions src/traces/bar/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,9 @@ function hoverOnBars(pointData, xval, yval, hovermode) {
var hasPeriod = di.orig_p !== undefined;
pointData[posLetter + 'LabelVal'] = hasPeriod ? di.orig_p : di.p;

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

// spikelines always want "closest" distance regardless of hovermode
pointData.spikeDistance = (thisBarSizeFn(di) + thisBarPositionFn(di)) / 2;
Expand Down
3 changes: 3 additions & 0 deletions src/traces/box/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
var scatterAttrs = require('../scatter/attributes');
var barAttrs = require('../bar/attributes');
var colorAttrs = require('../../components/color/attributes');
var axisHoverFormat = require('../../plots/hoverformat_attributes');
var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
var extendFlat = require('../../lib/extend').extendFlat;

Expand Down Expand Up @@ -70,6 +71,8 @@ module.exports = {
yperiod0: scatterAttrs.yperiod0,
xperiodalignment: scatterAttrs.xperiodalignment,
yperiodalignment: scatterAttrs.yperiodalignment,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),

name: {
valType: 'string',
Expand Down
2 changes: 2 additions & 0 deletions src/traces/box/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
if(traceOut.visible === false) return;

handlePeriodDefaults(traceIn, traceOut, layout, coerce);
coerce('xhoverformat');
coerce('yhoverformat');

var hasPreCompStats = traceOut._hasPreCompStats;

Expand Down
2 changes: 1 addition & 1 deletion src/traces/box/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) {
pointData2.attr = attr;
pointData2[vLetter + '0'] = pointData2[vLetter + '1'] = valPx;
pointData2[vLetter + 'LabelVal'] = val;
pointData2[vLetter + 'Label'] = (t.labels ? t.labels[attr] + ' ' : '') + Axes.hoverLabelText(vAxis, val);
pointData2[vLetter + 'Label'] = (t.labels ? t.labels[attr] + ' ' : '') + Axes.hoverLabelText(vAxis, val, trace[vLetter + 'hoverformat']);

// Note: introduced to be able to distinguish a
// clicked point from a box during click-to-select
Expand Down
4 changes: 4 additions & 0 deletions src/traces/candlestick/attributes.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

var extendFlat = require('../../lib').extendFlat;
var axisHoverFormat = require('../../plots/hoverformat_attributes');
var OHLCattrs = require('../ohlc/attributes');
var boxAttrs = require('../box/attributes');

Expand All @@ -21,6 +22,8 @@ module.exports = {
xperiod: OHLCattrs.xperiod,
xperiod0: OHLCattrs.xperiod0,
xperiodalignment: OHLCattrs.xperiodalignment,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),

x: OHLCattrs.x,
open: OHLCattrs.open,
Expand All @@ -46,6 +49,7 @@ module.exports = {

text: OHLCattrs.text,
hovertext: OHLCattrs.hovertext,

whiskerwidth: extendFlat({}, boxAttrs.whiskerwidth, { dflt: 0 }),

hoverlabel: OHLCattrs.hoverlabel,
Expand Down
2 changes: 2 additions & 0 deletions src/traces/candlestick/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
}

handlePeriodDefaults(traceIn, traceOut, layout, coerce, {x: true});
coerce('xhoverformat');
coerce('yhoverformat');

coerce('line.width');

Expand Down
5 changes: 3 additions & 2 deletions src/traces/carpet/axis_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ var colorAttrs = require('../../components/color/attributes');
var axesAttrs = require('../../plots/cartesian/layout_attributes');
var overrideAll = require('../../plot_api/edit_types').overrideAll;

var FORMAT_LINK = require('../../constants/docs').FORMAT_LINK;
var DATE_FORMAT_LINK = require('../../constants/docs').TIME_FORMAT_LINK;
var docs = require('../../constants/docs');
var FORMAT_LINK = docs.FORMAT_LINK;
var DATE_FORMAT_LINK = docs.DATE_FORMAT_LINK;

module.exports = {
color: {
Expand Down
8 changes: 8 additions & 0 deletions src/traces/cone/attributes.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

var colorScaleAttrs = require('../../components/colorscale/attributes');
var axisHoverFormat = require('../../plots/hoverformat_attributes');
var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
var mesh3dAttrs = require('../mesh3d/attributes');
var baseAttrs = require('../../plots/attributes');
Expand Down Expand Up @@ -152,6 +153,13 @@ var attrs = {
},

hovertemplate: hovertemplateAttrs({editType: 'calc'}, {keys: ['norm']}),
uhoverformat: axisHoverFormat('u', 1),
vhoverformat: axisHoverFormat('v', 1),
whoverformat: axisHoverFormat('w', 1),
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
zhoverformat: axisHoverFormat('z'),

showlegend: extendFlat({}, baseAttrs.showlegend, {dflt: false})
};

Expand Down
6 changes: 6 additions & 0 deletions src/traces/cone/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
coerce('uhoverformat');
coerce('vhoverformat');
coerce('whoverformat');
coerce('xhoverformat');
coerce('yhoverformat');
coerce('zhoverformat');

// disable 1D transforms (for now)
traceOut._length = null;
Expand Down
5 changes: 4 additions & 1 deletion src/traces/contour/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

var heatmapAttrs = require('../heatmap/attributes');
var scatterAttrs = require('../scatter/attributes');
var axisHoverFormat = require('../../plots/hoverformat_attributes');
var colorScaleAttrs = require('../../components/colorscale/attributes');
var dash = require('../../components/drawing/attributes').dash;
var fontAttrs = require('../../plots/font_attributes');
Expand Down Expand Up @@ -36,7 +37,9 @@ module.exports = extendFlat({
transpose: heatmapAttrs.transpose,
xtype: heatmapAttrs.xtype,
ytype: heatmapAttrs.ytype,
zhoverformat: heatmapAttrs.zhoverformat,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
zhoverformat: axisHoverFormat('z', 1),
hovertemplate: heatmapAttrs.hovertemplate,
hoverongaps: heatmapAttrs.hoverongaps,
connectgaps: extendFlat({}, heatmapAttrs.connectgaps, {
Expand Down
2 changes: 2 additions & 0 deletions src/traces/contour/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
}

handlePeriodDefaults(traceIn, traceOut, layout, coerce);
coerce('xhoverformat');
coerce('yhoverformat');

coerce('text');
coerce('hovertext');
Expand Down
3 changes: 3 additions & 0 deletions src/traces/funnel/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
var barAttrs = require('../bar/attributes');
var lineAttrs = require('../scatter/attributes').line;
var baseAttrs = require('../../plots/attributes');
var axisHoverFormat = require('../../plots/hoverformat_attributes');
var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs;
var constants = require('./constants');
Expand All @@ -23,6 +24,8 @@ module.exports = {
yperiod0: barAttrs.yperiod0,
xperiodalignment: barAttrs.xperiodalignment,
yperiodalignment: barAttrs.yperiodalignment,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),

hovertext: barAttrs.hovertext,
hovertemplate: hovertemplateAttrs({}, {
Expand Down
2 changes: 2 additions & 0 deletions src/traces/funnel/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
}

handlePeriodDefaults(traceIn, traceOut, layout, coerce);
coerce('xhoverformat');
coerce('yhoverformat');

coerce('orientation', (traceOut.y && !traceOut.x) ? 'v' : 'h');
coerce('offset');
Expand Down
16 changes: 5 additions & 11 deletions src/traces/heatmap/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

var scatterAttrs = require('../scatter/attributes');
var baseAttrs = require('../../plots/attributes');
var axisHoverFormat = require('../../plots/hoverformat_attributes');
var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
var colorScaleAttrs = require('../../components/colorscale/attributes');
var FORMAT_LINK = require('../../constants/docs').FORMAT_LINK;

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

Expand Down Expand Up @@ -111,16 +111,10 @@ module.exports = extendFlat({
editType: 'plot',
description: 'Sets the vertical gap (in pixels) between bricks.'
},
zhoverformat: {
valType: 'string',
dflt: '',
editType: 'none',
description: [
'Sets the hover text formatting rule using d3 formatting mini-languages',
'which are very similar to those in Python. See:',
FORMAT_LINK
].join(' ')
},
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
zhoverformat: axisHoverFormat('z', 1),

hovertemplate: hovertemplateAttrs(),
showlegend: extendFlat({}, baseAttrs.showlegend, {dflt: false})
}, {
Expand Down
Loading

0 comments on commit e446743

Please sign in to comment.