Skip to content

Commit 91a9bc4

Browse files
committed
implement densitymapbox
1 parent 7e15d81 commit 91a9bc4

File tree

11 files changed

+473
-3
lines changed

11 files changed

+473
-3
lines changed

lib/densitymapbox.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Copyright 2012-2019, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
module.exports = require('../src/traces/densitymapbox');

lib/index-mapbox.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ var Plotly = require('./core');
1212

1313
Plotly.register([
1414
require('./scattermapbox'),
15-
require('./choroplethmapbox')
15+
require('./choroplethmapbox'),
16+
require('./densitymapbox')
1617
]);
1718

1819
module.exports = Plotly;

lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Plotly.register([
5151

5252
require('./scattermapbox'),
5353
require('./choroplethmapbox'),
54+
require('./densitymapbox'),
5455

5556
require('./sankey'),
5657

src/plots/mapbox/mapbox.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,9 @@ proto.updateMap = function(calcData, fullLayout, resolve, reject) {
199199
};
200200

201201
var traceType2orderIndex = {
202-
'choroplethmapbox': 0,
203-
'scattermapbox': 1
202+
choroplethmapbox: 0,
203+
densitymapbox: 1,
204+
scattermapbox: 2
204205
};
205206

206207
proto.updateData = function(calcData) {

src/traces/densitymapbox/calc.js

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* Copyright 2012-2019, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
var isNumeric = require('fast-isnumeric');
12+
13+
var isArrayOrTypedArray = require('../../lib').isArrayOrTypedArray;
14+
var BADNUM = require('../../constants/numerical').BADNUM;
15+
16+
var colorscaleCalc = require('../../components/colorscale/calc');
17+
var _ = require('../../lib')._;
18+
19+
module.exports = function calc(gd, trace) {
20+
var len = trace._length;
21+
var calcTrace = new Array(len);
22+
var z = trace.z;
23+
var hasZ = isArrayOrTypedArray(z) && z.length;
24+
25+
for(var i = 0; i < len; i++) {
26+
var cdi = calcTrace[i] = {};
27+
28+
var lon = trace.lon[i];
29+
var lat = trace.lat[i];
30+
31+
cdi.lonlat = isNumeric(lon) && isNumeric(lat) ?
32+
[+lon, +lat] :
33+
[BADNUM, BADNUM];
34+
35+
if(hasZ) {
36+
var zi = z[i];
37+
cdi.z = isNumeric(zi) ? zi : BADNUM;
38+
}
39+
}
40+
41+
colorscaleCalc(gd, trace, {
42+
vals: hasZ ? z : [0, 1],
43+
containerStr: '',
44+
cLetter: 'z'
45+
});
46+
47+
if(len) {
48+
calcTrace[0].t = {
49+
labels: {
50+
lat: _(gd, 'lat:') + ' ',
51+
lon: _(gd, 'lon:') + ' '
52+
}
53+
};
54+
}
55+
56+
return calcTrace;
57+
};

src/traces/densitymapbox/convert.js

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/**
2+
* Copyright 2012-2019, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
var isNumeric = require('fast-isnumeric');
12+
13+
var Lib = require('../../lib');
14+
var Color = require('../../components/color');
15+
var Colorscale = require('../../components/colorscale');
16+
17+
var BADNUM = require('../../constants/numerical').BADNUM;
18+
var makeBlank = require('../../lib/geojson_utils').makeBlank;
19+
20+
module.exports = function convert(calcTrace) {
21+
var trace = calcTrace[0].trace;
22+
var isVisible = (trace.visible === true && trace._length !== 0);
23+
24+
var heatmap = {
25+
layout: {visibility: 'none'},
26+
paint: {}
27+
};
28+
29+
var opts = trace._opts = {
30+
heatmap: heatmap,
31+
geojson: makeBlank()
32+
};
33+
34+
// early return if not visible or placeholder
35+
if(!isVisible) return opts;
36+
37+
var features = [];
38+
var i;
39+
40+
var z = trace.z;
41+
var radius = trace.radius;
42+
var hasZ = Lib.isArrayOrTypedArray(z) && z.length;
43+
var hasArrayRadius = Lib.isArrayOrTypedArray(radius);
44+
45+
for(i = 0; i < calcTrace.length; i++) {
46+
var cdi = calcTrace[i];
47+
var lonlat = cdi.lonlat;
48+
49+
if(lonlat[0] !== BADNUM) {
50+
var props = {};
51+
52+
if(hasZ) {
53+
var zi = cdi.z;
54+
props.z = zi !== BADNUM ? zi : 0;
55+
}
56+
if(hasArrayRadius) {
57+
props.r = (isNumeric(radius[i]) && radius[i] > 0) ? +radius[i] : 0;
58+
}
59+
60+
features.push({
61+
type: 'Feature',
62+
geometry: {type: 'Point', coordinates: lonlat},
63+
properties: props
64+
});
65+
}
66+
}
67+
68+
var cOpts = Colorscale.extractOpts(trace);
69+
var scl = cOpts.reversescale ?
70+
Colorscale.flipScale(cOpts.colorscale) :
71+
cOpts.colorscale;
72+
73+
// Add alpha channel to first colorscale step.
74+
// If not, we would essentially color the entire map.
75+
// See https://docs.mapbox.com/mapbox-gl-js/example/heatmap-layer/
76+
var scl01 = scl[0][1];
77+
var color0 = Color.opacity(scl01) < 1 ? scl01 : Color.addOpacity(scl01, 0);
78+
79+
var heatmapColor = [
80+
'interpolate', ['linear'],
81+
['heatmap-density'],
82+
0, color0
83+
];
84+
for(i = 1; i < scl.length; i++) {
85+
heatmapColor.push(scl[i][0], scl[i][1]);
86+
}
87+
88+
// Those "weights" have to be in [0, 1], we can do this either:
89+
// - as here using a mapbox-gl expression
90+
// - or, scale the 'z' property in the feature loop
91+
var zExp = [
92+
'interpolate', ['linear'],
93+
['get', 'z'],
94+
cOpts.min, 0,
95+
cOpts.max, 1
96+
];
97+
98+
Lib.extendFlat(opts.heatmap.paint, {
99+
'heatmap-weight': hasZ ? zExp : 1 / (cOpts.max - cOpts.min),
100+
101+
'heatmap-color': heatmapColor,
102+
103+
'heatmap-radius': hasArrayRadius ?
104+
{type: 'identity', property: 'r'} :
105+
trace.radius,
106+
107+
'heatmap-opacity': trace.opacity
108+
});
109+
110+
opts.geojson = {type: 'FeatureCollection', features: features};
111+
opts.heatmap.layout.visibility = 'visible';
112+
opts.below = trace.below;
113+
114+
return opts;
115+
};

src/traces/densitymapbox/defaults.js

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Copyright 2012-2019, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
var Lib = require('../../lib');
12+
var colorscaleDefaults = require('../../components/colorscale/defaults');
13+
var attributes = require('./attributes');
14+
15+
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
16+
function coerce(attr, dflt) {
17+
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
18+
}
19+
20+
var lon = coerce('lon') || [];
21+
var lat = coerce('lat') || [];
22+
23+
var len = Math.min(lon.length, lat.length);
24+
if(!len) {
25+
traceOut.visible = false;
26+
return;
27+
}
28+
29+
traceOut._length = len;
30+
31+
coerce('z');
32+
coerce('radius');
33+
coerce('below');
34+
35+
coerce('text');
36+
coerce('hovertext');
37+
coerce('hovertemplate');
38+
39+
colorscaleDefaults(traceIn, traceOut, layout, coerce, {prefix: '', cLetter: 'z'});
40+
};
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* Copyright 2012-2019, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
module.exports = function eventData(out, pt) {
12+
out.lon = pt.lon;
13+
out.lat = pt.lat;
14+
out.z = pt.z;
15+
return out;
16+
};

src/traces/densitymapbox/hover.js

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* Copyright 2012-2019, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
var Lib = require('../../lib');
12+
var Axes = require('../../plots/cartesian/axes');
13+
var scatterMapboxHoverPoints = require('../scattermapbox/hover');
14+
15+
module.exports = function hoverPoints(pointData, xval, yval) {
16+
var pts = scatterMapboxHoverPoints(pointData, xval, yval);
17+
if(!pts) return;
18+
19+
var newPointData = pts[0];
20+
var cd = newPointData.cd;
21+
var trace = cd[0].trace;
22+
var di = cd[newPointData.index];
23+
24+
// let Fx.hover pick the color
25+
delete newPointData.color;
26+
27+
if('z' in di) {
28+
var ax = newPointData.subplot.mockAxis;
29+
newPointData.z = di.z;
30+
newPointData.zLabel = Axes.tickText(ax, ax.c2l(di.z), 'hover').text;
31+
}
32+
33+
newPointData.extraText = getExtraText(trace, di, cd[0].t.labels);
34+
35+
return [newPointData];
36+
};
37+
38+
function getExtraText(trace, di, labels) {
39+
if(trace.hovertemplate) return;
40+
41+
var hoverinfo = di.hi || trace.hoverinfo;
42+
var parts = hoverinfo.split('+');
43+
var isAll = parts.indexOf('all') !== -1;
44+
var hasLon = parts.indexOf('lon') !== -1;
45+
var hasLat = parts.indexOf('lat') !== -1;
46+
var lonlat = di.lonlat;
47+
var text = [];
48+
49+
function format(v) {
50+
return v + '\u00B0';
51+
}
52+
53+
if(isAll || (hasLon && hasLat)) {
54+
text.push('(' + format(lonlat[0]) + ', ' + format(lonlat[1]) + ')');
55+
} else if(hasLon) {
56+
text.push(labels.lon + format(lonlat[0]));
57+
} else if(hasLat) {
58+
text.push(labels.lat + format(lonlat[1]));
59+
}
60+
61+
if(isAll || parts.indexOf('text') !== -1) {
62+
Lib.fillText(di, trace, text);
63+
}
64+
65+
return text.join('<br>');
66+
}

src/traces/densitymapbox/index.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* Copyright 2012-2019, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
module.exports = {
12+
attributes: require('./attributes'),
13+
supplyDefaults: require('./defaults'),
14+
colorbar: require('../heatmap/colorbar'),
15+
calc: require('./calc'),
16+
plot: require('./plot'),
17+
hoverPoints: require('./hover'),
18+
eventData: require('./event_data'),
19+
20+
moduleType: 'trace',
21+
name: 'densitymapbox',
22+
basePlotModule: require('../../plots/mapbox'),
23+
categories: ['mapbox', 'gl'],
24+
meta: {
25+
hr_name: 'density_mapbox',
26+
description: [
27+
'Draws a bivariate kernel density estimation with a Gaussian kernel',
28+
'from `lon` and `lat` coordinates and optional `z` values using a colorscale.'
29+
].join(' ')
30+
}
31+
};

0 commit comments

Comments
 (0)