Skip to content

Add hoverongaps to heatmap and contour for suppressing hovers on missing data #4291

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

Merged
merged 4 commits into from
Oct 23, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion src/traces/contour/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ module.exports = extendFlat({
ytype: heatmapAttrs.ytype,
zhoverformat: heatmapAttrs.zhoverformat,
hovertemplate: heatmapAttrs.hovertemplate,

hovergaps: heatmapAttrs.hovergaps,
connectgaps: extendFlat({}, heatmapAttrs.connectgaps, {
description: [
'Determines whether or not gaps',
Expand Down
1 change: 1 addition & 0 deletions src/traces/contour/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
coerce('hovergaps');

var isConstraint = (coerce('contours.type') === 'constraint');
coerce('connectgaps', Lib.isArray1D(traceOut.z));
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 @@ -79,6 +79,17 @@ module.exports = extendFlat({
'Picks a smoothing algorithm use to smooth `z` data.'
].join(' ')
},
hovergaps: {
valType: 'boolean',
dflt: true,
role: 'style',
editType: 'none',
description: [
'Determines whether or not gaps',
'(i.e. {nan} or missing values)',
'in the `z` data are hovered on.'
].join(' ')
},
connectgaps: {
valType: 'boolean',
role: 'info',
Expand Down
1 change: 1 addition & 0 deletions src/traces/heatmap/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout

handleStyleDefaults(traceIn, traceOut, coerce, layout);

coerce('hovergaps');
coerce('connectgaps', Lib.isArray1D(traceOut.z) && (traceOut.zsmooth !== false));

colorscaleDefaults(traceIn, traceOut, layout, coerce, {prefix: '', cLetter: 'z'});
Expand Down
40 changes: 22 additions & 18 deletions src/traces/heatmap/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,28 +88,14 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, hoverLay
}
}

var zVal = z[ny][nx];
if(zmask && !zmask[ny][nx]) zVal = undefined;

var text;
if(Array.isArray(cd0.hovertext) && Array.isArray(cd0.hovertext[ny])) {
text = cd0.hovertext[ny][nx];
} else if(Array.isArray(cd0.text) && Array.isArray(cd0.text[ny])) {
text = cd0.text[ny][nx];
}

// dummy axis for formatting the z value
var cOpts = extractOpts(trace);
var dummyAx = {
type: 'linear',
range: [cOpts.min, cOpts.max],
hoverformat: zhoverformat,
_separators: xa._separators,
_numFormat: xa._numFormat
};
var zLabel = Axes.tickText(dummyAx, zVal, 'hover').text;

return [Lib.extendFlat(pointData, {
var obj = {
index: [ny, nx],
// never let a 2D override 1D type as closest point
distance: pointData.maxHoverDistance,
Expand All @@ -120,8 +106,26 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, hoverLay
y1: y1,
xLabelVal: xl,
yLabelVal: yl,
zLabelVal: zVal,
zLabel: zLabel,
text: text
})];
};

var zVal = z[ny][nx];
if(zmask && !zmask[ny][nx]) zVal = undefined;

if(zVal !== undefined || trace.hovergaps) {
// dummy axis for formatting the z value
var cOpts = extractOpts(trace);
var dummyAx = {
type: 'linear',
range: [cOpts.min, cOpts.max],
hoverformat: zhoverformat,
_separators: xa._separators,
_numFormat: xa._numFormat
};

obj.zLabelVal = zVal;
obj.zLabel = Axes.tickText(dummyAx, zVal, 'hover').text;
}

return [Lib.extendFlat(pointData, obj)];
Copy link
Contributor

Choose a reason for hiding this comment

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

So this mean when hovergaps:false, zLabel and zLabelVal remain undefined, but we still pass pointData back to Fx.hover?

Does this mean that the hover label is suppressed, but the plotly_hover event is still getting triggered?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here is a codepen displaying the current behaviour with hoverongaps disabled.
Please let me know if you prefer not to have hover effects at all.
cc: @emmanuelle

Copy link
Contributor

@etpinard etpinard Oct 22, 2019

Choose a reason for hiding this comment

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

I think the behaviour in @archmoj above codepen is incorrect. Under hoverongaps: false, there should be no hover labels shown and no plotly_hover event triggered.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now fixed in 9269352.
new demo

Copy link
Contributor

Choose a reason for hiding this comment

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

Fantastic!!

};
64 changes: 62 additions & 2 deletions test/jasmine/tests/contour_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ describe('contour defaults', function() {

it('should default connectgaps to false if `z` is not a one dimensional array', function() {
traceIn = {
type: 'heatmap',
type: 'contour',
z: [[0, null], [1, 2]]
};

Expand All @@ -76,7 +76,7 @@ describe('contour defaults', function() {

it('should default connectgaps to true if `z` is a one dimensional array', function() {
traceIn = {
type: 'heatmap',
type: 'contour',
x: [0, 1, 0, 1],
y: [0, 0, 1, 1],
z: [0, null, 1, 2]
Expand Down Expand Up @@ -591,3 +591,63 @@ describe('contour plotting and editing', function() {
.then(done);
});
});

describe('contour hover', function() {
'use strict';

var gd;

function _hover(gd, xval, yval) {
var fullLayout = gd._fullLayout;
var calcData = gd.calcdata;
var hoverData = [];

for(var i = 0; i < calcData.length; i++) {
var pointData = {
index: false,
distance: 20,
cd: calcData[i],
trace: calcData[i][0].trace,
xa: fullLayout.xaxis,
ya: fullLayout.yaxis
};

var hoverPoint = Contour.hoverPoints(pointData, xval, yval);
if(hoverPoint) hoverData.push(hoverPoint[0]);
}

return hoverData;
}

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

describe('missing data', function() {
beforeAll(function(done) {
gd = createGraphDiv();

Plotly.plot(gd, {
data: [{
type: 'contour',
x: [10, 11, 10, 11],
y: [100, 100, 101, 101],
z: [null, 1, 2, 3],
connectgaps: false,
hovergaps: false
}]
}).then(done);
});
afterAll(destroyGraphDiv);

it('should not create zLabels when hovering on missing data and hovergaps is disabled', function() {
var pt = _hover(gd, 10, 100)[0];

expect(pt.index).toEqual([0, 0], 'have correct index');
assertLabels(pt, 10, 100, undefined);
});
});
});
25 changes: 25 additions & 0 deletions test/jasmine/tests/heatmap_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -976,4 +976,29 @@ describe('heatmap hover', function() {
.then(done);
});
});

describe('missing data', function() {
beforeAll(function(done) {
gd = createGraphDiv();

Plotly.plot(gd, {
data: [{
type: 'heatmap',
x: [10, 11, 10, 11],
y: [100, 100, 101, 101],
z: [null, 1, 2, 3],
connectgaps: false,
hovergaps: false
}]
}).then(done);
});
afterAll(destroyGraphDiv);

it('should not create zLabels when hovering on missing data and hovergaps is disabled', function() {
var pt = _hover(gd, 10, 100)[0];

expect(pt.index).toEqual([0, 0], 'have correct index');
assertLabels(pt, 10, 100, undefined);
});
});
});