10000 A few more ways to configure `marker.size` scales by etpinard · Pull Request #2318 · plotly/plotly.js · GitHub
[go: up one dir, main page]

Skip to content

A few more ways to configure marker.size scales #2318

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/components/legend/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,12 @@ module.exports = function style(s, gd) {
dEdit.mlc = boundVal('marker.line.color', pickFirst);
dEdit.mlw = boundVal('marker.line.width', Lib.mean, [0, 5]);
tEdit.marker = {
sizemode: 'diameter',
sizeref: 1,
sizemin: 1,
sizemode: 'diameter'
sizemax: null,
sizedatamin: null,
sizedatamax: null
};
}

Expand Down
61 changes: 52 additions & 9 deletions src/traces/scatter/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,15 +288,37 @@ module.exports = {
'*0* corresponds to no limit.'
].join(' ')
},

sizemode: {
valType: 'enumerated',
values: ['diameter', 'area', 'log-diameter', 'log-area'],
dflt: 'diameter',
role: 'info',
editType: 'calc',
description: [
'Has an effect only if `marker.size` is set to a numerical array.',
'Sets the rule for which the data in `size` is converted',
'to pixels.',
'When set to *diameter*, `marker.size` data is proportional to',
'marker points\' diameter.',
'When set to *area*, `marker.size` data is proportional to',
'marker points\' area.',
'When set to *log-diameter*, the base10 log of the `marker.size` data',
'is proportional to marker points\' diameter .',
'When set to *log-area*, the base10 log of the `marker.size` data',
'is proportional to marker points\' area.',
'In each case the proportionality constant is set using `sizeref`.'
].join(' ')
},
sizeref: {
valType: 'number',
dflt: 1,
role: 'style',
editType: 'calc',
description: [
'Has an effect only if `marker.size` is set to a numerical array.',
'Sets the scale factor used to determine the rendered size of',
'marker points. Use with `sizemin` and `sizemode`.'
'Sets the proportionality constant in the `marker.size` data',
'to marker point size conversion (More info under `sizemode`).'
].join(' ')
},
sizemin: {
Expand All @@ -310,16 +332,37 @@ module.exports = {
'Sets the minimum size (in px) of the rendered marker points.'
].join(' ')
},
sizemode: {
valType: 'enumerated',
values: ['diameter', 'area'],
dflt: 'diameter',
role: 'info',
sizemax: {
valType: 'number',
min: 0,
role: 'style',
editType: 'calc',
description: [
'Has an effect only if `marker.size` is set to a numerical array.',
'Sets the rule for which the data in `size` is converted',
'to pixels.'
'Sets the maximum size (in px) of the rendered marker points.'
].join(' ')
},
sizedatamin: {
valType: 'number',
min: 0,
dflt: 0,
role: 'style',
editType: 'calc',
description: [
'Has an effect only if `marker.size` is set to a numerical array.',
'Sets the minimum `marker.size` value to be scaled.',
'Values smaller than `sizedatamin` are displayed with `sizemin`.'
].join(' ')
},
sizedatamax: {
valType: 'number',
min: 0,
role: 'style',
editType: 'calc',
description: [
'Has an effect only if `marker.size` is set to a numerical array.',
'Sets the maximum `marker.size` value to be scaled.',
'Values greater than `sizedatamin` are displayed with `sizemax`.'
].join(' ')
},

Expand Down
33 changes: 18 additions & 15 deletions src/traces/scatter/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@

var isNumeric = require('fast-isnumeric');

var Lib = require('../../lib');
var Axes = require('../../plots/cartesian/axes');
var BADNUM = require('../../constants/numerical').BADNUM;

var subTypes = require('./subtypes');
var calcColorscale = require('./colorscale_calc');
var arraysToCalcdata = require('./arrays_to_calcdata');
var calcSelection = require('./calc_selection');
var makeBubbleSizeFn = require('./make_bubble_size_func');

function calc(gd, trace) {
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
Expand Down Expand Up @@ -101,31 +103,32 @@ function calcMarkerSize(trace, serieslen) {
// Treat size like x or y arrays --- Run d2c
// this needs to go before ppad computation
var marker = trace.marker;
var sizeref = 1.6 * (trace.marker.sizeref || 1);
var markerTrans;

if(trace.marker.sizemode === 'area') {
markerTrans = function(v) {
return Math.max(Math.sqrt((v || 0) / sizeref), 3);
};
} else {
markerTrans = function(v) {
return Math.max((v || 0) / sizeref, 3);
};
}

// use a modified version of the bubble size function
// with smaller sizeref (resulting in a pad factor)
// and making non-numeric and size-0 points count as pad=3.
var sizeFn = makeBubbleSizeFn({
marker: Lib.extendFlat({}, marker, {
sizemode: marker.sizemode || 'diameter',
sizeref: 0.8 * (marker.sizeref || 1),
})
});
var markerTrans = function(v) {
return Math.max(sizeFn(v), 3);
};

if(Array.isArray(marker.size)) {
// I tried auto-type but category and dates dont make much sense.
// no need to auto-type as category and dates do not make much sense.
var ax = {type: 'linear'};
Axes.setConvert(ax);

var s = ax.makeCalcdata(trace.marker, 'size');
if(s.length > serieslen) s.splice(serieslen, s.length - serieslen);

return s.map(markerTrans);
} else {
return markerTrans(marker.size);
}

return markerTrans(marker.size);
}

module.exports = {
Expand Down
58 changes: 36 additions & 22 deletions src/traces/scatter/make_bubble_size_func.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,49 @@
* LICENSE file in the root directory of this source tree.
*/


'use strict';

var isNumeric = require('fast-isnumeric');

function toLog(v) {
return Math.log(v) / Math.LN10;
}

// used in the drawing step for 'scatter' and 'scattegeo' and
// in the convert step for 'scatter3d'
module.exports = function makeBubbleSizeFn(trace) {
var marker = trace.marker,
sizeRef = marker.sizeref || 1,
sizeMin = marker.sizemin || 0;

// for bubble charts, allow scaling the provided value linearly
// and by area or diameter.
// Note this only applies to the array-value sizes

var baseFn = (marker.sizemode === 'area') ?
function(v) { return Math.sqrt(v / sizeRef); } :
function(v) { return v / sizeRef; };

// TODO add support for position/negative bubbles?
// TODO add 'sizeoffset' attribute?
var marker = trace.marker;
var sizeRef = marker.sizeref || 1;
var sizeMin = marker.sizemin || 0;
var sizeMax = marker.sizemax || Infinity;
var sizeDataMin = marker.sizedatamin || 0;
var sizeDataMax = marker.sizedatamax || Infinity;
var baseFn;

switch(marker.sizemode) {
case 'area':
baseFn = function(v) { return Math.sqrt(v / sizeRef); };
break;
case 'log-diameter':
baseFn = function(v) { return toLog(v) / sizeRef; };
break;
case 'log-area':
baseFn = function(v) { return Math.sqrt(toLog(v) / sizeRef); };
break;
default:
baseFn = function(v) { return v / sizeRef; };
break;
}

// non-numeric and negative data values AND sizes correspond to size=0 points,
// clamp positive data values outside data range to px extrema
return function(v) {
var baseSize = baseFn(v / 2);

// don't show non-numeric and negative sizes
return (isNumeric(baseSize) && (baseSize > 0)) ?
Math.max(baseSize, sizeMin) :
if(isNumeric(v) && v > 0) {
if(v <= sizeDataMin) return sizeMin;
if(v >= sizeDataMax) return sizeMax;
}

var s = baseFn(v / 2);
return isNumeric(s) && s > 0 ?
Math.min(Math.max(s, sizeMin), sizeMax) :
0;
};
};
5 changes: 4 additions & 1 deletion src/traces/scatter/marker_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,12 @@ module.exports = function markerDefaults(traceIn, traceOut, defaultColor, layout
}

if(isBubble) {
coerce('marker.sizemode');
coerce('marker.sizeref');
coerce('marker.sizemin');
coerce('marker.sizemode');
coerce('marker.sizemax');
coerce('marker.sizedatamin');
coerce('marker.sizedatamax');
}

if(opts.gradient) {
Expand Down
5 changes: 4 additions & 1 deletion src/traces/scatter3d/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,12 @@ var attrs = module.exports = overrideAll({
description: 'Sets the marker symbol type.'
},
size: extendFlat({}, scatterMarkerAttrs.size, {dflt: 8}),
sizemode: scatterMarkerAttrs.sizemode,
sizeref: scatterMarkerAttrs.sizeref,
sizemin: scatterMarkerAttrs.sizemin,
sizemode: scatterMarkerAttrs.sizemode,
sizemax: scatterMarkerAttrs.sizemax,
sizedatamin: scatterMarkerAttrs.sizedatamin,
sizedatamax: scatterMarkerAttrs.sizedatamax,
opacity: extendFlat({}, scatterMarkerAttrs.opacity, {
arrayOk: false,
description: [
Expand Down
5 changes: 4 additions & 1 deletion src/traces/scattercarpet/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,12 @@ module.exports = {
opacity: scatterMarkerAttrs.opacity,
maxdisplayed: scatterMarkerAttrs.maxdisplayed,
size: scatterMarkerAttrs.size,
sizemode: scatterMarkerAttrs.sizemode,
sizeref: scatterMarkerAttrs.sizeref,
sizemin: scatterMarkerAttrs.sizemin,
sizemode: scatterMarkerAttrs.sizemode,
sizemax: scatterMarkerAttrs.sizemax,
sizedatamin: scatterMarkerAttrs.sizedatamin,
sizedatamax: scatterMarkerAttrs.sizedatamax,
line: extendFlat({
width: scatterMarkerLineAttrs.width,
editType: 'calc'
Expand Down
5 changes: 4 additions & 1 deletion src/traces/scattergeo/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,12 @@ module.exports = overrideAll({
symbol: scatterMarkerAttrs.symbol,
opacity: scatterMarkerAttrs.opacity,
size: scatterMarkerAttrs.size,
sizemode: scatterMarkerAttrs.sizemode,
sizeref: scatterMarkerAttrs.sizeref,
sizemin: scatterMarkerAttrs.sizemin,
sizemode: scatterMarkerAttrs.sizemode,
sizemax: scatterMarkerAttrs.sizemax,
sizedatamin: scatterMarkerAttrs.sizedatamin,
sizedatamax: scatterMarkerAttrs.sizedatamax,
showscale: scatterMarkerAttrs.showscale,
colorbar: scatterMarkerAttrs.colorbar,
line: extendFlat({
Expand Down
5 changes: 4 additions & 1 deletion src/traces/scattergl/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,12 @@ var attrs = module.exports = overrideAll({
marker: extendFlat({}, colorAttributes('marker'), {
symbol: scatterMarkerAttrs.symbol,
size: scatterMarkerAttrs.size,
sizemode: scatterMarkerAttrs.sizemode,
sizeref: scatterMarkerAttrs.sizeref,
sizemin: scatterMarkerAttrs.sizemin,
sizemode: scatterMarkerAttrs.sizemode,
sizemax: scatterMarkerAttrs.sizemax,
sizedatamin: scatterMarkerAttrs.sizedatamin,
sizedatamax: scatterMarkerAttrs.sizedatamax,
opacity: scatterMarkerAttrs.opacity,
showscale: scatterMarkerAttrs.showscale,
colorbar: scatterMarkerAttrs.colorbar,
Expand Down
5 changes: 4 additions & 1 deletion src/traces/scattermapbox/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,12 @@ module.exports = overrideAll({
},
opacity: markerAttrs.opacity,
size: markerAttrs.size,
sizemode: markerAttrs.sizemode,
sizeref: markerAttrs.sizeref,
sizemin: markerAttrs.sizemin,
sizemode: markerAttrs.sizemode,
sizemax: markerAttrs.sizemax,
sizedatamin: markerAttrs.sizedatamin,
sizedatamax: markerAttrs.sizedatamax,
color: markerAttrs.color,
colorscale: markerAttrs.colorscale,
cauto: markerAttrs.cauto,
Expand Down
5 changes: 4 additions & 1 deletion src/traces/scatterternary/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,12 @@ module.exports = {
opacity: scatterMarkerAttrs.opacity,
maxdisplayed: scatterMarkerAttrs.maxdisplayed,
size: scatterMarkerAttrs.size,
sizemode: scatterMarkerAttrs.sizemode,
sizeref: scatterMarkerAttrs.sizeref,
sizemin: scatterMarkerAttrs.sizemin,
sizemode: scatterMarkerAttrs.sizemode,
sizemax: scatterMarkerAttrs.sizemax,
sizedatamin: scatterMarkerAttrs.sizedatamin,
sizedatamax: scatterMarkerAttrs.sizedatamax,
line: extendFlat({
width: scatterMarkerLineAttrs.width,
editType: 'calc'
Expand Down
Binary file added test/image/baselines/bubble_scale.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions test/image/mocks/bubble_scale.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"data": [
{
"type": "scatter",
"mode": "markers",
"name": "log-diameter",
"x": [0, 9, 18, 27, 36, 45, 54, 63, 72, 81],
"y": [5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
"marker": {
"size": [10, 100, 1000, 20, 400, 5000, 50, 300, 7000],
"sizemode": "log-diameter",
"sizeref": 0.1
}
},
{
"type": "scatter",
"mode": "markers",
"name": "log-area",
"x": [0, 9, 18, 27, 36, 45, 54, 63, 72, 81],
"y": [4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
"marker": {
"size": [10, 100, 1000, 20, 400, 5000, 50, 300, 7000],
"sizemode": "log-area",
"sizeref": 0.01
}
},
{
"type": "scatter",
"mode": "markers",
"name": "data min-max",
"x": [0, 9, 18, 27, 36, 45, 54, 63, 72, 81],
"y": [3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
"marker": {
"size": [10, 100, 1000, 20, 400, 5000, 50, 300, 7000],
"sizedatamin": 20,
"sizedatamax": 100,
"sizemin": 50,
"sizemax": 60
}
}
],
"layout": {
"hovermode": "closest",
"showlegend": true,
"width": 800,
"height": 500
}
}
0