Skip to content

Commit 3875fcc

Browse files
committed
fast logic for axis expand where only data is an array
and use this instead of ad-hoc logic in scattergl and pointcloud
1 parent f262dc9 commit 3875fcc

File tree

4 files changed

+53
-66
lines changed

4 files changed

+53
-66
lines changed

src/plots/cartesian/autorange.js

+39-16
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ module.exports = {
1818
getAutoRange: getAutoRange,
1919
makePadFn: makePadFn,
2020
doAutoRange: doAutoRange,
21-
needsAutorange: needsAutorange,
2221
expand: expand
2322
};
2423

@@ -229,24 +228,48 @@ function expand(ax, data, options) {
229228
var len = data.length;
230229
var extrapad = options.padded || false;
231230
var tozero = options.tozero && (ax.type === 'linear' || ax.type === '-');
231+
var isLog = (ax.type === 'log');
232232

233233
var i, j, k, v, di, dmin, dmax, ppadiplus, ppadiminus, includeThis, vmin, vmax;
234234

235+
var hasArrayOption = false;
236+
235237
function makePadAccessor(item) {
236238
if(Array.isArray(item)) {
239+
hasArrayOption = true;
237240
return function(i) { return Math.max(Number(item[i]||0), 0); };
238241
}
239242
else {
240243
var v = Math.max(Number(item||0), 0);
241244
return function() { return v; };
242245
}
243246
}
247+
244248
var ppadplus = makePadAccessor((ax._m > 0 ?
245-
options.ppadplus : options.ppadminus) || options.ppad || 0),
246-
ppadminus = makePadAccessor((ax._m > 0 ?
247-
options.ppadminus : options.ppadplus) || options.ppad || 0),
248-
vpadplus = makePadAccessor(options.vpadplus || options.vpad),
249-
vpadminus = makePadAccessor(options.vpadminus || options.vpad);
249+
options.ppadplus : options.ppadminus) || options.ppad || 0);
250+
var ppadminus = makePadAccessor((ax._m > 0 ?
251+
options.ppadminus : options.ppadplus) || options.ppad || 0);
252+
var vpadplus = makePadAccessor(options.vpadplus || options.vpad);
253+
var vpadminus = makePadAccessor(options.vpadminus || options.vpad);
254+
255+
if(!hasArrayOption) {
256+
// with no arrays other than `data` we don't need to consider
257+
// every point, only the extreme data points
258+
vmin = Infinity;
259+
vmax = -Infinity;
260+
261+
for(i = 0; i < data.length; i++) {
262+
v = data[i];
263+
if(Math.abs(v) < FP_SAFE) {
264+
// data is not linearized yet so we still have to filter out negative logs
265+
if(v < vmin && (!isLog || v > 0)) vmin = v;
266+
if(v > vmax) vmax = v;
267+
}
268+
}
269+
270+
data = [vmin, vmax];
271+
len = 2;
272+
}
250273

