Skip to content

Commit 76eee4b

Browse files
committed
flesh out bin attribute descriptions and let autobin(x|y) pass validate
1 parent c0b8c6f commit 76eee4b

File tree

9 files changed

+198
-82
lines changed

9 files changed

+198
-82
lines changed

src/traces/histogram/attributes.js

+33-66
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
'use strict';
1010

1111
var barAttrs = require('../bar/attributes');
12+
var makeBinAttrs = require('./bin_attributes');
1213

1314
module.exports = {
1415
x: {
@@ -138,7 +139,7 @@ module.exports = {
138139
'Ignored if `xbins.size` is provided.'
139140
].join(' ')
140141
},
141-
xbins: makeBinsAttr('x'),
142+
xbins: makeBinAttrs('x', true),
142143

143144
nbinsy: {
144145
valType: 'integer',
@@ -153,77 +154,43 @@ module.exports = {
153154
'Ignored if `ybins.size` is provided.'
154155
].join(' ')
155156
},
156-
ybins: makeBinsAttr('y'),
157+
ybins: makeBinAttrs('y', true),
158+
autobinx: {
159+
valType: 'boolean',
160+
dflt: null,
161+
role: 'style',
162+
editType: 'calc',
163+
description: [
164+
'Obsolete: since v1.42 each bin attribute is auto-determined',
165+
'separately and `autobinx` is not needed. However, we accept',
166+
'`autobinx: true` or `false` and will update `xbins` accordingly',
167+
'before deleting `autobinx` from the trace.'
168+
].join(' ')
169+
},
170+
autobiny: {
171+
valType: 'boolean',
172+
dflt: null,
173+
role: 'style',
174+
editType: 'calc',
175+
impliedEdits: {
176+
'ybins.start': undefined,
177+
'ybins.end': undefined,
178+
'ybins.size': undefined
179+
},
180+
description: [
181+
'Obsolete: since v1.42 each bin attribute is auto-determined',
182+
'separately and `autobiny` is not needed. However, we accept',
183+
'`autobiny: true` or `false` and will update `ybins` accordingly',
184+
'before deleting `autobiny` from the trace.'
185+
].join(' ')
186+
},
157187

158188
marker: barAttrs.marker,
159189

160190
selected: barAttrs.selected,
161191
unselected: barAttrs.unselected,
162192

163193
_deprecated: {
164-
bardir: barAttrs._deprecated.bardir,
165-
autobinx: {
166-
valType: 'boolean',
167-
dflt: null,
168-
role: 'style',
169-
editType: 'calc',
170-
impliedEdits: {
171-
'xbins.start': undefined,
172-
'xbins.end': undefined,
173-
'xbins.size': undefined
174-
},
175-
description: [
176-
'Obsolete: since v1.42 each bin',
177-
'attribute is auto-determined separately.'
178-
].join(' ')
179-
},
180-
autobiny: {
181-
valType: 'boolean',
182-
dflt: null,
183-
role: 'style',
184-
editType: 'calc',
185-
impliedEdits: {
186-
'ybins.start': undefined,
187-
'ybins.end': undefined,
188-
'ybins.size': undefined
189-
},
190-
description: [
191-
'Obsolete: since v1.42 each bin',
192-
'attribute is auto-determined separately.'
193-
].join(' ')
194-
}
194+
bardir: barAttrs._deprecated.bardir
195195
}
196196
};
197-
198-
function makeBinsAttr(axLetter) {
199-
return {
200-
start: {
201-
valType: 'any', // for date axes
202-
role: 'style',
203-
editType: 'calc',
204-
description: [
205-
'Sets the starting value for the', axLetter,
206-
'axis bins.'
207-
].join(' ')
208-
},
209-
end: {
210-
valType: 'any', // for date axes
211-
role: 'style',
212-
editType: 'calc',
213-
description: [
214-
'Sets the end value for the', axLetter,
215-
'axis bins.'
216-
].join(' ')
217-
},
218-
size: {
219-
valType: 'any', // for date axes
220-
role: 'style',
221-
editType: 'calc',
222-
description: [
223-
'Sets the step in-between value each', axLetter,
224-
'axis bin.'
225-
].join(' ')
226-
},
227-
editType: 'calc'
228-
};
229-
}
+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* Copyright 2012-2018, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
module.exports = function makeBinAttrs(axLetter, match) {
12+
return {
13+
start: {
14+
valType: 'any', // for date axes
15+
role: 'style',
16+
editType: 'calc',
17+
description: [
18+
'Sets the starting value for the', axLetter,
19+
'axis bins. Defaults to the minimum data value,',
20+
'shifted down if necessary to make nice round values',
21+
'and to remove ambiguous bin edges. For example, if most of the',
22+
'data is integers we shift the bin edges 0.5 down, so a `size`',
23+
'of 5 would have a default `start` of -0.5, so it is clear',
24+
'that 0-4 are in the first bin, 5-9 in the second, but',
25+
'continuous data gets a start of 0 and bins [0,5), [5,10) etc.',
26+
'Dates behave similarly, and `start` should be a date string.',
27+
'For category data, `start` is based on the category serial',
28+
'numbers, and defaults to -0.5.',
29+
(match ? (
30+
'If multiple non-overlaying histograms share a subplot, ' +
31+
'the first explicit `start` is used exactly and all others ' +
32+
'are shifted down (if necessary) to differ from that one ' +
33+
'by an integer number of bins.'
34+
) : '')
35+
].join(' ')
36+
},
37+
end: {
38+
valType: 'any', // for date axes
39+
role: 'style',
40+
editType: 'calc',
41+
description: [
42+
'Sets the end value for the', axLetter,
43+
'axis bins. The last bin may not end exactly at this value,',
44+
'we increment the bin edge by `size` from `start` until we',
45+
'reach or exceed `end`. Defaults to the maximum data value.',
46+
'Like `start`, for dates use a date string, and for category',
47+
'data `end` is based on the category serial numbers.'
48+
].join(' ')
49+
},
50+
size: {
51+
valType: 'any', // for date axes
52+
role: 'style',
53+
editType: 'calc',
54+
description: [
55+
'Sets the size of each', axLetter, 'axis bin.',
56+
'Default behavior: If `nbins' + axLetter + '` is 0 or omitted,',
57+
'we choose a nice round bin size such that the number of bins',
58+
'is about the same as the typical number of samples in each bin.',
59+
'If `nbins' + axLetter + '` is provided, we choose a nice round',
60+
'bin size giving no more than that many bins.',
61+
'For date data, use milliseconds or *M<n>* for months, as in',
62+
'`axis.dtick`. For category data, the number of categories to',
63+
'bin together (always defaults to 1).',
64+
(match ? (
65+
'If multiple non-overlaying histograms share a subplot, ' +
66+
'the first explicit `size` is used and all others discarded. ' +
67+
'If no `size` is provided,the sample data from all traces ' +
68+
'is combined to determine `size` as described above.'
69+
) : '')
70+
].join(' ')
71+
},
72+
editType: 'calc'
73+
};
74+
};

