Skip to content

Commit 783bdaa

Browse files
authored
Merge pull request #1901 from plotly/autovals-restyle
copy histogram autobinx/y back to the input trace
2 parents b70ef1d + bf1aa6b commit 783bdaa

File tree

4 files changed

+155
-11
lines changed

4 files changed

+155
-11
lines changed

src/traces/histogram/calc.js

+10-6
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@ module.exports = function calc(gd, trace) {
4343
var pos0 = pa.makeCalcdata(trace, maindata);
4444

4545
// calculate the bins
46-
var binAttr = maindata + 'bins',
47-
binspec;
48-
if((trace['autobin' + maindata] !== false) || !(binAttr in trace)) {
46+
var binAttr = maindata + 'bins';
47+
var autoBinAttr = 'autobin' + maindata;
48+
var binspec = trace[binAttr];
49+
if((trace[autoBinAttr] !== false) || !binspec ||
50+
binspec.start === null || binspec.end === null) {
4951
binspec = Axes.autoBin(pos0, pa, trace['nbins' + maindata], false, calendar);
5052

5153
// adjust for CDF edge cases
@@ -60,9 +62,11 @@ module.exports = function calc(gd, trace) {
6062

6163
// copy bin info back to the source and full data.
6264
trace._input[binAttr] = trace[binAttr] = binspec;
63-
}
64-
else {
65-
binspec = trace[binAttr];
65+
// note that it's possible to get here with an explicit autobin: false
66+
// if the bins were not specified.
67+
// in that case this will remain in the trace, so that future updates
68+
// which would change the autobinning will not do so.
69+
trace._input[autoBinAttr] = trace[autoBinAttr];
6670
}
6771

6872
var nonuniformBins = typeof binspec.size === 'string',

src/traces/histogram2d/calc.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ module.exports = function calc(gd, trace) {
4545

4646

4747
// calculate the bins
48-
if(trace.autobinx || !('xbins' in trace)) {
48+
if(trace.autobinx || !trace.xbins ||
49+
trace.xbins.start === null || trace.xbins.end === null) {
4950
trace.xbins = Axes.autoBin(x, xa, trace.nbinsx, '2d', xcalendar);
5051
if(trace.type === 'histogram2dcontour') {
5152
// the "true" last argument reverses the tick direction (which we can't
@@ -58,8 +59,14 @@ module.exports = function calc(gd, trace) {
5859

5960
// copy bin info back to the source data.
6061
trace._input.xbins = trace.xbins;
62+
// note that it's possible to get here with an explicit autobin: false
63+
// if the bins were not specified.
64+
// in that case this will remain in the trace, so that future updates
65+
// which would change the autobinning will not do so.
66+
trace._input.autobinx = trace.autobinx;
6167
}
62-
if(trace.autobiny || !('ybins' in trace)) {
68+
if(trace.autobiny || !trace.ybins ||
69+
trace.ybins.start === null || trace.ybins.end === null) {
6370
trace.ybins = Axes.autoBin(y, ya, trace.nbinsy, '2d', ycalendar);
6471
if(trace.type === 'histogram2dcontour') {
6572
trace.ybins.start = yc2r(Axes.tickIncrement(
@@ -68,6 +75,7 @@ module.exports = function calc(gd, trace) {
6875
yr2c(trace.ybins.end), trace.ybins.size, false, ycalendar));
6976
}
7077
trace._input.ybins = trace.ybins;
78+
trace._input.autobiny = trace.autobiny;
7179
}
7280

7381
// make the empty bin array & scale the map

test/jasmine/tests/histogram2d_test.js

+76-3
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,17 @@ describe('Test histogram2d', function() {
137137
});
138138
});
139139

140-
describe('relayout interaction', function() {
140+
describe('restyle / relayout interaction', function() {
141+
142+
var gd;
143+
144+
beforeEach(function() {
145+
gd = createGraphDiv();
146+
});
141147

142148
afterEach(destroyGraphDiv);
143149

144150
it('should update paths on zooms', function(done) {
145-
var gd = createGraphDiv();
146-
147151
Plotly.newPlot(gd, [{
148152
type: 'histogram2dcontour',
149153
x: [1, 1, 2, 2, 3],
@@ -156,6 +160,75 @@ describe('Test histogram2d', function() {
156160
.then(done);
157161
});
158162

163+
164+
it('handles autobin correctly on restyles', function() {
165+
var x1 = [
166+
1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
167+
1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4];
168+
var y1 = [
169+
1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4,
170+
1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4];
171+
Plotly.newPlot(gd, [{type: 'histogram2d', x: x1, y: y1}]);
172+
expect(gd._fullData[0].xbins).toEqual({start: 0.5, end: 4.5, size: 1});
173+
expect(gd._fullData[0].ybins).toEqual({start: 0.5, end: 4.5, size: 1});
174+
expect(gd._fullData[0].autobinx).toBe(true);
175+
expect(gd._fullData[0].autobiny).toBe(true);
176+
177+
// same range but fewer samples increases sizes
178+
Plotly.restyle(gd, {x: [[1, 3, 4]], y: [[1, 2, 4]]});
179+
expect(gd._fullData[0].xbins).toEqual({start: -0.5, end: 5.5, size: 2});
180+
expect(gd._fullData[0].ybins).toEqual({start: -0.5, end: 5.5, size: 2});
181+
expect(gd._fullData[0].autobinx).toBe(true);
182+
expect(gd._fullData[0].autobiny).toBe(true);
183+
184+
// larger range
185+
Plotly.restyle(gd, {x: [[10, 30, 40]], y: [[10, 20, 40]]});
186+
expect(gd._fullData[0].xbins).toEqual({start: -0.5, end: 59.5, size: 20});
187+
expect(gd._fullData[0].ybins).toEqual({start: -0.5, end: 59.5, size: 20});
188+
expect(gd._fullData[0].autobinx).toBe(true);
189+
expect(gd._fullData[0].autobiny).toBe(true);
190+
191+
// explicit changes to bin settings
192+
Plotly.restyle(gd, 'xbins.start', 12);
193+
expect(gd._fullData[0].xbins).toEqual({start: 12, end: 59.5, size: 20});
194+
expect(gd._fullData[0].ybins).toEqual({start: -0.5, end: 59.5, size: 20});
195+
expect(gd._fullData[0].autobinx).toBe(false);
196+
expect(gd._fullData[0].autobiny).toBe(true);
197+
198+
Plotly.restyle(gd, {'ybins.end': 12, 'ybins.size': 3});
199+
expect(gd._fullData[0].xbins).toEqual({start: 12, end: 59.5, size: 20});
200+
expect(gd._fullData[0].ybins).toEqual({start: -0.5, end: 12, size: 3});
201+
expect(gd._fullData[0].autobinx).toBe(false);
202+
expect(gd._fullData[0].autobiny).toBe(false);
203+
204+
// restart autobin
205+
Plotly.restyle(gd, {autobinx: true, autobiny: true});
206+
expect(gd._fullData[0].xbins).toEqual({start: -0.5, end: 59.5, size: 20});
207+
expect(gd._fullData[0].ybins).toEqual({start: -0.5, end: 59.5, size: 20});
208+
expect(gd._fullData[0].autobinx).toBe(true);
209+
expect(gd._fullData[0].autobiny).toBe(true);
210+
});
211+
212+
it('respects explicit autobin: false as a one-time autobin', function() {
213+
var x1 = [
214+
1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
215+
1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4];
216+
var y1 = [
217+
1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4,
218+
1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4];
219+
Plotly.newPlot(gd, [{type: 'histogram2d', x: x1, y: y1, autobinx: false, autobiny: false}]);
220+
expect(gd._fullData[0].xbins).toEqual({start: 0.5, end: 4.5, size: 1});
221+
expect(gd._fullData[0].ybins).toEqual({start: 0.5, end: 4.5, size: 1});
222+
expect(gd._fullData[0].autobinx).toBe(false);
223+
expect(gd._fullData[0].autobiny).toBe(false);
224+
225+
// with autobin false this will no longer update the bins.
226+
Plotly.restyle(gd, {x: [[1, 3, 4]], y: [[1, 2, 4]]});
227+
expect(gd._fullData[0].xbins).toEqual({start: 0.5, end: 4.5, size: 1});
228+
expect(gd._fullData[0].ybins).toEqual({start: 0.5, end: 4.5, size: 1});
229+
expect(gd._fullData[0].autobinx).toBe(false);
230+
expect(gd._fullData[0].autobiny).toBe(false);
231+
});
159232
});
160233

161234
});

test/jasmine/tests/histogram_test.js

+59
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
var Plotly = require('@lib/index');
12
var Plots = require('@src/plots/plots');
23
var Lib = require('@src/lib');
34

45
var supplyDefaults = require('@src/traces/histogram/defaults');
56
var calc = require('@src/traces/histogram/calc');
67

8+
var createGraphDiv = require('../assets/create_graph_div');
9+
var destroyGraphDiv = require('../assets/destroy_graph_div');
10+
711

812
describe('Test histogram', function() {
913
'use strict';
@@ -365,4 +369,59 @@ describe('Test histogram', function() {
365369
});
366370

367371
});
372+
373+
describe('plot / restyle', function() {
374+
var gd;
375+
376+
beforeEach(function() {
377+
gd = createGraphDiv();
378+
});
379+
380+
afterEach(destroyGraphDiv);
381+
382+
it('should update autobins correctly when restyling', function() {
383+
// note: I'm *not* testing what this does to gd.data, as that's
384+
// really a matter of convenience and will perhaps change later (v2?)
385+
var data1 = [1.5, 2, 2, 3, 3, 3, 4, 4, 5];
386+
Plotly.plot(gd, [{x: data1, type: 'histogram' }]);
387+
expect(gd._fullData[0].xbins).toEqual({start: 1, end: 6, size: 1});
388+
expect(gd._fullData[0].autobinx).toBe(true);
389+
390+
// same range but fewer samples changes autobin size
391+
var data2 = [1.5, 5];
392+
Plotly.restyle(gd, 'x', [data2]);
393+
expect(gd._fullData[0].xbins).toEqual({start: -2.5, end: 7.5, size: 5});
394+
expect(gd._fullData[0].autobinx).toBe(true);
395+
396+
// different range
397+
var data3 = [10, 20.2, 20, 30, 30, 30, 40, 40, 50];
398+
Plotly.restyle(gd, 'x', [data3]);
399+
expect(gd._fullData[0].xbins).toEqual({start: 5, end: 55, size: 10});
400+
expect(gd._fullData[0].autobinx).toBe(true);
401+
402+
// explicit change to a bin attribute clears autobin
403+
Plotly.restyle(gd, 'xbins.start', 3);
404+
expect(gd._fullData[0].xbins).toEqual({start: 3, end: 55, size: 10});
405+
expect(gd._fullData[0].autobinx).toBe(false);
406+
407+
// restart autobin
408+
Plotly.restyle(gd, 'autobinx', true);
409+
expect(gd._fullData[0].xbins).toEqual({start: 5, end: 55, size: 10});
410+
expect(gd._fullData[0].autobinx).toBe(true);
411+
});
412+
413+
it('respects explicit autobin: false as a one-time autobin', function() {
414+
var data1 = [1.5, 2, 2, 3, 3, 3, 4, 4, 5];
415+
Plotly.plot(gd, [{x: data1, type: 'histogram', autobinx: false }]);
416+
// we have no bins, so even though autobin is false we have to autobin once
417+
expect(gd._fullData[0].xbins).toEqual({start: 1, end: 6, size: 1});
418+
expect(gd._fullData[0].autobinx).toBe(false);
419+
420+
// since autobin is false, this will not change the bins
421+
var data2 = [1.5, 5];
422+
Plotly.restyle(gd, 'x', [data2]);
423+
expect(gd._fullData[0].xbins).toEqual({start: 1, end: 6, size: 1});
424+
expect(gd._fullData[0].autobinx).toBe(false);
425+
});
426+
});
368427
});

0 commit comments

Comments
 (0)