Skip to content

Commit dd3e950

Browse files
authored
Merge pull request #3015 from plotly/splom-zeroline-logic
Update splom zero line logic
2 parents e545415 + 2d5cc0d commit dd3e950

File tree

5 files changed

+122
-112
lines changed

5 files changed

+122
-112
lines changed

src/plots/cartesian/axes.js

Lines changed: 99 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,19 +1687,13 @@ axes.doTicksSingle = function(gd, arg, skipTitle) {
16871687
vals = vals.filter(ax._tickFilter);
16881688
}
16891689

1690-
// remove zero lines, grid lines, and inside ticks if they're within
1691-
// 1 pixel of the end
1690+
// Remove zero lines, grid lines, and inside ticks if they're within
1691+
// 1 pixel of the end.
16921692
// The key case here is removing zero lines when the axis bound is zero.
1693-
function clipEnds(d) {
1694-
var p = ax.l2p(d.x);
1695-
return (p > 1 && p < ax._length - 1);
1696-
}
1697-
var valsClipped = vals.filter(clipEnds);
1698-
1699-
// don't clip angular values
1700-
if(isAngular(ax)) {
1701-
valsClipped = vals;
1702-
}
1693+
// Don't clip angular values.
1694+
var valsClipped = ax._valsClipped = isAngular(ax) ?
1695+
vals :
1696+
vals.filter(function(d) { return clipEnds(ax, d.x); });
17031697

17041698
function drawTicks(container, tickpath) {
17051699
var ticks = container.selectAll('path.' + tcls)
@@ -2142,69 +2136,17 @@ axes.doTicksSingle = function(gd, arg, skipTitle) {
21422136
});
21432137
}
21442138

