Skip to content

Commit 0b4e549

Browse files
authored
Merge pull request #3706 from plotly/geo-grid-fixes
Geo grid fixes
2 parents 0782274 + 7fce1b3 commit 0b4e549

15 files changed

+237
-81
lines changed

src/plots/geo/geo.js

+52-14
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ proto.updateBaseLayers = function(fullLayout, geoLayout) {
314314
} else if(isLineLayer(d) || isFillLayer(d)) {
315315
path.datum(topojsonFeature(topojson, topojson.objects[d]));
316316
} else if(isAxisLayer(d)) {
317-
path.datum(makeGraticule(d, geoLayout))
317+
path.datum(makeGraticule(d, geoLayout, fullLayout))
318318
.call(Color.stroke, geoLayout[d].gridcolor)
319319
.call(Drawing.dashLine, '', geoLayout[d].gridwidth);
320320
}
@@ -660,20 +660,58 @@ function getProjection(geoLayout) {
660660
return projection;
661661
}
662662

663-
function makeGraticule(axisName, geoLayout) {
664-
var axisLayout = geoLayout[axisName];
665-
var dtick = axisLayout.dtick;
663+
function makeGraticule(axisName, geoLayout, fullLayout) {
664+
// equivalent to the d3 "ε"
665+
var epsilon = 1e-6;
666+
// same as the geoGraticule default
667+
var precision = 2.5;
668+
669+
var axLayout = geoLayout[axisName];
666670
var scopeDefaults = constants.scopeDefaults[geoLayout.scope];
667-
var lonaxisRange = scopeDefaults.lonaxisRange;
668-
var lataxisRange = scopeDefaults.lataxisRange;
669-
var step = axisName === 'lonaxis' ? [dtick] : [0, dtick];
670-
671-
return d3.geo.graticule()
672-
.extent([
673-
[lonaxisRange[0], lataxisRange[0]],
674-
[lonaxisRange[1], lataxisRange[1]]
675-
])
676-
.step(step);
671+
var rng;
672+
var oppRng;
673+
var coordFn;
674+
675+
if(axisName === 'lonaxis') {
676+
rng = scopeDefaults.lonaxisRange;
677+
oppRng = scopeDefaults.lataxisRange;
678+
coordFn = function(v, l) { return [v, l]; };
679+
} else if(axisName === 'lataxis') {
680+
rng = scopeDefaults.lataxisRange;
681+
oppRng = scopeDefaults.lonaxisRange;
682+
coordFn = function(v, l) { return [l, v]; };
683+
}
684+
685+
var dummyAx = {
686+
type: 'linear',
687+
range: [rng[0], rng[1] - epsilon],
688+
tick0: axLayout.tick0,
689+
dtick: axLayout.dtick
690+
};
691+
692+
Axes.setConvert(dummyAx, fullLayout);
693+
var vals = Axes.calcTicks(dummyAx);
694+
695+
// remove duplicate on antimeridian
696+
if(!geoLayout.isScoped && axisName === 'lonaxis') {
697+
vals.pop();
698+
}
699+
700+
var len = vals.length;
701+
var coords = new Array(len);
702+
703+
for(var i = 0; i < len; i++) {
704+
var v = vals[i].x;
705+
var line = coords[i] = [];
706+
for(var l = oppRng[0]; l < oppRng[1] + precision; l += precision) {
707+
line.push(coordFn(v, l));
708+
}
709+
}
710+
711+
return {
712+
type: 'MultiLineString',
713+
coordinates: coords
714+
};
677715
}
678716

679717
// Returns polygon GeoJSON corresponding to lon/lat range box

src/plots/geo/index.js

+38-21
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,33 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9-
109
'use strict';
1110

12-
var createGeo = require('./geo');
1311
var getSubplotCalcData = require('../../plots/get_data').getSubplotCalcData;
1412
var counterRegex = require('../../lib').counterRegex;
1513

16-
var GEO = 'geo';
17-
18-
exports.name = GEO;
19-
20-
exports.attr = GEO;
21-
22-
exports.idRoot = GEO;
23-
24-
exports.idRegex = exports.attrRegex = counterRegex(GEO);
25-
26-
exports.attributes = require('./layout/attributes');
27-
28-
exports.layoutAttributes = require('./layout/layout_attributes');
14+
var createGeo = require('./geo');
2915

30-
exports.supplyLayoutDefaults = require('./layout/defaults');
16+
var GEO = 'geo';
17+
var counter = counterRegex(GEO);
18+
19+
var attributes = {};
20+
attributes[GEO] = {
21+
valType: 'subplotid',
22+
role: 'info',
23+
dflt: GEO,
24+
editType: 'calc',
25+
description: [
26+
'Sets a reference between this trace\'s geospatial coordinates and',
27+
'a geographic map.',
28+
'If *geo* (the default value), the geospatial coordinates refer to',
29+
'`layout.geo`.',
30+
'If *geo2*, the geospatial coordinates refer to `layout.geo2`,',
31+
'and so on.'
32+
].join(' ')
33+
};
3134

32-
exports.plot = function plotGeo(gd) {
35+
function plotGeo(gd) {
3336
var fullLayout = gd._fullLayout;
3437
var calcData = gd.calcdata;
3538
var geoIds = fullLayout._subplots[GEO];
@@ -62,9 +65,9 @@ exports.plot = function plotGeo(gd) {
6265

6366
geo.plot(geoCalcData, fullLayout, gd._promises);
6467
}
65-
};
68+
}
6669

67-
exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) {
70+
function clean(newFullData, newFullLayout, oldFullData, oldFullLayout) {
6871
var oldGeoKeys = oldFullLayout._subplots[GEO] || [];
6972

7073
for(var i = 0; i < oldGeoKeys.length; i++) {
@@ -76,9 +79,9 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout)
7679
oldGeo.clipDef.remove();
7780
}
7881
}
79-
};
82+
}
8083

