diff --git a/src/traces/scatter/link_traces.js b/src/traces/scatter/link_traces.js index 3b3741c9ed1..ed50bd73d00 100644 --- a/src/traces/scatter/link_traces.js +++ b/src/traces/scatter/link_traces.js @@ -75,9 +75,16 @@ module.exports = function linkTraces(gd, plotinfo, cdscatter) { } } + if(trace.fill && ( + trace.fill.substr(0, 6) === 'tozero' || trace.fill === 'toself' || + (trace.fill.substr(0, 2) === 'to' && !trace._prevtrace)) + ) { + trace._ownfill = true; + } + prevtraces[group] = trace; } else { - trace._prevtrace = trace._nexttrace = null; + trace._prevtrace = trace._nexttrace = trace._ownfill = null; } } diff --git a/src/traces/scatter/plot.js b/src/traces/scatter/plot.js index d4b3c61f921..ac589ce0ba0 100644 --- a/src/traces/scatter/plot.js +++ b/src/traces/scatter/plot.js @@ -93,19 +93,10 @@ function createFills(gd, traceJoin, plotinfo) { var trace = d[0].trace; var fillData = []; - if(trace.fill && (trace.fill.substr(0, 6) === 'tozero' || trace.fill === 'toself' || - (trace.fill.substr(0, 2) === 'to' && !trace._prevtrace)) - ) { - fillData = ['_ownFill']; - } - if(trace._nexttrace) { - // make the fill-to-next path now for the NEXT trace, so it shows - // behind both lines. - fillData.push('_nextFill'); - } + if(trace._ownfill) fillData.push('_ownFill'); + if(trace._nexttrace) fillData.push('_nextFill'); - var fillJoin = fills.selectAll('g') - .data(fillData, identity); + var fillJoin = fills.selectAll('g').data(fillData, identity); fillJoin.enter().append('g'); diff --git a/src/traces/scattergl/attributes.js b/src/traces/scattergl/attributes.js index 94731763ffc..aebdf2b4146 100644 --- a/src/traces/scattergl/attributes.js +++ b/src/traces/scattergl/attributes.js @@ -46,6 +46,17 @@ var attrs = module.exports = overrideAll({ line: { color: scatterLineAttrs.color, width: scatterLineAttrs.width, + shape: { + valType: 'enumerated', + values: ['linear', 'hv', 'vh', 'hvh', 'vhv'], + dflt: 'linear', + role: 'style', + editType: 'plot', + description: [ + 'Determines the line shape.', + 'The values correspond to step-wise line shapes.' + ].join(' ') + }, dash: { valType: 'enumerated', values: Object.keys(DASHES), diff --git a/src/traces/scattergl/convert.js b/src/traces/scattergl/convert.js index f0ffbf8220f..f674df669c5 100644 --- a/src/traces/scattergl/convert.js +++ b/src/traces/scattergl/convert.js @@ -385,7 +385,8 @@ function getSymbolSdf(symbol) { } function convertLinePositions(gd, trace, positions) { - var count = positions.length / 2; + var len = positions.length; + var count = len / 2; var linePositions; var i; @@ -394,38 +395,81 @@ function convertLinePositions(gd, trace, positions) { linePositions = []; for(i = 0; i < count - 1; i++) { if(isNaN(positions[i * 2]) || isNaN(positions[i * 2 + 1])) { - linePositions.push(NaN); - linePositions.push(NaN); - linePositions.push(NaN); - linePositions.push(NaN); + linePositions.push(NaN, NaN, NaN, NaN); + } else { + linePositions.push(positions[i * 2], positions[i * 2 + 1]); + if(!isNaN(positions[i * 2 + 2]) && !isNaN(positions[i * 2 + 3])) { + linePositions.push(positions[i * 2 + 2], positions[i * 2 + 1]); + } else { + linePositions.push(NaN, NaN); + } + } + } + linePositions.push(positions[len - 2], positions[len - 1]); + } else if(trace.line.shape === 'hvh') { + linePositions = []; + for(i = 0; i < count - 1; i++) { + if(isNaN(positions[i * 2]) || isNaN(positions[i * 2 + 1]) || isNaN(positions[i * 2 + 2]) || isNaN(positions[i * 2 + 3])) { + if(!isNaN(positions[i * 2]) && !isNaN(positions[i * 2 + 1])) { + linePositions.push(positions[i * 2], positions[i * 2 + 1]); + } else { + linePositions.push(NaN, NaN); + } + linePositions.push(NaN, NaN); } else { - linePositions.push(positions[i * 2]); - linePositions.push(positions[i * 2 + 1]); - linePositions.push(positions[i * 2 + 2]); - linePositions.push(positions[i * 2 + 1]); + var midPtX = (positions[i * 2] + positions[i * 2 + 2]) / 2; + linePositions.push( + positions[i * 2], + positions[i * 2 + 1], + midPtX, + positions[i * 2 + 1], + midPtX, + positions[i * 2 + 3] + ); } } - linePositions.push(positions[positions.length - 2]); - linePositions.push(positions[positions.length - 1]); + linePositions.push(positions[len - 2], positions[len - 1]); + } else if(trace.line.shape === 'vhv') { + linePositions = []; + for(i = 0; i < count - 1; i++) { + if(isNaN(positions[i * 2]) || isNaN(positions[i * 2 + 1]) || isNaN(positions[i * 2 + 2]) || isNaN(positions[i * 2 + 3])) { + if(!isNaN(positions[i * 2]) && !isNaN(positions[i * 2 + 1])) { + linePositions.push(positions[i * 2], positions[i * 2 + 1]); + } else { + linePositions.push(NaN, NaN); + } + linePositions.push(NaN, NaN); + } + else { + var midPtY = (positions[i * 2 + 1] + positions[i * 2 + 3]) / 2; + linePositions.push( + positions[i * 2], + positions[i * 2 + 1], + positions[i * 2], + midPtY, + positions[i * 2 + 2], + midPtY + ); + } + } + linePositions.push(positions[len - 2], positions[len - 1]); } else if(trace.line.shape === 'vh') { linePositions = []; for(i = 0; i < count - 1; i++) { if(isNaN(positions[i * 2]) || isNaN(positions[i * 2 + 1])) { - linePositions.push(NaN); - linePositions.push(NaN); - linePositions.push(NaN); - linePositions.push(NaN); + linePositions.push(NaN, NaN, NaN, NaN); } else { - linePositions.push(positions[i * 2]); - linePositions.push(positions[i * 2 + 1]); - linePositions.push(positions[i * 2]); - linePositions.push(positions[i * 2 + 3]); + linePositions.push(positions[i * 2], positions[i * 2 + 1]); + if(!isNaN(positions[i * 2 + 2]) && !isNaN(positions[i * 2 + 3])) { + linePositions.push(positions[i * 2], positions[i * 2 + 3]); + } else { + linePositions.push(NaN, NaN); + } } } - linePositions.push(positions[positions.length - 2]); - linePositions.push(positions[positions.length - 1]); + linePositions.push(positions[len - 2], positions[len - 1]); } else { linePositions = positions; } diff --git a/src/traces/scattergl/defaults.js b/src/traces/scattergl/defaults.js index 2703cb31b20..1120edea4f1 100644 --- a/src/traces/scattergl/defaults.js +++ b/src/traces/scattergl/defaults.js @@ -42,6 +42,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout if(subTypes.hasLines(traceOut)) { coerce('connectgaps'); handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce); + coerce('line.shape'); } if(subTypes.hasMarkers(traceOut)) { diff --git a/src/traces/scattergl/index.js b/src/traces/scattergl/index.js index 3a3aa242bfe..c3068932a5b 100644 --- a/src/traces/scattergl/index.js +++ b/src/traces/scattergl/index.js @@ -256,39 +256,38 @@ function sceneUpdate(gd, subplot) { // draw traces in proper order scene.draw = function draw() { - var i; - for(i = 0; i < scene.count; i++) { - if(scene.fill2d && scene.fillOptions[i]) { - // must do all fills first - scene.fill2d.draw(i); + var count = scene.count; + var fill2d = scene.fill2d; + var error2d = scene.error2d; + var line2d = scene.line2d; + var scatter2d = scene.scatter2d; + var glText = scene.glText; + var select2d = scene.select2d; + var selectBatch = scene.selectBatch; + var unselectBatch = scene.unselectBatch; + + for(var i = 0; i < count; i++) { + if(fill2d && scene.fillOrder[i]) { + fill2d.draw(scene.fillOrder[i]); } - } - for(i = 0; i < scene.count; i++) { - if(scene.line2d && scene.lineOptions[i]) { - scene.line2d.draw(i); + if(line2d && scene.lineOptions[i]) { + line2d.draw(i); } - if(scene.error2d && scene.errorXOptions[i]) { - scene.error2d.draw(i); + if(error2d) { + if(scene.errorXOptions[i]) error2d.draw(i); + if(scene.errorYOptions[i]) error2d.draw(i + count); } - if(scene.error2d && scene.errorYOptions[i]) { - scene.error2d.draw(i + scene.count); + if(scatter2d && scene.markerOptions[i] && (!selectBatch || !selectBatch[i])) { + scatter2d.draw(i); } - if(scene.scatter2d && scene.markerOptions[i] && (!scene.selectBatch || !scene.selectBatch[i])) { - // traces in no-selection mode - scene.scatter2d.draw(i); + if(glText[i] && scene.textOptions[i]) { + glText[i].render(); } } - // draw traces in selection mode - if(scene.scatter2d && scene.select2d && scene.selectBatch) { - scene.select2d.draw(scene.selectBatch); - scene.scatter2d.draw(scene.unselectBatch); - } - - for(i = 0; i < scene.count; i++) { - if(scene.glText[i] && scene.textOptions[i]) { - scene.glText[i].render(); - } + if(scatter2d && select2d && selectBatch) { + select2d.draw(selectBatch); + scatter2d.draw(unselectBatch); } scene.dirty = false; @@ -397,6 +396,24 @@ function plot(gd, subplot, cdata) { } if(scene.line2d) { scene.line2d.update(scene.lineOptions); + scene.lineOptions = scene.lineOptions.map(function(lineOptions) { + if(lineOptions && lineOptions.positions) { + var pos = [], srcPos = lineOptions.positions; + + var firstptdef = 0; + while(isNaN(srcPos[firstptdef]) || isNaN(srcPos[firstptdef + 1])) { + firstptdef += 2; + } + var lastptdef = srcPos.length - 2; + while(isNaN(srcPos[lastptdef]) || isNaN(srcPos[lastptdef + 1])) { + lastptdef += -2; + } + pos = pos.concat(srcPos.slice(firstptdef, lastptdef + 2)); + lineOptions.positions = pos; + } + return lineOptions; + }); + scene.line2d.update(scene.lineOptions); } if(scene.error2d) { var errorBatch = (scene.errorXOptions || []).concat(scene.errorYOptions || []); @@ -405,7 +422,9 @@ function plot(gd, subplot, cdata) { if(scene.scatter2d) { scene.scatter2d.update(scene.markerOptions); } + // fill requires linked traces, so we generate it's positions here + scene.fillOrder = Lib.repeat(null, scene.count); if(scene.fill2d) { scene.fillOptions = scene.fillOptions.map(function(fillOptions, i) { var cdscatter = cdata[i]; @@ -416,19 +435,46 @@ function plot(gd, subplot, cdata) { var lineOptions = scene.lineOptions[i]; var last, j; + var fillData = []; + if(trace._ownfill) fillData.push(i); + if(trace._nexttrace) fillData.push(i + 1); + if(fillData.length) scene.fillOrder[i] = fillData; + var pos = [], srcPos = (lineOptions && lineOptions.positions) || stash.positions; if(trace.fill === 'tozeroy') { - pos = [srcPos[0], 0]; - pos = pos.concat(srcPos); - pos.push(srcPos[srcPos.length - 2]); - pos.push(0); + var firstpdef = 0; + while(isNaN(srcPos[firstpdef + 1])) { + firstpdef += 2; + } + var lastpdef = srcPos.length - 2; + while(isNaN(srcPos[lastpdef + 1])) { + lastpdef += -2; + } + if(srcPos[firstpdef + 1] !== 0) { + pos = [ srcPos[firstpdef], 0 ]; + } + pos = pos.concat(srcPos.slice(firstpdef, lastpdef + 2)); + if(srcPos[lastpdef + 1] !== 0) { + pos = pos.concat([ srcPos[lastpdef], 0 ]); + } } else if(trace.fill === 'tozerox') { - pos = [0, srcPos[1]]; - pos = pos.concat(srcPos); - pos.push(0); - pos.push(srcPos[srcPos.length - 1]); + var firstptdef = 0; + while(isNaN(srcPos[firstptdef])) { + firstptdef += 2; + } + var lastptdef = srcPos.length - 2; + while(isNaN(srcPos[lastptdef])) { + lastptdef += -2; + } + if(srcPos[firstptdef] !== 0) { + pos = [ 0, srcPos[firstptdef + 1] ]; + } + pos = pos.concat(srcPos.slice(firstptdef, lastptdef + 2)); + if(srcPos[lastptdef] !== 0) { + pos = pos.concat([ 0, srcPos[lastptdef + 1]]); + } } else if(trace.fill === 'toself' || trace.fill === 'tonext') { pos = []; @@ -459,8 +505,7 @@ function plot(gd, subplot, cdata) { for(i = Math.floor(nextPos.length / 2); i--;) { var xx = nextPos[i * 2], yy = nextPos[i * 2 + 1]; if(isNaN(xx) || isNaN(yy)) continue; - pos.push(xx); - pos.push(yy); + pos.push(xx, yy); } fillOptions.fill = nextTrace.fillcolor; } @@ -486,7 +531,7 @@ function plot(gd, subplot, cdata) { pos = pos.concat(prevLinePos); fillOptions.hole = hole; } - + fillOptions.fillmode = trace.fill; fillOptions.opacity = trace.opacity; fillOptions.positions = pos; diff --git a/test/image/baselines/gl2d_fill-ordering.png b/test/image/baselines/gl2d_fill-ordering.png index 7b71d7d2dcb..ed2acbd53cc 100644 Binary files a/test/image/baselines/gl2d_fill-ordering.png and b/test/image/baselines/gl2d_fill-ordering.png differ diff --git a/test/image/baselines/gl2d_fill_trace_tozero_order.png b/test/image/baselines/gl2d_fill_trace_tozero_order.png new file mode 100644 index 00000000000..5fbfce15d4f Binary files /dev/null and b/test/image/baselines/gl2d_fill_trace_tozero_order.png differ diff --git a/test/image/baselines/gl2d_order_error.png b/test/image/baselines/gl2d_order_error.png new file mode 100644 index 00000000000..250eb8f64fe Binary files /dev/null and b/test/image/baselines/gl2d_order_error.png differ diff --git a/test/image/baselines/gl2d_scatter_fill_self_next_vs_nogl.png b/test/image/baselines/gl2d_scatter_fill_self_next_vs_nogl.png new file mode 100644 index 00000000000..aa5e6d7677d Binary files /dev/null and b/test/image/baselines/gl2d_scatter_fill_self_next_vs_nogl.png differ diff --git a/test/image/baselines/gl2d_shape_line.png b/test/image/baselines/gl2d_shape_line.png new file mode 100644 index 00000000000..f5b8767f9d8 Binary files /dev/null and b/test/image/baselines/gl2d_shape_line.png differ diff --git a/test/image/mocks/gl2d_fill_trace_tozero_order.json b/test/image/mocks/gl2d_fill_trace_tozero_order.json new file mode 100644 index 00000000000..1018bbe1a8a --- /dev/null +++ b/test/image/mocks/gl2d_fill_trace_tozero_order.json @@ -0,0 +1,141 @@ +{ + "data": [ + { + "x": [null, 3 , 3, null, null ], + "y": [ 25,30,35,40 ,50 ], + "type": "scattergl", + "fill": "tozerox", + "mode": "none", + "showlegend": true, "xaxis": "x", "yaxis": "y" , + "fillcolor": "#FF69B4", + "line": { "color": "#FF69B4" } + }, + { + "x": [ null, null, null, 5, 5 ], + "y": [ 25,30,35,40 ,50 ], + "type": "scattergl", + "fill": "tozerox", + "mode": "markers+lines", + "showlegend": true, "xaxis": "x", "yaxis": "y" , + "fillcolor": "#202ff0", + "line": { "color": "#101ff0" } + }, + { + "x": [null, 3 , 3, null, null ], + "y": [ 25,30,35,40 ,50 ], + "type": "scatter", + "fill": "tozerox", + "mode": "none", + "showlegend": true, "xaxis": "x2", "yaxis": "y2" , + "fillcolor": "#DD5792", + "line": { "color": "#DD5792" } + }, + { + "x": [ null, null, null, 5, 5 ], + "y": [ 25,30,35,40 ,50 ], + "type": "scatter", + "fill": "tozerox", + "mode": "markers+lines", + "showlegend": true, "xaxis": "x2", "yaxis": "y2" , + "fillcolor": "#000fd0", + "line": { "color": "#0000d0" } + }, + { + "x": [ 1, 2, 3, 4, 5 ], + "y": [ null, 50, 50,null ,null ], + "type": "scattergl", + "fill": "tozeroy", + "mode": "none", + "showlegend": true, "xaxis": "x3", "yaxis": "y3" , + "fillcolor": "#80aa70", + "line": { "color": "#80aa70" } + }, + { + "x": [ 1, 2, 3, 4, 5 ], + "y": [null ,null ,null , 50, 50 ], + "type": "scattergl", + "fill": "tozeroy", + "mode": "markers+lines", + "showlegend": true, "xaxis": "x3", "yaxis": "y3" , + "fillcolor": "#f09090", + "line": { "color": "#e0b0b0" } + }, + { + "x": [ 1, 2, 3, 4, 5 ], + "y": [ null, 50, 50,null ,null ], + "type": "scatter", + "fill": "tozeroy", + "mode": "none", + "showlegend": true, "xaxis": "x4", "yaxis": "y4" , + "fillcolor": "#608a50", + "line": { "color": "#608a50" } + }, + { + "x": [ 1, 2, 3, 4, 5 ], + "y": [null ,null ,null , 50, 50 ], + "type": "scatter", + "fill": "tozeroy", + "mode": "markers+lines", + "showlegend": true, "xaxis": "x4", "yaxis": "y4" , + "fillcolor": "#e07070", + "line": { "color": "#c09090" } + }, + { + "x": [ 1, 1, 2, 3, 4, 5,5 ], + "y": [ 0,25,25,25,25,25,0 ], + "type": "scattergl", + "fill": "tozeroy", + "mode": "markers+lines", + "showlegend": true, "xaxis": "x5", "yaxis": "y5" , + "fillcolor": "#f02f20", + "line": { "color": "#f01f10" } + }, + { + "x": [ 1, 2, 2, 3, 4, 4,5 ], + "y": [ 0, 0,50,50,50, 0,0 ], + "type": "scattergl", + "fill": "tozeroy", + "mode": "none", + "showlegend": true, "xaxis": "x5", "yaxis": "y5" , + "fillcolor": "#90ff70", + "line": { "color": "#90ff70" } + }, + { + "x": [ 1, 1, 2, 3, 4, 5,5 ], + "y": [ 0,25,25,25,25,25,0 ], + "type": "scatter", + "fill": "tozeroy", + "mode": "markers+lines", + "showlegend": true, "xaxis": "x6", "yaxis": "y6" , + "fillcolor": "#d00f00", + "line": { "color": "#d00000" } + }, + { + "x": [ 1, 2, 2, 3, 4, 4,5 ], + "y": [ 0, 0,50,50,50, 0,0 ], + "type": "scatter", + "fill": "tozeroy", + "mode": "none", + "showlegend": true, "xaxis": "x6", "yaxis": "y6" , + "fillcolor": "#70df50", + "line": { "color": "#70df50" } + } + ], + "layout": { + "width": 800,"height": 800, + "margin": {"l": 60, "r": 60, "t": 60, "b": 60}, + "grid": {"columns": 2, "rows": 3, "pattern": "independent", "roworder": "bottom to top"} , + "xaxis" : { "title": "GL" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "xaxis2": { "title": "" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "xaxis3": { "title": "GL" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "xaxis4": { "title": "" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "xaxis5": { "title": "GL" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "xaxis6": { "title": "" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "yaxis" : { "title": "" , "type": "linear", "range": [0,60], "nticks": 3 }, + "yaxis2": { "title": "" , "type": "linear", "range": [0,60], "nticks": 3 }, + "yaxis3": { "title": "" , "type": "linear", "range": [0,60], "nticks": 3 }, + "yaxis4": { "title": "" , "type": "linear", "range": [0,60], "nticks": 3 }, + "yaxis5": { "title": "" , "type": "linear", "range": [0,60], "nticks": 3 }, + "yaxis6": { "title": "" , "type": "linear", "range": [0,60], "nticks": 3 } + } +} diff --git a/test/image/mocks/gl2d_order_error.json b/test/image/mocks/gl2d_order_error.json new file mode 100644 index 00000000000..49158e78d38 --- /dev/null +++ b/test/image/mocks/gl2d_order_error.json @@ -0,0 +1,86 @@ +{ + "data": [{ + "type": "scattergl", + "y": [2, 3, 2, 0], + "xaxis": "x", "yaxis": "y" , + "error_x": {"value": 0.4, "type": "constant","color":"#028"}, + "error_y": {"value": 0.3, "type": "constant","color":"#820"}, + "marker": {"color": "#800"},"line": {"color": "#400"} + },{ + "type": "scattergl", + "y": [3, 2, 1, 1], "mode":"text","xaxis": "x", "yaxis": "y" , + "text": ["A","B","C","D"], + "textfont": { "size": [ 30, 20 , 30 , 30 ] } + },{ + "type": "scattergl", + "y": [1, 4, 0, 3], + "fillcolor":"#282","fill": "tozeroy", "xaxis": "x", "yaxis": "y" , + "error_x": {"value": 0.4, "type": "constant","color":"#028"}, + "error_y": {"value": 0.3, "type": "constant","color":"#820"}, + "marker": {"color": "#060"},"line": {"color": "#030"} + },{ + "type": "scatter", + "y": [2, 3, 2, 0], + "xaxis": "x2", "yaxis": "y2" , + "error_x": {"value": 0.4, "type": "constant","color":"#028"}, + "error_y": {"value": 0.3, "type": "constant","color":"#820"}, + "marker": {"color": "#088"},"line": {"color": "#044"} + },{ + "type": "scatter", + "y": [3, 2, 1, 1], "mode":"text","xaxis": "x2", "yaxis": "y2" , + "text": ["A","B","C","D"], + "textfont": { "size": [ 30, 20 , 30 , 30 ] } + },{ + "type": "scatter", + "y": [1, 4, 0, 3], + "fillcolor":"#882","fill": "tozeroy", "xaxis": "x2", "yaxis": "y2" , + "error_x": {"value": 0.4, "type": "constant","color":"#028"}, + "error_y": {"value": 0.3, "type": "constant","color":"#820"}, + "marker": {"color": "#660"},"line": {"color": "#330"} + },{ + "type": "scattergl", + "y": [2, 3, 2, 0], + "fill": "tozeroy", "xaxis": "x3", "yaxis": "y3" , + "fillcolor": "#f00", + "error_x": {"value": 0.4, "type": "constant","color":"#028"}, + "error_y": {"value": 0.3, "type": "constant","color":"#820"}, + "marker": {"color": "#800"},"line": {"color": "#400"} + },{ + "type": "scattergl", + "y": [1, 4, 0, 3], + "fill": "tozeroy", "xaxis": "x3", "yaxis": "y3" , + "fillcolor": "#0c0", + "error_x": {"value": 0.4, "type": "constant","color":"#028"}, + "error_y": {"value": 0.3, "type": "constant","color":"#820"}, + "marker": {"color": "#060"},"line": {"color": "#030"} + },{ + "type": "scatter", + "y": [2, 3, 2, 0], + "fill": "tozeroy", "xaxis": "x4", "yaxis": "y4" , + "fillcolor": "#f08", + "error_x": {"value": 0.4, "type": "constant","color":"#028"}, + "error_y": {"value": 0.3, "type": "constant","color":"#820"}, + "marker": {"color": "#088"},"line": {"color": "#044"} + },{ + "type": "scatter", + "y": [1, 4, 0, 3], + "fill": "tozeroy", "xaxis": "x4", "yaxis": "y4" , + "fillcolor": "#0c8", + "error_x": {"value": 0.4, "type": "constant","color":"#028"}, + "error_y": {"value": 0.3, "type": "constant","color":"#820"}, + "marker": {"color": "#660"},"line": {"color": "#330"} + }], + "layout": { + "width": 800,"height": 800, + "margin": {"l": 100, "r": 100, "t": 100, "b": 100}, + "grid": {"columns": 2, "rows": 2, "pattern": "independent", "roworder": "bottom to top"} , + "xaxis" : { "title": "GL" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "xaxis2": { "title": "" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "xaxis3": { "title": "GL" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "xaxis4": { "title": "" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "yaxis" : { "title": "GL" , "type": "linear", "range": [-1,5], "nticks": 3 }, + "yaxis2": { "title": "" , "type": "linear", "range": [-1,5], "nticks": 3 }, + "yaxis3": { "title": "GL" , "type": "linear", "range": [-1,5], "nticks": 3 }, + "yaxis4": { "title": "" , "type": "linear", "range": [-1,5], "nticks": 3 } + } +} diff --git a/test/image/mocks/gl2d_scatter_fill_self_next_vs_nogl.json b/test/image/mocks/gl2d_scatter_fill_self_next_vs_nogl.json new file mode 100644 index 00000000000..8298d023376 --- /dev/null +++ b/test/image/mocks/gl2d_scatter_fill_self_next_vs_nogl.json @@ -0,0 +1,110 @@ +{ + "data":[ + { + "x": [1, 2, 3, 1, null, 4, 5, 6], + "y": [2, 3, 2, 2, null, 3, 4, 3], + "fill": "tonext","fillcolor":"#282", "line": { "color": "#8c8" }, + "type": "scattergl" + }, + { + "x": [-1, 4, 9, null, 0, 1, 2], + "y": [1, 6, 1, null, 5, 6, 5], + "fill": "tonext","fillcolor":"#822", "line": { "color": "#c88" }, + "type": "scattergl" + }, + { + "x": [2, 7, 9], + "y": [2, 4, 2], + "fill": "toself","fillcolor":"#228", "line": { "color": "#88c" }, + "type": "scattergl" + }, + { + "x": [1, 2, 3, 1, null, 4, 5, 6], + "y": [2, 3, 2, 2, null, 3, 4, 3], + "fill": "tonext","fillcolor":"#282", "line": { "color": "#8c8" }, + "type": "scatter", "showlegend": true, "xaxis": "x2", "yaxis": "y2" + }, + { + "x": [-1, 4, 9, null, 0, 1, 2], + "y": [1, 6, 1, null, 5, 6, 5], + "fill": "tonext","fillcolor":"#822", "line": { "color": "#c88" }, + "type": "scatter", "showlegend": true, "xaxis": "x2", "yaxis": "y2" + }, + { + "x": [2, 7, 9], + "y": [2, 4, 2], + "fill": "toself","fillcolor":"#228", "line": { "color": "#88c" }, + "type": "scatter","showlegend": true, "xaxis": "x2", "yaxis": "y2" + }, + { + "x": [1, 2, 3, 1, null, 4, 5, 6], + "y": [2, 3, 2, 2, null, 3, 4, 3], + "error_x": {"value": 0.6, "type": "constant","color":"#cf0"}, + "error_y": {"value": 0.4, "type": "constant","color":"#fc0"}, + "fill": "tonext","fillcolor":"#282", "line": { "color": "#8c8" }, + "type": "scattergl", "showlegend": true, "xaxis": "x3", "yaxis": "y3" + }, + { + "x": [-1, 4, 9, null, 0, 1, 2], + "y": [1, 6, 1, null, 5, 6, 5], + "error_x": {"value": 0.6, "type": "constant","color":"#cf0"}, + "error_y": {"value": 0.4, "type": "constant","color":"#fc0"}, + "fill": "tonext","fillcolor":"#822", "line": { "color": "#c88" }, + "type": "scattergl", "showlegend": true, "xaxis": "x3", "yaxis": "y3" + }, + { + "x": [-2,-2, 0, 8,10 ,10], + "y": [ 0, 1, 7, 7, 1 , 0], + "fill": "tonext","fillcolor":"#828", "line": { "color": "#c8c" }, + "type": "scattergl", "showlegend": true, "xaxis": "x3", "yaxis": "y3" + }, + { + "x": [9,10,11], + "y": [7, 8, 7], + "fill": "toself","fillcolor":"#228", "line": { "color": "#88c" }, + "type": "scattergl", "showlegend": true, "xaxis": "x3", "yaxis": "y3" + }, + { + "x": [1, 2, 3, 1, null, 4, 5, 6], + "y": [2, 3, 2, 2, null, 3, 4, 3], + "error_x": {"value": 0.6, "type": "constant","color":"#cf0"}, + "error_y": {"value": 0.4, "type": "constant","color":"#fc0"}, + "fill": "tonext","fillcolor":"#282", "line": { "color": "#8c8" }, + "type": "scatter", "showlegend": true, "xaxis": "x4", "yaxis": "y4" + }, + { + "x": [-1, 4, 9, null, 0, 1, 2], + "y": [1, 6, 1, null, 5, 6, 5], + "error_x": {"value": 0.6, "type": "constant","color":"#cf0"}, + "error_y": {"value": 0.4, "type": "constant","color":"#fc0"}, + "fill": "tonext","fillcolor":"#822", "line": { "color": "#c88" }, + "type": "scatter", "showlegend": true, "xaxis": "x4", "yaxis": "y4" + }, + { + "x": [-2,-2, 0, 8,10 ,10], + "y": [ 0, 1, 7, 7, 1 , 0], + "fill": "tonext","fillcolor":"#828", "line": { "color": "#c8c" }, + "type": "scatter", "showlegend": true, "xaxis": "x4", "yaxis": "y4" + }, + { + "x": [9,10,11], + "y": [7, 8, 7], + "fill": "toself","fillcolor":"#228", "line": { "color": "#88c" }, + "type": "scatter","showlegend": true, "xaxis": "x4", "yaxis": "y4" + } + ], + "layout":{ + "title": "Fill toself and tonext", + "width": 600,"height": 600, + "margin": {"l": 20, "r": 40, "t": 40, "b": 40}, + "grid": {"columns": 2, "rows": 2, "pattern": "independent", "roworder": "bottom to top"} , + "xaxis" : { "title": "GL" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "xaxis2": { "title": "" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "yaxis" : { "title": "" , "type": "linear", "range": [0,9], "nticks": 3 }, + "yaxis2": { "title": "" , "type": "linear", "range": [0,9], "nticks": 3 }, + "xaxis3": { "title": "GL" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "xaxis4": { "title": "" , "type": "linear", "rangemode": "tozero", "nticks": 3 }, + "yaxis3": { "title": "" , "type": "linear", "range": [0,9], "nticks": 3 }, + "yaxis4": { "title": "" , "type": "linear", "range": [0,9], "nticks": 3 } + } +} diff --git a/test/image/mocks/gl2d_shape_line.json b/test/image/mocks/gl2d_shape_line.json new file mode 100644 index 00000000000..885e90bcabe --- /dev/null +++ b/test/image/mocks/gl2d_shape_line.json @@ -0,0 +1,194 @@ +{ + "data": [ +{ +"x": [20,21, 22, 23, 24, 25 ,null, 26 , 27 , 28 , 29 ], + "y": [null,26, 28, 27, 29,null,null, 26, 30, 30 , null ], + "mode": "lines+markers","fill":"tozeroy", + "name": "hv", + "line": {"shape": "hv"}, + "type": "scattergl" +},{ + "x": [20,21, 22, 23, 24, 25 ,null, 26 , 27 , 28 , 29 ], + "y": [null,21, 23, 22, 24,null,null, 21, 25 , 25 , null ], + "mode": "lines+markers","fill":"tozeroy", + "name": "vh", + "line": {"shape": "vh"}, + "type": "scattergl" +},{ + "x": [20,21, 22, 23, 24, 25 , null , 26 , 27 , 28 , 29 ], + "y": [null,16, 18, 17, 19,null,null , 16, 20 , 20 , null ], + "mode": "lines+markers","fill":"tozeroy", + "name": "hvh", + "line": {"shape": "hvh"}, + "type": "scattergl" +}, +{ + "x": [20,21, 22, 23, 24, 25 ,null, 26 , 27 , 28 , 29 ], + "y": [null,11, 13, 12, 14,null,null, 11, 15 , 15 , null ], + "mode": "lines+markers","fill":"tozeroy", + "name": "vhv", + "line": {"shape": "vhv"}, + "type": "scattergl" +}, +{ + "x": [20,21, 22, 23, 24, 25 ,null, 26 , 27 , 28 , 29 ], + "y": [null,6, 8, 7, 9,null, null, 6, 10 , 10 , null ], + "mode": "lines+markers","fill":"tozeroy", + "name": "spline", + "line": {"shape": "spline","smoothing":4}, + "type": "scattergl" +}, +{ + "x": [20,21, 22, 23, 24, 25 , 26 , 27 , 28 , 29 ], + "y": [null,1, 3, 2, 4,null, 1 , 5 , 5 , null ], + "mode": "lines+markers","fill":"tozeroy", + "name": "linear", + "line": {"shape": "linear"}, + "type": "scattergl" +},{ + "x": [ 1, 2, 3, 4, 5 , 6 , 7 , 8 , 9 , 10, 11 , 12 , null, 14 ], + "y": [26, 28, 27, 29,null ,26 , 30 , 30, null , 27, 28 , 28 , 30, 30 ], + "mode": "lines+markers", + "name": "hv", + "line": {"shape": "hv"}, + "type": "scattergl" , "xaxis": "x", "yaxis": "y" +},{ + "x": [ 1, 2, 3, 4, 5 , 6 , 7 , 8 , 9 , 10, 11 , 12 , null, 14 ], + "y": [21, 23, 22, 24,null, 21, 25 , 25 , null , 22, 23 , 23 , 25, 25 ], + "mode": "lines+markers", + "name": "vh", + "line": {"shape": "vh"}, + "type": "scattergl" , "xaxis": "x", "yaxis": "y" +},{ + "x": [ 1, 2, 3, 4, 5 , 6 , 7 , 8 , 9 , 10, 11 , 12 , null, 14 ], + "y": [16, 18,17, 19,null ,16 , 20 , 20, null , 17, 18 , 18 , 20, 20 ], + "mode": "lines+markers", + "name": "hvh", + "line": {"shape": "hvh"}, + "type": "scattergl" , "xaxis": "x", "yaxis": "y" +},{ + "x": [ 1, 2, 3, 4, 5 , 6 , 7 , 8 , 9 , 10, 11 , 12 , null, 14 ], + "y": [11, 13, 12, 14,null, 11, 15 , 15 , null , 11, 13 , 13 , 15, 15 ], + "mode": "lines+markers", + "name": "vhv", + "line": {"shape": "vhv"}, + "type": "scattergl" , "xaxis": "x", "yaxis": "y" +},{ + "x": [ 1, 2, 3, 4, 5 , 6 , 7 , 8 , 9 , 10, 11 , 12 , null, 14 ], + "y": [ 6, 8, 7, 9,null , 6 , 10 , 10, null , 7, 8 , 8 , 10, 10 ], + "mode": "lines+markers", + "name": "spline", + "line": {"shape": "spline","smoothing":4}, + "type": "scattergl" , "xaxis": "x", "yaxis": "y" +},{ + "x": [ 1, 2, 3, 4, 5 , 6 , 7 , 8 , 9 , 10, 11 , 12 , null, 14 ], + "y": [ 1, 3, 2, 4,null, 1, 5 , 5 , null , 1, 3 , 3 , 5, 5 ], + "mode": "lines+markers", + "name": "linear", + "line": {"shape": "linear"}, + "type": "scattergl" , "xaxis": "x", "yaxis": "y" +},{ +"x": [20,21, 22, 23, 24, 25 ,null, 26 , 27 , 28 , 29 ], + "y": [null,26, 28, 27, 29,null,null, 26, 30, 30 , null ], + "mode": "lines+markers","fill":"tozeroy", + "name": "hv", + "line": {"shape": "hv"}, + "type": "scatter" , "xaxis": "x2", "yaxis": "y2" +},{ + "x": [20,21, 22, 23, 24, 25 ,null, 26 , 27 , 28 , 29 ], + "y": [null,21, 23, 22, 24,null,null, 21, 25 , 25 , null ], + "mode": "lines+markers","fill":"tozeroy", + "name": "vh", + "line": {"shape": "vh"}, + "type": "scatter" , "xaxis": "x2", "yaxis": "y2" +},{ + "x": [20,21, 22, 23, 24, 25 , null , 26 , 27 , 28 , 29 ], + "y": [null,16, 18, 17, 19,null,null , 16, 20 , 20 , null ], + "mode": "lines+markers","fill":"tozeroy", + "name": "hvh", + "line": {"shape": "hvh"}, + "type": "scatter" , "xaxis": "x2", "yaxis": "y2" +}, +{ + "x": [20,21, 22, 23, 24, 25 ,null, 26 , 27 , 28 , 29 ], + "y": [null,11, 13, 12, 14,null,null, 11, 15 , 15 , null ], + "mode": "lines+markers","fill":"tozeroy", + "name": "vhv", + "line": {"shape": "vhv"}, + "type": "scatter" , "xaxis": "x2", "yaxis": "y2" +}, +{ + "x": [20,21, 22, 23, 24, 25 ,null, 26 , 27 , 28 , 29 ], + "y": [null,6, 8, 7, 9,null, null, 6, 10 , 10 , null ], + "mode": "lines+markers","fill":"tozeroy", + "name": "spline", + "line": {"shape": "spline","smoothing":4}, + "type": "scatter" , "xaxis": "x2", "yaxis": "y2" +}, +{ + "x": [20,21, 22, 23, 24, 25 , 26 , 27 , 28 , 29 ], + "y": [null,1, 3, 2, 4,null, 1 , 5 , 5 , null ], + "mode": "lines+markers","fill":"tozeroy", + "name": "linear", + "line": {"shape": "linear"}, + "type": "scatter" , "xaxis": "x2", "yaxis": "y2" +},{ + "x": [ 1, 2, 3, 4, 5 , 6 , 7 , 8 , 9 , 10, 11 , 12 , null, 14 ], + "y": [26, 28, 27, 29,null ,26 , 30 , 30, null , 27, 28 , 28 , 30, 30 ], + "mode": "lines+markers", + "name": "hv", + "line": {"shape": "hv"}, + "type": "scatter" , "xaxis": "x2", "yaxis": "y2" +},{ + "x": [ 1, 2, 3, 4, 5 , 6 , 7 , 8 , 9 , 10, 11 , 12 , null, 14 ], + "y": [21, 23, 22, 24,null, 21, 25 , 25 , null , 22, 23 , 23 , 25, 25 ], + "mode": "lines+markers", + "name": "vh", + "line": {"shape": "vh"}, + "type": "scatter" , "xaxis": "x2", "yaxis": "y2" +},{ + "x": [ 1, 2, 3, 4, 5 , 6 , 7 , 8 , 9 , 10, 11 , 12 , null, 14 ], + "y": [16, 18,17, 19,null ,16 , 20 , 20, null , 17, 18 , 18 , 20, 20 ], + "mode": "lines+markers", + "name": "hvh", + "line": {"shape": "hvh"}, + "type": "scatter" , "xaxis": "x2", "yaxis": "y2" +},{ + "x": [ 1, 2, 3, 4, 5 , 6 , 7 , 8 , 9 , 10, 11 , 12 , null, 14 ], + "y": [11, 13, 12, 14,null, 11, 15 , 15 , null , 11, 13 , 13 , 15, 15 ], + "mode": "lines+markers", + "name": "vhv", + "line": {"shape": "vhv"}, + "type": "scatter" , "xaxis": "x2", "yaxis": "y2" +},{ + "x": [ 1, 2, 3, 4, 5 , 6 , 7 , 8 , 9 , 10, 11 , 12 , null, 14 ], + "y": [ 6, 8, 7, 9,null , 6 , 10 , 10, null , 7, 8 , 8 , 10, 10 ], + "mode": "lines+markers", + "name": "spline", + "line": {"shape": "spline","smoothing":4}, + "type": "scatter" , "xaxis": "x2", "yaxis": "y2" +},{ + "x": [ 1, 2, 3, 4, 5 , 6 , 7 , 8 , 9 , 10, 11 , 12 , null, 14 ], + "y": [ 1, 3, 2, 4,null, 1, 5 , 5 , null , 1, 3 , 3 , 5, 5 ], + "mode": "lines+markers", + "name": "linear", + "line": {"shape": "linear"}, + "type": "scatter" , "xaxis": "x2", "yaxis": "y2" +} +], + "layout": { + "margin": { + "b": 40, + "l": 40, + "t": 40, + "r": 40 + }, + "width": 700,"height": 700, + "grid": {"columns": 1, "rows": 2, "pattern": "independent", "roworder": "bottom to top"} , + "xaxis": { "title": "GL x" }, + "yaxis": { "title": "GL y" }, + "xaxis2": { "title": "REG x" }, + "yaxis2": { "title": "REG y" }, + "dragmode": "zoom" + } +}