Skip to content

Commit a0bfaf3

Browse files
committed
collapse trace extremes before getAutorange
... by factoring out logic from findExtremes
1 parent 72f06a6 commit a0bfaf3

File tree

1 file changed

+89
-51
lines changed

1 file changed

+89
-51
lines changed

src/plots/cartesian/autorange.js

+89-51
Original file line numberDiff line numberDiff line change
@@ -195,14 +195,21 @@ function concatExtremes(gd, ax) {
195195
var fullLayout = gd._fullLayout;
196196
var minArray = [];
197197
var maxArray = [];
198+
var i, j, d;
198199

199200
function _concat(cont, indices) {
200-
for(var i = 0; i < indices.length; i++) {
201+
for(i = 0; i < indices.length; i++) {
201202
var item = cont[indices[i]];
202203
var extremes = (item._extremes || {})[axId];
203204
if(item.visible === true && extremes) {
204-
minArray = minArray.concat(extremes.min);
205-
maxArray = maxArray.concat(extremes.max);
205+
for(j = 0; j < extremes.min.length; j++) {
206+
d = extremes.min[j];
207+
collapseMinArray(minArray, d.val, d.pad, {extrapad: d.extrapad});
208+
}
209+
for(j = 0; j < extremes.max.length; j++) {
210+
d = extremes.max[j];
211+
collapseMaxArray(maxArray, d.val, d.pad, {extrapad: d.extrapad});
212+
}
206213
}
207214
}
208215
}
@@ -211,8 +218,6 @@ function concatExtremes(gd, ax) {
211218
_concat(fullLayout.annotations || [], ax._annIndices || []);
212219
_concat(fullLayout.shapes || [], ax._shapeIndices || []);
213220

214-
// TODO collapse more!
215-
216221
return {min: minArray, max: maxArray};
217222
}
218223

@@ -295,11 +300,9 @@ function findExtremes(ax, data, options) {
295300
var len = data.length;
296301
var extrapad = options.padded || false;
297302
var tozero = options.tozero && (ax.type === 'linear' || ax.type === '-');
298-
var isLog = (ax.type === 'log');
299-
300-
var i, j, k, v, di, dmin, dmax, ppadiplus, ppadiminus, includeThis, vmin, vmax;
301-
303+
var isLog = ax.type === 'log';
302304
var hasArrayOption = false;
305+
var i, v, di, dmin, dmax, ppadiplus, ppadiminus, vmin, vmax;
303306

304307
function makePadAccessor(item) {
305308
if(Array.isArray(item)) {
@@ -344,6 +347,8 @@ function findExtremes(ax, data, options) {
344347
len = 2;
345348
}
346349

350+
var collapseOpts = {tozero: tozero, extrapad: extrapad};
351+
347352
function addItem(i) {
348353
di = data[i];
349354
if(!isNumeric(di)) return;
@@ -364,48 +369,11 @@ function findExtremes(ax, data, options) {
364369
dmin = Math.min(0, dmin);
365370
dmax = Math.max(0, dmax);
366371
}
367-
368-
for(k = 0; k < 2; k++) {
369-
var newVal = k ? dmax : dmin;
370-
if(goodNumber(newVal)) {
371-
var extremes = k ? maxArray : minArray;
372-
var newPad = k ? ppadiplus : ppadiminus;
373-
var atLeastAsExtreme = k ? greaterOrEqual : lessOrEqual;
374-
375-
includeThis = true;
376-
/*
377-
* Take items v from ax._min/_max and compare them to the presently active point:
378-
* - Since we don't yet know the relationship between pixels and values
379-
* (that's what we're trying to figure out!) AND we don't yet know how
380-
* many pixels `extrapad` represents (it's going to be 5% of the length,
381-
* but we don't want to have to redo _min and _max just because length changed)
382-
* two point must satisfy three criteria simultaneously for one to supersede the other:
383-
* - at least as extreme a `val`
384-
* - at least as big a `pad`
385-
* - an unpadded point cannot supersede a padded point, but any other combination can
386-
*
387-
* - If the item supersedes the new point, set includethis false
388-
* - If the new pt supersedes the item, delete it from ax._min/_max
389-
*/
390-
for(j = 0; j < extremes.length && includeThis; j++) {
391-
v = extremes[j];
392-
if(atLeastAsExtreme(v.val, newVal) && v.pad >= newPad && (v.extrapad || !extrapad)) {
393-
includeThis = false;
394-
break;
395-
} else if(atLeastAsExtreme(newVal, v.val) && v.pad <= newPad && (extrapad || !v.extrapad)) {
396-
extremes.splice(j, 1);
397-
j--;
398-
}
399-
}
400-
if(includeThis) {
401-
var clipAtZero = (tozero && newVal === 0);
402-
extremes.push({
403-
val: newVal,
404-
pad: clipAtZero ? 0 : newPad,
405-
extrapad: clipAtZero ? false : extrapad
406-
});
407-
}
408-
}
372+
if(goodNumber(dmin)) {
373+
collapseMinArray(minArray, dmin, ppadiminus, collapseOpts);
374+
}
375+
if(goodNumber(dmax)) {
376+
collapseMaxArray(maxArray, dmax, ppadiplus, collapseOpts);
409377
}
410378
}
411379

@@ -419,6 +387,76 @@ function findExtremes(ax, data, options) {
419387
return {min: minArray, max: maxArray};
420388
}
421389

390+
function collapseMinArray(array, newVal, newPad, opts) {
391+
collapseArray(array, newVal, newPad, opts, lessOrEqual);
392+
}
393+
394+
function collapseMaxArray(array, newVal, newPad, opts) {
395+
collapseArray(array, newVal, newPad, opts, greaterOrEqual);
396+
}
397+
398+
/**
399+
* collapseArray
400+
*
401+
* Take items v from 'array' compare them to 'newVal', 'newPad'
402+
*
403+
* @param {array} array:
404+
* current set of min or max extremes
405+
* @param {number} newVal:
406+
* new value to compare against
407+
* @param {number} newPad:
408+
* pad value associated with 'newVal'
409+
* @param {object} opts:
410+
* - tozero {boolean}
411+
* - extrapad {number}
412+
* @param {function} atLeastAsExtreme:
413+
* comparison function, use
414+
* - lessOrEqual for min 'array' and
415+
* - greaterOrEqual for max 'array'
416+
*
417+
* In practice, 'array' is either
418+
* - 'extremes[ax._id].min' or
419+
* - 'extremes[ax._id].max
420+
* found in traces and layout items that affect autorange.
421+
*
422+
* Since we don't yet know the relationship between pixels and values
423+
* (that's what we're trying to figure out!) AND we don't yet know how
424+
* many pixels `extrapad` represents (it's going to be 5% of the length,
425+
* but we don't want to have to redo calc just because length changed)
426+
* two point must satisfy three criteria simultaneously for one to supersede the other:
427+
* - at least as extreme a `val`
428+
* - at least as big a `pad`
429+
* - an unpadded point cannot supersede a padded point, but any other combination can
430+
*
431+
* Then:
432+
* - If the item supersedes the new point, set includeThis false
433+
* - If the new pt supersedes the item, delete it from 'array'
434+
*/
435+
function collapseArray(array, newVal, newPad, opts, atLeastAsExtreme) {
436+
var tozero = opts.tozero;
437+
var extrapad = opts.extrapad;
438+
var includeThis = true;
439+
440+
for(var j = 0; j < array.length && includeThis; j++) {
441+
var v = array[j];
442+
if(atLeastAsExtreme(v.val, newVal) && v.pad >= newPad && (v.extrapad || !extrapad)) {
443+
includeThis = false;
444+
break;
445+
} else if(atLeastAsExtreme(newVal, v.val) && v.pad <= newPad && (extrapad || !v.extrapad)) {
446+
array.splice(j, 1);
447+
j--;
448+
}
449+
}
450+
if(includeThis) {
451+
var clipAtZero = (tozero && newVal === 0);
452+
array.push({
453+
val: newVal,
454+
pad: clipAtZero ? 0 : newPad,
455+
extrapad: clipAtZero ? false : extrapad
456+
});
457+
}
458+
}
459+
422460
// In order to stop overflow errors, don't consider points
423461
// too close to the limits of js floating point
424462
function goodNumber(v) {

0 commit comments

Comments
 (0)