diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js
index 9c15427cd1c..5010dcd3ce0 100644
--- a/src/components/fx/hover.js
+++ b/src/components/fx/hover.js
@@ -931,10 +931,24 @@ function createHoverText(hoverData, opts, gd) {
});
}
+ var xLetter = 'x';
+ var yLetter = 'y';
+ var zLetter = 'z';
+
+ if(gd._fullLayout.scene) {
+ xLetter = gd._fullLayout.scene.xaxis.hovertitle || xLetter;
+ yLetter = gd._fullLayout.scene.yaxis.hovertitle || yLetter;
+ zLetter = gd._fullLayout.scene.zaxis.hovertitle || zLetter;
+ }
+ else if(!gd._fullLayout.ternary) {
+ if(gd._fullLayout.xaxis) xLetter = gd._fullLayout.xaxis.hovertitle || xLetter;
+ if(gd._fullLayout.yaxis) yLetter = gd._fullLayout.yaxis.hovertitle || yLetter;
+ }
+
if(d.zLabel !== undefined) {
- if(d.xLabel !== undefined) text += 'x: ' + d.xLabel + '
';
- if(d.yLabel !== undefined) text += 'y: ' + d.yLabel + '
';
- text += (text ? 'z: ' : '') + d.zLabel;
+ if(d.xLabel !== undefined) text += xLetter + ': ' + d.xLabel + '
';
+ if(d.yLabel !== undefined) text += yLetter + ': ' + d.yLabel + '
';
+ text += (text ? zLetter + ': ' : '') + d.zLabel;
}
else if(showCommonLabel && d[hovermode + 'Label'] === t0) {
text = d[(hovermode === 'x' ? 'y' : 'x') + 'Label'] || '';
diff --git a/src/plots/cartesian/axis_defaults.js b/src/plots/cartesian/axis_defaults.js
index 2269152de39..d1ccaa5828e 100644
--- a/src/plots/cartesian/axis_defaults.js
+++ b/src/plots/cartesian/axis_defaults.js
@@ -56,7 +56,13 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,
handleCategoryOrderDefaults(containerIn, containerOut, coerce, options);
- if(axType !== 'category' && !options.noHover) coerce('hoverformat');
+ if(!options.noHover) {
+ coerce('hovertitle', letter);
+
+ if(axType !== 'category') {
+ coerce('hoverformat');
+ }
+ }
if(!visible) return containerOut;
diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js
index c0f7f9b3a83..445c95bb2d3 100644
--- a/src/plots/cartesian/layout_attributes.js
+++ b/src/plots/cartesian/layout_attributes.js
@@ -594,6 +594,14 @@ module.exports = {
'*%H~%M~%S.%2f* would display *09~15~23.46*'
].join(' ')
},
+ hovertitle: {
+ valType: 'string',
+ role: 'info',
+ editType: 'none',
+ description: [
+ 'Sets axis title to be displayed in the hovering popup'
+ ].join(' ')
+ },
// lines and grids
showline: {
valType: 'boolean',
diff --git a/src/plots/gl3d/layout/axis_attributes.js b/src/plots/gl3d/layout/axis_attributes.js
index 6699e73575a..6ff2e9a4a8c 100644
--- a/src/plots/gl3d/layout/axis_attributes.js
+++ b/src/plots/gl3d/layout/axis_attributes.js
@@ -109,6 +109,7 @@ module.exports = overrideAll({
tickformat: axesAttrs.tickformat,
tickformatstops: axesAttrs.tickformatstops,
hoverformat: axesAttrs.hoverformat,
+ hovertitle: axesAttrs.hovertitle,
// lines and grids
showline: axesAttrs.showline,
linecolor: axesAttrs.linecolor,
diff --git a/src/plots/polar/layout_attributes.js b/src/plots/polar/layout_attributes.js
index f6905453dd9..92d4ce80cd7 100644
--- a/src/plots/polar/layout_attributes.js
+++ b/src/plots/polar/layout_attributes.js
@@ -118,6 +118,7 @@ var radialAxisAttrs = {
// might need a 'titleside' and even 'titledirection' down the road
hoverformat: axesAttrs.hoverformat,
+ hovertitle: axesAttrs.hovertitle,
uirevision: {
valType: 'any',
@@ -234,6 +235,7 @@ var angularAxisAttrs = {
},
hoverformat: axesAttrs.hoverformat,
+ hovertitle: axesAttrs.hovertitle,
uirevision: {
valType: 'any',
diff --git a/src/plots/polar/layout_defaults.js b/src/plots/polar/layout_defaults.js
index 6c7fb220dc6..4af27b19718 100644
--- a/src/plots/polar/layout_defaults.js
+++ b/src/plots/polar/layout_defaults.js
@@ -179,6 +179,8 @@ function handleDefaults(contIn, contOut, coerce, opts) {
if(axType !== 'category') coerceAxis('hoverformat');
+ coerceAxis('hovertitle');
+
axOut._input = axIn;
}
diff --git a/src/plots/ternary/layout_attributes.js b/src/plots/ternary/layout_attributes.js
index effa824be8d..13948d130cb 100644
--- a/src/plots/ternary/layout_attributes.js
+++ b/src/plots/ternary/layout_attributes.js
@@ -42,6 +42,7 @@ var ternaryAxesAttrs = {
tickformat: axesAttrs.tickformat,
tickformatstops: axesAttrs.tickformatstops,
hoverformat: axesAttrs.hoverformat,
+ hovertitle: axesAttrs.hovertitle,
// lines and grids
showline: extendFlat({}, axesAttrs.showline, {dflt: true}),
linecolor: axesAttrs.linecolor,
diff --git a/src/plots/ternary/layout_defaults.js b/src/plots/ternary/layout_defaults.js
index 7ab47dee7ac..07400a67a25 100644
--- a/src/plots/ternary/layout_defaults.js
+++ b/src/plots/ternary/layout_defaults.js
@@ -86,7 +86,7 @@ function handleAxisDefaults(containerIn, containerOut, options, ternaryLayoutOut
var dfltTitle = 'Component ' + letterUpper;
var title = coerce('title.text', dfltTitle);
- containerOut._hovertitle = title === dfltTitle ? title : letterUpper;
+ coerce('hovertitle', title === dfltTitle ? title : letterUpper);
Lib.coerceFont(coerce, 'title.font', {
family: options.font.family,
@@ -126,5 +126,6 @@ function handleAxisDefaults(containerIn, containerOut, options, ternaryLayoutOut
});
coerce('hoverformat');
+ coerce('hovertitle');
coerce('layer');
}
diff --git a/src/traces/carpet/axis_attributes.js b/src/traces/carpet/axis_attributes.js
index 589c9dee56b..47f53aea561 100644
--- a/src/traces/carpet/axis_attributes.js
+++ b/src/traces/carpet/axis_attributes.js
@@ -68,6 +68,14 @@ module.exports = {
},
editType: 'calc',
},
+ hovertitle: {
+ valType: 'string',
+ role: 'info',
+ editType: 'none',
+ description: [
+ 'Sets axis title to be displayed in the hovering popup'
+ ].join(' ')
+ },
type: {
valType: 'enumerated',
// '-' means we haven't yet run autotype or couldn't find any data
diff --git a/src/traces/carpet/axis_defaults.js b/src/traces/carpet/axis_defaults.js
index a14341c2943..7cc184c3bb3 100644
--- a/src/traces/carpet/axis_defaults.js
+++ b/src/traces/carpet/axis_defaults.js
@@ -95,8 +95,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, options)
coerce('labelpadding');
- containerOut._hovertitle = letter;
-
+ coerce('hovertitle', letter);
if(axType === 'date') {
var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleDefaults');
diff --git a/src/traces/scattercarpet/hover.js b/src/traces/scattercarpet/hover.js
index f8b47447a39..c9d9364ecb6 100644
--- a/src/traces/scattercarpet/hover.js
+++ b/src/traces/scattercarpet/hover.js
@@ -58,7 +58,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
if(ax.labelprefix && ax.labelprefix.length > 0) {
prefix = ax.labelprefix.replace(/ = $/, '');
} else {
- prefix = ax._hovertitle;
+ prefix = ax.hovertitle;
}
text.push(prefix + ': ' + val.toFixed(3) + ax.labelsuffix);
diff --git a/src/traces/scatterpolar/hover.js b/src/traces/scatterpolar/hover.js
index ea52df6b1ee..c6e66bc0676 100644
--- a/src/traces/scatterpolar/hover.js
+++ b/src/traces/scatterpolar/hover.js
@@ -40,13 +40,11 @@ function makeHoverPointText(cdi, trace, subplot, pointData) {
var radialAxis = subplot.radialAxis;
var angularAxis = subplot.angularAxis;
- radialAxis._hovertitle = 'r';
- angularAxis._hovertitle = 'θ';
var hoverinfo = cdi.hi || trace.hoverinfo;
var text = [];
- function textPart(ax, val) {
- text.push(ax._hovertitle + ': ' + Axes.tickText(ax, val, 'hover').text);
+ function textPart(dfltText, ax, val) {
+ text.push((ax.hovertitle || dfltText) + ': ' + Axes.tickText(ax, val, 'hover').text);
}
if(!trace.hovertemplate) {
@@ -54,11 +52,12 @@ function makeHoverPointText(cdi, trace, subplot, pointData) {
if(parts.indexOf('all') !== -1) parts = ['r', 'theta', 'text'];
if(parts.indexOf('r') !== -1) {
- textPart(radialAxis, radialAxis.c2l(cdi.r));
+ textPart('r', radialAxis, radialAxis.c2l(cdi.r));
}
if(parts.indexOf('theta') !== -1) {
var theta = cdi.theta;
textPart(
+ 'θ',
angularAxis,
angularAxis.thetaunit === 'degrees' ? Lib.rad2deg(theta) : theta
);
diff --git a/src/traces/scatterternary/hover.js b/src/traces/scatterternary/hover.js
index eaf0ad26421..30e4722d2ce 100644
--- a/src/traces/scatterternary/hover.js
+++ b/src/traces/scatterternary/hover.js
@@ -54,7 +54,8 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
var hoverinfo = cdi.hi || trace.hoverinfo;
var text = [];
function textPart(ax, val) {
- text.push(ax._hovertitle + ': ' + Axes.tickText(ax, val, 'hover').text);
+ var axTitle = ax.hovertitle || ax.title.text;
+ text.push(axTitle + ': ' + Axes.tickText(ax, val, 'hover').text);
}
if(!trace.hovertemplate) {
var parts = hoverinfo.split('+');
diff --git a/test/image/baselines/gl3d_surface_after_heatmap.png b/test/image/baselines/gl3d_surface_after_heatmap.png
index e2e84ff714a..06bd02e3df2 100644
Binary files a/test/image/baselines/gl3d_surface_after_heatmap.png and b/test/image/baselines/gl3d_surface_after_heatmap.png differ
diff --git a/test/image/mocks/gl3d_ibm-plot.json b/test/image/mocks/gl3d_ibm-plot.json
index 166e16463e4..f15a887c8bc 100644
--- a/test/image/mocks/gl3d_ibm-plot.json
+++ b/test/image/mocks/gl3d_ibm-plot.json
@@ -304,6 +304,7 @@
"scene": {
"xaxis": {
"title": "Term",
+ "hovertitle": "Term",
"titlefont": {
"color": "#D9D9D9"
},
@@ -318,6 +319,7 @@
},
"yaxis": {
"title": "Moneyness",
+ "hovertitle": "Moneyness",
"titlefont": {
"color": "#D9D9D9"
},
@@ -332,6 +334,7 @@
},
"zaxis": {
"title": "Volatilty",
+ "hovertitle": "Volatilty",
"titlefont": {
"color": "#D9D9D9"
},
diff --git a/test/image/mocks/gl3d_surface_after_heatmap.json b/test/image/mocks/gl3d_surface_after_heatmap.json
index bd34b7f8c70..da6b4a4cf37 100644
--- a/test/image/mocks/gl3d_surface_after_heatmap.json
+++ b/test/image/mocks/gl3d_surface_after_heatmap.json
@@ -2,28 +2,72 @@
"data": [
{
"type": "heatmap",
- "x": [0, 1, 2],
- "y": [0, 1, 2],
+ "zsmooth": "best",
+ "x": [0, 1, 2, 3, 4],
+ "y": [0, 1, 2, 3, 4],
"z": [
- [0, 1, 0],
- [1, 0, 1],
- [0, 1, 0]
+ [0, 1, 0, 1, 0],
+ [1, 0.25, 0.75, 0.25, 1],
+ [0, 0.75, 0.25, 0.75, 0],
+ [1, 0.25, 0.75, 0.25, 1],
+ [0, 1, 0, 1, 0]
]
},
{
"type": "surface",
- "x": [0, 1, 2],
- "y": [0, 1, 2],
+ "x": [0, 1, 2, 3, 4],
+ "y": [0, 1, 2, 3, 4],
"z": [
- [0, 1, 0],
- [1, 0, 1],
- [0, 1, 0]
+ [0, 1, 0, 1, 0],
+ [1, 0.25, 0.75, 0.25, 1],
+ [0, 0.75, 0.25, 0.75, 0],
+ [1, 0.25, 0.75, 0.25, 1],
+ [0, 1, 0, 1, 0]
]
}
],
"layout": {
"title": "Surface 3d plot on top of 2d heatmap!",
"width": 600,
- "height": 400
+ "height": 400,
+ "xaxis": {
+ "hovertitle": "lon",
+ "title": {
+ "text": "Longitude"
+ }
+ },
+ "yaxis": {
+ "hovertitle": "lat",
+ "title": {
+ "text": "Latitude"
+ }
+ },
+ "scene": {
+ "xaxis": {
+ "hovertitle": "lon",
+ "title": {
+ "text": "Longitude"
+ }
+ },
+ "yaxis": {
+ "hovertitle": "lat",
+ "title": {
+ "text": "Latitude"
+ }
+ },
+ "zaxis": {
+ "hovertitle": "alt",
+ "title": {
+ "text": "Altitude"
+ }
+ },
+ "camera": {
+ "eye": {
+ "x": 2,
+ "y": 2,
+ "z": 2
+ }
+ }
+ }
}
}
diff --git a/test/image/mocks/polar_wind-rose.json b/test/image/mocks/polar_wind-rose.json
index fb40daa5592..3edd02cad3a 100644
--- a/test/image/mocks/polar_wind-rose.json
+++ b/test/image/mocks/polar_wind-rose.json
@@ -31,8 +31,8 @@
"polar": {
"barmode": "overlay",
"bargap": 0,
- "radialaxis": {"ticksuffix": "%", "angle": 45, "dtick": 20},
- "angularaxis": {"direction": "clockwise"}
+ "radialaxis": {"hovertitle": "distribution", "ticksuffix": "%", "angle": 45, "dtick": 20},
+ "angularaxis": {"hovertitle": "direction", "direction": "clockwise"}
}
}
}
diff --git a/test/jasmine/tests/ternary_test.js b/test/jasmine/tests/ternary_test.js
index f6475dbab1a..9fdae114349 100644
--- a/test/jasmine/tests/ternary_test.js
+++ b/test/jasmine/tests/ternary_test.js
@@ -131,7 +131,7 @@ describe('ternary plots', function() {
check([
'Component A: 0.5',
- 'B: 0.25',
+ 'chocolate: 0.25',
'Component C: 0.25'
].join('\n'), {
bgcolor: 'rgb(31, 119, 180)',
@@ -148,7 +148,7 @@ describe('ternary plots', function() {
.then(function() {
check([
'Component A: 0.5',
- 'B: 0.25',
+ 'chocolate: 0.25',
'Component C: 0.25'
].join('\n'), {
bgcolor: 'rgb(31, 119, 180)',