Skip to content

Commit 72f06a6

Browse files
committed
improve concatExtremes perf
- by using ax.(_traceIndices, annIndices, shapeIndices), to keep track of traces, annotations and shapes plotted on axis ax. Adapt concatExtremes accordingly!
1 parent 29db388 commit 72f06a6

File tree

12 files changed

+114
-92
lines changed

12 files changed

+114
-92
lines changed

src/components/annotations/defaults.js

+5
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ function handleAnnotationDefaults(annIn, annOut, fullLayout) {
4848
// xref, yref
4949
var axRef = Axes.coerceRef(annIn, annOut, gdMock, axLetter, '', 'paper');
5050

51+
if(axRef !== 'paper') {
52+
var ax = Axes.getFromId(gdMock, axRef);
53+
ax._annIndices.push(annOut._index);
54+
}
55+
5156
// x, y
5257
Axes.coercePosition(annOut, gdMock, coerce, axRef, axLetter, 0.5);
5358

src/components/shapes/defaults.js

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ function handleShapeDefaults(shapeIn, shapeOut, fullLayout) {
6161

6262
if(axRef !== 'paper') {
6363
ax = Axes.getFromId(gdMock, axRef);
64+
ax._shapeIndices.push(shapeOut._index);
6465
r2pos = helpers.rangeToShapePosition(ax);
6566
pos2r = helpers.shapePositionToRange(ax);
6667
}

src/plots/cartesian/autorange.js

+29-55
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ var isNumeric = require('fast-isnumeric');
1313
var Lib = require('../../lib');
1414
var FP_SAFE = require('../../constants/numerical').FP_SAFE;
1515

16-
var Registry = require('../../registry');
17-
1816
module.exports = {
1917
getAutoRange: getAutoRange,
2018
makePadFn: makePadFn,
@@ -31,16 +29,17 @@ module.exports = {
3129
*
3230
* getAutoRange uses return values from findExtremes where:
3331
*
34-
* {
35-
* val: calcdata value,
36-
* pad: extra pixels beyond this value,
37-
* extrapad: bool, does this point want 5% extra padding
38-
* }
39-
*
4032
* @param {object} gd:
41-
* graph div object with filled in fullData and fullLayout,
33+
* graph div object with filled-in fullData and fullLayout, in particular
34+
* with filled-in '_extremes' containers:
35+
* {
36+
* val: calcdata value,
37+
* pad: extra pixels beyond this value,
38+
* extrapad: bool, does this point want 5% extra padding
39+
* }
4240
* @param {object} ax:
43-
* full axis object
41+
* full axis object, in particular with filled-in '_traceIndices'
42+
* and '_annIndices' / '_shapeIndices' if applicable
4443
* @return {array}
4544
* an array of [min, max]. These are calcdata for log and category axes
4645
* and data for linear and date axes.
@@ -55,8 +54,9 @@ function getAutoRange(gd, ax) {
5554
var newRange = [];
5655

5756
var getPad = makePadFn(ax);
58-
var minArray = concatExtremes(gd, ax, 'min');
59-
var maxArray = concatExtremes(gd, ax, 'max');
57+
var extremes = concatExtremes(gd, ax);
58+
var minArray = extremes.min;
59+
var maxArray = extremes.max;
6060

6161
if(minArray.length === 0 || maxArray.length === 0) {
6262
return Lib.simpleMap(ax.range, ax.r2l);
@@ -189,57 +189,31 @@ function makePadFn(ax) {
189189
return function getPad(pt) { return pt.pad + (pt.extrapad ? extrappad : 0); };
190190
}
191191

192-
function concatExtremes(gd, ax, ext) {
193-
var i;
194-
var out = [];
195-
192+
function concatExtremes(gd, ax) {
193+
var axId = ax._id;
196194
var fullData = gd._fullData;
195+
var fullLayout = gd._fullLayout;
196+
var minArray = [];
197+
var maxArray = [];
197198

198-
for(i = 0; i < fullData.length; i++) {
199-
var trace = fullData[i];
200-
var extremes = trace._extremes;
201-
202-
if(trace.visible === true) {
203-
if(Registry.traceIs(trace, 'cartesian') || Registry.traceIs(trace, 'gl2d')) {
204-
var axId = ax._id;
205-
if(extremes[axId]) {
206-
out = out.concat(extremes[axId][ext]);
207-
}
208-
} else if(Registry.traceIs(trace, 'polar')) {
209-
if(trace.subplot === ax._subplot) {
210-
out = out.concat(extremes[ax._name][ext]);
211-
}
199+
function _concat(cont, indices) {
200+
for(var i = 0; i < indices.length; i++) {
201+
var item = cont[indices[i]];
202+
var extremes = (item._extremes || {})[axId];
203+
if(item.visible === true && extremes) {
204+
minArray = minArray.concat(extremes.min);
205+
maxArray = maxArray.concat(extremes.max);
212206
}
213207
}
214208
}
215209

216-
var fullLayout = gd._fullLayout;
217-
var annotations = fullLayout.annotations;
218-
var shapes = fullLayout.shapes;
219-
220-
if(Array.isArray(annotations)) {
221-
out = out.concat(concatComponentExtremes(annotations, ax, ext));
222-
}
223-
if(Array.isArray(shapes)) {
224-
out = out.concat(concatComponentExtremes(shapes, ax, ext));
225-
}
226-
227-
return out;
228-
}
210+
_concat(fullData, ax._traceIndices);
211+
_concat(fullLayout.annotations || [], ax._annIndices || []);
212+
_concat(fullLayout.shapes || [], ax._shapeIndices || []);
229213

230-
function concatComponentExtremes(items, ax, ext) {
231-
var out = [];
232-
var axId = ax._id;
233-
var letter = axId.charAt(0);
214+
// TODO collapse more!
234215

235-
for(var i = 0; i < items.length; i++) {
236-
var d = items[i];
237-
var extremes = d._extremes;
238-
if(d.visible && d[letter + 'ref'] === axId && extremes[axId]) {
239-
out = out.concat(extremes[axId][ext]);
240-
}
241-
}
242-
return out;
216+
return {min: minArray, max: maxArray};
243217
}
244218

245219
function doAutoRange(gd, ax) {

src/plots/cartesian/constraints.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -141,18 +141,19 @@ exports.enforce = function enforceAxisConstraints(gd) {
141141
updateDomain(ax, factor);
142142
ax.setScale();
143143
var m = Math.abs(ax._m);
144+
var extremes = concatExtremes(gd, ax);
145+
var minArray = extremes.min;
146+
var maxArray = extremes.max;
144147
var newVal;
145148
var k;
146149

147-
var minArray = concatExtremes(gd, ax, 'min');
148150
for(k = 0; k < minArray.length; k++) {
149151
newVal = minArray[k].val - getPad(minArray[k]) / m;
150152
if(newVal > outerMin && newVal < rangeMin) {
151153
rangeMin = newVal;
152154
}
153155
}
154156

155-
var maxArray = concatExtremes(gd, ax, 'max');
156157
for(k = 0; k < maxArray.length; k++) {
157158
newVal = maxArray[k].val + getPad(maxArray[k]) / m;
158159
if(newVal < outerMax && newVal > rangeMax) {

src/plots/cartesian/layout_defaults.js

+51-21
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
'use strict';
1111

12-
var Registry = require('../../registry');
1312
var Lib = require('../../lib');
1413
var Color = require('../../components/color');
1514
var Template = require('../../plot_api/plot_template');
@@ -20,31 +19,57 @@ var handleTypeDefaults = require('./type_defaults');
2019
var handleAxisDefaults = require('./axis_defaults');
2120
var handleConstraintDefaults = require('./constraint_defaults');
2221
var handlePositionDefaults = require('./position_defaults');
22+
2323
var axisIds = require('./axis_ids');
24+
var id2name = axisIds.id2name;
25+
var name2id = axisIds.name2id;
2426

27+
var Registry = require('../../registry');
28+
var traceIs = Registry.traceIs;
29+
var getComponentMethod = Registry.getComponentMethod;
30+
31+
function appendList(cont, k, item) {
32+
if(Array.isArray(cont[k])) cont[k].push(item);
33+
else cont[k] = [item];
34+
}
2535

2636
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
37+
var ax2traces = {};
2738
var xaCheater = {};
2839
var xaNonCheater = {};
2940
var outerTicks = {};
3041
var noGrids = {};
31-
var i;
42+
var i, j;
3243

3344
// look for axes in the data
3445
for(i = 0; i < fullData.length; i++) {
3546
var trace = fullData[i];
36-
37-
if(!Registry.traceIs(trace, 'cartesian') && !Registry.traceIs(trace, 'gl2d')) {
38-
continue;
47+
if(!traceIs(trace, 'cartesian') && !traceIs(trace, 'gl2d')) continue;
48+
49+
var xaName;
50+
if(trace.xaxis) {
51+
xaName = id2name(trace.xaxis);
52+
appendList(ax2traces, xaName, trace);
53+
} else if(trace.xaxes) {
54+
for(j = 0; j < trace.xaxes.length; j++) {
55+
appendList(ax2traces, id2name(trace.xaxes[j]), trace);
56+
}
3957
}
4058

41-
var xaName = axisIds.id2name(trace.xaxis);
42-
var yaName = axisIds.id2name(trace.yaxis);
59+
var yaName;
60+
if(trace.yaxis) {
61+
yaName = id2name(trace.yaxis);
62+
appendList(ax2traces, yaName, trace);
63+
} else if(trace.yaxes) {
64+
for(j = 0; j < trace.yaxes.length; j++) {
65+
appendList(ax2traces, id2name(trace.yaxes[j]), trace);
66+
}
67+
}
4368

4469
// Two things trigger axis visibility:
4570
// 1. is not carpet
4671
// 2. carpet that's not cheater
47-
if(!Registry.traceIs(trace, 'carpet') || (trace.type === 'carpet' && !trace._cheater)) {
72+
if(!traceIs(trace, 'carpet') || (trace.type === 'carpet' && !trace._cheater)) {
4873
if(xaName) xaNonCheater[xaName] = 1;
4974
}
5075

@@ -57,22 +82,22 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
5782
}
5883

5984
// check for default formatting tweaks
60-
if(Registry.traceIs(trace, '2dMap')) {
61-
outerTicks[xaName] = true;
62-
outerTicks[yaName] = true;
85+
if(traceIs(trace, '2dMap')) {
86+
outerTicks[xaName] = 1;
87+
outerTicks[yaName] = 1;
6388
}
6489

65-
if(Registry.traceIs(trace, 'oriented')) {
90+
if(traceIs(trace, 'oriented')) {
6691
var positionAxis = trace.orientation === 'h' ? yaName : xaName;
67-
noGrids[positionAxis] = true;
92+
noGrids[positionAxis] = 1;
6893
}
6994
}
7095

7196
var subplots = layoutOut._subplots;
7297
var xIds = subplots.xaxis;
7398
var yIds = subplots.yaxis;
74-
var xNames = Lib.simpleMap(xIds, axisIds.id2name);
75-
var yNames = Lib.simpleMap(yIds, axisIds.id2name);
99+
var xNames = Lib.simpleMap(xIds, id2name);
100+
var yNames = Lib.simpleMap(yIds, id2name);
76101
var axNames = xNames.concat(yNames);
77102

78103
// plot_bgcolor only makes sense if there's a (2D) plot!
@@ -108,7 +133,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
108133
var axName2 = list[j];
109134

110135
if(axName2 !== axName && !(layoutIn[axName2] || {}).overlaying) {
111-
out.push(axisIds.name2id(axName2));
136+
out.push(name2id(axName2));
112137
}
113138
}
114139

@@ -127,7 +152,12 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
127152
axLayoutIn = layoutIn[axName];
128153
axLayoutOut = Template.newContainer(layoutOut, axName, axLetter + 'axis');
129154

130-
handleTypeDefaults(axLayoutIn, axLayoutOut, coerce, fullData, axName);
155+
var traces = ax2traces[axName] || [];
156+
axLayoutOut._traceIndices = traces.map(function(t) { return t._expandedIndex; });
157+
axLayoutOut._annIndices = [];
158+
axLayoutOut._shapeIndices = [];
159+
160+
handleTypeDefaults(axLayoutIn, axLayoutOut, coerce, traces, axName);
131161

132162
var overlayableAxes = getOverlayableAxes(axLetter, axName);
133163

@@ -136,7 +166,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
136166
font: layoutOut.font,
137167
outerTicks: outerTicks[axName],
138168
showGrid: !noGrids[axName],
139-
data: fullData,
169+
data: traces,
140170
bgColor: bgColor,
141171
calendar: layoutOut.calendar,
142172
automargin: true,
@@ -173,8 +203,8 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
173203
}
174204

175205
// quick second pass for range slider and selector defaults
176-
var rangeSliderDefaults = Registry.getComponentMethod('rangeslider', 'handleDefaults');
177-
var rangeSelectorDefaults = Registry.getComponentMethod('rangeselector', 'handleDefaults');
206+
var rangeSliderDefaults = getComponentMethod('rangeslider', 'handleDefaults');
207+
var rangeSelectorDefaults = getComponentMethod('rangeselector', 'handleDefaults');
178208

179209
for(i = 0; i < xNames.length; i++) {
180210
axName = xNames[i];
@@ -201,7 +231,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
201231
axLayoutIn = layoutIn[axName];
202232
axLayoutOut = layoutOut[axName];
203233

204-
var anchoredAxis = layoutOut[axisIds.id2name(axLayoutOut.anchor)];
234+
var anchoredAxis = layoutOut[id2name(axLayoutOut.anchor)];
205235

206236
var fixedRangeDflt = (
207237
anchoredAxis &&

src/plots/polar/layout_defaults.js

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ function handleDefaults(contIn, contOut, coerce, opts) {
5555
// propagate the template.
5656
var axOut = contOut[axName] = {};
5757
axOut._id = axOut._name = axName;
58+
axOut._traceIndices = subplotData.map(function(t) { return t.index; });
5859

5960
var dataAttr = constants.axisName2dataArray[axName];
6061
var axType = handleAxisTypeDefaults(axIn, axOut, coerceAxis, subplotData, dataAttr);

src/plots/polar/polar.js

-1
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,6 @@ proto.updateLayout = function(fullLayout, polarLayout) {
300300
proto.doAutoRange = function(fullLayout, polarLayout) {
301301
var radialLayout = polarLayout.radialaxis;
302302
var ax = this.radialAxis;
303-
ax._subplot = this.id;
304303

305304
setScale(ax, radialLayout, fullLayout);
306305
doAutoRange(this.gd, ax);

src/traces/scatterpolar/calc.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ module.exports = function calc(gd, trace) {
4848
}
4949

5050
var ppad = calcMarkerSize(trace, len);
51-
trace._extremes.radialaxis = Axes.findExtremes(radialAxis, rArray, {ppad: ppad});
51+
trace._extremes.x = Axes.findExtremes(radialAxis, rArray, {ppad: ppad});
5252

5353
calcColorscale(trace);
5454
arraysToCalcdata(cd, trace);

src/traces/scatterpolargl/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ function calc(container, trace) {
3636
stash.r = rArray;
3737
stash.theta = thetaArray;
3838

39-
trace._extremes.radialaxis = Axes.findExtremes(radialAxis, rArray, {tozero: true});
39+
trace._extremes.x = Axes.findExtremes(radialAxis, rArray, {tozero: true});
4040

4141
return [{x: false, y: false, t: stash, trace: trace}];
4242
}

test/jasmine/tests/annotations_test.js

+16-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ describe('Test annotations', function() {
2727
layoutOut._has = Plots._hasPlotType.bind(layoutOut);
2828
layoutOut._subplots = {xaxis: ['x', 'x2'], yaxis: ['y', 'y2']};
2929
['xaxis', 'yaxis', 'xaxis2', 'yaxis2'].forEach(function(axName) {
30-
if(!layoutOut[axName]) layoutOut[axName] = {type: 'linear', range: [0, 1]};
30+
if(!layoutOut[axName]) {
31+
layoutOut[axName] = {
32+
type: 'linear',
33+
range: [0, 1],
34+
_annIndices: []
35+
};
36+
}
3137
Axes.setConvert(layoutOut[axName]);
3238
});
3339

@@ -90,7 +96,11 @@ describe('Test annotations', function() {
9096
};
9197

9298
var layoutOut = {
93-
xaxis: { type: 'date', range: ['2000-01-01', '2016-01-01'] }
99+
xaxis: {
100+
type: 'date',
101+
range: ['2000-01-01', '2016-01-01'],
102+
_annIndices: []
103+
}
94104
};
95105

96106
_supply(layoutIn, layoutOut);
@@ -128,10 +138,10 @@ describe('Test annotations', function() {
128138
};
129139

130140
var layoutOut = {
131-
xaxis: {type: 'linear', range: [0, 1]},
132-
yaxis: {type: 'date', range: ['2000-01-01', '2018-01-01']},
133-
xaxis2: {type: 'log', range: [1, 2]},
134-
yaxis2: {type: 'category', range: [0, 1]}
141+
xaxis: {type: 'linear', range: [0, 1], _annIndices: []},
142+
yaxis: {type: 'date', range: ['2000-01-01', '2018-01-01'], _annIndices: []},
143+
xaxis2: {type: 'log', range: [1, 2], _annIndices: []},
144+
yaxis2: {type: 'category', range: [0, 1], _annIndices: []}
135145
};
136146

137147
_supply(layoutIn, layoutOut);

0 commit comments

Comments
 (0)