Skip to content
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

Histogram autobin #3044

Merged
merged 10 commits into from
Oct 4, 2018
13 changes: 13 additions & 0 deletions src/plot_api/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,19 @@ exports.cleanData = function(data) {
// sanitize rgb(fractions) and rgba(fractions) that old tinycolor
// supported, but new tinycolor does not because they're not valid css
Color.clean(trace);

// remove obsolete autobin(x|y) attributes, but only if true
// if false, this needs to happen in Histogram.calc because it
// can be a one-time autobin so we need to know the results before
// we can push them back into the trace.
if(trace.autobinx) {
delete trace.autobinx;
delete trace.xbins;
}
if(trace.autobiny) {
delete trace.autobiny;
delete trace.ybins;
}
}
};

Expand Down
33 changes: 28 additions & 5 deletions src/plot_api/plot_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1434,6 +1434,18 @@ function _restyle(gd, aobj, traces) {
}
}

function allBins(binAttr) {
return function(j) {
return fullData[j][binAttr];
};
}

function arrayBins(binAttr) {
return function(vij, j) {
return vij === false ? fullData[traces[j]][binAttr] : null;
};
}

// now make the changes to gd.data (and occasionally gd.layout)
// and figure out what kind of graphics update we need to do
for(var ai in aobj) {
Expand All @@ -1449,6 +1461,17 @@ function _restyle(gd, aobj, traces) {
newVal,
valObject;

// Backward compatibility shim for turning histogram autobin on,
// or freezing previous autobinned values.
// Replace obsolete `autobin(x|y): true` with `(x|y)bins: null`
// and `autobin(x|y): false` with the `(x|y)bins` in `fullData`
if(ai === 'autobinx' || ai === 'autobiny') {
ai = ai.charAt(ai.length - 1) + 'bins';
if(Array.isArray(vi)) vi = vi.map(arrayBins(ai));
else if(vi === false) vi = traces.map(allBins(ai));
else vi = null;
}

redoit[ai] = vi;

if(ai.substr(0, 6) === 'LAYOUT') {
Expand Down Expand Up @@ -1609,8 +1632,12 @@ function _restyle(gd, aobj, traces) {
}
}

// major enough changes deserve autoscale, autobin, and
// Major enough changes deserve autoscale and
// non-reversed axes so people don't get confused
//
// Note: autobin (or its new analog bin clearing) is not included here
// since we're not pushing bins back to gd.data, so if we have bin
// info it was explicitly provided by the user.
if(['orientation', 'type'].indexOf(ai) !== -1) {
axlist = [];
for(i = 0; i < traces.length; i++) {
Expand All @@ -1619,10 +1646,6 @@ function _restyle(gd, aobj, traces) {
if(Registry.traceIs(trace, 'cartesian')) {
addToAxlist(trace.xaxis || 'x');
addToAxlist(trace.yaxis || 'y');

if(ai === 'type') {
doextra(['autobinx', 'autobiny'], true, i);
etpinard marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

Expand Down
21 changes: 14 additions & 7 deletions src/plots/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,13 +428,6 @@ plots.supplyDefaults = function(gd, opts) {
// attach helper method to check whether a plot type is present on graph
newFullLayout._has = plots._hasPlotType.bind(newFullLayout);

// special cases that introduce interactions between traces
var _modules = newFullLayout._visibleModules;
for(i = 0; i < _modules.length; i++) {
var _module = _modules[i];
if(_module.cleanData) _module.cleanData(newFullData);
}

if(oldFullData.length === newFullData.length) {
for(i = 0; i < newFullData.length; i++) {
relinkPrivateKeys(newFullData[i], oldFullData[i]);
Expand All @@ -444,6 +437,20 @@ plots.supplyDefaults = function(gd, opts) {
// finally, fill in the pieces of layout that may need to look at data
plots.supplyLayoutModuleDefaults(newLayout, newFullLayout, newFullData, gd._transitionData);

// Special cases that introduce interactions between traces.
// This is after relinkPrivateKeys so we can use those in cleanData
// and after layout module defaults, so we can use eg barmode
var _modules = newFullLayout._visibleModules;
var cleanDataFuncs = [];
for(i = 0; i < _modules.length; i++) {
var _module = _modules[i];
// some trace types share cleanData (ie histogram2d, histogram2dcontour)
if(_module.cleanData) Lib.pushUnique(cleanDataFuncs, _module.cleanData);
}
for(i = 0; i < cleanDataFuncs.length; i++) {
cleanDataFuncs[i](newFullData, newFullLayout);
}

// turn on flag to optimize large splom-only graphs
// mostly by omitting SVG layers during Cartesian.drawFramework
newFullLayout._hasOnlyLargeSploms = (
Expand Down
2 changes: 1 addition & 1 deletion src/traces/bar/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module.exports = function(layoutIn, layoutOut, fullData) {

for(var i = 0; i < fullData.length; i++) {
var trace = fullData[i];
if(Registry.traceIs(trace, 'bar')) hasBars = true;
if(Registry.traceIs(trace, 'bar') && trace.visible) hasBars = true;
etpinard marked this conversation as resolved.
Show resolved Hide resolved
else continue;

// if we have at least 2 grouped bar traces on the same subplot,
Expand Down
87 changes: 36 additions & 51 deletions src/traces/histogram/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,24 +125,6 @@ module.exports = {
},
editType: 'calc'
},

autobinx: {
valType: 'boolean',
dflt: null,
role: 'style',
editType: 'calc',
impliedEdits: {
'xbins.start': undefined,
'xbins.end': undefined,
'xbins.size': undefined
},
description: [
'Determines whether or not the x axis bin attributes are picked',
'by an algorithm. Note that this should be set to false if you',
'want to manually set the number of bins using the attributes in',
'xbins.'
].join(' ')
},
nbinsx: {
valType: 'integer',
min: 0,
Expand All @@ -152,28 +134,12 @@ module.exports = {
description: [
'Specifies the maximum number of desired bins. This value will be used',
'in an algorithm that will decide the optimal bin size such that the',
'histogram best visualizes the distribution of the data.'
'histogram best visualizes the distribution of the data.',
'Ignored if `xbins.size` is provided.'
].join(' ')
},
xbins: makeBinsAttr('x'),

autobiny: {
valType: 'boolean',
dflt: null,
role: 'style',
editType: 'calc',
impliedEdits: {
'ybins.start': undefined,
'ybins.end': undefined,
'ybins.size': undefined
},
description: [
'Determines whether or not the y axis bin attributes are picked',
'by an algorithm. Note that this should be set to false if you',
'want to manually set the number of bins using the attributes in',
'ybins.'
].join(' ')
},
nbinsy: {
valType: 'integer',
min: 0,
Expand All @@ -183,7 +149,8 @@ module.exports = {
description: [
'Specifies the maximum number of desired bins. This value will be used',
'in an algorithm that will decide the optimal bin size such that the',
'histogram best visualizes the distribution of the data.'
'histogram best visualizes the distribution of the data.',
'Ignored if `ybins.size` is provided.'
].join(' ')
},
ybins: makeBinsAttr('y'),
Expand All @@ -194,51 +161,69 @@ module.exports = {
unselected: barAttrs.unselected,

_deprecated: {
bardir: barAttrs._deprecated.bardir
bardir: barAttrs._deprecated.bardir,
autobinx: {
valType: 'boolean',
dflt: null,
role: 'style',
editType: 'calc',
impliedEdits: {
'xbins.start': undefined,
'xbins.end': undefined,
'xbins.size': undefined
},
description: [
'Obsolete: since v1.42 each bin',
'attribute is auto-determined separately.'
].join(' ')
},
autobiny: {
valType: 'boolean',
dflt: null,
role: 'style',
editType: 'calc',
impliedEdits: {
'ybins.start': undefined,
'ybins.end': undefined,
'ybins.size': undefined
},
description: [
'Obsolete: since v1.42 each bin',
'attribute is auto-determined separately.'
].join(' ')
}
}
};

function makeBinsAttr(axLetter) {
var impliedEdits = {};
impliedEdits['autobin' + axLetter] = false;
var impliedEditsInner = {};
impliedEditsInner['^autobin' + axLetter] = false;

return {
start: {
valType: 'any', // for date axes
dflt: null,
role: 'style',
editType: 'calc',
impliedEdits: impliedEditsInner,
description: [
'Sets the starting value for the', axLetter,
'axis bins.'
].join(' ')
},
end: {
valType: 'any', // for date axes
dflt: null,
role: 'style',
editType: 'calc',
impliedEdits: impliedEditsInner,
description: [
'Sets the end value for the', axLetter,
'axis bins.'
].join(' ')
},
size: {
valType: 'any', // for date axes
dflt: null,
role: 'style',
editType: 'calc',
impliedEdits: impliedEditsInner,
description: [
'Sets the step in-between value each', axLetter,
'axis bin.'
].join(' ')
},
editType: 'calc',
impliedEdits: impliedEdits
editType: 'calc'
};
}
32 changes: 0 additions & 32 deletions src/traces/histogram/bin_defaults.js

This file was deleted.

Loading