src/traces/histogram/calc.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,11 @@ function calcAllAutoBins(gd, trace, pa, mainData, _overlayEdgeCase) {
359359
// Backward compatibility for one-time autobinning.
360360
// autobin: true is handled in cleanData, but autobin: false
361361
// needs to be here where we have determined the values.
362-
if(trace._input['autobin' + mainData] === false) {
362+
var autoBinAttr = 'autobin' + mainData;
363+
if(trace._input[autoBinAttr] === false) {
363364
trace._input[binAttr] = Lib.extendFlat({}, trace[binAttr] || {});
364-
delete trace._input['autobin' + mainData];
365+
delete trace._input[autoBinAttr];
366+
delete trace[autoBinAttr];
365367
}
366368

367369
return [traceBinOptsCalc, pos0];

src/traces/histogram/defaults.js

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
5353
coerce('histnorm');
5454

5555
// Note: bin defaults are now handled in Histogram.cleanData
56+
// autobin(x|y) are only included here to appease Plotly.validate
57+
coerce('autobin' + sampleLetter);
5658

5759
handleStyleDefaults(traceIn, traceOut, coerce, defaultColor, layout);
5860

src/traces/histogram2d/attributes.js

+6-7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
'use strict';
1010

1111
var histogramAttrs = require('../histogram/attributes');
12+
var makeBinAttrs = require('../histogram/bin_attributes');
1213
var heatmapAttrs = require('../heatmap/attributes');
1314
var colorscaleAttrs = require('../../components/colorscale/attributes');
1415
var colorbarAttrs = require('../../components/colorbar/attributes');
@@ -37,18 +38,16 @@ module.exports = extendFlat(
3738
histnorm: histogramAttrs.histnorm,
3839
histfunc: histogramAttrs.histfunc,
3940
nbinsx: histogramAttrs.nbinsx,
40-
xbins: histogramAttrs.xbins,
41+
xbins: makeBinAttrs('x'),
4142
nbinsy: histogramAttrs.nbinsy,
42-
ybins: histogramAttrs.ybins,
43+
ybins: makeBinAttrs('y'),
44+
autobinx: histogramAttrs.autobinx,
45+
autobiny: histogramAttrs.autobiny,
4346

4447
xgap: heatmapAttrs.xgap,
4548
ygap: heatmapAttrs.ygap,
4649
zsmooth: heatmapAttrs.zsmooth,
47-
zhoverformat: heatmapAttrs.zhoverformat,
48-
_deprecated: {
49-
autobinx: histogramAttrs._deprecated.autobinx,
50-
autobiny: histogramAttrs._deprecated.autobiny
51-
}
50+
zhoverformat: heatmapAttrs.zhoverformat
5251
},
5352
colorscaleAttrs('', {
5453
cLetter: 'z',

src/traces/histogram2d/calc.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,11 @@ function doAutoBin(trace, axLetter, data, ax, r2c, c2r, calendar) {
219219
// Backward compatibility for one-time autobinning.
220220
// autobin: true is handled in cleanData, but autobin: false
221221
// needs to be here where we have determined the values.
222-
if(trace._input['autobin' + axLetter] === false) {
222+
var autoBinAttr = 'autobin' + axLetter;
223+
if(trace._input[autoBinAttr] === false) {
223224
trace._input[binAttr] = Lib.extendFlat({}, binSpec);
224-
delete trace._input['autobin' + axLetter];
225+
delete trace._input[autoBinAttr];
226+
delete trace[autoBinAttr];
225227
}
226228
}
227229

src/traces/histogram2d/sample_defaults.js

+3
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,7 @@ module.exports = function handleSampleDefaults(traceIn, traceOut, coerce, layout
3535
coerce('histnorm');
3636

3737
// Note: bin defaults are now handled in Histogram2D.cleanData
38+
// autobin(x|y) are only included here to appease Plotly.validate
39+
coerce('autobinx');
40+
coerce('autobiny');
3841
};

src/traces/histogram2dcontour/attributes.js

+3-5
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,14 @@ module.exports = extendFlat({
2727
xbins: histogram2dAttrs.xbins,
2828
nbinsy: histogram2dAttrs.nbinsy,
2929
ybins: histogram2dAttrs.ybins,
30+
autobinx: histogram2dAttrs.autobinx,
31+
autobiny: histogram2dAttrs.autobiny,
3032

3133
autocontour: contourAttrs.autocontour,
3234
ncontours: contourAttrs.ncontours,
3335
contours: contourAttrs.contours,
3436
line: contourAttrs.line,
35-
zhoverformat: histogram2dAttrs.zhoverformat,
36-
_deprecated: {
37-
autobinx: histogram2dAttrs._deprecated.autobinx,
38-
autobiny: histogram2dAttrs._deprecated.autobiny
39-
}
37+
zhoverformat: histogram2dAttrs.zhoverformat
4038
},
4139
colorscaleAttrs('', {
4240
cLetter: 'z',

test/jasmine/tests/validate_test.js

+69
Original file line numberDiff line numberDiff line change
@@ -568,4 +568,73 @@ describe('Plotly.validate', function() {
568568
'In layout, container polar3 did not get coerced'
569569
);
570570
});
571+
572+
it('understands histogram bin and autobin attributes', function() {
573+
var out = Plotly.validate([{
574+
type: 'histogram',
575+
x: [1, 2, 3],
576+
// allowed by Plotly.validate, even though we get rid of it
577+
// in a real plot call
578+
autobinx: true,
579+
// valid attribute, but not coerced
580+
autobiny: false
581+
}]);
582+
expect(out.length).toBe(1);
583+
assertErrorContent(
584+
out[0], 'unused', 'data', 0, ['autobiny'], 'autobiny',
585+
'In data trace 0, key autobiny did not get coerced'
586+
);
587+
588+
out = Plotly.validate([{
589+
type: 'histogram',
590+
x: [1, 2, 3],
591+
xbins: {start: 1, end: 4, size: 0.5}
592+
}]);
593+
expect(out).toBeUndefined();
594+
595+
out = Plotly.validate([{
596+
type: 'histogram',
597+
x: [1, 2, 3],
598+
xbins: {start: 0.8, end: 4, size: 0.5}
599+
}, {
600+
type: 'histogram',
601+
x: [1, 2, 3],
602+
// start and end still get coerced, even though start will get modified
603+
// during calc. size will not be coerced because trace 0 already has it.
604+
xbins: {start: 2, end: 3, size: 1}
605+
}]);
606+
607+
expect(out.length).toBe(1);
608+
assertErrorContent(
609+
out[0], 'unused', 'data', 1, ['xbins', 'size'], 'xbins.size',
610+
'In data trace 1, key xbins.size did not get coerced'
611+
);
612+
});
613+
614+
it('understands histogram2d(contour) bin and autobin attributes', function() {
615+
var out = Plotly.validate([{
616+
type: 'histogram2d',
617+
x: [1, 2, 3],
618+
y: [1, 2, 3],
619+
autobinx: true,
620+
autobiny: false,
621+
xbins: {start: 5, end: 10},
622+
ybins: {size: 2}
623+
}, {
624+
type: 'histogram2d',
625+
x: [1, 2, 3],
626+
y: [1, 2, 3],
627+
xbins: {start: 0, end: 7, size: 1},
628+
ybins: {size: 3}
629+
}, {
630+
type: 'histogram2dcontour',
631+
x: [1, 2, 3],
632+
y: [1, 2, 3],
633+
autobinx: false,
634+
autobiny: false,
635+
xbins: {start: 1, end: 5, size: 2},
636+
ybins: {size: 4}
637+
}]);
638+
expect(out).toBeUndefined();
639+
});
571640
});

0 commit comments

Comments
 (0)