Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test adding an option to use country borderlines from a UN geojson dataset for geo subplots #7327

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
7 changes: 3 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
"regl-line2d": "^3.1.3",
"regl-scatter2d": "^3.3.1",
"regl-splom": "^1.0.14",
"sane-topojson": "github:etpinard/sane-topojson#c76e75396879a1a8d96e37237383b3ca5305afc6",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"strongly-connected-components": "^1.0.1",
"style-loader": "^4.0.0",
"superscript-text": "^1.0.0",
Expand Down Expand Up @@ -172,7 +173,6 @@
"raw-loader": "^4.0.2",
"read-last-lines": "^1.8.0",
"run-series": "^1.1.9",
"sane-topojson": "^4.0.0",
"sass": "^1.78.0",
"stream-browserify": "^3.0.0",
"through2": "^4.0.2",
Expand Down
1 change: 1 addition & 0 deletions src/components/drawing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1775,6 +1775,7 @@ function getMarkerAngle(d, trace) {
}

if(trace._geo) {
if(!d.latlon) return null;
var lon = d.lonlat[0];
var lat = d.lonlat[1];

Expand Down
66 changes: 64 additions & 2 deletions src/lib/geo_location_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ function locationToFeature(locationmode, location, features) {
var filteredFeatures;
var f, i;

var allParts = [];

if(locationId) {
if(locationmode === 'USA-states') {
// Filter out features out in USA
Expand All @@ -63,6 +65,12 @@ function locationToFeature(locationmode, location, features) {
for(i = 0; i < filteredFeatures.length; i++) {
f = filteredFeatures[i];
if(f.id === locationId) return f;
if(
f.properties &&
f.properties.iso3cd === locationId
) {
allParts.push(f);
}
}

loggers.log([
Expand All @@ -71,13 +79,38 @@ function locationToFeature(locationmode, location, features) {
].join(' '));
}

if(allParts.length) {
return allParts; //[allParts.length - 1];
}

return false;
}

function feature2polygons(feature) {
if(!Array.isArray(feature)) {
return _feature2polygons(feature);
}

var polygons;
for(var i = 0; i < feature.length; i++) {
var pts = _feature2polygons(feature[i]);

if(pts.length) {
if(!polygons) {
polygons = pts;
} else {
polygons.push(polygon.tester(pts));
}
}
}

return polygons;
}

function _feature2polygons(feature) {
var geometry = feature.geometry;
var coords = geometry.coordinates;
var loc = feature.id;
var loc = feature.properties.iso3cd || feature.id;

var polygons = [];
var appendPolygon, j, k, m;
Expand Down Expand Up @@ -173,6 +206,9 @@ function feature2polygons(feature) {
appendPolygon(coords[j]);
}
break;
case 'LineString':
appendPolygon(coords);
break;
}

return polygons;
Expand Down Expand Up @@ -363,9 +399,35 @@ function fetchTraceGeoData(calcData) {
return promises;
}


function computeBbox(d) {
if(!Array.isArray(d)) {
return _computeBbox(d);
}

var minLon = Infinity;
var maxLon = -Infinity;
var minLat = Infinity;
var maxLat = -Infinity;

for(var i = 0; i < d.length; i++) {
var p = _computeBbox(d[i]);

minLon = Math.min(minLon, p[0]);
minLat = Math.min(minLat, p[1]);
maxLon = Math.max(maxLon, p[2]);
maxLat = Math.max(maxLat, p[3]);
}

return [
minLon, minLat,
maxLon, maxLat
];
}

// TODO `turf/bbox` gives wrong result when the input feature/geometry
// crosses the anti-meridian. We should try to implement our own bbox logic.
function computeBbox(d) {
function _computeBbox(d) {
return turfBbox(d);
}

Expand Down
11 changes: 10 additions & 1 deletion src/lib/topojson_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,16 @@ topojsonUtils.getTopojsonName = function(geoLayout) {
};

topojsonUtils.getTopojsonPath = function(topojsonURL, topojsonName) {
return topojsonURL + topojsonName + '.json';
var path = topojsonURL;

if(topojsonName.startsWith('un_')) {
path += 'un';
return 'https://raw.githubusercontent.com/etpinard/sane-topojson/refs/heads/un-borders/dist/un.json';
} else {
path += topojsonName;
}

return path + '.json';
};

topojsonUtils.getTopojsonFeatures = function(trace, topojson) {
Expand Down
15 changes: 9 additions & 6 deletions src/plots/geo/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,17 @@ exports.lataxisSpan = {
'*': 180
};

var world = {
lonaxisRange: [-180, 180],
lataxisRange: [-90, 90],
projType: 'equirectangular',
projRotate: [0, 0, 0]
};

// defaults for each scope
exports.scopeDefaults = {
world: {
lonaxisRange: [-180, 180],
lataxisRange: [-90, 90],
projType: 'equirectangular',
projRotate: [0, 0, 0]
},
un: world,
world: world,
usa: {
lonaxisRange: [-180, -50],
lataxisRange: [15, 80],
Expand Down
5 changes: 5 additions & 0 deletions src/plots/geo/geo.js
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,7 @@ proto.makeFramework = function() {

// sane lonlat to px
_this.project = function(v) {
if(!v) return [null, null];
var px = _this.projection(v);
return px ?
[px[0] - _this.xaxis._offset, px[1] - _this.yaxis._offset] :
Expand Down Expand Up @@ -625,6 +626,8 @@ proto._render = function() {
var k;

function translatePoints(d) {
if(!d.lonlat) return null;

var lonlatPx = projection(d.lonlat);
return lonlatPx ?
strTranslate(lonlatPx[0], lonlatPx[1]) :
Expand Down Expand Up @@ -685,6 +688,8 @@ function getProjection(geoLayout) {
}

projection.isLonLatOverEdges = function(lonlat) {
if(!lonlat) return false;

if(projection(lonlat) === null) {
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/plots/geo/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ var attrs = module.exports = overrideAll({
scope: {
valType: 'enumerated',
values: sortObjectKeys(constants.scopeDefaults),
dflt: 'world',
dflt: 'un',
description: 'Set the scope of the map.'
},
projection: {
Expand Down
2 changes: 1 addition & 1 deletion src/plots/geo/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce, opts) {
// no other scopes are allowed for 'albers usa' projection
if(isAlbersUsa) scope = geoLayoutOut.scope = 'usa';

var isScoped = geoLayoutOut._isScoped = (scope !== 'world');
var isScoped = geoLayoutOut._isScoped = (scope !== 'world' && scope !== 'un');
var isSatellite = geoLayoutOut._isSatellite = projType === 'satellite';
var isConic = geoLayoutOut._isConic = projType.indexOf('conic') !== -1 || projType === 'albers';
var isClipped = geoLayoutOut._isClipped = !!constants.lonaxisSpan[projType];
Expand Down
5 changes: 3 additions & 2 deletions src/traces/choropleth/plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ function calcGeoJSON(calcTrace, fullLayout) {
geoUtils.locationToFeature(locationmode, calcPt.loc, features);

if(feature) {
calcPt.geojson = feature;
calcPt.ct = feature.properties.ct;
var f0 = Array.isArray(feature) ? feature[0] : feature;
calcPt.geojson = f0;
calcPt.ct = f0.properties.ct;
calcPt._polygons = geoUtils.feature2polygons(feature);

var bboxFeature = geoUtils.computeBbox(feature);
Expand Down
8 changes: 4 additions & 4 deletions src/traces/scattergeo/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ module.exports = function hoverPoints(pointData, xval, yval) {
var project = geo.project;

function distFn(d) {
var lonlat = d.lonlat;
var _lonlat = d.lonlat;

if(lonlat[0] === BADNUM) return Infinity;
if(isLonLatOverEdges(lonlat)) return Infinity;
if(!_lonlat || _lonlat[0] === BADNUM) return Infinity;
if(isLonLatOverEdges(_lonlat)) return Infinity;

var pt = project(lonlat);
var pt = project(_lonlat);
var px = project([xval, yval]);
var dx = Math.abs(pt[0] - px[0]);
var dy = Math.abs(pt[1] - px[1]);
Expand Down
14 changes: 9 additions & 5 deletions src/traces/scattergeo/plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ function plot(gd, geo, calcData) {
var gTraces = Lib.makeTraceGroups(scatterLayer, calcData, 'trace scattergeo');

function removeBADNUM(d, node) {
if(d.lonlat[0] === BADNUM) {
if(
d.lonlat &&
d.lonlat[0] === BADNUM
) {
d3.select(node).remove();
}
}
Expand Down Expand Up @@ -98,12 +101,13 @@ function calcGeoJSON(calcTrace, fullLayout) {
lonArray = [bboxGeojson[0], bboxGeojson[2]];
latArray = [bboxGeojson[1], bboxGeojson[3]];
} else {
lonArray = new Array(len);
latArray = new Array(len);
lonArray = [];
latArray = [];
for(i = 0; i < len; i++) {
calcPt = calcTrace[i];
lonArray[i] = calcPt.lonlat[0];
latArray[i] = calcPt.lonlat[1];
if(!calcPt.lonlat) continue;
lonArray.push(calcPt.lonlat[0]);
latArray.push(calcPt.lonlat[1]);
}

opts.ppad = calcMarkerSize(trace, len);
Expand Down
3 changes: 2 additions & 1 deletion test/plot-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2540,7 +2540,7 @@
"role": "object",
"scope": {
"description": "Set the scope of the map.",
"dflt": "world",
"dflt": "un",
"editType": "plot",
"valType": "enumerated",
"values": [
Expand All @@ -2549,6 +2549,7 @@
"europe",
"north america",
"south america",
"un",
"usa",
"world"
]
Expand Down