81-
exports.updateFx = function(gd) {
84+
function updateFx(gd) {
8285
var fullLayout = gd._fullLayout;
8386
var subplotIds = fullLayout._subplots[GEO];
8487

@@ -87,4 +90,18 @@ exports.updateFx = function(gd) {
8790
var subplotObj = subplotLayout._subplot;
8891
subplotObj.updateFx(fullLayout, subplotLayout);
8992
}
93+
}
94+
95+
module.exports = {
96+
attr: GEO,
97+
name: GEO,
98+
idRoot: GEO,
99+
idRegex: counter,
100+
attrRegex: counter,
101+
attributes: attributes,
102+
layoutAttributes: require('./layout_attributes'),
103+
supplyLayoutDefaults: require('./layout_defaults'),
104+
plot: plotGeo,
105+
updateFx: updateFx,
106+
clean: clean
90107
};

src/plots/geo/layout/attributes.js

-27
This file was deleted.

src/plots/geo/layout/layout_attributes.js renamed to src/plots/geo/layout_attributes.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88

99
'use strict';
1010

11-
var colorAttrs = require('../../../components/color/attributes');
12-
var domainAttrs = require('../../domain').attributes;
13-
var constants = require('../constants');
14-
var overrideAll = require('../../../plot_api/edit_types').overrideAll;
11+
var colorAttrs = require('../../components/color/attributes');
12+
var domainAttrs = require('../domain').attributes;
13+
var constants = require('./constants');
14+
var overrideAll = require('../../plot_api/edit_types').overrideAll;
1515

1616
var geoAxesAttrs = {
1717
range: {
@@ -35,6 +35,7 @@ var geoAxesAttrs = {
3535
tick0: {
3636
valType: 'number',
3737
role: 'info',
38+
dflt: 0,
3839
description: [
3940
'Sets the graticule\'s starting tick longitude/latitude.'
4041
].join(' ')

src/plots/geo/layout/defaults.js renamed to src/plots/geo/layout_defaults.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99

1010
'use strict';
1111

12-
var handleSubplotDefaults = require('../../subplot_defaults');
13-
var constants = require('../constants');
12+
var handleSubplotDefaults = require('../subplot_defaults');
13+
var constants = require('./constants');
1414
var layoutAttributes = require('./layout_attributes');
1515

1616
var axesNames = constants.axesNames;
@@ -58,9 +58,8 @@ function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce) {
5858
rangeDflt = [rot - hSpan, rot + hSpan];
5959
}
6060

61-
var range = coerce(axisName + '.range', rangeDflt);
62-
63-
coerce(axisName + '.tick0', range[0]);
61+
coerce(axisName + '.range', rangeDflt);
62+
coerce(axisName + '.tick0');
6463
coerce(axisName + '.dtick', dtickDflt);
6564

6665
show = coerce(axisName + '.showgrid');
7.23 KB
Loading
630 Bytes
Loading
13 Bytes
Loading
-54 Bytes
Loading
10 Bytes
Loading

test/image/baselines/geo_tick0.png

150 KB
Loading
395 Bytes
Loading

test/image/mocks/geo_kavrayskiy7.json

+1-4
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,7 @@
7272
},
7373
"lataxis": {
7474
"showgrid": true,
75-
"range": [
76-
-75,
77-
85
78-
],
75+
"range": [ -75, 85 ],
7976
"gridwidth": 2,
8077
"gridcolor": "black"
8178
}

test/image/mocks/geo_tick0.json

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
{
2+
"data": [
3+
{"type": "scattergeo", "lon": [5], "lat": [2], "name": "lonaxis.tick0: 5 | lataxis.tick0: 2"},
4+
{"type": "scattergeo", "lon": [10], "lat": [1], "name": "lonaxis.tick0: 10 | lataxis.tick0: 1", "geo": "geo2"},
5+
{"type": "scattergeo", "lon": [40], "lat": [-40], "name": "lonaxis.tick0: 40 | lataxis.tick0: -40", "geo": "geo3"},
6+
{"type": "scattergeo", "lon": [73], "lat": [45], "name": "lonaxis.tick0: 73 | lataxis.tick0: 45", "geo": "geo4"}
7+
],
8+
"layout": {
9+
"legend": {
10+
"x": -0.05,
11+
"xanchor": "right",
12+
"y": 0.5,
13+
"yanchor": "middle"
14+
},
15+
"grid": {"columns": 2, "rows": 2},
16+
"geo": {
17+
"domain": {"row": 0, "column": 0},
18+
"lonaxis": {
19+
"showgrid": true,
20+
"gridcolor": "#444",
21+
"tick0": 5
22+
},
23+
"lataxis": {
24+
"showgrid": true,
25+
"gridcolor": "#444",
26+
"tick0": 2
27+
}
28+
},
29+
"geo2": {
30+
"domain": {"row": 0, "column": 1},
31+
"lonaxis": {
32+
"showgrid": true,
33+
"gridcolor": "#444",
34+
"tick0": 10
35+
},
36+
"lataxis": {
37+
"showgrid": true,
38+
"gridcolor": "#444",
39+
"tick0": 1
40+
}
41+
},
42+
"geo3": {
43+
"domain": {"row": 1, "column": 0},
44+
"lonaxis": {
45+
"showgrid": true,
46+
"gridcolor": "#444",
47+
"tick0": 40
48+
},
49+
"lataxis": {
50+
"showgrid": true,
51+
"gridcolor": "#444",
52+
"tick0": -40
53+
}
54+
},
55+
"geo4": {
56+
"domain": {"row": 1, "column": 1},
57+
"lonaxis": {
58+
"showgrid": true,
59+
"gridcolor": "#444",
60+
"tick0": 73
61+
},
62+
"lataxis": {
63+
"showgrid": true,
64+
"gridcolor": "#444",
65+
"tick0": 45
66+
}
67+
},
68+
"margin": {"t": 10, "b": 10},
69+
"width": 1100,
70+
"height": 400
71+
}
72+
}

0 commit comments

Comments
 (0)