From acce9bf5515d6443085080bd224d32152094230a Mon Sep 17 00:00:00 2001 From: Juernjakob Dugge Date: Sun, 15 Oct 2017 21:13:11 +0200 Subject: [PATCH 1/8] Add hoverlabel.zformat attribute --- src/components/fx/attributes.js | 11 +++++++ src/components/fx/calc.js | 1 + src/components/fx/hover.js | 9 +++++- src/components/fx/hoverlabel_defaults.js | 1 + src/components/fx/layout_attributes.js | 11 +++++++ test/image/mocks/heatmap_hoverlabel.json | 39 ++++++++++++++++++++++++ 6 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 test/image/mocks/heatmap_hoverlabel.json diff --git a/src/components/fx/attributes.js b/src/components/fx/attributes.js index 1dd31102375..76b6491c66c 100644 --- a/src/components/fx/attributes.js +++ b/src/components/fx/attributes.js @@ -50,6 +50,17 @@ module.exports = { '`namelength - 3` characters and add an ellipsis.' ].join(' ') }, + zformat: { + 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(' ') + }, editType: 'calc' } }; diff --git a/src/components/fx/calc.js b/src/components/fx/calc.js index 677dc620778..1dd4c2b3d08 100644 --- a/src/components/fx/calc.js +++ b/src/components/fx/calc.js @@ -42,6 +42,7 @@ module.exports = function calc(gd) { fillFn(trace.hoverlabel.font.color, cd, 'htc'); fillFn(trace.hoverlabel.font.family, cd, 'htf'); fillFn(trace.hoverlabel.namelength, cd, 'hnl'); + fillFn(trace.hoverlabel.zformat, cd, 'hzf'); } }; diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index bc5866198bd..9eac7c8d00e 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -1054,6 +1054,7 @@ function cleanPoint(d, hovermode) { fill('fontSize', 'hts', 'hoverlabel.font.size'); fill('fontColor', 'htc', 'hoverlabel.font.color'); fill('nameLength', 'hnl', 'hoverlabel.namelength'); + fill('zformat', 'hzf', 'hoverlabel.zformat'); d.posref = hovermode === 'y' ? (d.x0 + d.x1) / 2 : (d.y0 + d.y1) / 2; @@ -1095,7 +1096,13 @@ function cleanPoint(d, hovermode) { d.yVal = d.ya.c2d(d.yLabelVal); } - if(d.zLabelVal !== undefined) d.zLabel = String(d.zLabelVal); + if(d.zLabelVal !== undefined) { + if(d.zformat !== undefined) { + d.zLabel = d3.format(d.zformat)(d.zLabelVal).replace(/-/g, constants.MINUS_SIGN); + } else { + 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)) { diff --git a/src/components/fx/hoverlabel_defaults.js b/src/components/fx/hoverlabel_defaults.js index 0b3573fe92d..205e97bb874 100644 --- a/src/components/fx/hoverlabel_defaults.js +++ b/src/components/fx/hoverlabel_defaults.js @@ -16,5 +16,6 @@ module.exports = function handleHoverLabelDefaults(contIn, contOut, coerce, opts coerce('hoverlabel.bgcolor', opts.bgcolor); coerce('hoverlabel.bordercolor', opts.bordercolor); coerce('hoverlabel.namelength', opts.namelength); + coerce('hoverlabel.zformat', opts.zformat); Lib.coerceFont(coerce, 'hoverlabel.font', opts.font); }; diff --git a/src/components/fx/layout_attributes.js b/src/components/fx/layout_attributes.js index 25c6503a0ce..c37957a9b24 100644 --- a/src/components/fx/layout_attributes.js +++ b/src/components/fx/layout_attributes.js @@ -72,6 +72,17 @@ module.exports = { '`namelength - 3` characters and add an ellipsis.' ].join(' ') }, + zformat: { + 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(' ') + }, editType: 'none' } }; diff --git a/test/image/mocks/heatmap_hoverlabel.json b/test/image/mocks/heatmap_hoverlabel.json new file mode 100644 index 00000000000..953f2a19be1 --- /dev/null +++ b/test/image/mocks/heatmap_hoverlabel.json @@ -0,0 +1,39 @@ +{ + "data": [ + { + "z": [ + [ + 0.123456789, + 10.123456789, + 20.123456789 + ] + ], + "type": "heatmap" + }, + { + "x": [0,1,2], + "y": [2, 2, 2], + "z": [ + 1.123456789, + 2.123456789, + 3.123456789 + ], + "type": "heatmap", + "hoverlabel": { + "zformat": "undefined" + }, + "zmin": 0, + "zmax": 20, + "showscale": false + } + ], + "layout": { + "title": "XXX", + "xaxis": { + "hoverformat": ".1f" + }, + "hoverlabel": { + "zformat": ".2f" + } + } +} From b918176fe8a83811269c28ffa343081656826adb Mon Sep 17 00:00:00 2001 From: Juernjakob Dugge Date: Wed, 18 Oct 2017 22:31:49 +0200 Subject: [PATCH 2/8] Move property out of hoverlabel, use Axis.tickText for formatting, write tests --- src/components/fx/attributes.js | 11 ----- src/components/fx/calc.js | 1 - src/components/fx/hover.js | 9 +---- src/components/fx/hoverlabel_defaults.js | 1 - src/traces/heatmap/attributes.js | 11 +++++ src/traces/heatmap/defaults.js | 3 ++ src/traces/heatmap/hover.js | 16 ++++++++ test/image/mocks/heatmap_hoverlabel.json | 39 ------------------ test/jasmine/tests/heatmap_test.js | 51 ++++++++++++++++++++---- test/jasmine/tests/hover_label_test.js | 37 +++++++++++++++++ 10 files changed, 112 insertions(+), 67 deletions(-) delete mode 100644 test/image/mocks/heatmap_hoverlabel.json diff --git a/src/components/fx/attributes.js b/src/components/fx/attributes.js index 76b6491c66c..1dd31102375 100644 --- a/src/components/fx/attributes.js +++ b/src/components/fx/attributes.js @@ -50,17 +50,6 @@ module.exports = { '`namelength - 3` characters and add an ellipsis.' ].join(' ') }, - zformat: { - 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(' ') - }, editType: 'calc' } }; diff --git a/src/components/fx/calc.js b/src/components/fx/calc.js index 1dd4c2b3d08..677dc620778 100644 --- a/src/components/fx/calc.js +++ b/src/components/fx/calc.js @@ -42,7 +42,6 @@ module.exports = function calc(gd) { fillFn(trace.hoverlabel.font.color, cd, 'htc'); fillFn(trace.hoverlabel.font.family, cd, 'htf'); fillFn(trace.hoverlabel.namelength, cd, 'hnl'); - fillFn(trace.hoverlabel.zformat, cd, 'hzf'); } }; diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index 9eac7c8d00e..8c25908e286 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -1054,7 +1054,6 @@ function cleanPoint(d, hovermode) { fill('fontSize', 'hts', 'hoverlabel.font.size'); fill('fontColor', 'htc', 'hoverlabel.font.color'); fill('nameLength', 'hnl', 'hoverlabel.namelength'); - fill('zformat', 'hzf', 'hoverlabel.zformat'); d.posref = hovermode === 'y' ? (d.x0 + d.x1) / 2 : (d.y0 + d.y1) / 2; @@ -1096,12 +1095,8 @@ function cleanPoint(d, hovermode) { d.yVal = d.ya.c2d(d.yLabelVal); } - if(d.zLabelVal !== undefined) { - if(d.zformat !== undefined) { - d.zLabel = d3.format(d.zformat)(d.zLabelVal).replace(/-/g, constants.MINUS_SIGN); - } else { - d.zLabel = String(d.zLabelVal); - } + if(d.zLabelVal !== undefined && d.zLabel === undefined) { // Traces like heatmaps generate the zLabel in their hoverPoints function + d.zLabel = String(d.zLabelVal); } // for box means and error bars, add the range to the label diff --git a/src/components/fx/hoverlabel_defaults.js b/src/components/fx/hoverlabel_defaults.js index 205e97bb874..0b3573fe92d 100644 --- a/src/components/fx/hoverlabel_defaults.js +++ b/src/components/fx/hoverlabel_defaults.js @@ -16,6 +16,5 @@ module.exports = function handleHoverLabelDefaults(contIn, contOut, coerce, opts coerce('hoverlabel.bgcolor', opts.bgcolor); coerce('hoverlabel.bordercolor', opts.bordercolor); coerce('hoverlabel.namelength', opts.namelength); - coerce('hoverlabel.zformat', opts.zformat); Lib.coerceFont(coerce, 'hoverlabel.font', opts.font); }; diff --git a/src/traces/heatmap/attributes.js b/src/traces/heatmap/attributes.js index 372197a5f7b..e967f17860a 100644 --- a/src/traces/heatmap/attributes.js +++ b/src/traces/heatmap/attributes.js @@ -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}) }, diff --git a/src/traces/heatmap/defaults.js b/src/traces/heatmap/defaults.js index 3dbbaa0f380..b80c76d6e2b 100644 --- a/src/traces/heatmap/defaults.js +++ b/src/traces/heatmap/defaults.js @@ -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 }; diff --git a/src/traces/heatmap/hover.js b/src/traces/heatmap/hover.js index e3a870f3cb7..2993f2262b1 100644 --- a/src/traces/heatmap/hover.js +++ b/src/traces/heatmap/hover.js @@ -11,6 +11,7 @@ var Fx = require('../../components/fx'); var Lib = require('../../lib'); +var Axes = require('../../plots/cartesian/axes'); var MAXDIST = Fx.constants.MAXDIST; @@ -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, + zmax = trace.zmax, + zhoverformat = trace.zhoverformat, + _separators = trace._separators, x2 = x, y2 = y, xl, @@ -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 + 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 @@ -110,6 +125,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, contour) xLabelVal: xl, yLabelVal: yl, zLabelVal: zVal, + zLabel: zLabel, text: text })]; }; diff --git a/test/image/mocks/heatmap_hoverlabel.json b/test/image/mocks/heatmap_hoverlabel.json deleted file mode 100644 index 953f2a19be1..00000000000 --- a/test/image/mocks/heatmap_hoverlabel.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "data": [ - { - "z": [ - [ - 0.123456789, - 10.123456789, - 20.123456789 - ] - ], - "type": "heatmap" - }, - { - "x": [0,1,2], - "y": [2, 2, 2], - "z": [ - 1.123456789, - 2.123456789, - 3.123456789 - ], - "type": "heatmap", - "hoverlabel": { - "zformat": "undefined" - }, - "zmin": 0, - "zmax": 20, - "showscale": false - } - ], - "layout": { - "title": "XXX", - "xaxis": { - "hoverformat": ".1f" - }, - "hoverlabel": { - "zformat": ".2f" - } - } -} diff --git a/test/jasmine/tests/heatmap_test.js b/test/jasmine/tests/heatmap_test.js index 81e7737c736..b22155665ba 100644 --- a/test/jasmine/tests/heatmap_test.js +++ b/test/jasmine/tests/heatmap_test.js @@ -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'); } @@ -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'); }); }); @@ -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); }); diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index b6be796bdbe..b8fa0ad2693 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -499,6 +499,43 @@ describe('hover info', function() { .catch(fail) .then(done); }); + + it('should display correct label content with specified format', function(done) { + 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() { From 7a27542d08bdb2f1cfb2a323cb3490ff3df7fc23 Mon Sep 17 00:00:00 2001 From: Juernjakob Dugge Date: Wed, 18 Oct 2017 22:34:04 +0200 Subject: [PATCH 3/8] Remove zformat from hoverlabels layout properties --- src/components/fx/layout_attributes.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/components/fx/layout_attributes.js b/src/components/fx/layout_attributes.js index c37957a9b24..25c6503a0ce 100644 --- a/src/components/fx/layout_attributes.js +++ b/src/components/fx/layout_attributes.js @@ -72,17 +72,6 @@ module.exports = { '`namelength - 3` characters and add an ellipsis.' ].join(' ') }, - zformat: { - 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(' ') - }, editType: 'none' } }; From 919feea33d7d3668df714511f1eabdeed638a423 Mon Sep 17 00:00:00 2001 From: Juernjakob Dugge Date: Thu, 19 Oct 2017 22:39:56 +0200 Subject: [PATCH 4/8] Add zhoverformat to contour plots --- src/components/fx/hover.js | 3 +- src/traces/contour/attributes.js | 1 + src/traces/contour/defaults.js | 4 +++ src/traces/heatmap/hover.js | 8 ++--- test/jasmine/tests/heatmap_test.js | 51 +++++------------------------- 5 files changed, 19 insertions(+), 48 deletions(-) diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index 8c25908e286..5b91220a73e 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -1095,7 +1095,8 @@ function cleanPoint(d, hovermode) { d.yVal = d.ya.c2d(d.yLabelVal); } - if(d.zLabelVal !== undefined && d.zLabel === undefined) { // Traces like heatmaps generate the zLabel in their hoverPoints function + // Traces like heatmaps generate the zLabel in their hoverPoints function + if(d.zLabelVal !== undefined && d.zLabel === undefined) { d.zLabel = String(d.zLabelVal); } diff --git a/src/traces/contour/attributes.js b/src/traces/contour/attributes.js index 5414afe9f48..8db880b2317 100644 --- a/src/traces/contour/attributes.js +++ b/src/traces/contour/attributes.js @@ -30,6 +30,7 @@ module.exports = extendFlat({ transpose: heatmapAttrs.transpose, xtype: heatmapAttrs.xtype, ytype: heatmapAttrs.ytype, + zhoverformat: heatmapAttrs.zhoverformat, connectgaps: heatmapAttrs.connectgaps, diff --git a/src/traces/contour/defaults.js b/src/traces/contour/defaults.js index a616f818045..1e30d6b17c5 100644 --- a/src/traces/contour/defaults.js +++ b/src/traces/contour/defaults.js @@ -34,4 +34,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout handleContoursDefaults(traceIn, traceOut, coerce); handleStyleDefaults(traceIn, traceOut, coerce, layout); + + coerce('zhoverformat'); + // Needed for formatting of hoverlabel if format is not explicitly specified + traceOut._separators = layout.separators; }; diff --git a/src/traces/heatmap/hover.js b/src/traces/heatmap/hover.js index 2993f2262b1..310f92c0b84 100644 --- a/src/traces/heatmap/hover.js +++ b/src/traces/heatmap/hover.js @@ -27,8 +27,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, contour) y = cd0.y, z = cd0.z, zmask = cd0.zmask, - zmin = trace.zmin, - zmax = trace.zmax, + range = [trace.zmin, trace.zmax], zhoverformat = trace.zhoverformat, _separators = trace._separators, x2 = x, @@ -105,9 +104,10 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, contour) } var zLabel; - var dummyAx = { // dummy axis for formatting the z value + // dummy axis for formatting the z value + var dummyAx = { type: 'linear', - range: [zmin, zmax], + range: range, hoverformat: zhoverformat, _separators: _separators }; diff --git a/test/jasmine/tests/heatmap_test.js b/test/jasmine/tests/heatmap_test.js index b22155665ba..81e7737c736 100644 --- a/test/jasmine/tests/heatmap_test.js +++ b/test/jasmine/tests/heatmap_test.js @@ -616,11 +616,10 @@ describe('heatmap hover', function() { return hoverData; } - 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'); + 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'); expect(hoverPoint.text).toEqual(text, 'have correct text label'); } @@ -641,14 +640,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, '4'); + assertLabels(pt, 1, 1, 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, '6'); + assertLabels(pt, 2, 0.2, 6); }); }); @@ -674,47 +673,13 @@ 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, '10', 'a'); + assertLabels(pt, 1, 1, 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, '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'); + assertLabels(pt2, 2, 1, 4, 'b'); }) .then(done); }); From 5e20a483e14ff6230cc53965242011e30827ea62 Mon Sep 17 00:00:00 2001 From: Juernjakob Dugge Date: Sun, 15 Oct 2017 21:13:11 +0200 Subject: [PATCH 5/8] Add zhoverformat to heatmap and contour traces --- src/components/fx/hover.js | 5 +++- src/traces/contour/attributes.js | 1 + src/traces/contour/defaults.js | 4 +++ src/traces/heatmap/attributes.js | 11 ++++++++ src/traces/heatmap/defaults.js | 3 +++ src/traces/heatmap/hover.js | 16 +++++++++++ test/jasmine/tests/hover_label_test.js | 37 ++++++++++++++++++++++++++ 7 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index bc5866198bd..5b91220a73e 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -1095,7 +1095,10 @@ function cleanPoint(d, hovermode) { d.yVal = d.ya.c2d(d.yLabelVal); } - if(d.zLabelVal !== undefined) d.zLabel = String(d.zLabelVal); + // Traces like heatmaps generate the zLabel in their hoverPoints function + if(d.zLabelVal !== undefined && d.zLabel === undefined) { + 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)) { diff --git a/src/traces/contour/attributes.js b/src/traces/contour/attributes.js index 5414afe9f48..8db880b2317 100644 --- a/src/traces/contour/attributes.js +++ b/src/traces/contour/attributes.js @@ -30,6 +30,7 @@ module.exports = extendFlat({ transpose: heatmapAttrs.transpose, xtype: heatmapAttrs.xtype, ytype: heatmapAttrs.ytype, + zhoverformat: heatmapAttrs.zhoverformat, connectgaps: heatmapAttrs.connectgaps, diff --git a/src/traces/contour/defaults.js b/src/traces/contour/defaults.js index a616f818045..1e30d6b17c5 100644 --- a/src/traces/contour/defaults.js +++ b/src/traces/contour/defaults.js @@ -34,4 +34,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout handleContoursDefaults(traceIn, traceOut, coerce); handleStyleDefaults(traceIn, traceOut, coerce, layout); + + coerce('zhoverformat'); + // Needed for formatting of hoverlabel if format is not explicitly specified + traceOut._separators = layout.separators; }; diff --git a/src/traces/heatmap/attributes.js b/src/traces/heatmap/attributes.js index 372197a5f7b..e967f17860a 100644 --- a/src/traces/heatmap/attributes.js +++ b/src/traces/heatmap/attributes.js @@ -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}) }, diff --git a/src/traces/heatmap/defaults.js b/src/traces/heatmap/defaults.js index 3dbbaa0f380..b80c76d6e2b 100644 --- a/src/traces/heatmap/defaults.js +++ b/src/traces/heatmap/defaults.js @@ -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 }; diff --git a/src/traces/heatmap/hover.js b/src/traces/heatmap/hover.js index e3a870f3cb7..310f92c0b84 100644 --- a/src/traces/heatmap/hover.js +++ b/src/traces/heatmap/hover.js @@ -11,6 +11,7 @@ var Fx = require('../../components/fx'); var Lib = require('../../lib'); +var Axes = require('../../plots/cartesian/axes'); var MAXDIST = Fx.constants.MAXDIST; @@ -26,6 +27,9 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, contour) y = cd0.y, z = cd0.z, zmask = cd0.zmask, + range = [trace.zmin, trace.zmax], + zhoverformat = trace.zhoverformat, + _separators = trace._separators, x2 = x, y2 = y, xl, @@ -99,6 +103,17 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, contour) text = cd0.text[ny][nx]; } + var zLabel; + // dummy axis for formatting the z value + var dummyAx = { + type: 'linear', + range: range, + 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 @@ -110,6 +125,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, contour) xLabelVal: xl, yLabelVal: yl, zLabelVal: zVal, + zLabel: zLabel, text: text })]; }; diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index b6be796bdbe..b8fa0ad2693 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -499,6 +499,43 @@ describe('hover info', function() { .catch(fail) .then(done); }); + + it('should display correct label content with specified format', function(done) { + 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() { From 86277f21bcdd6867f6f55bbbb5af81cf8477e678 Mon Sep 17 00:00:00 2001 From: Juernjakob Dugge Date: Fri, 20 Oct 2017 06:52:02 +0200 Subject: [PATCH 6/8] Fix formatting --- src/components/fx/hover.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index b4ea861cd40..4888f353cf2 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -1073,7 +1073,7 @@ function cleanPoint(d, hovermode) { d.yLabel = ('yLabel' in d) ? d.yLabel : Axes.hoverLabelText(d.ya, d.yLabelVal); d.yVal = d.ya.c2d(d.yLabelVal); } - + // Traces like heatmaps generate the zLabel in their hoverPoints function if(d.zLabelVal !== undefined && d.zLabel === undefined) { d.zLabel = String(d.zLabelVal); From 1760d660b7815c5adfed7b7edd26ea26dac2a77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Etienne=20T=C3=A9treault-Pinard?= Date: Fri, 20 Oct 2017 10:13:56 -0400 Subject: [PATCH 7/8] fixup choropleth select test - PR https://github.com/plotly/plotly.js/pull/2099 got merged on a branch behind https://github.com/plotly/plotly.js/pull/2081 which caused the test to fail on master. --- test/jasmine/tests/select_test.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/jasmine/tests/select_test.js b/test/jasmine/tests/select_test.js index 9915cb9583f..72f29593e3f 100644 --- a/test/jasmine/tests/select_test.js +++ b/test/jasmine/tests/select_test.js @@ -717,10 +717,11 @@ describe('Test select box and lasso per trace:', function() { addInvisible(fig, false); // add a trace with no locations which will then make trace invisible, lacking DOM elements - fig.data.push(Lib.extendDeep({}, fig.data[0])); - fig.data[1].text = []; - fig.data[1].locations = []; - fig.data[1].z = []; + var emptyChoroplethTrace = Lib.extendDeep({}, fig.data[0]); + emptyChoroplethTrace.text = []; + emptyChoroplethTrace.locations = []; + emptyChoroplethTrace.z = []; + fig.data.push(emptyChoroplethTrace); Plotly.plot(gd, fig) .then(function() { From 48509f36647cf6d46f4e3f219e706b7b265bb91f Mon Sep 17 00:00:00 2001 From: Juernjakob Dugge Date: Sun, 15 Oct 2017 21:13:11 +0200 Subject: [PATCH 8/8] Add zhoverformat to heatmap and contour traces --- src/components/fx/hover.js | 6 ++++- src/traces/contour/attributes.js | 1 + src/traces/contour/defaults.js | 4 +++ src/traces/heatmap/attributes.js | 11 ++++++++ src/traces/heatmap/defaults.js | 3 +++ src/traces/heatmap/hover.js | 16 +++++++++++ test/jasmine/tests/hover_label_test.js | 37 ++++++++++++++++++++++++++ 7 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index cc366193eb3..4888f353cf2 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -1073,7 +1073,11 @@ function cleanPoint(d, hovermode) { d.yLabel = ('yLabel' in d) ? d.yLabel : Axes.hoverLabelText(d.ya, d.yLabelVal); d.yVal = d.ya.c2d(d.yLabelVal); } - if(d.zLabelVal !== undefined) d.zLabel = String(d.zLabelVal); + + // Traces like heatmaps generate the zLabel in their hoverPoints function + if(d.zLabelVal !== undefined && d.zLabel === undefined) { + 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)) { diff --git a/src/traces/contour/attributes.js b/src/traces/contour/attributes.js index 5414afe9f48..8db880b2317 100644 --- a/src/traces/contour/attributes.js +++ b/src/traces/contour/attributes.js @@ -30,6 +30,7 @@ module.exports = extendFlat({ transpose: heatmapAttrs.transpose, xtype: heatmapAttrs.xtype, ytype: heatmapAttrs.ytype, + zhoverformat: heatmapAttrs.zhoverformat, connectgaps: heatmapAttrs.connectgaps, diff --git a/src/traces/contour/defaults.js b/src/traces/contour/defaults.js index a616f818045..1e30d6b17c5 100644 --- a/src/traces/contour/defaults.js +++ b/src/traces/contour/defaults.js @@ -34,4 +34,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout handleContoursDefaults(traceIn, traceOut, coerce); handleStyleDefaults(traceIn, traceOut, coerce, layout); + + coerce('zhoverformat'); + // Needed for formatting of hoverlabel if format is not explicitly specified + traceOut._separators = layout.separators; }; diff --git a/src/traces/heatmap/attributes.js b/src/traces/heatmap/attributes.js index 372197a5f7b..e967f17860a 100644 --- a/src/traces/heatmap/attributes.js +++ b/src/traces/heatmap/attributes.js @@ -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}) }, diff --git a/src/traces/heatmap/defaults.js b/src/traces/heatmap/defaults.js index 3dbbaa0f380..b80c76d6e2b 100644 --- a/src/traces/heatmap/defaults.js +++ b/src/traces/heatmap/defaults.js @@ -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 }; diff --git a/src/traces/heatmap/hover.js b/src/traces/heatmap/hover.js index e3a870f3cb7..310f92c0b84 100644 --- a/src/traces/heatmap/hover.js +++ b/src/traces/heatmap/hover.js @@ -11,6 +11,7 @@ var Fx = require('../../components/fx'); var Lib = require('../../lib'); +var Axes = require('../../plots/cartesian/axes'); var MAXDIST = Fx.constants.MAXDIST; @@ -26,6 +27,9 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, contour) y = cd0.y, z = cd0.z, zmask = cd0.zmask, + range = [trace.zmin, trace.zmax], + zhoverformat = trace.zhoverformat, + _separators = trace._separators, x2 = x, y2 = y, xl, @@ -99,6 +103,17 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, contour) text = cd0.text[ny][nx]; } + var zLabel; + // dummy axis for formatting the z value + var dummyAx = { + type: 'linear', + range: range, + 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 @@ -110,6 +125,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, contour) xLabelVal: xl, yLabelVal: yl, zLabelVal: zVal, + zLabel: zLabel, text: text })]; }; diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index b6be796bdbe..b8fa0ad2693 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -499,6 +499,43 @@ describe('hover info', function() { .catch(fail) .then(done); }); + + it('should display correct label content with specified format', function(done) { + 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() {