Skip to content

Add hoverlabel.zformat attribute #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/components/fx/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,9 @@ function cleanPoint(d, hovermode) {
d.yVal = d.ya.c2d(d.yLabelVal);
}

if(d.zLabelVal !== undefined) d.zLabel = String(d.zLabelVal);
if(d.zLabelVal !== undefined && d.zLabel === undefined) { // Traces like heatmaps generate the zLabel in their hoverPoints function

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. Too bad we need this. Good catch ⚾ cleanPoint could use a little bit of a refactor.

Would you mind putting that // comment about the if() statement?

d.zLabel = String(d.zLabelVal);
}

// for box means and error bars, add the range to the label
if(!isNaN(d.xerr) && !(d.xa.type === 'log' && d.xerr <= 0)) {
Expand Down
11 changes: 11 additions & 0 deletions src/traces/heatmap/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,17 @@ module.exports = extendFlat({}, {
editType: 'plot',
description: 'Sets the vertical gap (in pixels) between bricks.'
},
zhoverformat: {
valType: 'string',
dflt: '',
role: 'style',
editType: 'none',
description: [
'Sets the hover text formatting rule using d3 formatting mini-languages',
'which are very similar to those in Python. See:',
'https://github.com/d3/d3-format/blob/master/README.md#locale_format'
].join(' ')
},
},
colorscaleAttrs,
{ autocolorscale: extendFlat({}, colorscaleAttrs.autocolorscale, {dflt: false}) },
Expand Down
3 changes: 3 additions & 0 deletions src/traces/heatmap/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
coerce('connectgaps', hasColumns(traceOut) && (traceOut.zsmooth !== false));

colorscaleDefaults(traceIn, traceOut, layout, coerce, {prefix: '', cLetter: 'z'});

coerce('zhoverformat');
traceOut._separators = layout.separators; // Needed for formatting of hoverlabel if format is not explicitly specified
};
16 changes: 16 additions & 0 deletions src/traces/heatmap/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

var Fx = require('../../components/fx');
var Lib = require('../../lib');
var Axes = require('../../plots/cartesian/axes');

var MAXDIST = Fx.constants.MAXDIST;

Expand All @@ -26,6 +27,10 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, contour)
y = cd0.y,
z = cd0.z,
zmask = cd0.zmask,
zmin = trace.zmin,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't scope variables if you're only going to use them once. The block below could be rewritten as:

   var dummyAx = {
        type: 'linear',
        range: [trace.zmin, trace.zmax],
        hoverformat: trace.zhoverformat,
        _separators: trace._separators
   };
   var zLabel =  Axes.tickText(dummyAx, zVal, 'hover').text;

zmax = trace.zmax,
zhoverformat = trace.zhoverformat,
_separators = trace._separators,
x2 = x,
y2 = y,
xl,
Expand Down Expand Up @@ -99,6 +104,16 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, contour)
text = cd0.text[ny][nx];
}

var zLabel;
var dummyAx = { // dummy axis for formatting the z value

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nicely done.

Creating the dummy axis here isn't optimal, but shouldn't make much of a difference. 👍

type: 'linear',
range: [zmin, zmax],
hoverformat: zhoverformat,
_separators: _separators
};
var zLabelObj = Axes.tickText(dummyAx, zVal, 'hover');
zLabel = zLabelObj.text;