2145-
function traceHasBarsOrFill(trace, subplot) {
2146-
if(trace.visible !== true || trace.xaxis + trace.yaxis !== subplot) return false;
2147-
if(Registry.traceIs(trace, 'bar') && trace.orientation === {x: 'h', y: 'v'}[axLetter]) return true;
2148-
return trace.fill && trace.fill.charAt(trace.fill.length - 1) === axLetter;
2149-
}
2150-
2151-
function lineNearZero(ax2, position) {
2152-
if(!ax2.showline || !ax2.linewidth) return false;
2153-
var tolerance = Math.max((ax2.linewidth + ax.zerolinewidth) / 2, 1);
2154-
2155-
function closeEnough(pos2) {
2156-
return typeof pos2 === 'number' && Math.abs(pos2 - position) < tolerance;
2157-
}
2158-
2159-
if(closeEnough(ax2._mainLinePosition) || closeEnough(ax2._mainMirrorPosition)) {
2160-
return true;
2161-
}
2162-
var linePositions = ax2._linepositions || {};
2163-
for(var k in linePositions) {
2164-
if(closeEnough(linePositions[k][0]) || closeEnough(linePositions[k][1])) {
2165-
return true;
2166-
}
2167-
}
2168-
}
2169-
2170-
function anyCounterAxLineAtZero(counterAxis, rng) {
2171-
var mainCounterAxis = counterAxis._mainAxis;
2172-
if(!mainCounterAxis) return;
2173-
2174-
var zeroPosition = ax._offset + (
2175-
((Math.abs(rng[0]) < Math.abs(rng[1])) === (axLetter === 'x')) ?
2176-
0 : ax._length
2177-
);
2178-
2179-
var plotinfo = fullLayout._plots[counterAxis._mainSubplot];
2180-
if(!(plotinfo.mainplotinfo || plotinfo).overlays.length) {
2181-
return lineNearZero(counterAxis, zeroPosition);
2182-
}
2183-
2184-
var counterLetterAxes = axes.list(gd, counterLetter);
2185-
for(var i = 0; i < counterLetterAxes.length; i++) {
2186-
var counterAxis2 = counterLetterAxes[i];
2187-
if(
2188-
counterAxis2._mainAxis === mainCounterAxis &&
2189-
lineNearZero(counterAxis2, zeroPosition)
2190-
) {
2191-
return true;
2192-
}
2193-
}
2194-
}
2195-
2196-
function drawGrid(plotinfo, counteraxis, subplot) {
2139+
function drawGrid(plotinfo, counteraxis) {
21972140
if(fullLayout._hasOnlyLargeSploms) return;
21982141

21992142
var gridcontainer = plotinfo.gridlayer.selectAll('.' + axid);
22002143
var zlcontainer = plotinfo.zerolinelayer;
2201-
var gridvals = plotinfo['hidegrid' + axLetter] ? [] : valsClipped;
22022144
var gridpath = ax._gridpath || ((axLetter === 'x' ?
22032145
('M0,' + counteraxis._offset + 'v') :
22042146
('M' + counteraxis._offset + ',0h')
22052147
) + counteraxis._length);
22062148
var grid = gridcontainer.selectAll('path.' + gcls)
2207-
.data((ax.showgrid === false) ? [] : gridvals, datafn);
2149+
.data((ax.showgrid === false) ? [] : valsClipped, datafn);
22082150
grid.enter().append('path').classed(gcls, 1)
22092151
.classed('crisp', 1)
22102152
.attr('d', gridpath)
@@ -2222,24 +2164,8 @@ axes.doTicksSingle = function(gd, arg, skipTitle) {
22222164

22232165
// zero line
22242166
if(zlcontainer) {
2225-
var hasBarsOrFill = false;
2226-
for(var i = 0; i < gd._fullData.length; i++) {
2227-
if(traceHasBarsOrFill(gd._fullData[i], subplot)) {
2228-
hasBarsOrFill = true;
2229-
break;
2230-
}
2231-
}
2232-
var rng = Lib.simpleMap(ax.range, ax.r2l);
22332167
var zlData = {x: 0, id: axid};
2234-
2235-
var showZl = (rng[0] * rng[1] <= 0) && ax.zeroline &&
2236-
(ax.type === 'linear' || ax.type === '-') && gridvals.length &&
2237-
(
2238-
hasBarsOrFill ||
2239-
clipEnds(zlData) ||
2240-
!anyCounterAxLineAtZero(counteraxis, rng)
2241-
);
2242-
2168+
var showZl = axes.shouldShowZeroLine(gd, ax, counteraxis);
22432169
var zl = zlcontainer.selectAll('path.' + zcls)
22442170
.data(showZl ? [zlData] : []);
22452171
zl.enter().append('path').classed(zcls, 1).classed('zl', 1)
@@ -2327,6 +2253,96 @@ axes.doTicksSingle = function(gd, arg, skipTitle) {
23272253
}
23282254
};
23292255

2256+
axes.shouldShowZeroLine = function(gd, ax, counterAxis) {
2257+
var rng = Lib.simpleMap(ax.range, ax.r2l);
2258+
return (
2259+
(rng[0] * rng[1] <= 0) &&
2260+
ax.zeroline &&
2261+
(ax.type === 'linear' || ax.type === '-') &&
2262+
ax._valsClipped.length &&
2263+
(
2264+
clipEnds(ax, 0) ||
2265+
!anyCounterAxLineAtZero(gd, ax, counterAxis, rng) ||
2266+
hasBarsOrFill(gd, ax)
2267+
)
2268+
);
2269+
};
2270+
2271+
function clipEnds(ax, l) {
2272+
var p = ax.l2p(l);
2273+
return (p > 1 && p < ax._length - 1);
2274+
}
2275+
2276+
function anyCounterAxLineAtZero(gd, ax, counterAxis, rng) {
2277+
var mainCounterAxis = counterAxis._mainAxis;
2278+
if(!mainCounterAxis) return;
2279+
2280+
var fullLayout = gd._fullLayout;
2281+
var axLetter = ax._id.charAt(0);
2282+
var counterLetter = axes.counterLetter(ax._id);
2283+
2284+
var zeroPosition = ax._offset + (
2285+
((Math.abs(rng[0]) < Math.abs(rng[1])) === (axLetter === 'x')) ?
2286+
0 : ax._length
2287+
);
2288+
2289+
function lineNearZero(ax2) {
2290+
if(!ax2.showline || !ax2.linewidth) return false;
2291+
var tolerance = Math.max((ax2.linewidth + ax.zerolinewidth) / 2, 1);
2292+
2293+
function closeEnough(pos2) {
2294+
return typeof pos2 === 'number' && Math.abs(pos2 - zeroPosition) < tolerance;
2295+
}
2296+
2297+
if(closeEnough(ax2._mainLinePosition) || closeEnough(ax2._mainMirrorPosition)) {
2298+
return true;
2299+
}
2300+
var linePositions = ax2._linepositions || {};
2301+
for(var k in linePositions) {
2302+
if(closeEnough(linePositions[k][0]) || closeEnough(linePositions[k][1])) {
2303+
return true;
2304+
}
2305+
}
2306+
}
2307+
2308+
var plotinfo = fullLayout._plots[counterAxis._mainSubplot];
2309+
if(!(plotinfo.mainplotinfo || plotinfo).overlays.length) {
2310+
return lineNearZero(counterAxis, zeroPosition);
2311+
}
2312+
2313+
var counterLetterAxes = axes.list(gd, counterLetter);
2314+
for(var i = 0; i < counterLetterAxes.length; i++) {
2315+
var counterAxis2 = counterLetterAxes[i];
2316+
if(
2317+
counterAxis2._mainAxis === mainCounterAxis &&
2318+
lineNearZero(counterAxis2, zeroPosition)
2319+
) {
2320+
return true;
2321+
}
2322+
}
2323+
}
2324+
2325+
function hasBarsOrFill(gd, ax) {
2326+
var fullData = gd._fullData;
2327+
var subplot = ax._mainSubplot;
2328+
var axLetter = ax._id.charAt(0);
2329+
2330+
for(var i = 0; i < fullData.length; i++) {
2331+
var trace = fullData[i];
2332+
2333+
if(trace.visible === true &&
2334+
(trace.xaxis + trace.yaxis) === subplot &&
2335+
(
2336+
Registry.traceIs(trace, 'bar') && trace.orientation === {x: 'h', y: 'v'}[axLetter] ||
2337+
trace.fill && trace.fill.charAt(trace.fill.length - 1) === axLetter
2338+
)
2339+
) {
2340+
return true;
2341+
}
2342+
}
2343+
return false;
2344+
}
2345+
23302346
/**
23312347
* Find all margin pushers for 2D axes and reserve them for later use
23322348
* Both label and rangeslider automargin calculations happen later so

src/traces/splom/base_plot.js

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
var createLine = require('regl-line2d');
1212

1313
var Registry = require('../../registry');
14-
var Lib = require('../../lib');
1514
var prepareRegl = require('../../lib/prepare_regl');
1615
var getModuleCalcData = require('../../plots/get_data').getModuleCalcData;
1716
var Cartesian = require('../../plots/cartesian');
18-
var AxisIDs = require('../../plots/cartesian/axis_ids');
17+
var getFromId = require('../../plots/cartesian/axis_ids').getFromId;
18+
var shouldShowZeroLine = require('../../plots/cartesian/axes').shouldShowZeroLine;
1919

2020
var SPLOM = 'splom';
2121

@@ -63,13 +63,13 @@ function dragOne(gd, trace, stash, scene) {
6363
var i = visibleDims[k];
6464
var rng = ranges[k] = new Array(4);
6565

66-
var xa = AxisIDs.getFromId(gd, trace._diag[i][0]);
66+
var xa = getFromId(gd, trace._diag[i][0]);
6767
if(xa) {
6868
rng[0] = xa.r2l(xa.range[0]);
6969
rng[2] = xa.r2l(xa.range[1]);
7070
}
7171

72-
var ya = AxisIDs.getFromId(gd, trace._diag[i][1]);
72+
var ya = getFromId(gd, trace._diag[i][1]);
7373
if(ya) {
7474
rng[1] = ya.r2l(ya.range[0]);
7575
rng[3] = ya.r2l(ya.range[1]);
@@ -144,17 +144,17 @@ function makeGridData(gd) {
144144
push('grid', xa, x, yOffset, x, yOffset + ya._length);
145145
}
146146
}
147-
if(showZeroLine(xa)) {
148-
x = xa._offset + xa.l2p(0);
149-
push('zeroline', xa, x, yOffset, x, yOffset + ya._length);
150-
}
151147
if(ya.showgrid) {
152148
for(k = 0; k < yVals.length; k++) {
153149
y = yOffset + yb + ym * yVals[k].x;
154150
push('grid', ya, xa._offset, y, xa._offset + xa._length, y);
155151
}
156152
}
157-
if(showZeroLine(ya)) {
153+
if(shouldShowZeroLine(gd, xa, ya)) {
154+
x = xa._offset + xa.l2p(0);
155+
push('zeroline', xa, x, yOffset, x, yOffset + ya._length);
156+
}
157+
if(shouldShowZeroLine(gd, ya, xa)) {
158158
y = yOffset + yb + 0;
159159
push('zeroline', ya, xa._offset, y, xa._offset + xa._length, y);
160160
}
@@ -168,20 +168,6 @@ function makeGridData(gd) {
168168
return gridBatches;
169169
}
170170

171-
// just like in Axes.doTicks but without the loop over traces
172-
function showZeroLine(ax) {
173-
var rng = Lib.simpleMap(ax.range, ax.r2l);
174-
var p0 = ax.l2p(0);
175-
176-
return (
177-
ax.zeroline &&
178-
ax._vals && ax._vals.length &&
179-
(rng[0] * rng[1] <= 0) &&
180-
(ax.type === 'linear' || ax.type === '-') &&
181-
((p0 > 1 && p0 < ax._length - 1) || !ax.showline)
182-
);
183-
}
184-
185171
function clean(newFullData, newFullLayout, oldFullData, oldFullLayout, oldCalcdata) {
186172
var oldModules = oldFullLayout._modules || [];
187173
var newModules = newFullLayout._modules || [];

test/image/baselines/splom_large.png

19.3 KB
Loading

test/image/mocks/splom_large.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,14 @@
297297
"yaxis": {
298298
"zerolinecolor": "red",
299299
"zerolinewidth": 2
300+
},
301+
"xaxis2": {
302+
"zeroline": false
303+
},
304+
"yaxis2": {
305+
"rangemode": "tozero",
306+
"zeroline": true,
307+
"showline": true
300308
}
301309
}
302310
}

test/jasmine/tests/splom_test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -478,26 +478,26 @@ describe('Test splom interactions:', function() {
478478
}
479479

480480
Plotly.plot(gd, fig).then(function() {
481-
_assert([1198, 3478, 16318, 118]);
481+
_assert([1198, 16678, 3358, 118]);
482482
return Plotly.restyle(gd, 'showupperhalf', false);
483483
})
484484
.then(function() {
485-
_assert([1198, 1882, 8452, 4]);
485+
_assert([1198, 8488, 1768, 4]);
486486
return Plotly.restyle(gd, 'diagonal.visible', false);
487487
})
488488
.then(function() {
489-
_assert([1138, 1702, 7636, 4]);
489+
_assert([1138, 7636, 1594, 4]);
490490
return Plotly.restyle(gd, {
491491
showupperhalf: true,
492492
showlowerhalf: false
493493
});
494494
})
495495
.then(function() {
496-
_assert([64, 1594, 7852, 112]);
496+
_assert([64, 8176, 1582, 112]);
497497
return Plotly.restyle(gd, 'diagonal.visible', true);
498498
})
499499
.then(function() {
500-
_assert([58, 1768, 8680, 118]);
500+
_assert([58, 9022, 1756, 118]);
501501
return Plotly.relayout(gd, {
502502
'xaxis.gridcolor': null,
503503
'xaxis.gridwidth': null,
@@ -508,7 +508,7 @@ describe('Test splom interactions:', function() {
508508
.then(function() {
509509
// one batch for all 'grid' lines
510510
// and another for all 'zeroline' lines
511-
_assert([8740, 1888]);
511+
_assert([9082, 1876]);
512512
})
513513
.catch(failTest)
514514
.then(done);

0 commit comments

Comments
 (0)