Skip to content

Include values of all array attributes in hover/click/select event data #1770

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 8 commits into from
Jun 15, 2017
27 changes: 27 additions & 0 deletions src/components/fx/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

'use strict';

var Lib = require('../../lib');
var constants = require('./constants');

// look for either subplot or xaxis and yaxis attributes
Expand Down Expand Up @@ -83,3 +84,29 @@ function quadrature(dx, dy) {
return Math.sqrt(x * x + y * y);
};
}

/** Appends values inside array attributes corresponding to given point number
*
* @param {object} pointData : point data object (gets mutated here)
* @param {object} trace : full trace object
* @param {number} pointNumber : point number
*/
exports.appendArrayPointValue = function(pointData, trace, pointNumber) {
var arrayAttrs = trace._arrayAttrs;

for(var i = 0; i < arrayAttrs.length; i++) {
var astr = arrayAttrs[i];
var key;

if(astr === 'ids') key = 'id';
else if(astr === 'locations') key = 'location';
else key = astr;

if(pointData[key] === undefined) {
var val = Lib.nestedProperty(trace, astr).get();
Copy link
Collaborator

Choose a reason for hiding this comment

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

not blocking, but if we find that this starts dragging on performance (particularly for selecting I guess) then I suspect nestedProperty would be the primary cost. Could possibly store these instead of attribute strings in _arrayAttrs? It would be a little weird, since they could be referencing data arrays inside an outdated trace if we've redrawn without a recalc, but in as far as recalc is always triggered by changing an array attribute it seems like it would be ok?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call. I didn't notice any serious slow downs so far, so I won't address this in this PR.

pointData[key] = Array.isArray(pointNumber) ?
val[pointNumber[0]][pointNumber[1]] :
val[pointNumber];
}
}
};
1 change: 1 addition & 0 deletions src/components/fx/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ function _hover(gd, evt, subplot) {
if(pt.zLabelVal !== undefined) out.z = pt.zLabelVal;
}

helpers.appendArrayPointValue(out, pt.trace, pt.index);
newhoverdata.push(out);
}

