Skip to content

Commit 96950d5

Browse files
authored
Merge pull request #3021 from plotly/polar-fail-gracefully-on-non-sense-inputs
Make polar be more graceful on non sense inputs
2 parents f86e4d1 + cb5b336 commit 96950d5

File tree

10 files changed

+88
-26
lines changed

10 files changed

+88
-26
lines changed

Diff for: src/lib/angles.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@ function rad2deg(rad) { return rad / PI * 180; }
2323
* is sector a full circle?
2424
* ... this comes up a lot in SVG path-drawing routines
2525
*
26+
* N.B. we consider all sectors that span more that 2pi 'full' circles
27+
*
2628
* @param {2-item array} aBnds : angular bounds in *radians*
2729
* @return {boolean}
2830
*/
2931
function isFullCircle(aBnds) {
30-
return Math.abs(Math.abs(aBnds[1] - aBnds[0]) - twoPI) < 1e-15;
32+
return Math.abs(aBnds[1] - aBnds[0]) > twoPI - 1e-15;
3133
}
3234

3335
/**

Diff for: src/plots/polar/polar.js

+35-20
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ proto.updateRadialAxis = function(fullLayout, polarLayout) {
380380
var radialLayout = polarLayout.radialaxis;
381381
var a0 = mod(polarLayout.sector[0], 360);
382382
var ax = _this.radialAxis;
383+
var hasRoomForIt = innerRadius < radius;
383384

384385
_this.fillViewInitialKey('radialaxis.angle', radialLayout.angle);
385386
_this.fillViewInitialKey('radialaxis.range', ax.range.slice());
@@ -410,8 +411,10 @@ proto.updateRadialAxis = function(fullLayout, polarLayout) {
410411
_this.radialTickLayout = newTickLayout;
411412
}
412413

413-
ax.setScale();
414-
doTicksSingle(gd, ax, true);
414+
if(hasRoomForIt) {
415+
ax.setScale();
416+
doTicksSingle(gd, ax, true);
417+
}
415418

416419
// stash 'actual' radial axis angle for drag handlers (in degrees)
417420
var angle = _this.radialAxisAngle = _this.vangles ?
@@ -420,24 +423,31 @@ proto.updateRadialAxis = function(fullLayout, polarLayout) {
420423

421424
var trans = strTranslate(cx, cy) + strRotate(-angle);
422425

423-
updateElement(layers['radial-axis'], radialLayout.showticklabels || radialLayout.ticks, {
424-
transform: trans
425-
});
426+
updateElement(
427+
layers['radial-axis'],
428+
hasRoomForIt && (radialLayout.showticklabels || radialLayout.ticks),
429+
{transform: trans}
430+
);
426431

427432
// move all grid paths to about circle center,
428433
// undo individual grid lines translations
429-
updateElement(layers['radial-grid'], radialLayout.showgrid, {
430-
transform: strTranslate(cx, cy)
431-
})
432-
.selectAll('path').attr('transform', null);
433-
434-
updateElement(layers['radial-line'].select('line'), radialLayout.showline, {
435-
x1: innerRadius,
436-
y1: 0,
437-
x2: radius,
438-
y2: 0,
439-
transform: trans
440-
})
434+
updateElement(
435+
layers['radial-grid'],
436+
hasRoomForIt && radialLayout.showgrid,
437+
{transform: strTranslate(cx, cy)}
438+
).selectAll('path').attr('transform', null);
439+
440+
updateElement(
441+
layers['radial-line'].select('line'),
442+
hasRoomForIt && radialLayout.showline,
443+
{
444+
x1: innerRadius,
445+
y1: 0,
446+
x2: radius,
447+
y2: 0,
448+
transform: trans
449+
}
450+
)
441451
.attr('stroke-width', radialLayout.linewidth)
442452
.call(Color.stroke, radialLayout.linecolor);
443453
};
@@ -802,7 +812,8 @@ proto.updateMainDrag = function(fullLayout) {
802812
var cpath;
803813

804814
if(clampAndSetR0R1(rr0, rr1)) {
805-
path1 = path0 + _this.pathSector(r1) + _this.pathSector(r0);
815+
path1 = path0 + _this.pathSector(r1);
816+
if(r0) path1 += _this.pathSector(r0);
806817
// keep 'starting' angle
807818
cpath = pathCorner(r0, a0) + pathCorner(r1, a0);
808819
}
@@ -827,7 +838,8 @@ proto.updateMainDrag = function(fullLayout) {
827838
var cpath;
828839

829840
if(clampAndSetR0R1(rr0, rr1)) {
830-
path1 = path0 + _this.pathSector(r1) + _this.pathSector(r0);
841+
path1 = path0 + _this.pathSector(r1);
842+
if(r0) path1 += _this.pathSector(r0);
831843
// keep 'starting' angle here too
832844
cpath = [
833845
pathCornerForPolygons(r0, vangles0[0], vangles0[1]),
@@ -963,7 +975,10 @@ proto.updateRadialDrag = function(fullLayout, polarLayout, rngIndex) {
963975

964976
var radialDrag = dragBox.makeRectDragger(layers, className, 'crosshair', -bl2, -bl2, bl, bl);
965977
var dragOpts = {element: radialDrag, gd: gd};
966-
d3.select(radialDrag).attr('transform', strTranslate(tx, ty));
978+
979+
updateElement(d3.select(radialDrag), radialAxis.visible && innerRadius < radius, {
980+
transform: strTranslate(tx, ty)
981+
});
967982

968983
// move function (either rotate or re-range flavor)
969984
var moveFn2;

Diff for: src/plots/polar/set_convert.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ function setConvertAngular(ax, polarLayout) {
166166
// Set the angular range in degrees to make auto-tick computation cleaner,
167167
// changing rotation/direction should not affect the angular tick value.
168168
ax.range = Lib.isFullCircle(sectorInRad) ?
169-
sector.slice() :
169+
[sector[0], sector[0] + 360] :
170170
sectorInRad.map(g2rad).map(rad2deg);
171171
break;
172172

Diff for: src/traces/splom/defaults.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ function handleAxisDefaults(traceIn, traceOut, layout, coerce) {
8989
// fill in splom subplot keys
9090
for(i = 0; i < axLength; i++) {
9191
for(j = 0; j < axLength; j++) {
92-
var id = [xaxes[i] + yaxes[j]];
92+
var id = xaxes[i] + yaxes[j];
9393

9494
if(i > j && showUpper) {
9595
layout._splomSubplots[id] = 1;

Diff for: test/image/baselines/polar_blank.png

3.17 KB
Loading

Diff for: test/image/mocks/polar_blank.json

+13
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
"text": "<b>N.B.</b><br>radial<br>auotrange<br>for (0,0)<br>gives [0,1]",
2222
"textposition": "left",
2323
"subplot": "polar4"
24+
}, {
25+
"type": "scatterpolar",
26+
"r": [1, 2, 3],
27+
"theta": [0, 90, 200],
28+
"subplot": "polar5"
2429
}],
2530
"layout": {
2631
"polar": {
@@ -69,6 +74,14 @@
6974
},
7075
"radialaxis": {"visible": false}
7176
},
77+
"polar5": {
78+
"domain": {
79+
"x": [0.12, 0.34],
80+
"y": [0.11, 0.34]
81+
},
82+
"hole": 1
83+
},
84+
"showlegend": false,
7285
"width": 600,
7386
"height": 500
7487
}

Diff for: test/image/mocks/polar_sector.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1143,7 +1143,7 @@
11431143
"polar20": {
11441144
"sector": [
11451145
-180,
1146-
180
1146+
200
11471147
],
11481148
"bgcolor": "#d3d3d3",
11491149
"domain": {

Diff for: test/jasmine/tests/gl2d_plot_interact_test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ describe('Test gl plot side effects', function() {
215215
.then(done);
216216
});
217217

218-
it('@gl should fire *plotly_webglcontextlost* when on webgl context lost', function(done) {
218+
it('@noCI @gl should fire *plotly_webglcontextlost* when on webgl context lost', function(done) {
219219
var _mock = Lib.extendDeep({}, require('@mocks/gl2d_12.json'));
220220

221221
function _trigger(name) {

Diff for: test/jasmine/tests/polar_test.js

+32
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ var doubleClick = require('../assets/double_click');
1313
var drag = require('../assets/drag');
1414
var delay = require('../assets/delay');
1515

16+
var customAssertions = require('../assets/custom_assertions');
17+
var assertNodeDisplay = customAssertions.assertNodeDisplay;
18+
1619
describe('Test legacy polar plots logs:', function() {
1720
var gd;
1821

@@ -628,6 +631,35 @@ describe('Test relayout on polar subplots:', function() {
628631
.catch(failTest)
629632
.then(done);
630633
});
634+
635+
it('should not attempt to draw radial axis when *polar.hole* is set to 1', function(done) {
636+
var gd = createGraphDiv();
637+
638+
var queries = [
639+
'.radial-axis', '.radial-grid', '.radial-line > line',
640+
'.radialdrag', '.radialdrag-inner'
641+
];
642+
643+
function _assert(msg, showing) {
644+
var exp = showing ? null : 'none';
645+
var sp3 = d3.select(gd).select('.polarlayer > .polar');
646+
queries.forEach(function(q) {
647+
assertNodeDisplay(sp3.selectAll(q), [exp], msg + ' ' + q);
648+
});
649+
}
650+
651+
Plotly.plot(gd, [{
652+
type: 'scatterpolar',
653+
r: ['a', 'b', 'c']
654+
}])
655+
.then(function() { _assert('base', true); })
656+
.then(function() { return Plotly.relayout(gd, 'polar.hole', 1); })
657+
.then(function() { _assert('hole=1', false); })
658+
.then(function() { return Plotly.relayout(gd, 'polar.hole', 0.2); })
659+
.then(function() { _assert('hole=0.2', true); })
660+
.catch(failTest)
661+
.then(done);
662+
});
631663
});
632664

633665
describe('Test polar interactions:', function() {

Diff for: test/jasmine/tests/select_test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1296,7 +1296,7 @@ describe('Test select box and lasso in general:', function() {
12961296
.then(done);
12971297
});
12981298

1299-
it('should cleanly clear and restart selections on double click when add/subtract mode on', function(done) {
1299+
it('@flaky should cleanly clear and restart selections on double click when add/subtract mode on', function(done) {
13001300
var gd = createGraphDiv();
13011301
var fig = Lib.extendDeep({}, require('@mocks/0.json'));
13021302

0 commit comments

Comments
 (0)