return [Lib.extendFlat(pointData, {
index: [ny, nx],
// never let a 2D override 1D type as closest point
Expand All @@ -110,6 +125,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, contour)
xLabelVal: xl,
yLabelVal: yl,
zLabelVal: zVal,
zLabel: zLabel,
text: text
})];
};
51 changes: 43 additions & 8 deletions test/jasmine/tests/heatmap_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -616,10 +616,11 @@ describe('heatmap hover', function() {
return hoverData;
}

function assertLabels(hoverPoint, xLabel, yLabel, zLabel, text) {
expect(hoverPoint.xLabelVal).toEqual(xLabel, 'have correct x label');
expect(hoverPoint.yLabelVal).toEqual(yLabel, 'have correct y label');
expect(hoverPoint.zLabelVal).toEqual(zLabel, 'have correct z label');
function assertLabels(hoverPoint, xLabelVal, yLabelVal, zLabelVal, zLabel, text) {
expect(hoverPoint.xLabelVal).toEqual(xLabelVal, 'have correct x label value');
expect(hoverPoint.yLabelVal).toEqual(yLabelVal, 'have correct y label value');
expect(hoverPoint.zLabelVal).toEqual(zLabelVal, 'have correct z label value');
expect(hoverPoint.zLabel).toEqual(zLabel, 'have correct z label');
expect(hoverPoint.text).toEqual(text, 'have correct text label');
}

Expand All @@ -640,14 +641,14 @@ describe('heatmap hover', function() {
var pt = _hover(gd, 0.5, 0.5)[0];

expect(pt.index).toEqual([1, 0], 'have correct index');
assertLabels(pt, 1, 1, 4);
assertLabels(pt, 1, 1, 4, '4');
});

it('should find closest point (case 2) and should', function() {
var pt = _hover(gd, 1.5, 0.5)[0];

expect(pt.index).toEqual([0, 0], 'have correct index');
assertLabels(pt, 2, 0.2, 6);
assertLabels(pt, 2, 0.2, 6, '6');
});
});

Expand All @@ -673,13 +674,47 @@ describe('heatmap hover', function() {
var pt = _hover(gd, 0.5, 0.5)[0];

expect(pt.index).toEqual([0, 0], 'have correct index');
assertLabels(pt, 1, 1, 10, 'a');
assertLabels(pt, 1, 1, 10, '10', 'a');

Plotly.relayout(gd, 'xaxis.range', [1, 2]).then(function() {
var pt2 = _hover(gd, 1.5, 0.5)[0];

expect(pt2.index).toEqual([0, 1], 'have correct index');
assertLabels(pt2, 2, 1, 4, 'b');
assertLabels(pt2, 2, 1, 4, '4', 'b');
})
.then(done);
});

});

describe('for hovering with specific number format', function() {

beforeAll(function(done) {
gd = createGraphDiv();

Plotly.plot(gd, [{
type: 'heatmap',
x: [1, 2, 3],
y: [1, 1, 1],
z: [0.123456789, 2.9999, 4],
zhoverformat: '.2f'
}])
.then(done);
});

afterAll(destroyGraphDiv);

it('should find closest point and should', function(done) {
var pt = _hover(gd, 0.5, 0.5)[0];

expect(pt.index).toEqual([0, 0], 'have correct index');
assertLabels(pt, 1, 1, 0.123456789, '0.12');

Plotly.relayout(gd, 'xaxis.range', [1, 2]).then(function() {
var pt2 = _hover(gd, 1.5, 0.5)[0];

expect(pt2.index).toEqual([0, 1], 'have correct index');
assertLabels(pt2, 2, 1, 2.9999, '3.00');
})
.then(done);
});
Expand Down
37 changes: 37 additions & 0 deletions test/jasmine/tests/hover_label_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,43 @@ describe('hover info', function() {
.catch(fail)
.then(done);
});

it('should display correct label content with specified format', function(done) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the two test cases you added are pretty much equivalent. Pick your favorite and 🔪 the other.

var gd = createGraphDiv();

Plotly.plot(gd, [{
type: 'heatmap',
y: [0, 1],
z: [[1.11111, 2.2222, 3.33333], [4.44444, 5.55555, 6.66666]],
name: 'one',
zhoverformat: '.2f'
}, {
type: 'heatmap',
y: [2, 3],
z: [[1, 2, 3], [2, 2, 1]],
name: 'two'
}], {
width: 500,
height: 400,
margin: {l: 0, t: 0, r: 0, b: 0}
})
.then(function() {
_hover(gd, 250, 100);
assertHoverLabelContent({
nums: 'x: 1\ny: 3\nz: 2',
name: 'two'
});
})
.then(function() {
_hover(gd, 250, 300);
assertHoverLabelContent({
nums: 'x: 1\ny: 1\nz: 5.56',
name: 'one'
});
})
.catch(fail)
.then(done);
});
});

describe('hoverformat', function() {
Expand Down