Expand Down
1 change: 1 addition & 0 deletions src/components/fx/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ module.exports = {
getDistanceFunction: helpers.getDistanceFunction,
getClosest: helpers.getClosest,
inbox: helpers.inbox,
appendArrayPointValue: helpers.appendArrayPointValue,

castHoverOption: castHoverOption,
castHoverinfo: castHoverinfo,
Expand Down
7 changes: 4 additions & 3 deletions src/plot_api/plot_schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,9 @@ exports.findArrayAttributes = function(trace) {
}

exports.crawl(baseAttributes, callback);
exports.crawl(trace._module.attributes, callback);
if(trace._module && trace._module.attributes) {
exports.crawl(trace._module.attributes, callback);
}

if(trace.transforms) {
var transforms = trace.transforms;
Expand All @@ -177,9 +179,8 @@ exports.findArrayAttributes = function(trace) {
// At the moment, we need this block to make sure that
// ohlc and candlestick 'open', 'high', 'low', 'close' can be
// used with filter ang groupby transforms.
if(trace._fullInput) {
if(trace._fullInput && trace._fullInput._module && trace._fullInput._module.attributes) {
exports.crawl(trace._fullInput._module.attributes, callback);

arrayAttributes = Lib.filterUnique(arrayAttributes);
}

Expand Down
16 changes: 16 additions & 0 deletions src/plots/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,22 @@ module.exports = {
role: 'info',
dflt: ''
},
ids: {
valType: 'data_array',
description: [
'Assigns id labels to each datum.',
'These ids for object constancy of data points during animation.'
].join(' ')
},
customdata: {
valType: 'data_array',
description: [
'Assigns extra data each datum.',
'This may be useful when listening to hover, click and selection events.',
'Note that, *scatter* traces also appends customdata items in the markers',
'DOM elements'
].join(' ')
},
hoverinfo: {
valType: 'flaglist',
role: 'info',
Expand Down
22 changes: 21 additions & 1 deletion src/plots/cartesian/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

var polygon = require('../../lib/polygon');
var color = require('../../components/color');
var appendArrayPointValue = require('../../components/fx/helpers').appendArrayPointValue;

var axes = require('./axes');
var constants = require('./constants');
Expand Down Expand Up @@ -151,7 +152,9 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
selection = [];
for(i = 0; i < searchTraces.length; i++) {
searchInfo = searchTraces[i];
[].push.apply(selection, searchInfo.selectPoints(searchInfo, poly));
[].push.apply(selection, fillSelectionItem(
searchInfo.selectPoints(searchInfo, poly), searchInfo
));
}

eventData = {points: selection};
Expand Down Expand Up @@ -196,3 +199,20 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
}
};
};

function fillSelectionItem(selection, searchInfo) {
if(Array.isArray(selection)) {
var trace = searchInfo.cd[0].trace;

for(var i = 0; i < selection.length; i++) {
var sel = selection[i];

sel.curveNumber = trace.index;
sel.data = trace._input;
sel.fullData = trace;
appendArrayPointValue(sel, trace, sel.pointNumber);
}
}

return selection;
}
27 changes: 15 additions & 12 deletions src/plots/gl2d/scene2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ proto.updateTraces = function(fullData, calcData) {

proto.emitPointAction = function(nextSelection, eventType) {
var uid = nextSelection.trace.uid;
var ptNumber = nextSelection.pointIndex;
var trace;

for(var i = 0; i < this.fullData.length; i++) {
Expand All @@ -520,18 +521,20 @@ proto.emitPointAction = function(nextSelection, eventType) {
}
}

this.graphDiv.emit(eventType, {
points: [{
x: nextSelection.traceCoord[0],
y: nextSelection.traceCoord[1],
curveNumber: trace.index,
pointNumber: nextSelection.pointIndex,
data: trace._input,
fullData: this.fullData,
xaxis: this.xaxis,
yaxis: this.yaxis
}]
});
var pointData = {
x: nextSelection.traceCoord[0],
y: nextSelection.traceCoord[1],
curveNumber: trace.index,
pointNumber: ptNumber,
data: trace._input,
fullData: this.fullData,
xaxis: this.xaxis,
yaxis: this.yaxis
};

Fx.appendArrayPointValue(pointData, trace, ptNumber);

this.graphDiv.emit(eventType, {points: [pointData]});
};

proto.draw = function() {
Expand Down
22 changes: 12 additions & 10 deletions src/plots/gl3d/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,18 +102,20 @@ function render(scene) {
});
}

var eventData = {
points: [{
x: selection.traceCoordinate[0],
y: selection.traceCoordinate[1],
z: selection.traceCoordinate[2],
data: trace._input,
fullData: trace,
curveNumber: trace.index,
pointNumber: ptNumber
}]
var pointData = {
x: selection.traceCoordinate[0],
y: selection.traceCoordinate[1],
z: selection.traceCoordinate[2],
data: trace._input,
fullData: trace,
curveNumber: trace.index,
pointNumber: ptNumber
};

Fx.appendArrayPointValue(pointData, trace, ptNumber);

var eventData = {points: [pointData]};

if(selection.buttons && selection.distance < 5) {
scene.graphDiv.emit('plotly_click', eventData);
}
Expand Down
11 changes: 10 additions & 1 deletion src/plots/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ plots.supplyDefaults = function(gd) {

function remapTransformedArrays(cd0, newTrace) {
var oldTrace = cd0.trace;
var arrayAttrs = PlotSchema.findArrayAttributes(oldTrace);
var arrayAttrs = oldTrace._arrayAttrs;
var transformedArrayHash = {};
var i, astr;

Expand Down Expand Up @@ -862,6 +862,9 @@ plots.supplyTraceDefaults = function(traceIn, traceOutIndex, layout, traceInInde
}

if(visible) {
coerce('customdata');
coerce('ids');

var _module = plots.getModule(traceOut);
traceOut._module = _module;

Expand Down Expand Up @@ -2032,6 +2035,12 @@ plots.doCalcdata = function(gd, traces) {
}
}

// find array attributes in trace
for(i = 0; i < fullData.length; i++) {
trace = fullData[i];
trace._arrayAttrs = PlotSchema.findArrayAttributes(trace);
}

initCategories(axList);

var hasCalcTransform = false;
Expand Down
8 changes: 0 additions & 8 deletions src/traces/scatter/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,6 @@ module.exports = {
'where `y0` is the starting coordinate and `dy` the step.'
].join(' ')
},
customdata: {
valType: 'data_array',
description: 'Assigns extra data to each scatter point DOM element'
},
dy: {
valType: 'number',
dflt: 1,
Expand All @@ -70,10 +66,6 @@ module.exports = {
'See `y0` for more info.'
].join(' ')
},
ids: {
valType: 'data_array',
description: 'A list of keys for object constancy of data points during animation'
},
text: {
valType: 'string',
role: 'info',
Expand Down
2 changes: 0 additions & 2 deletions src/traces/scatter/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,9 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
return;
}

coerce('customdata');
coerce('text');
coerce('hovertext');
coerce('mode', defaultMode);
coerce('ids');

if(subTypes.hasLines(traceOut)) {
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce);
Expand Down
5 changes: 1 addition & 4 deletions src/traces/scatter/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ module.exports = function selectPoints(searchInfo, polygon) {
ya = searchInfo.yaxis,
selection = [],
trace = cd[0].trace,
curveNumber = trace.index,
marker = trace.marker,
i,
di,
Expand All @@ -43,11 +42,9 @@ module.exports = function selectPoints(searchInfo, polygon) {

if(polygon.contains([x, y])) {
selection.push({
curveNumber: curveNumber,
pointNumber: i,
x: di.x,
y: di.y,
id: di.id
y: di.y
});
di.dim = 0;
}
Expand Down
3 changes: 1 addition & 2 deletions src/transforms/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

var Lib = require('../lib');
var Registry = require('../registry');
var PlotSchema = require('../plot_api/plot_schema');
var Axes = require('../plots/cartesian/axes');

var COMPARISON_OPS = ['=', '!=', '<', '>=', '>', '<='];
Expand Down Expand Up @@ -148,6 +147,7 @@ exports.calcTransform = function(gd, trace, opts) {
var target = opts.target;
var len = targetArray.length;
var targetCalendar = opts.targetcalendar;
var arrayAttrs = trace._arrayAttrs;

// even if you provide targetcalendar, if target is a string and there
// is a calendar attribute matching target it will get used instead.
Expand All @@ -158,7 +158,6 @@ exports.calcTransform = function(gd, trace, opts) {

var d2c = Axes.getDataToCoordFunc(gd, trace, target, targetArray);
var filterFunc = getFilterFunc(opts, d2c, targetCalendar);
var arrayAttrs = PlotSchema.findArrayAttributes(trace);
var originalArrays = {};

function forAllAttrs(fn, index) {
Expand Down
3 changes: 1 addition & 2 deletions src/transforms/sort.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
'use strict';

var Lib = require('../lib');
var PlotSchema = require('../plot_api/plot_schema');
var Axes = require('../plots/cartesian/axes');

exports.moduleType = 'transform';
Expand Down Expand Up @@ -78,7 +77,7 @@ exports.calcTransform = function(gd, trace, opts) {

var target = opts.target;
var len = targetArray.length;
var arrayAttrs = PlotSchema.findArrayAttributes(trace);
var arrayAttrs = trace._arrayAttrs;
var d2c = Axes.getDataToCoordFunc(gd, trace, target, targetArray);
var indices = getIndices(opts, targetArray, d2c);

Expand Down
Loading