Skip to content

Commit 89093ad

Browse files
committed
handle _pos0 totally inside calcAllAutoBins
1 parent 3f173a4 commit 89093ad

File tree

1 file changed

+95
-97
lines changed

1 file changed

+95
-97
lines changed

src/traces/histogram/calc.js

Lines changed: 95 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,9 @@ module.exports = function calc(gd, trace) {
4040

4141
cleanBins(trace, pa, maindata);
4242

43-
var binspec = calcAllAutoBins(gd, trace, pa, maindata);
44-
45-
// the raw data was prepared in calcAllAutoBins (during the first trace in
46-
// this group) and stashed. Pull it out and drop the stash
47-
var pos0 = trace._pos0;
48-
delete trace._pos0;
43+
var binsAndPos = calcAllAutoBins(gd, trace, pa, maindata);
44+
var binspec = binsAndPos[0];
45+
var pos0 = binsAndPos[1];
4946

5047
var nonuniformBins = typeof binspec.size === 'string';
5148
var bins = nonuniformBins ? [] : binspec;
@@ -166,115 +163,116 @@ module.exports = function calc(gd, trace) {
166163
*/
167164
function calcAllAutoBins(gd, trace, pa, maindata) {
168165
var binAttr = maindata + 'bins';
166+
var i, tracei, calendar, firstManual, pos0;
169167

170168
// all but the first trace in this group has already been marked finished
171169
// clear this flag, so next time we run calc we will run autobin again
172170
if(trace._autoBinFinished) {
173171
delete trace._autoBinFinished;
174-
175-
return trace[binAttr];
176172
}
173+
else {
174+
// must be the first trace in the group - do the autobinning on them all
175+
var traceGroup = getConnectedHistograms(gd, trace);
176+
var autoBinnedTraces = [];
177+
178+
var minSize = Infinity;
179+
var minStart = Infinity;
180+
var maxEnd = -Infinity;
181+
182+
var autoBinAttr = 'autobin' + maindata;
183+
184+
for(i = 0; i < traceGroup.length; i++) {
185+
tracei = traceGroup[i];
186+
187+
// stash pos0 on the trace so we don't need to duplicate this
188+
// in the main body of calc
189+
pos0 = tracei._pos0 = pa.makeCalcdata(tracei, maindata);
190+
var binspec = tracei[binAttr];
191+
192+
if((tracei[autoBinAttr]) || !binspec ||
193+
binspec.start === null || binspec.end === null) {
194+
calendar = tracei[maindata + 'calendar'];
195+
var cumulativeSpec = tracei.cumulative;
196+
197+
binspec = Axes.autoBin(pos0, pa, tracei['nbins' + maindata], false, calendar);
198+
199+
// adjust for CDF edge cases
200+
if(cumulativeSpec.enabled && (cumulativeSpec.currentbin !== 'include')) {
201+
if(cumulativeSpec.direction === 'decreasing') {
202+
minStart = Math.min(minStart, pa.r2c(binspec.start, 0, calendar) - binspec.size);
203+
}
204+
else {
205+
maxEnd = Math.max(maxEnd, pa.r2c(binspec.end, 0, calendar) + binspec.size);
206+
}
207+
}
177208

178-
// must be the first trace in the group - do the autobinning on them all
179-
var traceGroup = getConnectedHistograms(gd, trace);
180-
var autoBinnedTraces = [];
181-
182-
var minSize = Infinity;
183-
var minStart = Infinity;
184-
var maxEnd = -Infinity;
185-
186-
var autoBinAttr = 'autobin' + maindata;
187-
var i, tracei, calendar, firstManual;
188-
209+
// note that it's possible to get here with an explicit autobin: false
210+
// if the bins were not specified. mark this trace for followup
211+
autoBinnedTraces.push(tracei);
212+
}
213+
else if(!firstManual) {
214+
// Remember the first manually set binspec. We'll try to be extra
215+
// accommodating of this one, so other bins line up with these
216+
// if there's more than one manual bin set and they're mutually inconsistent,
217+
// then there's not much we can do...
218+
firstManual = {
219+
size: binspec.size,
220+
start: pa.r2c(binspec.start, 0, calendar),
221+
end: pa.r2c(binspec.end, 0, calendar)
222+
};
223+
}
189224

190-
for(i = 0; i < traceGroup.length; i++) {
191-
tracei = traceGroup[i];
225+
// Even non-autobinned traces get included here, so we get the greatest extent
226+
// and minimum bin size of them all.
227+
// But manually binned traces won't be adjusted, even if the auto values
228+
// are inconsistent with the manual ones (or the manual ones are inconsistent
229+
// with each other).
230+
minSize = getMinSize(minSize, binspec.size);
231+
minStart = Math.min(minStart, pa.r2c(binspec.start, 0, calendar));
232+
maxEnd = Math.max(maxEnd, pa.r2c(binspec.end, 0, calendar));
233+
234+
// add the flag that lets us abort autobin on later traces
235+
if(i) trace._autoBinFinished = 1;
236+
}
192237

193-
// stash pos0 on the trace so we don't need to duplicate this
194-
// in the main body of calc
195-
var pos0 = tracei._pos0 = pa.makeCalcdata(tracei, maindata);
196-
var binspec = tracei[binAttr];
238+
// do what we can to match the auto bins to the first manual bins
239+
// but only if sizes are all numeric
240+
if(firstManual && isNumeric(firstManual.size) && isNumeric(minSize)) {
241+
// first need to ensure the bin size is the same as or an integer fraction
242+
// of the first manual bin
243+
// allow the bin size to increase just under the autobin step size to match,
244+
// (which is a factor of 2 or 2.5) otherwise shrink it
245+
if(minSize > firstManual.size / 1.9) minSize = firstManual.size;
246+
else minSize = firstManual.size / Math.ceil(firstManual.size / minSize);
247+
248+
// now decrease minStart if needed to make the bin centers line up
249+
var adjustedFirstStart = firstManual.start + (firstManual.size - minSize) / 2;
250+
minStart = adjustedFirstStart - minSize * Math.ceil((adjustedFirstStart - minStart) / minSize);
251+
}
197252

198-
if((tracei[autoBinAttr]) || !binspec ||
199-
binspec.start === null || binspec.end === null) {
253+
// now go back to the autobinned traces and update their bin specs with the final values
254+
for(i = 0; i < autoBinnedTraces.length; i++) {
255+
tracei = autoBinnedTraces[i];
200256
calendar = tracei[maindata + 'calendar'];
201-
var cumulativeSpec = tracei.cumulative;
202-
203-
binspec = Axes.autoBin(pos0, pa, tracei['nbins' + maindata], false, calendar);
204257

205-
// adjust for CDF edge cases
206-
if(cumulativeSpec.enabled && (cumulativeSpec.currentbin !== 'include')) {
207-
if(cumulativeSpec.direction === 'decreasing') {
208-
minStart = Math.min(minStart, pa.r2c(binspec.start, 0, calendar) - binspec.size);
209-
}
210-
else {
211-
maxEnd = Math.max(maxEnd, pa.r2c(binspec.end, 0, calendar) + binspec.size);
212-
}
213-
}
258+
tracei._input[binAttr] = tracei[binAttr] = {
259+
start: pa.c2r(minStart, 0, calendar),
260+
end: pa.c2r(maxEnd, 0, calendar),
261+
size: minSize
262+
};
214263

215264
// note that it's possible to get here with an explicit autobin: false
216-
// if the bins were not specified. mark this trace for followup
217-
autoBinnedTraces.push(tracei);
265+
// if the bins were not specified.
266+
// in that case this will remain in the trace, so that future updates
267+
// which would change the autobinning will not do so.
268+
tracei._input[autoBinAttr] = tracei[autoBinAttr];
218269
}
219-
else if(!firstManual) {
220-
// Remember the first manually set binspec. We'll try to be extra
221-
// accommodating of this one, so other bins line up with these
222-
// if there's more than one manual bin set and they're mutually inconsistent,
223-
// then there's not much we can do...
224-
firstManual = {
225-
size: binspec.size,
226-
start: pa.r2c(binspec.start, 0, calendar),
227-
end: pa.r2c(binspec.end, 0, calendar)
228-
};
229-
}
230-
231-
// Even non-autobinned traces get included here, so we get the greatest extent
232-
// and minimum bin size of them all.
233-
// But manually binned traces won't be adjusted, even if the auto values
234-
// are inconsistent with the manual ones (or the manual ones are inconsistent
235-
// with each other).
236-
minSize = getMinSize(minSize, binspec.size);
237-
minStart = Math.min(minStart, pa.r2c(binspec.start, 0, calendar));
238-
maxEnd = Math.max(maxEnd, pa.r2c(binspec.end, 0, calendar));
239-
240-
// add the flag that lets us abort autobin on later traces
241-
if(i) trace._autoBinFinished = 1;
242270
}
243271

244-
// do what we can to match the auto bins to the first manual bins
245-
// but only if sizes are all numeric
246-
if(firstManual && isNumeric(firstManual.size) && isNumeric(minSize)) {
247-
// first need to ensure the bin size is the same as or an integer fraction
248-
// of the first manual bin
249-
// allow the bin size to increase just under the autobin step size to match,
250-
// (which is a factor of 2 or 2.5) otherwise shrink it
251-
if(minSize > firstManual.size / 1.9) minSize = firstManual.size;
252-
else minSize = firstManual.size / Math.ceil(firstManual.size / minSize);
253-
254-
// now decrease minStart if needed to make the bin centers line up
255-
var adjustedFirstStart = firstManual.start + (firstManual.size - minSize) / 2;
256-
minStart = adjustedFirstStart - minSize * Math.ceil((adjustedFirstStart - minStart) / minSize);
257-
}
258-
259-
// now go back to the autobinned traces and update their bin specs with the final values
260-
for(i = 0; i < autoBinnedTraces.length; i++) {
261-
tracei = autoBinnedTraces[i];
262-
calendar = tracei[maindata + 'calendar'];
263-
264-
tracei._input[binAttr] = tracei[binAttr] = {
265-
start: pa.c2r(minStart, 0, calendar),
266-
end: pa.c2r(maxEnd, 0, calendar),
267-
size: minSize
268-
};
269-
270-
// note that it's possible to get here with an explicit autobin: false
271-
// if the bins were not specified.
272-
// in that case this will remain in the trace, so that future updates
273-
// which would change the autobinning will not do so.
274-
tracei._input[autoBinAttr] = tracei[autoBinAttr];
275-
}
272+
pos0 = trace._pos0;
273+
delete trace._pos0;
276274

277-
return trace[binAttr];
275+
return [trace[binAttr], pos0];
278276
}
279277

280278
/*

0 commit comments

Comments
 (0)