Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 3 additions & 0 deletions src/plots/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var BADNUM = require('../constants/numerical').BADNUM;

var axisIDs = require('./cartesian/axis_ids');
var clearOutline = require('../components/shapes/handle_outline').clearOutline;
var scatterAttrs = require('../traces/scatter/layout_attributes');

var animationAttrs = require('./animation_attributes');
var frameAttrs = require('./frame_attributes');
Expand Down Expand Up @@ -1566,6 +1567,8 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut, formatObj) {
'fx',
'supplyLayoutGlobalDefaults'
)(layoutIn, layoutOut, coerce);

Lib.coerce(layoutIn, layoutOut, scatterAttrs, 'scattermode');
};

function getComputedSize(attr) {
Expand Down
17 changes: 14 additions & 3 deletions src/traces/bar/cross_trace_calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,14 @@ function setBarCenterAndWidth(pa, sieve) {

// store the actual bar width and position, for use by hover
var width = calcBar.w = barwidthIsArray ? barwidth[j] : barwidth;
calcBar[pLetter] = calcBar.p + (poffsetIsArray ? poffset[j] : poffset) + width / 2;

if(calcBar.p === undefined) {
calcBar.p = calcBar[pLetter];
calcBar['orig_' + pLetter] = calcBar[pLetter];
}

var delta = (poffsetIsArray ? poffset[j] : poffset) + width / 2;
calcBar[pLetter] = calcBar.p + delta;
}
}
}
Expand Down Expand Up @@ -498,13 +505,17 @@ function setBaseAndTop(sa, sieve) {
for(var i = 0; i < calcTraces.length; i++) {
var calcTrace = calcTraces[i];
var fullTrace = calcTrace[0].trace;
var isScatter = fullTrace.type === 'scatter';
var isVertical = fullTrace.orientation === 'v';
var pts = [];
var tozero = false;

for(var j = 0; j < calcTrace.length; j++) {
var bar = calcTrace[j];
var base = bar.b;
var top = base + bar.s;
var base = isScatter ? 0 : bar.b;
var top = isScatter ? (
isVertical ? bar.y : bar.x
) : base + bar.s;

bar[sLetter] = top;
pts.push(top);
Expand Down
9 changes: 7 additions & 2 deletions src/traces/bar/sieve.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
module.exports = Sieve;

var distinctVals = require('../../lib').distinctVals;
var BADNUM = require('../../constants/numerical').BADNUM;

/**
* Helper class to sieve data from traces into bins
Expand All @@ -27,12 +26,18 @@ function Sieve(traces, opts) {
// for single-bin histograms - see histogram/calc
var width1 = Infinity;

var axLetter = opts.posAxis._id.charAt(0);

var positions = [];
for(var i = 0; i < traces.length; i++) {
var trace = traces[i];
for(var j = 0; j < trace.length; j++) {
var bar = trace[j];
if(bar.p !== BADNUM) positions.push(bar.p);
var pos = bar.p;
if(pos === undefined) {
pos = bar[axLetter];
}
if(pos !== undefined) positions.push(pos);
}
if(trace[0] && trace[0].width1) {
width1 = Math.min(trace[0].width1, width1);
Expand Down
4 changes: 3 additions & 1 deletion src/traces/scatter/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ module.exports = {
values: ['v', 'h'],
editType: 'calc',
description: [
'Only relevant when `stackgroup` is used, and only the first',
'Only relevant in the following cases:',
'1. when `scattermode` is set to *group*.',
'2. when `stackgroup` is used, and only the first',
'`orientation` found in the `stackgroup` will be used - including',
'if `visible` is *legendonly* but not if it is `false`. Sets the',
'stacking direction. With *v* (*h*), the y (x) values of subsequent',
Expand Down
41 changes: 41 additions & 0 deletions src/traces/scatter/cross_trace_calc.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,54 @@
'use strict';

var calc = require('./calc');
var setGroupPositions = require('../bar/cross_trace_calc').setGroupPositions;

function groupCrossTraceCalc(gd, plotinfo) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;

var fullLayout = gd._fullLayout;
var fullTraces = gd._fullData;
var calcTraces = gd.calcdata;
var calcTracesHorz = [];
var calcTracesVert = [];

for(var i = 0; i < fullTraces.length; i++) {
var fullTrace = fullTraces[i];
if(
fullTrace.visible === true &&
fullTrace.type === 'scatter' &&
fullTrace.xaxis === xa._id &&
fullTrace.yaxis === ya._id
) {
if(fullTrace.orientation === 'h') {
calcTracesHorz.push(calcTraces[i]);
} else if(fullTrace.orientation === 'v') { // check for v since certain scatter traces may not have an orientation
calcTracesVert.push(calcTraces[i]);
}
}
}

var opts = {
mode: fullLayout.scattermode,
gap: fullLayout.scattergap,
groupgap: fullLayout.scattergroupgap
};

setGroupPositions(gd, xa, ya, calcTracesVert, opts);
setGroupPositions(gd, ya, xa, calcTracesHorz, opts);
}

/*
* Scatter stacking & normalization calculations
* runs per subplot, and can handle multiple stacking groups
*/

module.exports = function crossTraceCalc(gd, plotinfo) {
if(gd._fullLayout.scattermode === 'group') {
groupCrossTraceCalc(gd, plotinfo);
}

var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
var subplot = xa._id + ya._id;
Expand Down
6 changes: 6 additions & 0 deletions src/traces/scatter/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
coerce('yhoverformat');

var stackGroupOpts = handleStackDefaults(traceIn, traceOut, layout, coerce);
if(
layout.scattermode === 'group' &&
traceOut.orientation === undefined
) {
coerce('orientation', 'v');
}

var defaultMode = !stackGroupOpts && (len < constants.PTS_LINESONLY) ?
'lines+markers' : 'lines';
Expand Down
10 changes: 8 additions & 2 deletions src/traces/scatter/format_labels.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@ module.exports = function formatLabels(cdi, trace, fullLayout) {
var xa = Axes.getFromTrace(mockGd, trace, 'x');
var ya = Axes.getFromTrace(mockGd, trace, 'y');

labels.xLabel = Axes.tickText(xa, xa.c2l(cdi.x), true).text;
labels.yLabel = Axes.tickText(ya, ya.c2l(cdi.y), true).text;
var x = cdi.orig_x;
if(x === undefined) x = cdi.x;

var y = cdi.orig_y;
if(y === undefined) y = cdi.y;

labels.xLabel = Axes.tickText(xa, xa.c2l(x), true).text;
labels.yLabel = Axes.tickText(ya, ya.c2l(y), true).text;

return labels;
};
2 changes: 2 additions & 0 deletions src/traces/scatter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ module.exports = {
isBubble: subtypes.isBubble,

attributes: require('./attributes'),
layoutAttributes: require('./layout_attributes'),
supplyDefaults: require('./defaults'),
crossTraceDefaults: require('./cross_trace_defaults'),
supplyLayoutDefaults: require('./layout_defaults'),
calc: require('./calc').calc,
crossTraceCalc: require('./cross_trace_calc'),
arraysToCalcdata: require('./arrays_to_calcdata'),
Expand Down
41 changes: 41 additions & 0 deletions src/traces/scatter/layout_attributes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';


module.exports = {
scattermode: {
valType: 'enumerated',
values: ['group', 'overlay'],
dflt: 'overlay',
editType: 'calc',
description: [
'Determines how scatter points at the same location coordinate',
'are displayed on the graph.',
'With *group*, the scatter points are plotted next to one another',
'centered around the shared location.',
'With *overlay*, the scatter points are plotted over one another,',
'you might need to reduce *opacity* to see multiple scatter points.'
].join(' ')
},
scattergap: {
valType: 'number',
min: 0,
max: 1,
editType: 'calc',
description: [
'Sets the gap (in plot fraction) between scatter points of',
'adjacent location coordinates.',
'Defaults to `bargap`.'
].join(' ')
},
scattergroupgap: {
valType: 'number',
min: 0,
max: 1,
dflt: 0,
editType: 'calc',
description: [
'Sets the gap (in plot fraction) between scatter points of',
'the same location coordinate.'
].join(' ')
}
};
18 changes: 18 additions & 0 deletions src/traces/scatter/layout_defaults.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict';

var Lib = require('../../lib');

var layoutAttributes = require('./layout_attributes');

module.exports = function(layoutIn, layoutOut) {
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}

var groupBarmode = layoutOut.barmode === 'group';

if(layoutOut.scattermode === 'group') {
coerce('scattergap', groupBarmode ? layoutOut.bargap : 0.2);
coerce('scattergroupgap');
}
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/image/baselines/zz-grouped_scatter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions test/image/mocks/zz-grouped_scatter-linear.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"data": [
{
"mode": "markers+lines+text",
"texttemplate": "x:%{x}",
"textposition": "bottom center",
"textfont": { "size": 16 },
"y": [
1,
3,
2
]
},
{
"mode": "markers+lines+text",
"texttemplate": "x:%{x}",
"textposition": "bottom center",
"textfont": { "size": 16 },
"y": [
2,
1,
3
]
}
],
"layout": {
"width": 600,
"height": 400,
"scattermode": "group"
}
}
35 changes: 35 additions & 0 deletions test/image/mocks/zz-grouped_scatter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"data": [
{
"x": [
"giraffes",
"orangutans",
"monkeys"
],
"y": [
20,
14,
23
],
"name": "SF Zoo"
},
{
"x": [
"giraffes",
"orangutans",
"monkeys"
],
"y": [
12,
18,
29
],
"name": "LA Zoo"
}
],
"layout": {
"width": 600,
"height": 400,
"scattermode": "group"
}
}
29 changes: 28 additions & 1 deletion test/plot-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -44902,7 +44902,7 @@
"valType": "number"
},
"orientation": {
"description": "Only relevant when `stackgroup` is used, and only the first `orientation` found in the `stackgroup` will be used - including if `visible` is *legendonly* but not if it is `false`. Sets the stacking direction. With *v* (*h*), the y (x) values of subsequent traces are added. Also affects the default value of `fill`.",
"description": "Only relevant in the following cases: 1. when `scattermode` is set to *group*. 2. when `stackgroup` is used, and only the first `orientation` found in the `stackgroup` will be used - including if `visible` is *legendonly* but not if it is `false`. Sets the stacking direction. With *v* (*h*), the y (x) values of subsequent traces are added. Also affects the default value of `fill`.",
"editType": "calc",
"valType": "enumerated",
"values": [
Expand Down Expand Up @@ -45307,6 +45307,33 @@
"scatter-like",
"zoomScale"
],
"layoutAttributes": {
"scattergap": {
"description": "Sets the gap (in plot fraction) between scatter points of adjacent location coordinates. Defaults to `bargap`.",
"editType": "calc",
"max": 1,
"min": 0,
"valType": "number"
},
"scattergroupgap": {
"description": "Sets the gap (in plot fraction) between scatter points of the same location coordinate.",
"dflt": 0,
"editType": "calc",
"max": 1,
"min": 0,
"valType": "number"
},
"scattermode": {
"description": "Determines how scatter points at the same location coordinate are displayed on the graph. With *group*, the scatter points are plotted next to one another centered around the shared location. With *overlay*, the scatter points are plotted over one another, you might need to reduce *opacity* to see multiple scatter points.",
"dflt": "overlay",
"editType": "calc",
"valType": "enumerated",
"values": [
"group",
"overlay"
]
}
},
"meta": {
"description": "The scatter trace type encompasses line charts, scatter charts, text charts, and bubble charts. The data visualized as scatter point or lines is set in `x` and `y`. Text (appearing either on the chart or on hover only) is via `text`. Bubble charts are achieved by setting `marker.size` and/or `marker.color` to numerical arrays."
},
Expand Down