diff --git a/draftlogs/6535_add.md b/draftlogs/6535_add.md new file mode 100644 index 00000000000..05b1d98d823 --- /dev/null +++ b/draftlogs/6535_add.md @@ -0,0 +1,3 @@ + - Add `legend` references to traces and `legend2`, `legend3`, etc. to layout + to allow positioning multiple legends on a graph [[#6535](https://github.com/plotly/plotly.js/pull/6535)], + this feature was anonymously sponsored: thank you to our sponsor! diff --git a/src/components/legend/attributes.js b/src/components/legend/attributes.js index 3ef9b701e98..135f1209b69 100644 --- a/src/components/legend/attributes.js +++ b/src/components/legend/attributes.js @@ -5,6 +5,20 @@ var colorAttrs = require('../color/attributes'); module.exports = { + // not really a 'subplot' attribute container, + // but this is the flag we use to denote attributes that + // support yaxis, yaxis2, yaxis3, ... counters + _isSubplotObj: true, + + visible: { + valType: 'boolean', + dflt: true, + editType: 'legend', + description: [ + 'Determines whether or not this legend is visible.' + ].join(' ') + }, + bgcolor: { valType: 'color', editType: 'legend', diff --git a/src/components/legend/defaults.js b/src/components/legend/defaults.js index a2bfc776848..3906070cb1c 100644 --- a/src/components/legend/defaults.js +++ b/src/components/legend/defaults.js @@ -9,15 +9,22 @@ var attributes = require('./attributes'); var basePlotLayoutAttributes = require('../../plots/layout_attributes'); var helpers = require('./helpers'); - -module.exports = function legendDefaults(layoutIn, layoutOut, fullData) { - var containerIn = layoutIn.legend || {}; - var containerOut = Template.newContainer(layoutOut, 'legend'); +function groupDefaults(legendId, layoutIn, layoutOut, fullData) { + var containerIn = layoutIn[legendId] || {}; + var containerOut = Template.newContainer(layoutOut, legendId); function coerce(attr, dflt) { return Lib.coerce(containerIn, containerOut, attributes, attr, dflt); } + // N.B. unified hover needs to inherit from font, bgcolor & bordercolor even when legend.visible is false + var itemFont = Lib.coerceFont(coerce, 'font', layoutOut.font); + coerce('bgcolor', layoutOut.paper_bgcolor); + coerce('bordercolor'); + + var visible = coerce('visible'); + if(!visible) return; + var trace; var traceCoerce = function(attr, dflt) { var traceIn = trace._input; @@ -91,10 +98,7 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) { if(showLegend === false) return; - coerce('bgcolor', layoutOut.paper_bgcolor); - coerce('bordercolor'); coerce('borderwidth'); - var itemFont = Lib.coerceFont(coerce, 'font', layoutOut.font); var orientation = coerce('orientation'); var isHorizontal = orientation === 'h'; @@ -147,4 +151,29 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) { Lib.coerceFont(coerce, 'title.font', dfltTitleFont); } +} + +module.exports = function legendDefaults(layoutIn, layoutOut, fullData) { + var i; + var legends = ['legend']; + + for(i = 0; i < fullData.length; i++) { + Lib.pushUnique(legends, fullData[i].legend); + } + + layoutOut._legends = []; + for(i = 0; i < legends.length; i++) { + var legendId = legends[i]; + + groupDefaults(legendId, layoutIn, layoutOut, fullData); + + if( + layoutOut[legendId] && + layoutOut[legendId].visible + ) { + layoutOut[legendId]._id = legendId; + } + + layoutOut._legends.push(legendId); + } }; diff --git a/src/components/legend/draw.js b/src/components/legend/draw.js index 9f000a6c26c..dcb9093b927 100644 --- a/src/components/legend/draw.js +++ b/src/components/legend/draw.js @@ -24,32 +24,61 @@ var helpers = require('./helpers'); var MAIN_TITLE = 1; +var LEGEND_PATTERN = /^legend[0-9]*$/; + module.exports = function draw(gd, opts) { - if(!opts) opts = gd._fullLayout.legend || {}; - return _draw(gd, opts); + if(opts) { + drawOne(gd, opts); + } else { + var fullLayout = gd._fullLayout; + var newLegends = fullLayout._legends; + + // remove old legends that won't stay on the graph + var oldLegends = fullLayout._infolayer.selectAll('[class^="legend"]'); + + oldLegends.each(function() { + var el = d3.select(this); + var classes = el.attr('class'); + var cls = classes.split(' ')[0]; + if(cls.match(LEGEND_PATTERN) && newLegends.indexOf(cls) === -1) { + el.remove(); + } + }); + + // draw/update new legends + for(var i = 0; i < newLegends.length; i++) { + var legendId = newLegends[i]; + var legendObj = gd._fullLayout[legendId]; + drawOne(gd, legendObj); + } + } }; -function _draw(gd, legendObj) { +function drawOne(gd, opts) { + var legendObj = opts || {}; + var fullLayout = gd._fullLayout; - var clipId = 'legend' + fullLayout._uid; - var layer; + var legendId = getId(legendObj); + + var clipId, layer; var inHover = legendObj._inHover; if(inHover) { layer = legendObj.layer; - clipId += '-hover'; + clipId = 'hover'; } else { layer = fullLayout._infolayer; + clipId = legendId; } - if(!layer) return; + clipId += fullLayout._uid; if(!gd._legendMouseDownTime) gd._legendMouseDownTime = 0; var legendData; if(!inHover) { if(!gd.calcdata) return; - legendData = fullLayout.showlegend && getLegendData(gd.calcdata, legendObj); + legendData = fullLayout.showlegend && getLegendData(gd.calcdata, legendObj, fullLayout._legends.length > 1); } else { if(!legendObj.entries) return; legendData = getLegendData(legendObj.entries, legendObj); @@ -58,12 +87,12 @@ function _draw(gd, legendObj) { var hiddenSlices = fullLayout.hiddenlabels || []; if(!inHover && (!fullLayout.showlegend || !legendData.length)) { - layer.selectAll('.legend').remove(); + layer.selectAll('.' + legendId).remove(); fullLayout._topdefs.select('#' + clipId).remove(); - return Plots.autoMargin(gd, 'legend'); + return Plots.autoMargin(gd, legendId); } - var legend = Lib.ensureSingle(layer, 'g', 'legend', function(s) { + var legend = Lib.ensureSingle(layer, 'g', legendId, function(s) { if(!inHover) s.attr('pointer-events', 'all'); }); @@ -84,14 +113,14 @@ function _draw(gd, legendObj) { legendObj._titleWidth = 0; legendObj._titleHeight = 0; if(title.text) { - var titleEl = Lib.ensureSingle(scrollBox, 'text', 'legendtitletext'); + var titleEl = Lib.ensureSingle(scrollBox, 'text', legendId + 'titletext'); titleEl.attr('text-anchor', 'start') .call(Drawing.font, title.font) .text(title.text); textLayout(titleEl, scrollBox, gd, legendObj, MAIN_TITLE); // handle mathjax or multi-line text and compute title height } else { - scrollBox.selectAll('.legendtitletext').remove(); + scrollBox.selectAll('.' + legendId + 'titletext').remove(); } var scrollBar = Lib.ensureSingle(legend, 'rect', 'scrollbar', function(s) { @@ -117,7 +146,7 @@ function _draw(gd, legendObj) { }) .each(function() { d3.select(this).call(drawTexts, gd, legendObj); }) .call(style, gd, legendObj) - .each(function() { if(!inHover) d3.select(this).call(setupTraceToggle, gd); }); + .each(function() { if(!inHover) d3.select(this).call(setupTraceToggle, gd, legendId); }); Lib.syncOrAsync([ Plots.previousPromises, @@ -127,7 +156,7 @@ function _draw(gd, legendObj) { var bw = legendObj.borderwidth; if(!inHover) { - var expMargin = expandMargin(gd); + var expMargin = expandMargin(gd, legendId); // IF expandMargin return a Promise (which is truthy), // we're under a doAutoMargin redraw, so we don't have to @@ -145,10 +174,10 @@ function _draw(gd, legendObj) { ly = Lib.constrain(ly, 0, fullLayout.height - legendObj._effHeight); if(lx !== lx0) { - Lib.log('Constrain legend.x to make legend fit inside graph'); + Lib.log('Constrain ' + legendId + '.x to make legend fit inside graph'); } if(ly !== ly0) { - Lib.log('Constrain legend.y to make legend fit inside graph'); + Lib.log('Constrain ' + legendId + '.y to make legend fit inside graph'); } } @@ -294,7 +323,7 @@ function _draw(gd, legendObj) { } function scrollHandler(scrollBoxY, scrollBarHeight, scrollRatio) { - legendObj._scrollY = gd._fullLayout.legend._scrollY = scrollBoxY; + legendObj._scrollY = gd._fullLayout[legendId]._scrollY = scrollBoxY; Drawing.setTranslate(scrollBox, 0, -scrollBoxY); Drawing.setRect( @@ -330,11 +359,14 @@ function _draw(gd, legendObj) { }, doneFn: function() { if(xf !== undefined && yf !== undefined) { - Registry.call('_guiRelayout', gd, {'legend.x': xf, 'legend.y': yf}); + var obj = {}; + obj[legendId + '.x'] = xf; + obj[legendId + '.y'] = yf; + Registry.call('_guiRelayout', gd, obj); } }, clickFn: function(numClicks, e) { - var clickedTrace = layer.selectAll('g.traces').filter(function() { + var clickedTrace = groups.selectAll('g.traces').filter(function() { var bbox = this.getBoundingClientRect(); return ( e.clientX >= bbox.left && e.clientX <= bbox.right && @@ -402,6 +434,7 @@ function clickOrDoubleClick(gd, legend, legendItem, numClicks, evt) { } function drawTexts(g, gd, legendObj) { + var legendId = getId(legendObj); var legendItem = g.data()[0][0]; var trace = legendItem.trace; var isPieLike = Registry.traceIs(trace, 'pie-like'); @@ -424,7 +457,7 @@ function drawTexts(g, gd, legendObj) { } } - var textEl = Lib.ensureSingle(g, 'text', 'legendtext'); + var textEl = Lib.ensureSingle(g, 'text', legendId + 'text'); textEl.attr('text-anchor', 'start') .call(Drawing.font, font) @@ -478,12 +511,12 @@ function ensureLength(str, maxLength) { return str; } -function setupTraceToggle(g, gd) { +function setupTraceToggle(g, gd, legendId) { var doubleClickDelay = gd._context.doubleClickDelay; var newMouseDownTime; var numClicks = 1; - var traceToggle = Lib.ensureSingle(g, 'rect', 'legendtoggle', function(s) { + var traceToggle = Lib.ensureSingle(g, 'rect', legendId + 'toggle', function(s) { if(!gd._context.staticPlot) { s.style('cursor', 'pointer').attr('pointer-events', 'all'); } @@ -505,7 +538,7 @@ function setupTraceToggle(g, gd) { }); traceToggle.on('mouseup', function() { if(gd._dragged || gd._editing) return; - var legend = gd._fullLayout.legend; + var legend = gd._fullLayout[legendId]; if((new Date()).getTime() - gd._legendMouseDownTime > doubleClickDelay) { numClicks = Math.max(numClicks - 1, 1); @@ -531,7 +564,11 @@ function computeTextDimensions(g, gd, legendObj, aTitle) { var mathjaxGroup = g.select('g[class*=math-group]'); var mathjaxNode = mathjaxGroup.node(); - if(!legendObj) legendObj = gd._fullLayout.legend; + + var legendId = getId(legendObj); + if(!legendObj) { + legendObj = gd._fullLayout[legendId]; + } var bw = legendObj.borderwidth; var font; if(aTitle === MAIN_TITLE) { @@ -556,9 +593,12 @@ function computeTextDimensions(g, gd, legendObj, aTitle) { Drawing.setTranslate(mathjaxGroup, 0, height * 0.25); } } else { - var textEl = g.select(aTitle === MAIN_TITLE ? - '.legendtitletext' : '.legendtext' - ); + var cls = '.' + legendId + ( + aTitle === MAIN_TITLE ? 'title' : '' + ) + 'text'; + + var textEl = g.select(cls); + var textLines = svgTextUtils.lineCount(textEl); var textNode = textEl.node(); @@ -619,7 +659,7 @@ function getTitleSize(legendObj) { } /* - * Computes in fullLayout.legend: + * Computes in fullLayout[legendId]: * * - _height: legend height including items past scrollbox height * - _maxHeight: maximum legend height before scrollbox is required @@ -630,7 +670,10 @@ function getTitleSize(legendObj) { */ function computeLegendDimensions(gd, groups, traces, legendObj) { var fullLayout = gd._fullLayout; - if(!legendObj) legendObj = fullLayout.legend; + var legendId = getId(legendObj); + if(!legendObj) { + legendObj = fullLayout[legendId]; + } var gs = fullLayout._size; var isVertical = helpers.isVertical(legendObj); @@ -818,7 +861,7 @@ function computeLegendDimensions(gd, groups, traces, legendObj) { var edits = gd._context.edits; var isEditable = edits.legendText || edits.legendPosition; traces.each(function(d) { - var traceToggle = d3.select(this).select('.legendtoggle'); + var traceToggle = d3.select(this).select('.' + legendId + 'toggle'); var h = d[0].height; var legendgroup = d[0].trace.legendgroup; var traceWidth = getTraceWidth(d, legendObj, textGap); @@ -833,13 +876,13 @@ function computeLegendDimensions(gd, groups, traces, legendObj) { }); } -function expandMargin(gd) { +function expandMargin(gd, legendId) { var fullLayout = gd._fullLayout; - var legendObj = fullLayout.legend; + var legendObj = fullLayout[legendId]; var xanchor = getXanchor(legendObj); var yanchor = getYanchor(legendObj); - return Plots.autoMargin(gd, 'legend', { + return Plots.autoMargin(gd, legendId, { x: legendObj.x, y: legendObj.y, l: legendObj._width * (FROM_TL[xanchor]), @@ -860,3 +903,7 @@ function getYanchor(legendObj) { Lib.isMiddleAnchor(legendObj) ? 'middle' : 'top'; } + +function getId(legendObj) { + return legendObj._id || 'legend'; +} diff --git a/src/components/legend/get_legend_data.js b/src/components/legend/get_legend_data.js index a19d582b536..4bb7ec60f27 100644 --- a/src/components/legend/get_legend_data.js +++ b/src/components/legend/get_legend_data.js @@ -3,7 +3,7 @@ var Registry = require('../../registry'); var helpers = require('./helpers'); -module.exports = function getLegendData(calcdata, opts) { +module.exports = function getLegendData(calcdata, opts, hasMultipleLegends) { var inHover = opts._inHover; var grouped = helpers.isGrouped(opts); var reversed = helpers.isReversed(opts); @@ -16,7 +16,10 @@ module.exports = function getLegendData(calcdata, opts) { var maxNameLength = 0; var i, j; - function addOneItem(legendGroup, legendItem) { + function addOneItem(legendId, legendGroup, legendItem) { + if(opts.visible === false) return; + if(hasMultipleLegends && legendId !== opts._id) return; + // each '' legend group is treated as a separate group if(legendGroup === '' || !helpers.isGrouped(opts)) { // TODO: check this against fullData legendgroups? @@ -38,6 +41,7 @@ module.exports = function getLegendData(calcdata, opts) { var cd = calcdata[i]; var cd0 = cd[0]; var trace = cd0.trace; + var lid = trace.legend; var lgroup = trace.legendgroup; if(!inHover && (!trace.visible || !trace.showlegend)) continue; @@ -49,7 +53,7 @@ module.exports = function getLegendData(calcdata, opts) { var labelj = cd[j].label; if(!slicesShown[lgroup][labelj]) { - addOneItem(lgroup, { + addOneItem(lid, lgroup, { label: labelj, color: cd[j].color, i: cd[j].i, @@ -62,7 +66,7 @@ module.exports = function getLegendData(calcdata, opts) { } } } else { - addOneItem(lgroup, cd0); + addOneItem(lid, lgroup, cd0); maxNameLength = Math.max(maxNameLength, (trace.name || '').length); } } diff --git a/src/plots/attributes.js b/src/plots/attributes.js index 9f9952cbfc5..c76def47a14 100644 --- a/src/plots/attributes.js +++ b/src/plots/attributes.js @@ -32,6 +32,18 @@ module.exports = { 'trace is shown in the legend.' ].join(' ') }, + legend: { + valType: 'subplotid', + dflt: 'legend', + editType: 'style', + + description: [ + 'Sets the reference to a legend to show this trace in.', + 'References to these legends are *legend*, *legend2*, *legend3*, etc.', + 'Settings for these legends are set in the layout, under', + '`layout.legend`, `layout.legend2`, etc.' + ].join(' ') + }, legendgroup: { valType: 'string', dflt: '', diff --git a/src/plots/plots.js b/src/plots/plots.js index 385df065112..45900550cfb 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -1321,6 +1321,7 @@ plots.supplyTraceDefaults = function(traceIn, traceOut, colorIndex, layout, trac 'showlegend' ); + coerce('legend'); coerce('legendwidth'); coerce('legendgroup'); coerce('legendgrouptitle.text'); diff --git a/src/traces/parcats/attributes.js b/src/traces/parcats/attributes.js index cb0ddb4d912..f04f0c73921 100644 --- a/src/traces/parcats/attributes.js +++ b/src/traces/parcats/attributes.js @@ -197,6 +197,7 @@ module.exports = { customdata: undefined, hoverlabel: undefined, ids: undefined, + legend: undefined, legendgroup: undefined, legendrank: undefined, opacity: undefined, diff --git a/test/image/baselines/zz-multi-legends.png b/test/image/baselines/zz-multi-legends.png new file mode 100644 index 00000000000..e7078b921dd Binary files /dev/null and b/test/image/baselines/zz-multi-legends.png differ diff --git a/test/image/mocks/zz-multi-legends.json b/test/image/mocks/zz-multi-legends.json new file mode 100644 index 00000000000..ad2d01466a9 --- /dev/null +++ b/test/image/mocks/zz-multi-legends.json @@ -0,0 +1,63 @@ +{ + "data": [ + { + "y": [0] + }, + { + "y": [1] + }, + { + "y": [2] + }, + { + "y": [3], + "legend": "legend2" + }, + { + "y": [4], + "legend": "legend3" + }, + { + "y": [5], + "legend": "legend3" + } + ], + "layout": { + "title": { + "text": "Multiple legends" + }, + "width": 500, + "height": 500, + "yaxis": { + "autorange": "reversed" + }, + "legend": { + "bgcolor": "lightgray", + "title": { + "text": "Legend" + } + }, + "legend2": { + "x": -0.05, + "y": 0.5, + "xanchor": "right", + "yanchor": "middle", + "bgcolor": "lightblue", + "title": { + "text": "Legend 2" + } + }, + "legend3": { + "y": 0, + "yanchor": "bottom", + "bgcolor": "yellow", + "title": { + "text": "Legend 3" + } + }, + "hovermode": "x unified" + }, + "config": { + "editable": true + } +} diff --git a/test/jasmine/bundle_tests/plotschema_test.js b/test/jasmine/bundle_tests/plotschema_test.js index 81139ab5f06..6d1f4546b3a 100644 --- a/test/jasmine/bundle_tests/plotschema_test.js +++ b/test/jasmine/bundle_tests/plotschema_test.js @@ -138,6 +138,7 @@ describe('plot schema', function() { // not really a 'subplot' object but supports yaxis, yaxis2, yaxis3, // ... counters, so list it here 'xaxis.rangeslider.yaxis', + 'legend', 'coloraxis' ]; diff --git a/test/jasmine/tests/legend_test.js b/test/jasmine/tests/legend_test.js index 0f7a1ceb99b..5172048bcd0 100644 --- a/test/jasmine/tests/legend_test.js +++ b/test/jasmine/tests/legend_test.js @@ -1122,6 +1122,44 @@ describe('legend relayout update', function() { }) .then(done, done.fail); }); + + it('should be able to add & clear multiple legends using react', function(done) { + var fig1 = { + data: [{ + y: [1, 2, 3] + }] + }; + + var fig2 = { + data: [{ + y: [1, 2, 3] + }, { + y: [3, 1, 2], + legend: 'legend2' + }], + layout: { + legend2: {y: 0.5} + } + }; + + Plotly.newPlot(gd, fig1) + .then(function() { + expect(d3SelectAll('.legend2')[0].length).toBe(0); + }) + .then(function() { + return Plotly.react(gd, fig2); + }) + .then(function() { + expect(d3SelectAll('.legend2')[0].length).toBe(1); + }) + .then(function() { + return Plotly.react(gd, fig1); + }) + .then(function() { + expect(d3SelectAll('.legend2')[0].length).toBe(0); + }) + .then(done, done.fail); + }); }); describe('legend orientation change:', function() { diff --git a/test/plot-schema.json b/test/plot-schema.json index 411afae1354..e8fe9297497 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -2743,6 +2743,7 @@ "role": "object" }, "legend": { + "_isSubplotObj": true, "bgcolor": { "description": "Sets the legend background color. Defaults to `layout.paper_bgcolor`.", "editType": "legend", @@ -2956,6 +2957,12 @@ "bottom" ] }, + "visible": { + "description": "Determines whether or not this legend is visible.", + "dflt": true, + "editType": "legend", + "valType": "boolean" + }, "x": { "description": "Sets the x position (in normalized coordinates) of the legend. Defaults to *1.02* for vertical legends and defaults to *0* for horizontal legends.", "editType": "legend", @@ -12894,6 +12901,12 @@ "valType": "string" } }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -14421,6 +14434,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -15727,6 +15746,12 @@ "min": 0, "valType": "number" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -17071,6 +17096,12 @@ }, "role": "object" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -18591,6 +18622,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgrouptitle": { "editType": "style", "font": { @@ -19445,6 +19482,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -20444,6 +20487,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -21472,6 +21521,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -22676,6 +22731,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -23926,6 +23987,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -24887,6 +24954,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -25424,6 +25497,12 @@ "valType": "string" } }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -26857,6 +26936,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -27939,6 +28024,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -29082,6 +29173,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgrouptitle": { "editType": "style", "font": { @@ -29869,6 +29966,12 @@ "valType": "number" } }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -31839,6 +31942,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -33111,6 +33220,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -33874,6 +33989,12 @@ }, "role": "object" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgrouptitle": { "editType": "style", "font": { @@ -35095,6 +35216,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgrouptitle": { "editType": "style", "font": { @@ -35966,6 +36093,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgrouptitle": { "editType": "style", "font": { @@ -36999,6 +37132,12 @@ "editType": "calc", "valType": "number" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -38288,6 +38427,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -38916,6 +39061,12 @@ }, "role": "object" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -40390,6 +40541,12 @@ "bottom" ] }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgrouptitle": { "editType": "style", "font": { @@ -41591,6 +41748,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -42187,6 +42350,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -42657,6 +42826,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgrouptitle": { "editType": "style", "font": { @@ -43859,6 +44034,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -46216,6 +46397,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -48217,6 +48404,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -50110,6 +50303,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -52170,6 +52369,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -54173,6 +54378,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -55350,6 +55561,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -57265,6 +57482,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -59111,6 +59334,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -61024,6 +61253,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -62939,6 +63174,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -65133,6 +65374,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -65845,6 +66092,12 @@ }, "role": "object" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgrouptitle": { "editType": "style", "font": { @@ -67773,6 +68026,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -68678,6 +68937,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgrouptitle": { "editType": "style", "font": { @@ -69090,6 +69355,12 @@ "editType": "none", "valType": "string" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgrouptitle": { "editType": "style", "font": { @@ -70420,6 +70691,12 @@ "min": 0, "valType": "number" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -72235,6 +72512,12 @@ "editType": "calc", "valType": "number" }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "", @@ -73080,6 +73363,12 @@ "valType": "string" } }, + "legend": { + "description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.", + "dflt": "legend", + "editType": "style", + "valType": "subplotid" + }, "legendgroup": { "description": "Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items.", "dflt": "",