251274
function addItem(i) {
252275
di = data[i];
@@ -259,7 +282,7 @@ function expand(ax, data, options) {
259282
// more than an order of mag, clip it to one order. This is so
260283
// we don't have non-positive errors or absurdly large lower
261284
// range due to rounding errors
262-
if(ax.type === 'log' && vmin < vmax / 10) vmin = vmax / 10;
285+
if(isLog && vmin < vmax / 10) vmin = vmax / 10;
263286

264287
dmin = ax.c2l(vmin);
265288
dmax = ax.c2l(vmax);
@@ -269,15 +292,6 @@ function expand(ax, data, options) {
269292
dmax = Math.max(0, dmax);
270293
}
271294

272-
// In order to stop overflow errors, don't consider points
273-
// too close to the limits of js floating point
274-
function goodNumber(v) {
275-
return isNumeric(v) && Math.abs(v) < FP_SAFE;
276-
}
277-
278-
function lessOrEqual(v0, v1) { return v0 <= v1; }
279-
function greaterOrEqual(v0, v1) { return v0 >= v1; }
280-
281295
for(k = 0; k < 2; k++) {
282296
var newVal = k ? dmax : dmin;
283297
if(goodNumber(newVal)) {
@@ -329,3 +343,12 @@ function expand(ax, data, options) {
329343
for(i = 0; i < 6; i++) addItem(i);
330344
for(i = len - 1; i > 5; i--) addItem(i);
331345
}
346+
347+
// In order to stop overflow errors, don't consider points
348+
// too close to the limits of js floating point
349+
function goodNumber(v) {
350+
return isNumeric(v) && Math.abs(v) < FP_SAFE;
351+
}
352+
353+
function lessOrEqual(v0, v1) { return v0 <= v1; }
354+
function greaterOrEqual(v0, v1) { return v0 >= v1; }

src/traces/pointcloud/convert.js

+3-14
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111
var createPointCloudRenderer = require('gl-pointcloud2d');
1212

1313
var str2RGBArray = require('../../lib/str2rgbarray');
14+
var expandAxis = require('../../plots/cartesian/autorange').expand;
1415
var getTraceColor = require('../scatter/get_trace_color');
1516

16-
var AXES = ['xaxis', 'yaxis'];
17-
1817
function Pointcloud(scene, uid) {
1918
this.scene = scene;
2019
this.uid = uid;
@@ -201,19 +200,9 @@ proto.updateFast = function(options) {
201200

202201
proto.expandAxesFast = function(bounds, markerSize) {
203202
var pad = markerSize || 0.5;
204-
var ax, min, max;
205-
206-
for(var i = 0; i < 2; i++) {
207-
ax = this.scene[AXES[i]];
208203

209-
min = ax._min;
210-
if(!min) min = [];
211-
min.push({ val: bounds[i], pad: pad });
212-
213-
max = ax._max;
214-
if(!max) max = [];
215-
max.push({ val: bounds[i + 2], pad: pad });
216-
}
204+
expandAxis(this.scene.xaxis, [bounds[0], bounds[2]], {ppad: pad});
205+
expandAxis(this.scene.yaxis, [bounds[1], bounds[3]], {ppad: pad});
217206
};
218207

219208
proto.dispose = function() {

src/traces/scattergl/index.js

+3-28
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ var arrayRange = require('array-range');
2020
var Registry = require('../../registry');
2121
var Lib = require('../../lib');
2222
var AxisIDs = require('../../plots/cartesian/axis_ids');
23-
var needsAutorange = require('../../plots/cartesian/autorange').needsAutorange;
2423
var Drawing = require('../../components/drawing');
2524
var formatColor = require('../../lib/gl_format_color');
2625

@@ -104,14 +103,10 @@ function calc(gd, trace) {
104103
// and an average size for array marker.size inputs.
105104
if(count < TOO_MANY_POINTS) {
106105
ppad = calcMarkerSize(trace, count);
107-
calcAxisExpansion(gd, trace, xa, ya, x, y, ppad);
108-
} else {
109-
if(markerOptions) {
110-
ppad = 2 * (markerOptions.sizeAvg || Math.max(markerOptions.size, 3));
111-
}
112-
fastAxisExpand(xa, x, ppad);
113-
fastAxisExpand(ya, y, ppad);
106+
} else if(markerOptions) {
107+
ppad = 2 * (markerOptions.sizeAvg || Math.max(markerOptions.size, 3));
114108
}
109+
calcAxisExpansion(gd, trace, xa, ya, x, y, ppad);
115110

116111
// set flags to create scene renderers
117112
if(options.fill && !scene.fill2d) scene.fill2d = true;
@@ -141,26 +136,6 @@ function calc(gd, trace) {
141136
return [{x: false, y: false, t: stash, trace: trace}];
142137
}
143138

144-
// Approximate Axes.expand results with speed
145-
function fastAxisExpand(ax, vals, ppad) {
146-
if(!needsAutorange(ax) || !vals) return;
147-
148-
var b0 = Infinity;
149-
var b1 = -Infinity;
150-
151-
for(var i = 0; i < vals.length; i += 2) {
152-
var v = vals[i];
153-
if(v < b0) b0 = v;
154-
if(v > b1) b1 = v;
155-
}
156-
157-
if(ax._min) ax._min = [];
158-
ax._min.push({val: b0, pad: ppad});
159-
160-
if(ax._max) ax._max = [];
161-
ax._max.push({val: b1, pad: ppad});
162-
}
163-
164139
// create scene options
165140
function sceneOptions(gd, subplot, trace, positions) {
166141
var fullLayout = gd._fullLayout;

test/jasmine/tests/gl2d_pointcloud_test.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,11 @@ describe('@gl pointcloud traces', function() {
165165
var mock = plotData;
166166
var scene2d;
167167

168-
var xBaselineMins = [{'val': 0, 'pad': 50}, {'val': 0, 'pad': 50}, {'val': 3, 'pad': 50}, {'val': 1, 'pad': 50}, {'val': 1, 'pad': 50}, {'val': 1, 'pad': 50}, {'val': 1, 'pad': 50}];
169-
var xBaselineMaxes = [{'val': 9, 'pad': 50}, {'val': 9, 'pad': 50}, {'val': 6, 'pad': 50}, {'val': 9, 'pad': 50}, {'val': 9, 'pad': 50}, {'val': 9, 'pad': 50}, {'val': 9, 'pad': 50}];
168+
var xBaselineMins = [{val: 0, pad: 50, extrapad: false}];
169+
var xBaselineMaxes = [{val: 9, pad: 50, extrapad: false}];
170170

171-
var yBaselineMins = [{'val': 0, 'pad': 50}, {'val': 0, 'pad': 50}, {'val': 9, 'pad': 50}, {'val': 3, 'pad': 50}, {'val': 4, 'pad': 50}, {'val': 5, 'pad': 50}, {'val': 6, 'pad': 50}];
172-
var yBaselineMaxes = [{'val': 9, 'pad': 50}, {'val': 9, 'pad': 50}, {'val': 9, 'pad': 50}, {'val': 3, 'pad': 50}, {'val': 4, 'pad': 50}, {'val': 5, 'pad': 50}, {'val': 6, 'pad': 50}];
171+
var yBaselineMins = [{val: 0, pad: 50, extrapad: false}];
172+
var yBaselineMaxes = [{val: 9, pad: 50, extrapad: false}];
173173

174174
Plotly.plot(gd, mock.data, mock.layout).then(function() {
175175
scene2d = gd._fullLayout._plots.xy._scene2d;
@@ -185,8 +185,8 @@ describe('@gl pointcloud traces', function() {
185185
return Plotly.relayout(gd, 'xaxis.range', [3, 6]);
186186
}).then(function() {
187187

188-
expect(scene2d.xaxis._min).toEqual(xBaselineMins);
189-
expect(scene2d.xaxis._max).toEqual(xBaselineMaxes);
188+
expect(scene2d.xaxis._min).toEqual([]);
189+
expect(scene2d.xaxis._max).toEqual([]);
190190

191191
return Plotly.relayout(gd, 'xaxis.autorange', true);
192192
}).then(function() {
@@ -197,8 +197,8 @@ describe('@gl pointcloud traces', function() {
197197
return Plotly.relayout(gd, 'yaxis.range', [8, 20]);
198198
}).then(function() {
199199

200-
expect(scene2d.yaxis._min).toEqual(yBaselineMins);
201-
expect(scene2d.yaxis._max).toEqual(yBaselineMaxes);
200+
expect(scene2d.yaxis._min).toEqual([]);
201+
expect(scene2d.yaxis._max).toEqual([]);
202202

203203
return Plotly.relayout(gd, 'yaxis.autorange', true);
204204
}).then(function() {

0 commit comments

Comments
 (0)