diff --git a/lib/index.js b/lib/index.js index 36083aa498b..7dfb08a60d3 100644 --- a/lib/index.js +++ b/lib/index.js @@ -26,6 +26,7 @@ Plotly.register([ require('./pie'), require('./sunburst'), + require('./treemap'), require('./funnelarea'), require('./scatter3d'), diff --git a/lib/treemap.js b/lib/treemap.js new file mode 100644 index 00000000000..040cec276f7 --- /dev/null +++ b/lib/treemap.js @@ -0,0 +1,11 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +module.exports = require('../src/traces/treemap'); diff --git a/src/lib/index.js b/src/lib/index.js index 0073533aab1..7a43f10b300 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -1159,6 +1159,10 @@ lib.isValidTextValue = function(v) { return v || v === 0; }; +/** + * @param {number} ratio + * @param {number} n (number of decimal places) + */ lib.formatPercent = function(ratio, n) { n = n || 0; var str = (Math.round(100 * ratio * Math.pow(10, n)) * Math.pow(0.1, n)).toFixed(n) + '%'; @@ -1175,3 +1179,32 @@ lib.isHidden = function(gd) { var display = window.getComputedStyle(gd).display; return !display || display === 'none'; }; + +lib.getTextTransform = function(opts) { + var textX = opts.textX; + var textY = opts.textY; + var targetX = opts.targetX; + var targetY = opts.targetY; + var scale = opts.scale; + var rotate = opts.rotate; + + var transformScale; + var transformRotate; + var transformTranslate; + + if(scale < 1) transformScale = 'scale(' + scale + ') '; + else { + scale = 1; + transformScale = ''; + } + + transformRotate = (rotate) ? + 'rotate(' + rotate + ' ' + textX + ' ' + textY + ') ' : ''; + + // Note that scaling also affects the center of the text box + var translateX = (targetX - scale * textX); + var translateY = (targetY - scale * textY); + transformTranslate = 'translate(' + translateX + ' ' + translateY + ')'; + + return transformTranslate + transformScale + transformRotate; +}; diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 241f437ca3b..cd8353a81b8 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -2450,7 +2450,7 @@ var traceUIControlPatterns = [ {pattern: /(^|value\.)visible$/, attr: 'legend.uirevision'}, {pattern: /^dimensions\[\d+\]\.constraintrange/}, {pattern: /^node\.(x|y|groups)/}, // for Sankey nodes - {pattern: /^level$/}, // for Sunburst traces + {pattern: /^level$/}, // for Sunburst & Treemap traces // below this you must be in editable: true mode // TODO: I still put name and title with `trace.uirevision` @@ -3780,6 +3780,9 @@ function makePlotFramework(gd) { // single pie layer for the whole plot fullLayout._pielayer = fullLayout._paper.append('g').classed('pielayer', true); + // single treemap layer for the whole plot + fullLayout._treemaplayer = fullLayout._paper.append('g').classed('treemaplayer', true); + // single sunburst layer for the whole plot fullLayout._sunburstlayer = fullLayout._paper.append('g').classed('sunburstlayer', true); diff --git a/src/plots/plots.js b/src/plots/plots.js index c9aa68b131d..80ce2f2b7e3 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -23,6 +23,8 @@ var axisIDs = require('./cartesian/axis_ids'); var animationAttrs = require('./animation_attributes'); var frameAttrs = require('./frame_attributes'); +var getModuleCalcData = require('../plots/get_data').getModuleCalcData; + var relinkPrivateKeys = Lib.relinkPrivateKeys; var _ = Lib._; @@ -2771,9 +2773,10 @@ plots.doCalcdata = function(gd, traces) { gd._hmpixcount = 0; gd._hmlumcount = 0; - // for sharing colors across pies / sunbursts / funnelarea (and for legend) + // for sharing colors across pies / sunbursts / treemap / funnelarea (and for legend) fullLayout._piecolormap = {}; fullLayout._sunburstcolormap = {}; + fullLayout._treemapcolormap = {}; fullLayout._funnelareacolormap = {}; // If traces were specified and this trace was not included, @@ -3203,3 +3206,18 @@ plots.generalUpdatePerTraceModule = function(gd, subplot, subplotCalcData, subpl // update moduleName -> calcData hash subplot.traceHash = traceHash; }; + +plots.plotBasePlot = function(desiredType, gd, traces, transitionOpts, makeOnCompleteCallback) { + var _module = Registry.getModule(desiredType); + var cdmodule = getModuleCalcData(gd.calcdata, _module)[0]; + _module.plot(gd, cdmodule, transitionOpts, makeOnCompleteCallback); +}; + +plots.cleanBasePlot = function(desiredType, newFullData, newFullLayout, oldFullData, oldFullLayout) { + var had = (oldFullLayout._has && oldFullLayout._has(desiredType)); + var has = (newFullLayout._has && newFullLayout._has(desiredType)); + + if(had && !has) { + oldFullLayout['_' + desiredType + 'layer'].selectAll('g.trace').remove(); + } +}; diff --git a/src/traces/bar/attributes.js b/src/traces/bar/attributes.js index c800d8bc30a..206e1619ebc 100644 --- a/src/traces/bar/attributes.js +++ b/src/traces/bar/attributes.js @@ -13,7 +13,7 @@ var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplat var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs; var colorScaleAttrs = require('../../components/colorscale/attributes'); var fontAttrs = require('../../plots/font_attributes'); -var constants = require('./constants.js'); +var constants = require('./constants'); var extendFlat = require('../../lib/extend').extendFlat; diff --git a/src/traces/bar/constants.js b/src/traces/bar/constants.js index 89c9c2ba941..608bcc22041 100644 --- a/src/traces/bar/constants.js +++ b/src/traces/bar/constants.js @@ -10,5 +10,6 @@ 'use strict'; module.exports = { + TEXTPAD: 3, // padding in pixels around text eventDataKeys: [] }; diff --git a/src/traces/bar/plot.js b/src/traces/bar/plot.js index 11d8ad24f68..2a513d4ee23 100644 --- a/src/traces/bar/plot.js +++ b/src/traces/bar/plot.js @@ -21,6 +21,7 @@ var tickText = require('../../plots/cartesian/axes').tickText; var style = require('./style'); var helpers = require('./helpers'); +var constants = require('./constants'); var attributes = require('./attributes'); var attributeText = attributes.text; @@ -28,8 +29,7 @@ var attributeTextPosition = attributes.textposition; var appendArrayPointValue = require('../../components/fx/helpers').appendArrayPointValue; -// padding in pixels around text -var TEXTPAD = 3; +var TEXTPAD = constants.TEXTPAD; function dirSign(a, b) { return (a < b) ? 1 : -1; @@ -342,7 +342,7 @@ function appendBarText(gd, plotinfo, bar, calcTrace, i, x0, x1, y0, y1, opts) { trace.constraintext === 'both' || trace.constraintext === 'outside'; - transform = getTransform(toMoveOutsideBar(x0, x1, y0, y1, textBB, { + transform = Lib.getTextTransform(toMoveOutsideBar(x0, x1, y0, y1, textBB, { isHorizontal: isHorizontal, constrained: constrained, angle: trace.textangle @@ -352,7 +352,7 @@ function appendBarText(gd, plotinfo, bar, calcTrace, i, x0, x1, y0, y1, opts) { trace.constraintext === 'both' || trace.constraintext === 'inside'; - transform = getTransform(toMoveInsideBar(x0, x1, y0, y1, textBB, { + transform = Lib.getTextTransform(toMoveInsideBar(x0, x1, y0, y1, textBB, { isHorizontal: isHorizontal, constrained: constrained, angle: trace.textangle, @@ -510,35 +510,6 @@ function toMoveOutsideBar(x0, x1, y0, y1, textBB, opts) { }; } -function getTransform(opts) { - var textX = opts.textX; - var textY = opts.textY; - var targetX = opts.targetX; - var targetY = opts.targetY; - var scale = opts.scale; - var rotate = opts.rotate; - - var transformScale; - var transformRotate; - var transformTranslate; - - if(scale < 1) transformScale = 'scale(' + scale + ') '; - else { - scale = 1; - transformScale = ''; - } - - transformRotate = (rotate) ? - 'rotate(' + rotate + ' ' + textX + ' ' + textY + ') ' : ''; - - // Note that scaling also affects the center of the text box - var translateX = (targetX - scale * textX); - var translateY = (targetY - scale * textY); - transformTranslate = 'translate(' + translateX + ' ' + translateY + ')'; - - return transformTranslate + transformScale + transformRotate; -} - function getText(fullLayout, calcTrace, index, xa, ya) { var trace = calcTrace[0].trace; var texttemplate = trace.texttemplate; @@ -695,7 +666,6 @@ function calcTextinfo(calcTrace, index, xa, ya) { module.exports = { plot: plot, - getTransform: getTransform, toMoveInsideBar: toMoveInsideBar, toMoveOutsideBar: toMoveOutsideBar }; diff --git a/src/traces/funnelarea/base_plot.js b/src/traces/funnelarea/base_plot.js index 739fbc3050e..3dcfab8563c 100644 --- a/src/traces/funnelarea/base_plot.js +++ b/src/traces/funnelarea/base_plot.js @@ -8,22 +8,14 @@ 'use strict'; -var Registry = require('../../registry'); -var getModuleCalcData = require('../../plots/get_data').getModuleCalcData; +var plots = require('../../plots/plots'); exports.name = 'funnelarea'; -exports.plot = function(gd) { - var Funnelarea = Registry.getModule('funnelarea'); - var cdFunnelarea = getModuleCalcData(gd.calcdata, Funnelarea)[0]; - Funnelarea.plot(gd, cdFunnelarea); +exports.plot = function(gd, traces, transitionOpts, makeOnCompleteCallback) { + plots.plotBasePlot(exports.name, gd, traces, transitionOpts, makeOnCompleteCallback); }; exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) { - var hadFunnelarea = (oldFullLayout._has && oldFullLayout._has('funnelarea')); - var hasFunnelarea = (newFullLayout._has && newFullLayout._has('funnelarea')); - - if(hadFunnelarea && !hasFunnelarea) { - oldFullLayout._funnelarealayer.selectAll('g.trace').remove(); - } + plots.cleanBasePlot(exports.name, newFullData, newFullLayout, oldFullData, oldFullLayout); }; diff --git a/src/traces/funnelarea/plot.js b/src/traces/funnelarea/plot.js index 9e1091e2d66..29ce263c1d1 100644 --- a/src/traces/funnelarea/plot.js +++ b/src/traces/funnelarea/plot.js @@ -15,7 +15,6 @@ var Lib = require('../../lib'); var svgTextUtils = require('../../lib/svg_text_utils'); var barPlot = require('../bar/plot'); -var getTransform = barPlot.getTransform; var toMoveInsideBar = barPlot.toMoveInsideBar; var pieHelpers = require('../pie/helpers'); @@ -115,7 +114,7 @@ module.exports = function plot(gd, cdModule) { x0 = Math.max(pt.TL[0], pt.BL[0]); x1 = Math.min(pt.TR[0], pt.BR[0]); - transform = getTransform(toMoveInsideBar(x0, x1, y0, y1, textBB, { + transform = Lib.getTextTransform(toMoveInsideBar(x0, x1, y0, y1, textBB, { isHorizontal: true, constrained: true, angle: 0, diff --git a/src/traces/indicator/base_plot.js b/src/traces/indicator/base_plot.js index 07a0e8b35de..1d8f5c48c88 100644 --- a/src/traces/indicator/base_plot.js +++ b/src/traces/indicator/base_plot.js @@ -8,22 +8,14 @@ 'use strict'; -var Registry = require('../../registry'); -var getModuleCalcData = require('../../plots/get_data').getModuleCalcData; +var plots = require('../../plots/plots'); -var name = exports.name = 'indicator'; +exports.name = 'indicator'; exports.plot = function(gd, traces, transitionOpts, makeOnCompleteCallback) { - var _module = Registry.getModule(name); - var cdmodule = getModuleCalcData(gd.calcdata, _module)[0]; - _module.plot(gd, cdmodule, transitionOpts, makeOnCompleteCallback); + plots.plotBasePlot(exports.name, gd, traces, transitionOpts, makeOnCompleteCallback); }; exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) { - var had = (oldFullLayout._has && oldFullLayout._has(name)); - var has = (newFullLayout._has && newFullLayout._has(name)); - - if(had && !has) { - oldFullLayout._indicatorlayer.selectAll('g.trace').remove(); - } + plots.cleanBasePlot(exports.name, newFullData, newFullLayout, oldFullData, oldFullLayout); }; diff --git a/src/traces/pie/base_plot.js b/src/traces/pie/base_plot.js index af1d15543a1..4842d10e652 100644 --- a/src/traces/pie/base_plot.js +++ b/src/traces/pie/base_plot.js @@ -8,22 +8,14 @@ 'use strict'; -var Registry = require('../../registry'); -var getModuleCalcData = require('../../plots/get_data').getModuleCalcData; +var plots = require('../../plots/plots'); exports.name = 'pie'; -exports.plot = function(gd) { - var Pie = Registry.getModule('pie'); - var cdPie = getModuleCalcData(gd.calcdata, Pie)[0]; - Pie.plot(gd, cdPie); +exports.plot = function(gd, traces, transitionOpts, makeOnCompleteCallback) { + plots.plotBasePlot(exports.name, gd, traces, transitionOpts, makeOnCompleteCallback); }; exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) { - var hadPie = (oldFullLayout._has && oldFullLayout._has('pie')); - var hasPie = (newFullLayout._has && newFullLayout._has('pie')); - - if(hadPie && !hasPie) { - oldFullLayout._pielayer.selectAll('g.trace').remove(); - } + plots.cleanBasePlot(exports.name, newFullData, newFullLayout, oldFullData, oldFullLayout); }; diff --git a/src/traces/sunburst/attributes.js b/src/traces/sunburst/attributes.js index f36294917aa..2a3d60c2c71 100644 --- a/src/traces/sunburst/attributes.js +++ b/src/traces/sunburst/attributes.js @@ -11,9 +11,11 @@ var plotAttrs = require('../../plots/attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs; + +var colorScaleAttrs = require('../../components/colorscale/attributes'); var domainAttrs = require('../../plots/domain').attributes; var pieAttrs = require('../pie/attributes'); - +var constants = require('./constants'); var extendFlat = require('../../lib/extend').extendFlat; module.exports = { @@ -21,14 +23,14 @@ module.exports = { valType: 'data_array', editType: 'calc', description: [ - 'Sets the labels of each of the sunburst sectors.' + 'Sets the labels of each of the sectors.' ].join(' ') }, parents: { valType: 'data_array', editType: 'calc', description: [ - 'Sets the parent sectors for each of the sunburst sectors.', + 'Sets the parent sectors for each of the sectors.', 'Empty string items \'\' are understood to reference', 'the root node in the hierarchy.', 'If `ids` is filled, `parents` items are understood to be "ids" themselves.', @@ -41,7 +43,7 @@ module.exports = { valType: 'data_array', editType: 'calc', description: [ - 'Sets the values associated with each of the sunburst sectors.', + 'Sets the values associated with each of the sectors.', 'Use with `branchvalues` to determine how the values are summed.' ].join(' ') }, @@ -58,6 +60,20 @@ module.exports = { 'are taken to be the extra part not part of the sum of the values at their leaves.' ].join(' ') }, + count: { + valType: 'flaglist', + flags: [ + 'branches', + 'leaves' + ], + dflt: 'leaves', + editType: 'calc', + role: 'info', + description: [ + 'Determines counting the number of *leaves* and/or *branches*,', + 'when a `values` array is not provided.' + ].join(' ') + }, level: { valType: 'any', @@ -65,8 +81,8 @@ module.exports = { anim: true, role: 'info', description: [ - 'Sets the level from which this sunburst trace hierarchy is rendered.', - 'Set `level` to `\'\'` to start the sunburst from the root node in the hierarchy.', + 'Sets the level from which this trace hierarchy is rendered.', + 'Set `level` to `\'\'` to start from the root node in the hierarchy.', 'Must be an "id" if `ids` is filled in, otherwise plotly attempts to find a matching', 'item in `labels`.' ].join(' ') @@ -77,17 +93,17 @@ module.exports = { role: 'info', dflt: -1, description: [ - 'Sets the number of rendered sunburst rings from any given `level`.', + 'Sets the number of rendered sectors from any given `level`.', 'Set `maxdepth` to *-1* to render all the levels in the hierarchy.' ].join(' ') }, - marker: { + marker: extendFlat({ colors: { valType: 'data_array', editType: 'calc', description: [ - 'Sets the color of each sector of this sunburst chart.', + 'Sets the color of each sector of this trace.', 'If not specified, the default trace color set is used', 'to pick the sector colors.' ].join(' ') @@ -111,6 +127,11 @@ module.exports = { }, editType: 'calc' }, + colorScaleAttrs('marker', { + colorAttr: 'colors', + anim: false // TODO: set to anim: true? + }) + ), leaf: { opacity: { @@ -119,28 +140,58 @@ module.exports = { role: 'style', min: 0, max: 1, - dflt: 0.7, - description: 'Sets the opacity of the leaves.' + description: [ + 'Sets the opacity of the leaves. With colorscale', + 'it is defaulted to 1; otherwise it is defaulted to 0.7' + ].join(' ') }, editType: 'plot' }, text: pieAttrs.text, - textinfo: extendFlat({}, pieAttrs.textinfo, { + textinfo: { + valType: 'flaglist', + role: 'info', + flags: [ + 'label', + 'text', + 'value', + 'current path', + 'percent root', + 'percent entry', + 'percent parent' + ], + extras: ['none'], editType: 'plot', - flags: ['label', 'text', 'value'] - }), + description: [ + 'Determines which trace information appear on the graph.' + ].join(' ') + }, + + // TODO: incorporate `label` and `value` in the eventData texttemplate: texttemplateAttrs({editType: 'plot'}, { - keys: ['label', 'text', 'value', 'color'] + keys: constants.eventDataKeys.concat(['label', 'value']) }), - textfont: pieAttrs.textfont, hovertext: pieAttrs.hovertext, hoverinfo: extendFlat({}, plotAttrs.hoverinfo, { - flags: ['label', 'text', 'value', 'name'] + flags: [ + 'label', + 'text', + 'value', + 'name', + 'current path', + 'percent root', + 'percent entry', + 'percent parent' + ], + dflt: 'label+text+value+name' + }), + hovertemplate: hovertemplateAttrs({}, { + keys: constants.eventDataKeys }), - hovertemplate: hovertemplateAttrs(), + textfont: pieAttrs.textfont, insidetextfont: pieAttrs.insidetextfont, outsidetextfont: pieAttrs.outsidetextfont, diff --git a/src/traces/sunburst/base_plot.js b/src/traces/sunburst/base_plot.js index 82dddc89d59..3ae714a1689 100644 --- a/src/traces/sunburst/base_plot.js +++ b/src/traces/sunburst/base_plot.js @@ -8,22 +8,14 @@ 'use strict'; -var Registry = require('../../registry'); -var getModuleCalcData = require('../../plots/get_data').getModuleCalcData; +var plots = require('../../plots/plots'); -var name = exports.name = 'sunburst'; +exports.name = 'sunburst'; exports.plot = function(gd, traces, transitionOpts, makeOnCompleteCallback) { - var _module = Registry.getModule(name); - var cdmodule = getModuleCalcData(gd.calcdata, _module)[0]; - _module.plot(gd, cdmodule, transitionOpts, makeOnCompleteCallback); + plots.plotBasePlot(exports.name, gd, traces, transitionOpts, makeOnCompleteCallback); }; exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) { - var had = (oldFullLayout._has && oldFullLayout._has(name)); - var has = (newFullLayout._has && newFullLayout._has(name)); - - if(had && !has) { - oldFullLayout._sunburstlayer.selectAll('g.trace').remove(); - } + plots.cleanBasePlot(exports.name, newFullData, newFullLayout, oldFullData, oldFullLayout); }; diff --git a/src/traces/sunburst/calc.js b/src/traces/sunburst/calc.js index a864e9bd708..04d8a196106 100644 --- a/src/traces/sunburst/calc.js +++ b/src/traces/sunburst/calc.js @@ -12,21 +12,25 @@ var d3Hierarchy = require('d3-hierarchy'); var isNumeric = require('fast-isnumeric'); var Lib = require('../../lib'); +var makeColorScaleFn = require('../../components/colorscale').makeColorScaleFuncFromTrace; var makePullColorFn = require('../pie/calc').makePullColorFn; var generateExtendedColors = require('../pie/calc').generateExtendedColors; -var isArrayOrTypedArray = Lib.isArrayOrTypedArray; +var Colorscale = require('../../components/colorscale'); +var hasColorscale = Colorscale.hasColorscale; +var colorscaleCalc = Colorscale.calc; var sunburstExtendedColorWays = {}; +var treemapExtendedColorWays = {}; exports.calc = function(gd, trace) { var fullLayout = gd._fullLayout; var ids = trace.ids; - var hasIds = isArrayOrTypedArray(ids); + var hasIds = Lib.isArrayOrTypedArray(ids); var labels = trace.labels; var parents = trace.parents; - var vals = trace.values; - var hasVals = isArrayOrTypedArray(vals); + var values = trace.values; + var hasValues = Lib.isArrayOrTypedArray(values); var cd = []; var parent2children = {}; @@ -43,7 +47,7 @@ exports.calc = function(gd, trace) { }; var isValidVal = function(i) { - return !hasVals || (isNumeric(vals[i]) && vals[i] >= 0); + return !hasValues || (isNumeric(values[i]) && values[i] >= 0); }; var len; @@ -67,7 +71,7 @@ exports.calc = function(gd, trace) { getId = function(i) { return String(labels[i]); }; } - if(hasVals) len = Math.min(len, vals.length); + if(hasValues) len = Math.min(len, values.length); for(var i = 0; i < len; i++) { if(isValid(i)) { @@ -81,7 +85,7 @@ exports.calc = function(gd, trace) { label: isValidKey(labels[i]) ? String(labels[i]) : '' }; - if(hasVals) cdi.v = +vals[i]; + if(hasValues) cdi.v = +values[i]; cd.push(cdi); addToLookup(pid, id); } @@ -107,7 +111,7 @@ exports.calc = function(gd, trace) { label: k }); } else { - return Lib.warn('Multiple implied roots, cannot build sunburst hierarchy.'); + return Lib.warn('Multiple implied roots, cannot build ' + trace.type + ' hierarchy.'); } } else if(parent2children[''].length > 1) { var dummyId = Lib.randstr(); @@ -135,13 +139,13 @@ exports.calc = function(gd, trace) { .id(function(d) { return d.id; }) .parentId(function(d) { return d.pid; })(cd); } catch(e) { - return Lib.warn('Failed to build sunburst hierarchy. Error: ' + e.message); + return Lib.warn('Failed to build ' + trace.type + ' hierarchy. Error: ' + e.message); } var hierarchy = d3Hierarchy.hierarchy(root); var failed = false; - if(hasVals) { + if(hasValues) { switch(trace.branchvalues) { case 'remainder': hierarchy.sum(function(d) { return d.data.v; }); @@ -158,7 +162,9 @@ exports.calc = function(gd, trace) { failed = true; return Lib.warn([ 'Total value for node', d.data.data.id, - 'is smaller than the sum of its children.' + 'is smaller than the sum of its children.', + '\nparent value =', v, + '\nchildren sum =', partialSum ].join(' ')); } } @@ -168,7 +174,10 @@ exports.calc = function(gd, trace) { break; } } else { - hierarchy.count(); + countDescendants(hierarchy, trace, { + branches: trace.count.indexOf('branches') !== -1, + leaves: trace.count.indexOf('leaves') !== -1 + }); } if(failed) return; @@ -176,16 +185,34 @@ exports.calc = function(gd, trace) { // TODO add way to sort by height also? hierarchy.sort(function(a, b) { return b.value - a.value; }); + var pullColor; + var scaleColor; var colors = trace.marker.colors || []; - var pullColor = makePullColorFn(fullLayout._sunburstcolormap); + trace._hasColorscale = hasColorscale(trace, 'marker'); + if(trace._hasColorscale) { + if(!colors.length) { + colors = hasValues ? trace.values : trace._values; + } + + colorscaleCalc(gd, trace, { + vals: colors, + containerStr: 'marker', + cLetter: 'c' + }); + + scaleColor = makeColorScaleFn(trace.marker); + } else { + pullColor = makePullColorFn(fullLayout['_' + trace.type + 'colormap']); + } // TODO keep track of 'root-children' (i.e. branch) for hover info etc. hierarchy.each(function(d) { var cdi = d.data.data; - var id = cdi.id; // N.B. this mutates items in `cd` - cdi.color = pullColor(colors[cdi.i], id); + cdi.color = trace._hasColorscale ? + scaleColor(colors[cdi.i]) : + pullColor(colors[cdi.i], cdi.id); }); cd[0].hierarchy = hierarchy; @@ -200,14 +227,16 @@ exports.calc = function(gd, trace) { * This is done after sorting, so we pick defaults * in the order slices will be displayed */ -exports.crossTraceCalc = function(gd) { +exports._runCrossTraceCalc = function(desiredType, gd) { var fullLayout = gd._fullLayout; var calcdata = gd.calcdata; - var colorWay = fullLayout.sunburstcolorway; - var colorMap = fullLayout._sunburstcolormap; + var colorWay = fullLayout[desiredType + 'colorway']; + var colorMap = fullLayout['_' + desiredType + 'colormap']; - if(fullLayout.extendsunburstcolors) { - colorWay = generateExtendedColors(colorWay, sunburstExtendedColorWays); + if(fullLayout['extend' + desiredType + 'colors']) { + colorWay = generateExtendedColors(colorWay, + desiredType === 'treemap' ? treemapExtendedColorWays : sunburstExtendedColorWays + ); } var dfltColorCount = 0; @@ -238,8 +267,38 @@ exports.crossTraceCalc = function(gd) { for(var i = 0; i < calcdata.length; i++) { var cd = calcdata[i]; var cd0 = cd[0]; - if(cd0.trace.type === 'sunburst' && cd0.hierarchy) { + if(cd0.trace.type === desiredType && cd0.hierarchy) { cd0.hierarchy.each(pickColor); } } }; + +exports.crossTraceCalc = function(gd) { + return exports._runCrossTraceCalc('sunburst', gd); +}; + +function countDescendants(node, trace, opts) { + var nChild = 0; + + var children = node.children; + if(children) { + var len = children.length; + + for(var i = 0; i < len; i++) { + nChild += countDescendants(children[i], trace, opts); + } + + if(opts.branches) nChild++; // count this branch + } else { + if(opts.leaves) nChild++; // count this leaf + } + + // save to the node + node.value = node.data.data.value = nChild; + + // save to the trace + if(!trace._values) trace._values = []; + trace._values[node.data.data.i] = nChild; + + return nChild; +} diff --git a/src/traces/sunburst/constants.js b/src/traces/sunburst/constants.js index fafc4c52c0d..753f2b6986f 100644 --- a/src/traces/sunburst/constants.js +++ b/src/traces/sunburst/constants.js @@ -10,5 +10,17 @@ module.exports = { CLICK_TRANSITION_TIME: 750, - CLICK_TRANSITION_EASING: 'linear' + CLICK_TRANSITION_EASING: 'linear', + eventDataKeys: [ + // string + 'currentPath', + 'root', + 'entry', + // no need to add 'parent' here + + // percentages i.e. ratios + 'percentRoot', + 'percentEntry', + 'percentParent' + ] }; diff --git a/src/traces/sunburst/defaults.js b/src/traces/sunburst/defaults.js index c34e27b019e..a8f758cbcff 100644 --- a/src/traces/sunburst/defaults.js +++ b/src/traces/sunburst/defaults.js @@ -13,6 +13,10 @@ var attributes = require('./attributes'); var handleDomainDefaults = require('../../plots/domain').defaults; var handleText = require('../bar/defaults').handleText; +var Colorscale = require('../../components/colorscale'); +var hasColorscale = Colorscale.hasColorscale; +var colorscaleDefaults = Colorscale.handleDefaults; + module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) { function coerce(attr, dflt) { return Lib.coerce(traceIn, traceOut, attributes, attr, dflt); @@ -27,7 +31,11 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout } var vals = coerce('values'); - if(vals && vals.length) coerce('branchvalues'); + if(vals && vals.length) { + coerce('branchvalues'); + } else { + coerce('count'); + } coerce('level'); coerce('maxdepth'); @@ -36,8 +44,12 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout if(lineWidth) coerce('marker.line.color', layout.paper_bgcolor); coerce('marker.colors'); + var withColorscale = hasColorscale(traceIn, 'marker'); + if(withColorscale) { + colorscaleDefaults(traceIn, traceOut, layout, coerce, {prefix: 'marker.', cLetter: 'c'}); + } - coerce('leaf.opacity'); + coerce('leaf.opacity', withColorscale ? 1 : 0.7); var text = coerce('text'); coerce('texttemplate'); diff --git a/src/traces/sunburst/fx.js b/src/traces/sunburst/fx.js new file mode 100644 index 00000000000..25f4eceb1a1 --- /dev/null +++ b/src/traces/sunburst/fx.js @@ -0,0 +1,315 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var d3 = require('d3'); +var Registry = require('../../registry'); +var appendArrayPointValue = require('../../components/fx/helpers').appendArrayPointValue; +var Fx = require('../../components/fx'); +var Lib = require('../../lib'); +var Events = require('../../lib/events'); + +var helpers = require('./helpers'); +var pieHelpers = require('../pie/helpers'); + +var formatValue = pieHelpers.formatPieValue; + +module.exports = function attachFxHandlers(sliceTop, entry, gd, cd, opts) { + var cd0 = cd[0]; + var trace = cd0.trace; + var hierarchy = cd0.hierarchy; + var rootLabel = hierarchy.data.data.pid; + var readLabel = function(refPt) { + var l = helpers.getPtLabel(refPt); + return l === undefined ? rootLabel : l; + }; + + var isSunburst = trace.type === 'sunburst'; + var isTreemap = trace.type === 'treemap'; + + // hover state vars + // have we drawn a hover label, so it should be cleared later + if(!('_hasHoverLabel' in trace)) trace._hasHoverLabel = false; + // have we emitted a hover event, so later an unhover event should be emitted + // note that click events do not depend on this - you can still get them + // with hovermode: false or if you were earlier dragging, then clicked + // in the same slice that you moused up in + if(!('_hasHoverEvent' in trace)) trace._hasHoverEvent = false; + + var onMouseOver = function(pt) { + var fullLayoutNow = gd._fullLayout; + + if(gd._dragging || fullLayoutNow.hovermode === false) return; + + var traceNow = gd._fullData[trace.index]; + var cdi = pt.data.data; + var ptNumber = cdi.i; + var isRoot = helpers.isHierarchyRoot(pt); + var parent = helpers.getParent(hierarchy, pt); + + var val = helpers.getVal(pt); + + var _cast = function(astr) { + return Lib.castOption(traceNow, ptNumber, astr); + }; + + var hovertemplate = _cast('hovertemplate'); + var hoverinfo = Fx.castHoverinfo(traceNow, fullLayoutNow, ptNumber); + var separators = fullLayoutNow.separators; + + if(hovertemplate || (hoverinfo && hoverinfo !== 'none' && hoverinfo !== 'skip')) { + var hoverCenterX; + var hoverCenterY; + if(isSunburst) { + hoverCenterX = cd0.cx + pt.pxmid[0] * (1 - pt.rInscribed); + hoverCenterY = cd0.cy + pt.pxmid[1] * (1 - pt.rInscribed); + } + if(isTreemap) { + hoverCenterX = pt._hoverX; + hoverCenterY = pt._hoverY; + } + + var hoverPt = {}; + var parts = []; + var thisText = []; + var hasFlag = function(flag) { return parts.indexOf(flag) !== -1; }; + + if(hoverinfo) { + parts = hoverinfo === 'all' ? + traceNow._module.attributes.hoverinfo.flags : + hoverinfo.split('+'); + } + + hoverPt.label = cdi.label; + if(hasFlag('label') && hoverPt.label) thisText.push(hoverPt.label); + + if(cdi.hasOwnProperty('v')) { + hoverPt.value = cdi.v; + hoverPt.valueLabel = formatValue(hoverPt.value, separators); + if(hasFlag('value')) thisText.push(hoverPt.valueLabel); + } + + hoverPt.currentPath = pt.currentPath = helpers.getPath(pt.data); + if(hasFlag('current path') && !isRoot) { + thisText.push(hoverPt.currentPath); + } + + var tx; + var allPercents = []; + var insertPercent = function() { + if(allPercents.indexOf(tx) === -1) { // no need to add redundant info + thisText.push(tx); + allPercents.push(tx); + } + }; + + if(parent) { + hoverPt.percentParent = pt.percentParent = val / helpers.getVal(parent); + hoverPt.parent = pt.parentString = readLabel(parent); + if(hasFlag('percent parent')) { + tx = helpers.formatPercent(hoverPt.percentParent, separators) + ' of ' + hoverPt.parent; + insertPercent(); + } + } + + hoverPt.percentEntry = pt.percentEntry = val / helpers.getVal(entry); + hoverPt.entry = pt.entry = readLabel(entry); + if(hasFlag('percent entry') && !isRoot && !pt.onPathbar) { + tx = helpers.formatPercent(hoverPt.percentEntry, separators) + ' of ' + hoverPt.entry; + insertPercent(); + } + + hoverPt.percentRoot = pt.percentRoot = val / helpers.getVal(hierarchy); + hoverPt.root = pt.root = readLabel(hierarchy); + if(hasFlag('percent root') && !isRoot) { + tx = helpers.formatPercent(hoverPt.percentRoot, separators) + ' of ' + hoverPt.root; + insertPercent(); + } + + hoverPt.text = _cast('hovertext') || _cast('text'); + if(hasFlag('text')) { + tx = hoverPt.text; + if(Lib.isValidTextValue(tx)) thisText.push(tx); + } + + var hoverItems = { + trace: traceNow, + y: hoverCenterY, + text: thisText.join('
'), + name: (hovertemplate || hasFlag('name')) ? traceNow.name : undefined, + color: _cast('hoverlabel.bgcolor') || cdi.color, + borderColor: _cast('hoverlabel.bordercolor'), + fontFamily: _cast('hoverlabel.font.family'), + fontSize: _cast('hoverlabel.font.size'), + fontColor: _cast('hoverlabel.font.color'), + nameLength: _cast('hoverlabel.namelength'), + textAlign: _cast('hoverlabel.align'), + hovertemplate: hovertemplate, + hovertemplateLabels: hoverPt, + eventData: [makeEventData(pt, traceNow, opts.eventDataKeys)] + }; + + if(isSunburst) { + hoverItems.x0 = hoverCenterX - pt.rInscribed * pt.rpx1; + hoverItems.x1 = hoverCenterX + pt.rInscribed * pt.rpx1; + hoverItems.idealAlign = pt.pxmid[0] < 0 ? 'left' : 'right'; + } + if(isTreemap) { + hoverItems.x = hoverCenterX; + hoverItems.idealAlign = hoverCenterX < 0 ? 'left' : 'right'; + } + + Fx.loneHover(hoverItems, { + container: fullLayoutNow._hoverlayer.node(), + outerContainer: fullLayoutNow._paper.node(), + gd: gd + }); + + trace._hasHoverLabel = true; + } + + if(isTreemap) { + var slice = sliceTop.select('path.surface'); + opts.styleOne(slice, pt, traceNow, { + hovered: true + }); + } + + trace._hasHoverEvent = true; + gd.emit('plotly_hover', { + points: [makeEventData(pt, traceNow, opts.eventDataKeys)], + event: d3.event + }); + }; + + var onMouseOut = function(evt) { + var fullLayoutNow = gd._fullLayout; + var traceNow = gd._fullData[trace.index]; + var pt = d3.select(this).datum(); + + if(trace._hasHoverEvent) { + evt.originalEvent = d3.event; + gd.emit('plotly_unhover', { + points: [makeEventData(pt, traceNow, opts.eventDataKeys)], + event: d3.event + }); + trace._hasHoverEvent = false; + } + + if(trace._hasHoverLabel) { + Fx.loneUnhover(fullLayoutNow._hoverlayer.node()); + trace._hasHoverLabel = false; + } + + if(isTreemap) { + var slice = sliceTop.select('path.surface'); + opts.styleOne(slice, pt, traceNow, { + hovered: false + }); + } + }; + + var onClick = function(pt) { + // TODO: this does not support right-click. If we want to support it, we + // would likely need to change pie to use dragElement instead of straight + // mapbox event binding. Or perhaps better, make a simple wrapper with the + // right mousedown, mousemove, and mouseup handlers just for a left/right click + // mapbox would use this too. + var fullLayoutNow = gd._fullLayout; + var traceNow = gd._fullData[trace.index]; + + var clickVal = Events.triggerHandler(gd, 'plotly_' + trace.type + 'click', { + points: [makeEventData(pt, traceNow, opts.eventDataKeys)], + event: d3.event + }); + + // 'regular' click event when sunburst/treemap click is disabled or when + // clicking on leaves or the hierarchy root + if( + clickVal === false || + isSunburst && ( + helpers.isHierarchyRoot(pt) || + helpers.isLeaf(pt) + ) + ) { + if(fullLayoutNow.hovermode) { + gd._hoverdata = [makeEventData(pt, traceNow, opts.eventDataKeys)]; + Fx.click(gd, d3.event); + } + return; + } + + // skip if triggered from dragging a nearby cartesian subplot + if(gd._dragging) return; + + // skip during transitions, to avoid potential bugs + // we could remove this check later + if(gd._transitioning) return; + + // store 'old' level in guiEdit stash, so that subsequent Plotly.react + // calls with the same uirevision can start from the same entry + Registry.call('_storeDirectGUIEdit', traceNow, fullLayoutNow._tracePreGUI[traceNow.uid], { + level: traceNow.level + }); + + var id = helpers.getPtId(pt); + var nextEntry = helpers.isEntry(pt) ? + helpers.findEntryWithChild(hierarchy, id) : + helpers.findEntryWithLevel(hierarchy, id); + + var frame = { + data: [{level: helpers.getPtId(nextEntry)}], + traces: [trace.index] + }; + + var animOpts = { + frame: { + redraw: false, + duration: opts.transitionTime + }, + transition: { + duration: opts.transitionTime, + easing: opts.transitionEasing + }, + mode: 'immediate', + fromcurrent: true + }; + + Fx.loneUnhover(fullLayoutNow._hoverlayer.node()); + Registry.call('animate', gd, frame, animOpts); + }; + + sliceTop.on('mouseover', onMouseOver); + sliceTop.on('mouseout', onMouseOut); + sliceTop.on('click', onClick); +}; + +function makeEventData(pt, trace, keys) { + var cdi = pt.data.data; + + var out = { + curveNumber: trace.index, + pointNumber: cdi.i, + data: trace._input, + fullData: trace, + + // TODO more things like 'children', 'siblings', 'hierarchy? + }; + + for(var i = 0; i < keys.length; i++) { + var key = keys[i]; + if(key in pt) out[key] = pt[key]; + } + // handle special case of parent + if('parentString' in pt) out.parent = pt.parentString; + + appendArrayPointValue(out, trace, cdi.i); + + return out; +} diff --git a/src/traces/sunburst/helpers.js b/src/traces/sunburst/helpers.js index a475e31a3f8..269dfcbbeec 100644 --- a/src/traces/sunburst/helpers.js +++ b/src/traces/sunburst/helpers.js @@ -11,24 +11,7 @@ var Lib = require('../../lib'); var Color = require('../../components/color'); var setCursor = require('../../lib/setcursor'); -var appendArrayPointValue = require('../../components/fx/helpers').appendArrayPointValue; - -exports.makeEventData = function(pt, trace) { - var cdi = pt.data.data; - - var out = { - curveNumber: trace.index, - pointNumber: cdi.i, - data: trace._input, - fullData: trace, - - // TODO more things like 'children', 'siblings', 'hierarchy? - }; - - appendArrayPointValue(out, trace, cdi.i); - - return out; -}; +var pieHelpers = require('../pie/helpers'); exports.findEntryWithLevel = function(hierarchy, level) { var out; @@ -56,11 +39,6 @@ exports.findEntryWithChild = function(hierarchy, childId) { return out || hierarchy; }; -exports.isHierachyRoot = function(pt) { - var cdi = pt.data.data; - return cdi.pid === ''; -}; - exports.isEntry = function(pt) { return !pt.parent; }; @@ -70,40 +48,42 @@ exports.isLeaf = function(pt) { }; exports.getPtId = function(pt) { - var cdi = pt.data.data; - return cdi.id; + return pt.data.data.id; }; -exports.setSliceCursor = function(sliceTop, gd, opts) { - var pt = sliceTop.datum(); - var isTransitioning = (opts || {}).isTransitioning; - setCursor(sliceTop, (isTransitioning || exports.isLeaf(pt) || exports.isHierachyRoot(pt)) ? null : 'pointer'); +exports.getPtLabel = function(pt) { + return pt.data.data.label; }; -exports.determineOutsideTextFont = function(trace, pt, layoutFont) { - var cdi = pt.data.data; - var ptNumber = cdi.i; - - var color = Lib.castOption(trace, ptNumber, 'outsidetextfont.color') || - Lib.castOption(trace, ptNumber, 'textfont.color') || - layoutFont.color; +exports.getVal = function(d) { + return d.value; +}; - var family = Lib.castOption(trace, ptNumber, 'outsidetextfont.family') || - Lib.castOption(trace, ptNumber, 'textfont.family') || - layoutFont.family; +exports.isHierarchyRoot = function(pt) { + return getParentId(pt) === ''; +}; - var size = Lib.castOption(trace, ptNumber, 'outsidetextfont.size') || - Lib.castOption(trace, ptNumber, 'textfont.size') || - layoutFont.size; +exports.setSliceCursor = function(sliceTop, gd, opts) { + var hide = opts.isTransitioning; + if(!hide) { + var pt = sliceTop.datum(); + hide = ( + (opts.hideOnRoot && exports.isHierarchyRoot(pt)) || + (opts.hideOnLeaves && exports.isLeaf(pt)) + ); + } + setCursor(sliceTop, hide ? null : 'pointer'); +}; +function determineOutsideTextFont(trace, pt, layoutFont) { return { - color: color, - family: family, - size: size + color: exports.getOutsideTextFontKey('color', trace, pt, layoutFont), + family: exports.getOutsideTextFontKey('family', trace, pt, layoutFont), + size: exports.getOutsideTextFontKey('size', trace, pt, layoutFont) }; -}; +} -exports.determineInsideTextFont = function(trace, pt, layoutFont) { +function determineInsideTextFont(trace, pt, layoutFont, cont) { var cdi = pt.data.data; var ptNumber = cdi.i; @@ -116,17 +96,84 @@ exports.determineInsideTextFont = function(trace, pt, layoutFont) { customColor = Lib.castOption(trace._input, ptNumber, 'textfont.color'); } - var family = Lib.castOption(trace, ptNumber, 'insidetextfont.family') || - Lib.castOption(trace, ptNumber, 'textfont.family') || - layoutFont.family; - - var size = Lib.castOption(trace, ptNumber, 'insidetextfont.size') || - Lib.castOption(trace, ptNumber, 'textfont.size') || - layoutFont.size; - return { color: customColor || Color.contrast(cdi.color), - family: family, - size: size + family: exports.getInsideTextFontKey('family', cont || trace, pt, layoutFont), + size: exports.getInsideTextFontKey('size', cont || trace, pt, layoutFont) }; +} + +exports.getInsideTextFontKey = function(keyStr, trace, pt, layoutFont) { + var ptNumber = pt.data.data.i; + + return ( + Lib.castOption(trace, ptNumber, 'insidetextfont.' + keyStr) || + Lib.castOption(trace, ptNumber, 'textfont.' + keyStr) || + layoutFont.size + ); +}; + +exports.getOutsideTextFontKey = function(keyStr, trace, pt, layoutFont) { + var ptNumber = pt.data.data.i; + + return ( + Lib.castOption(trace, ptNumber, 'outsidetextfont.' + keyStr) || + Lib.castOption(trace, ptNumber, 'textfont.' + keyStr) || + layoutFont.size + ); +}; + +exports.isOutsideText = function(trace, pt) { + return !trace._hasColorscale && exports.isHierarchyRoot(pt); +}; + +exports.determineTextFont = function(trace, pt, layoutFont, cont) { + return exports.isOutsideText(trace, pt) ? + determineOutsideTextFont(trace, pt, layoutFont) : + determineInsideTextFont(trace, pt, layoutFont, cont); +}; + +exports.hasTransition = function(transitionOpts) { + // We could optimize hasTransition per trace, + // as sunburst & treemap have no cross-trace logic! + return !!(transitionOpts && transitionOpts.duration > 0); +}; + +exports.getMaxDepth = function(trace) { + return trace.maxdepth >= 0 ? trace.maxdepth : Infinity; +}; + +exports.isHeader = function(pt, trace) { // it is only used in treemap. + return !(exports.isLeaf(pt) || pt.depth === trace._maxDepth - 1); +}; + +function getParentId(pt) { + return pt.data.data.pid; +} + +exports.getParent = function(hierarchy, pt) { + var parentId = getParentId(pt); + return parentId === '' ? + undefined : + exports.findEntryWithLevel(hierarchy, parentId); +}; + +exports.listPath = function(d, keyStr) { + var parent = d.parent; + if(!parent) return []; + var list = keyStr ? [parent.data[keyStr]] : [parent]; + return exports.listPath(parent, keyStr).concat(list); +}; + +exports.getPath = function(d) { + return exports.listPath(d, 'label').join('/') + '/'; +}; + +exports.formatValue = pieHelpers.formatPieValue; + +// TODO: should combine the two in a separate PR - Also please note Lib.formatPercent should support separators. +exports.formatPercent = function(v, separators) { + var tx = Lib.formatPercent(v, 0); // use funnel(area) version + if(tx === '0%') tx = pieHelpers.formatPiePercent(v, separators); // use pie version + return tx; }; diff --git a/src/traces/sunburst/index.js b/src/traces/sunburst/index.js index 05246586994..83f7dd70c2d 100644 --- a/src/traces/sunburst/index.js +++ b/src/traces/sunburst/index.js @@ -23,9 +23,11 @@ module.exports = { calc: require('./calc').calc, crossTraceCalc: require('./calc').crossTraceCalc, - plot: require('./plot'), + plot: require('./plot').plot, style: require('./style').style, + colorbar: require('../scatter/marker_colorbar'), + meta: { description: [ 'Visualize hierarchal data spanning outward radially from root to leaves.', diff --git a/src/traces/sunburst/plot.js b/src/traces/sunburst/plot.js index d8bedac6df0..89028f8bbe7 100644 --- a/src/traces/sunburst/plot.js +++ b/src/traces/sunburst/plot.js @@ -11,21 +11,18 @@ var d3 = require('d3'); var d3Hierarchy = require('d3-hierarchy'); -var Registry = require('../../registry'); -var Fx = require('../../components/fx'); var Drawing = require('../../components/drawing'); var Lib = require('../../lib'); -var Events = require('../../lib/events'); var svgTextUtils = require('../../lib/svg_text_utils'); var transformInsideText = require('../pie/plot').transformInsideText; -var formatPieValue = require('../pie/helpers').formatPieValue; var styleOne = require('./style').styleOne; +var attachFxHandlers = require('./fx'); var constants = require('./constants'); var helpers = require('./helpers'); -module.exports = function(gd, cdmodule, transitionOpts, makeOnCompleteCallback) { +exports.plot = function(gd, cdmodule, transitionOpts, makeOnCompleteCallback) { var fullLayout = gd._fullLayout; var layer = fullLayout._sunburstlayer; var join, onComplete; @@ -33,7 +30,7 @@ module.exports = function(gd, cdmodule, transitionOpts, makeOnCompleteCallback) // If transition config is provided, then it is only a partial replot and traces not // updated are removed. var isFullReplot = !transitionOpts; - var hasTransition = transitionOpts && transitionOpts.duration > 0; + var hasTransition = helpers.hasTransition(transitionOpts); join = layer.selectAll('g.trace.sunburst') .data(cdmodule, function(cd) { return cd[0].trace.uid; }); @@ -80,9 +77,7 @@ module.exports = function(gd, cdmodule, transitionOpts, makeOnCompleteCallback) function plotOne(gd, cd, element, transitionOpts) { var fullLayout = gd._fullLayout; - // We could optimize hasTransition per trace, - // as sunburst has no cross-trace logic! - var hasTransition = transitionOpts && transitionOpts.duration > 0; + var hasTransition = helpers.hasTransition(transitionOpts); var gTrace = d3.select(element); var slices = gTrace.selectAll('g.slice'); @@ -90,8 +85,8 @@ function plotOne(gd, cd, element, transitionOpts) { var cd0 = cd[0]; var trace = cd0.trace; var hierarchy = cd0.hierarchy; - var entry = findEntryWithLevel(hierarchy, trace.level); - var maxDepth = trace.maxdepth >= 0 ? trace.maxdepth : Infinity; + var entry = helpers.findEntryWithLevel(hierarchy, trace.level); + var maxDepth = helpers.getMaxDepth(trace); var gs = fullLayout._size; var domain = trace.domain; @@ -130,12 +125,12 @@ function plotOne(gd, cd, element, transitionOpts) { // N.B. slice data isn't the calcdata, // grab corresponding calcdata item in sliceData[i].data.data var sliceData = partition(entry).descendants(); + var maxHeight = entry.height + 1; var yOffset = 0; var cutoff = maxDepth; - // N.B. handle multiple-root special case - if(cd0.hasMultipleRoots && helpers.isHierachyRoot(entry)) { + if(cd0.hasMultipleRoots && helpers.isHierarchyRoot(entry)) { sliceData = sliceData.slice(1); maxHeight -= 1; yOffset = 1; @@ -197,9 +192,13 @@ function plotOne(gd, cd, element, transitionOpts) { if(hasTransition) { updateSlices = updateSlices.transition().each('end', function() { // N.B. gd._transitioning is (still) *true* by the time - // transition updates get hare + // transition updates get here var sliceTop = d3.select(this); - helpers.setSliceCursor(sliceTop, gd, {isTransitioning: false}); + helpers.setSliceCursor(sliceTop, gd, { + hideOnRoot: true, + hideOnLeaves: true, + isTransitioning: false + }); }); } @@ -221,7 +220,7 @@ function plotOne(gd, cd, element, transitionOpts) { if(hasTransition) { slicePath.transition().attrTween('d', function(pt2) { - var interp = makeUpdateSliceIntepolator(pt2); + var interp = makeUpdateSliceInterpolator(pt2); return function(t) { return pathSlice(interp(t)); }; }); } else { @@ -229,8 +228,16 @@ function plotOne(gd, cd, element, transitionOpts) { } sliceTop - .call(attachFxHandlers, gd, cd) - .call(helpers.setSliceCursor, gd, {isTransitioning: gd._transitioning}); + .call(attachFxHandlers, entry, gd, cd, { + eventDataKeys: constants.eventDataKeys, + transitionTime: constants.CLICK_TRANSITION_TIME, + transitionEasing: constants.CLICK_TRANSITION_EASING + }) + .call(helpers.setSliceCursor, gd, { + hideOnRoot: true, + hideOnLeaves: true, + isTransitioning: gd._transitioning + }); slicePath.call(styleOne, pt, trace); @@ -241,12 +248,10 @@ function plotOne(gd, cd, element, transitionOpts) { s.attr('data-notex', 1); }); - sliceText.text(formatSliceLabel(pt, trace, fullLayout)) + sliceText.text(exports.formatSliceLabel(pt, entry, trace, cd, fullLayout)) .classed('slicetext', true) .attr('text-anchor', 'middle') - .call(Drawing.font, helpers.isHierachyRoot(pt) ? - helpers.determineOutsideTextFont(trace, pt, fullLayout.font) : - helpers.determineInsideTextFont(trace, pt, fullLayout.font)) + .call(Drawing.font, helpers.determineTextFont(trace, pt, fullLayout.font)) .call(svgTextUtils.convertToTspans, gd); // position the text relative to the slice @@ -267,7 +272,7 @@ function plotOne(gd, cd, element, transitionOpts) { if(hasTransition) { sliceText.transition().attrTween('transform', function(pt2) { - var interp = makeUpdateTextInterpolar(pt2); + var interp = makeUpdateTextInterpolator(pt2); return function(t) { return strTransform(interp(t), textBB); }; }); } else { @@ -315,7 +320,7 @@ function plotOne(gd, cd, element, transitionOpts) { return d3.interpolate(prev, next); } - function makeUpdateSliceIntepolator(pt) { + function makeUpdateSliceInterpolator(pt) { var prev0 = prevLookup[helpers.getPtId(pt)]; var prev; var next = {x0: pt.x0, x1: pt.x1, rpx0: pt.rpx0, rpx1: pt.rpx1}; @@ -354,7 +359,7 @@ function plotOne(gd, cd, element, transitionOpts) { return d3.interpolate(prev, next); } - function makeUpdateTextInterpolar(pt) { + function makeUpdateTextInterpolator(pt) { var prev0 = prevLookup[helpers.getPtId(pt)]; var prev; var transform = pt.transform; @@ -471,211 +476,7 @@ function partition(entry) { .size([2 * Math.PI, entry.height + 1])(entry); } -function findEntryWithLevel(hierarchy, level) { - var out; - if(level) { - hierarchy.eachAfter(function(pt) { - if(helpers.getPtId(pt) === level) { - return out = pt.copy(); - } - }); - } - return out || hierarchy; -} - -function findEntryWithChild(hierarchy, childId) { - var out; - hierarchy.eachAfter(function(pt) { - var children = pt.children || []; - for(var i = 0; i < children.length; i++) { - var child = children[i]; - if(helpers.getPtId(child) === childId) { - return out = pt.copy(); - } - } - }); - return out || hierarchy; -} - -function attachFxHandlers(sliceTop, gd, cd) { - var cd0 = cd[0]; - var trace = cd0.trace; - - // hover state vars - // have we drawn a hover label, so it should be cleared later - if(!('_hasHoverLabel' in trace)) trace._hasHoverLabel = false; - // have we emitted a hover event, so later an unhover event should be emitted - // note that click events do not depend on this - you can still get them - // with hovermode: false or if you were earlier dragging, then clicked - // in the same slice that you moused up in - if(!('_hasHoverEvent' in trace)) trace._hasHoverEvent = false; - - sliceTop.on('mouseover', function(pt) { - var fullLayoutNow = gd._fullLayout; - - if(gd._dragging || fullLayoutNow.hovermode === false) return; - - var traceNow = gd._fullData[trace.index]; - var cdi = pt.data.data; - var ptNumber = cdi.i; - - var _cast = function(astr) { - return Lib.castOption(traceNow, ptNumber, astr); - }; - - var hovertemplate = _cast('hovertemplate'); - var hoverinfo = Fx.castHoverinfo(traceNow, fullLayoutNow, ptNumber); - var separators = fullLayoutNow.separators; - - if(hovertemplate || (hoverinfo && hoverinfo !== 'none' && hoverinfo !== 'skip')) { - var rInscribed = pt.rInscribed; - var hoverCenterX = cd0.cx + pt.pxmid[0] * (1 - rInscribed); - var hoverCenterY = cd0.cy + pt.pxmid[1] * (1 - rInscribed); - var hoverPt = {}; - var parts = []; - var thisText = []; - var hasFlag = function(flag) { return parts.indexOf(flag) !== -1; }; - - if(hoverinfo) { - parts = hoverinfo === 'all' ? - traceNow._module.attributes.hoverinfo.flags : - hoverinfo.split('+'); - } - - hoverPt.label = cdi.label; - if(hasFlag('label') && hoverPt.label) thisText.push(hoverPt.label); - - if(cdi.hasOwnProperty('v')) { - hoverPt.value = cdi.v; - hoverPt.valueLabel = formatPieValue(hoverPt.value, separators); - if(hasFlag('value')) thisText.push(hoverPt.valueLabel); - } - - hoverPt.text = _cast('hovertext') || _cast('text'); - if(hasFlag('text')) { - var tx = hoverPt.text; - if(Lib.isValidTextValue(tx)) thisText.push(tx); - } - - Fx.loneHover({ - trace: traceNow, - x0: hoverCenterX - rInscribed * pt.rpx1, - x1: hoverCenterX + rInscribed * pt.rpx1, - y: hoverCenterY, - idealAlign: pt.pxmid[0] < 0 ? 'left' : 'right', - text: thisText.join('
'), - name: (hovertemplate || hasFlag('name')) ? traceNow.name : undefined, - color: _cast('hoverlabel.bgcolor') || cdi.color, - borderColor: _cast('hoverlabel.bordercolor'), - fontFamily: _cast('hoverlabel.font.family'), - fontSize: _cast('hoverlabel.font.size'), - fontColor: _cast('hoverlabel.font.color'), - nameLength: _cast('hoverlabel.namelength'), - textAlign: _cast('hoverlabel.align'), - hovertemplate: hovertemplate, - hovertemplateLabels: hoverPt, - eventData: [helpers.makeEventData(pt, traceNow)] - }, { - container: fullLayoutNow._hoverlayer.node(), - outerContainer: fullLayoutNow._paper.node(), - gd: gd - }); - - trace._hasHoverLabel = true; - } - - trace._hasHoverEvent = true; - gd.emit('plotly_hover', { - points: [helpers.makeEventData(pt, traceNow)], - event: d3.event - }); - }); - - sliceTop.on('mouseout', function(evt) { - var fullLayoutNow = gd._fullLayout; - var traceNow = gd._fullData[trace.index]; - var pt = d3.select(this).datum(); - - if(trace._hasHoverEvent) { - evt.originalEvent = d3.event; - gd.emit('plotly_unhover', { - points: [helpers.makeEventData(pt, traceNow)], - event: d3.event - }); - trace._hasHoverEvent = false; - } - - if(trace._hasHoverLabel) { - Fx.loneUnhover(fullLayoutNow._hoverlayer.node()); - trace._hasHoverLabel = false; - } - }); - - sliceTop.on('click', function(pt) { - // TODO: this does not support right-click. If we want to support it, we - // would likely need to change pie to use dragElement instead of straight - // mapbox event binding. Or perhaps better, make a simple wrapper with the - // right mousedown, mousemove, and mouseup handlers just for a left/right click - // mapbox would use this too. - var fullLayoutNow = gd._fullLayout; - var traceNow = gd._fullData[trace.index]; - - var clickVal = Events.triggerHandler(gd, 'plotly_sunburstclick', { - points: [helpers.makeEventData(pt, traceNow)], - event: d3.event - }); - - // 'regular' click event when sunburstclick is disabled or when - // clikcin on leaves or the hierarchy root - if(clickVal === false || helpers.isLeaf(pt) || helpers.isHierachyRoot(pt)) { - if(fullLayoutNow.hovermode) { - gd._hoverdata = [helpers.makeEventData(pt, traceNow)]; - Fx.click(gd, d3.event); - } - return; - } - - // skip if triggered from dragging a nearby cartesian subplot - if(gd._dragging) return; - - // skip during transitions, to avoid potential bugs - // we could remove this check later - if(gd._transitioning) return; - - // store 'old' level in guiEdit stash, so that subsequent Plotly.react - // calls with the same uirevision can start from the same entry - Registry.call('_storeDirectGUIEdit', traceNow, fullLayoutNow._tracePreGUI[traceNow.uid], {level: traceNow.level}); - - var hierarchy = cd0.hierarchy; - var id = helpers.getPtId(pt); - var nextEntry = helpers.isEntry(pt) ? - findEntryWithChild(hierarchy, id) : - findEntryWithLevel(hierarchy, id); - - var frame = { - data: [{level: helpers.getPtId(nextEntry)}], - traces: [trace.index] - }; - - var animOpts = { - frame: { - redraw: false, - duration: constants.CLICK_TRANSITION_TIME - }, - transition: { - duration: constants.CLICK_TRANSITION_TIME, - easing: constants.CLICK_TRANSITION_EASING - }, - mode: 'immediate', - fromcurrent: true - }; - - Fx.loneUnhover(fullLayoutNow._hoverlayer.node()); - Registry.call('animate', gd, frame, animOpts); - }); -} - -function formatSliceLabel(pt, trace, fullLayout) { +exports.formatSliceLabel = function(pt, entry, trace, cd, fullLayout) { var texttemplate = trace.texttemplate; var textinfo = trace.textinfo; @@ -683,23 +484,71 @@ function formatSliceLabel(pt, trace, fullLayout) { return ''; } - var cdi = pt.data.data; var separators = fullLayout.separators; + var cd0 = cd[0]; + var cdi = pt.data.data; + var hierarchy = cd0.hierarchy; + var rootLabel = hierarchy.data.data.pid; + var readLabel = function(refPt) { + var l = helpers.getPtLabel(refPt); + return l === undefined ? rootLabel : l; + }; + + var isRoot = helpers.isHierarchyRoot(pt); + var parent = helpers.getParent(hierarchy, pt); + var val = helpers.getVal(pt); + if(!texttemplate) { var parts = textinfo.split('+'); var hasFlag = function(flag) { return parts.indexOf(flag) !== -1; }; var thisText = []; + var tx; if(hasFlag('label') && cdi.label) { thisText.push(cdi.label); } if(cdi.hasOwnProperty('v') && hasFlag('value')) { - thisText.push(formatPieValue(cdi.v, separators)); + thisText.push(helpers.formatValue(cdi.v, separators)); + } + + if(!isRoot) { + if(hasFlag('current path')) { + thisText.push(helpers.getPath(pt.data)); + } + + var nPercent = 0; + if(hasFlag('percent parent')) nPercent++; + if(hasFlag('percent entry')) nPercent++; + if(hasFlag('percent root')) nPercent++; + var hasMultiplePercents = nPercent > 1; + + if(nPercent) { + var percent; + var addPercent = function(key) { + tx = helpers.formatPercent(percent, separators); + + if(hasMultiplePercents) tx += ' of ' + key; + thisText.push(tx); + }; + + if(hasFlag('percent parent') && parent) { + percent = val / helpers.getVal(parent); + addPercent('parent'); + } + if(hasFlag('percent entry')) { + percent = val / helpers.getVal(entry); + addPercent('entry'); + } + if(hasFlag('percent root')) { + percent = val / helpers.getVal(hierarchy); + addPercent('root'); + } + } } if(hasFlag('text')) { - var tx = Lib.castOption(trace, cdi.i, 'text'); + tx = Lib.castOption(trace, cdi.i, 'text'); if(Lib.isValidTextValue(tx)) thisText.push(tx); } @@ -712,8 +561,31 @@ function formatSliceLabel(pt, trace, fullLayout) { if(cdi.label) obj.label = cdi.label; if(cdi.hasOwnProperty('v')) { obj.value = cdi.v; - obj.valueLabel = formatPieValue(cdi.v, separators); + obj.valueLabel = helpers.formatValue(cdi.v, separators); + } + + obj.currentPath = helpers.getPath(pt.data); + + if(parent) { + obj.percentParent = val / helpers.getVal(parent); + obj.percentParentLabel = helpers.formatPercent( + obj.percentParent, separators + ); + obj.parent = readLabel(parent); } + + obj.percentEntry = val / helpers.getVal(entry); + obj.percentEntryLabel = helpers.formatPercent( + obj.percentEntry, separators + ); + obj.entry = readLabel(entry); + + obj.percentRoot = val / helpers.getVal(hierarchy); + obj.percentRootLabel = helpers.formatPercent( + obj.percentRoot, separators + ); + obj.root = readLabel(hierarchy); + if(cdi.hasOwnProperty('color')) { obj.color = cdi.color; } @@ -721,7 +593,7 @@ function formatSliceLabel(pt, trace, fullLayout) { if(Lib.isValidTextValue(ptTx) || ptTx === '') obj.text = ptTx; obj.customdata = Lib.castOption(trace, cdi.i, 'customdata'); return Lib.texttemplateString(txt, obj, fullLayout._d3locale, obj, trace._meta || {}); -} +}; function getInscribedRadiusFraction(pt) { if(pt.rpx0 === 0 && Lib.isFullCircle([pt.x0, pt.x1])) { diff --git a/src/traces/treemap/attributes.js b/src/traces/treemap/attributes.js new file mode 100644 index 00000000000..58fc9c80a23 --- /dev/null +++ b/src/traces/treemap/attributes.js @@ -0,0 +1,286 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; +var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs; + +var colorScaleAttrs = require('../../components/colorscale/attributes'); +var domainAttrs = require('../../plots/domain').attributes; +var pieAttrs = require('../pie/attributes'); +var sunburstAttrs = require('../sunburst/attributes'); +var constants = require('./constants'); +var extendFlat = require('../../lib/extend').extendFlat; + +module.exports = { + labels: sunburstAttrs.labels, + parents: sunburstAttrs.parents, + + values: sunburstAttrs.values, + branchvalues: sunburstAttrs.branchvalues, + count: sunburstAttrs.count, + + level: sunburstAttrs.level, + maxdepth: sunburstAttrs.maxdepth, + + tiling: { + packing: { + valType: 'enumerated', + values: [ + 'squarify', + 'binary', + 'dice', + 'slice', + 'slice-dice', + 'dice-slice' + ], + dflt: 'squarify', + role: 'info', + editType: 'plot', + description: [ + 'Determines d3 treemap solver.', + 'For more info please refer to https://github.com/d3/d3-hierarchy#treemap-tiling' + ].join(' ') + }, + + squarifyratio: { + valType: 'number', + role: 'info', + min: 1, + dflt: 1, + editType: 'plot', + description: [ + 'When using *squarify* `packing` algorithm, according to https://github.com/d3/d3-hierarchy/blob/master/README.md#squarify_ratio', + 'this option specifies the desired aspect ratio of the generated rectangles.', + 'The ratio must be specified as a number greater than or equal to one.', + 'Note that the orientation of the generated rectangles (tall or wide)', + 'is not implied by the ratio; for example, a ratio of two will attempt', + 'to produce a mixture of rectangles whose width:height ratio is either 2:1 or 1:2.', + 'When using *squarify*, unlike d3 which uses the Golden Ratio i.e. 1.618034,', + 'Plotly applies 1 to increase squares in treemap layouts.' + ].join(' ') + }, + + flip: { + valType: 'flaglist', + role: 'info', + flags: [ + 'x', + 'y' + ], + dflt: '', + editType: 'plot', + description: [ + 'Determines if the positions obtained from solver are flipped on each axis.' + ].join(' ') + }, + + pad: { + valType: 'number', + role: 'style', + min: 0, + dflt: 3, + editType: 'plot', + description: [ + 'Sets the inner padding (in px).' + ].join(' ') + }, + + editType: 'calc', + }, + + marker: extendFlat({ + pad: { + t: { + valType: 'number', + role: 'style', + min: 0, + editType: 'plot', + description: [ + 'Sets the padding form the top (in px).' + ].join(' ') + }, + l: { + valType: 'number', + role: 'style', + min: 0, + editType: 'plot', + description: [ + 'Sets the padding form the left (in px).' + ].join(' ') + }, + r: { + valType: 'number', + role: 'style', + min: 0, + editType: 'plot', + description: [ + 'Sets the padding form the right (in px).' + ].join(' ') + }, + b: { + valType: 'number', + role: 'style', + min: 0, + editType: 'plot', + description: [ + 'Sets the padding form the bottom (in px).' + ].join(' ') + }, + + editType: 'calc' + }, + + colors: sunburstAttrs.marker.colors, + + opacitybase: { + valType: 'number', + editType: 'style', + role: 'style', + min: 0, + max: 1, + dflt: 0.5, + description: [ + 'Sets the base opacity of the headers based on the depth from the entry.', + 'This options is not available when having a `colorscale`.' + ].join(' ') + }, + + opacitystep: { + valType: 'number', + editType: 'style', + role: 'style', + min: 0, + max: 1, + dflt: 0.5, + description: [ + 'Sets the increment for opacity of the headers based on the depth from the entry.', + 'This options is not available when having a `colorscale`.' + ].join(' ') + }, + + line: sunburstAttrs.marker.line, + + editType: 'calc' + }, + colorScaleAttrs('marker', { + colorAttr: 'colors', + anim: false // TODO: set to anim: true? + }) + ), + + pathbar: { + visible: { + valType: 'boolean', + dflt: true, + role: 'info', + editType: 'plot', + description: [ + 'Determines if the path bar is drawn', + 'i.e. outside the trace `domain` and', + 'with one pixel gap.' + ].join(' ') + }, + + side: { + valType: 'enumerated', + values: [ + 'top', + 'bottom' + ], + dflt: 'top', + role: 'info', + editType: 'plot', + description: [ + 'Determines on which side of the the treemap the', + '`pathbar` should be presented.' + ].join(' ') + }, + + edgeshape: { + valType: 'enumerated', + values: [ + '>', + '<', + '|', + '/', + '\\' + ], + dflt: '>', + role: 'style', + editType: 'plot', + description: [ + 'Determines which shape is used for edges between `barpath` labels.' + ].join(' ') + }, + + thickness: { + valType: 'number', + min: 12, + role: 'info', + editType: 'plot', + description: [ + 'Sets the thickness of `pathbar` (in px). If not specified the `pathbar.textfont.size` is used', + 'with 3 pixles extra padding on each side.' + ].join(' ') + }, + + opacity: { + valType: 'number', + editType: 'style', + role: 'style', + min: 0, + dflt: 0.5, + description: [ + 'Sets the opacity of the pathbar', + 'This options is not available when having a `colorscale`.' + ].join(' ') + }, + + textfont: extendFlat({}, pieAttrs.textfont, { + description: 'Sets the font used inside `pathbar`.' + }), + + editType: 'calc' + }, + + text: pieAttrs.text, + textinfo: sunburstAttrs.textinfo, + // TODO: incorporate `label` and `value` in the eventData + texttemplate: texttemplateAttrs({editType: 'plot'}, { + keys: constants.eventDataKeys.concat(['label', 'value']) + }), + + hovertext: pieAttrs.hovertext, + hoverinfo: sunburstAttrs.hoverinfo, + hovertemplate: hovertemplateAttrs({}, { + keys: constants.eventDataKeys + }), + + textfont: pieAttrs.textfont, + insidetextfont: pieAttrs.insidetextfont, + outsidetextfont: pieAttrs.outsidetextfont, + + textposition: { + valType: 'enumerated', + values: [ + 'top left', 'top center', 'top right', + 'middle left', 'middle center', 'middle right', + 'bottom left', 'bottom center', 'bottom right' + ], + dflt: 'top left', + role: 'style', + editType: 'plot', + description: [ + 'Sets the positions of the `text` elements.' + ].join(' ') + }, + + domain: domainAttrs({name: 'treemap', trace: true, editType: 'calc'}), +}; diff --git a/src/traces/treemap/base_plot.js b/src/traces/treemap/base_plot.js new file mode 100644 index 00000000000..3573a6e537b --- /dev/null +++ b/src/traces/treemap/base_plot.js @@ -0,0 +1,21 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var plots = require('../../plots/plots'); + +exports.name = 'treemap'; + +exports.plot = function(gd, traces, transitionOpts, makeOnCompleteCallback) { + plots.plotBasePlot(exports.name, gd, traces, transitionOpts, makeOnCompleteCallback); +}; + +exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) { + plots.cleanBasePlot(exports.name, newFullData, newFullLayout, oldFullData, oldFullLayout); +}; diff --git a/src/traces/treemap/calc.js b/src/traces/treemap/calc.js new file mode 100644 index 00000000000..0d2469ecac2 --- /dev/null +++ b/src/traces/treemap/calc.js @@ -0,0 +1,19 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var calc = require('../sunburst/calc'); + +exports.calc = function(gd, trace) { + return calc.calc(gd, trace); +}; + +exports.crossTraceCalc = function(gd) { + return calc._runCrossTraceCalc('treemap', gd); +}; diff --git a/src/traces/treemap/constants.js b/src/traces/treemap/constants.js new file mode 100644 index 00000000000..388ad69ca49 --- /dev/null +++ b/src/traces/treemap/constants.js @@ -0,0 +1,27 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +module.exports = { + CLICK_TRANSITION_TIME: 750, + CLICK_TRANSITION_EASING: 'poly', + eventDataKeys: [ + // string + 'currentPath', + 'root', + 'entry', + // no need to add 'parent' here + + // percentages i.e. ratios + 'percentRoot', + 'percentEntry', + 'percentParent' + ], + gapWithPathbar: 1 // i.e. one pixel +}; diff --git a/src/traces/treemap/defaults.js b/src/traces/treemap/defaults.js new file mode 100644 index 00000000000..ef53c076af3 --- /dev/null +++ b/src/traces/treemap/defaults.js @@ -0,0 +1,118 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var Lib = require('../../lib'); +var attributes = require('./attributes'); +var Color = require('../../components/color'); +var handleDomainDefaults = require('../../plots/domain').defaults; +var handleText = require('../bar/defaults').handleText; +var TEXTPAD = require('../bar/constants').TEXTPAD; + +var Colorscale = require('../../components/colorscale'); +var hasColorscale = Colorscale.hasColorscale; +var colorscaleDefaults = Colorscale.handleDefaults; + +module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) { + function coerce(attr, dflt) { + return Lib.coerce(traceIn, traceOut, attributes, attr, dflt); + } + + var labels = coerce('labels'); + var parents = coerce('parents'); + + if(!labels || !labels.length || !parents || !parents.length) { + traceOut.visible = false; + return; + } + + var vals = coerce('values'); + if(vals && vals.length) { + coerce('branchvalues'); + } else { + coerce('count'); + } + + coerce('level'); + coerce('maxdepth'); + + var packing = coerce('tiling.packing'); + if(packing === 'squarify') { + coerce('tiling.squarifyratio'); + } + + coerce('tiling.flip'); + coerce('tiling.pad'); + + var text = coerce('text'); + coerce('texttemplate'); + if(!traceOut.texttemplate) coerce('textinfo', Array.isArray(text) ? 'text+label' : 'label'); + + coerce('hovertext'); + coerce('hovertemplate'); + + var textposition = 'auto'; + handleText(traceIn, traceOut, layout, coerce, textposition, { + moduleHasSelected: false, + moduleHasUnselected: false, + moduleHasConstrain: false, + moduleHasCliponaxis: false, + moduleHasTextangle: false, + moduleHasInsideanchor: false + }); + coerce('textposition'); + var bottomText = traceOut.textposition.indexOf('bottom') !== -1; + + var lineWidth = coerce('marker.line.width'); + if(lineWidth) coerce('marker.line.color', layout.paper_bgcolor); + + coerce('marker.colors'); + var withColorscale = hasColorscale(traceIn, 'marker'); + + var headerSize = traceOut.textfont.size * 2; + + coerce('marker.pad.t', bottomText ? headerSize / 4 : headerSize); + coerce('marker.pad.l', headerSize / 4); + coerce('marker.pad.r', headerSize / 4); + coerce('marker.pad.b', bottomText ? headerSize : headerSize / 4); + + if(withColorscale) { + colorscaleDefaults(traceIn, traceOut, layout, coerce, {prefix: 'marker.', cLetter: 'c'}); + } else { + coerce('marker.opacitybase'); + coerce('marker.opacitystep'); + coerce('pathbar.opacity'); + } + + traceOut._hovered = { + marker: { + opacity: 1, + line: { + width: 2, + color: Color.contrast(layout.paper_bgcolor) + } + } + }; + + var hasPathbar = coerce('pathbar.visible'); + if(hasPathbar) { + Lib.coerceFont(coerce, 'pathbar.textfont', layout.font); + + // This works even for multi-line labels as treemap pathbar trim out line breaks + coerce('pathbar.thickness', traceOut.pathbar.textfont.size + 2 * TEXTPAD); + + coerce('pathbar.side'); + coerce('pathbar.edgeshape'); + } + + handleDomainDefaults(traceOut, layout, coerce); + + // do not support transforms for now + traceOut._length = null; +}; diff --git a/src/traces/treemap/draw_ancestors.js b/src/traces/treemap/draw_ancestors.js new file mode 100644 index 00000000000..87b87451f36 --- /dev/null +++ b/src/traces/treemap/draw_ancestors.js @@ -0,0 +1,179 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var d3 = require('d3'); +var Lib = require('../../lib'); +var Drawing = require('../../components/drawing'); +var svgTextUtils = require('../../lib/svg_text_utils'); + +var partition = require('./partition'); +var styleOne = require('./style').styleOne; +var constants = require('./constants'); +var helpers = require('../sunburst/helpers'); +var attachFxHandlers = require('../sunburst/fx'); + +var onPathbar = true; // for Ancestors + +module.exports = function drawAncestors(gd, cd, entry, slices, opts) { + var barDifY = opts.barDifY; + var width = opts.width; + var height = opts.height; + var viewX = opts.viewX; + var viewY = opts.viewY; + var pathSlice = opts.pathSlice; + var toMoveInsideSlice = opts.toMoveInsideSlice; + var strTransform = opts.strTransform; + var hasTransition = opts.hasTransition; + var handleSlicesExit = opts.handleSlicesExit; + var makeUpdateSliceInterpolator = opts.makeUpdateSliceInterpolator; + var makeUpdateTextInterpolator = opts.makeUpdateTextInterpolator; + var refRect = {}; + + var fullLayout = gd._fullLayout; + var cd0 = cd[0]; + var trace = cd0.trace; + var hierarchy = cd0.hierarchy; + + var eachWidth = width / trace._entryDepth; + + var pathIds = helpers.listPath(entry.data, 'id'); + + var sliceData = partition(hierarchy.copy(), [width, height], { + packing: 'dice', + pad: { + inner: 0, + top: 0, + left: 0, + right: 0, + bottom: 0 + } + }).descendants(); + + // edit slices that show up on graph + sliceData = sliceData.filter(function(pt) { + var level = pathIds.indexOf(pt.data.id); + if(level === -1) return false; + + pt.x0 = eachWidth * level; + pt.x1 = eachWidth * (level + 1); + pt.y0 = barDifY; + pt.y1 = barDifY + height; + + pt.onPathbar = true; + + return true; + }); + + sliceData.reverse(); + + slices = slices.data(sliceData, function(pt) { return helpers.getPtId(pt); }); + + slices.enter().append('g') + .classed('pathbar', true); + + handleSlicesExit(slices, onPathbar, refRect, [width, height], pathSlice); + + slices.order(); + + var updateSlices = slices; + if(hasTransition) { + updateSlices = updateSlices.transition().each('end', function() { + // N.B. gd._transitioning is (still) *true* by the time + // transition updates get here + var sliceTop = d3.select(this); + helpers.setSliceCursor(sliceTop, gd, { + hideOnRoot: false, + hideOnLeaves: false, + isTransitioning: false + }); + }); + } + + updateSlices.each(function(pt) { + pt._hoverX = viewX(pt.x1 - height / 2); + pt._hoverY = viewY(pt.y1 - height / 2); + + var sliceTop = d3.select(this); + + var slicePath = Lib.ensureSingle(sliceTop, 'path', 'surface', function(s) { + s.style('pointer-events', 'all'); + }); + + if(hasTransition) { + slicePath.transition().attrTween('d', function(pt2) { + var interp = makeUpdateSliceInterpolator(pt2, onPathbar, refRect, [width, height]); + return function(t) { return pathSlice(interp(t)); }; + }); + } else { + slicePath.attr('d', pathSlice); + } + + sliceTop + .call(attachFxHandlers, entry, gd, cd, { + styleOne: styleOne, + eventDataKeys: constants.eventDataKeys, + transitionTime: constants.CLICK_TRANSITION_TIME, + transitionEasing: constants.CLICK_TRANSITION_EASING + }) + .call(helpers.setSliceCursor, gd, { + hideOnRoot: false, + hideOnLeaves: false, + isTransitioning: gd._transitioning + }); + + slicePath.call(styleOne, pt, trace, { + hovered: false + }); + + var sliceTextGroup = Lib.ensureSingle(sliceTop, 'g', 'slicetext'); + var sliceText = Lib.ensureSingle(sliceTextGroup, 'text', '', function(s) { + // prohibit tex interpretation until we can handle + // tex and regular text together + s.attr('data-notex', 1); + }); + + var tx = (helpers.getPtLabel(pt) || ' ').split('
').join(' '); + + sliceText.text(tx) + .classed('slicetext', true) + .attr('text-anchor', 'start') + .call(Drawing.font, helpers.determineTextFont(trace, pt, fullLayout.font, trace.pathdir)) + .call(svgTextUtils.convertToTspans, gd); + + pt.textBB = Drawing.bBox(sliceText.node()); + pt.transform = toMoveInsideSlice( + pt.x0, + pt.x1, + pt.y0, + pt.y1, + pt.textBB, + { + onPathbar: true + } + ); + + if(helpers.isOutsideText(trace, pt)) { + // consider in/out diff font sizes + pt.transform.targetY -= ( + helpers.getOutsideTextFontKey('size', trace, pt, fullLayout.font) - + helpers.getInsideTextFontKey('size', trace, pt, fullLayout.font) + ); + } + + if(hasTransition) { + sliceText.transition().attrTween('transform', function(pt2) { + var interp = makeUpdateTextInterpolator(pt2, onPathbar, refRect, [width, height]); + return function(t) { return strTransform(interp(t)); }; + }); + } else { + sliceText.attr('transform', strTransform(pt)); + } + }); +}; diff --git a/src/traces/treemap/draw_descendants.js b/src/traces/treemap/draw_descendants.js new file mode 100644 index 00000000000..88e481ae0ce --- /dev/null +++ b/src/traces/treemap/draw_descendants.js @@ -0,0 +1,213 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var d3 = require('d3'); +var Lib = require('../../lib'); +var Drawing = require('../../components/drawing'); +var svgTextUtils = require('../../lib/svg_text_utils'); + +var partition = require('./partition'); +var styleOne = require('./style').styleOne; +var constants = require('./constants'); +var helpers = require('../sunburst/helpers'); +var attachFxHandlers = require('../sunburst/fx'); +var formatSliceLabel = require('../sunburst/plot').formatSliceLabel; + +var onPathbar = false; // for Descendants + +module.exports = function drawDescendants(gd, cd, entry, slices, opts) { + var width = opts.width; + var height = opts.height; + var viewX = opts.viewX; + var viewY = opts.viewY; + var pathSlice = opts.pathSlice; + var toMoveInsideSlice = opts.toMoveInsideSlice; + var strTransform = opts.strTransform; + var hasTransition = opts.hasTransition; + var handleSlicesExit = opts.handleSlicesExit; + var makeUpdateSliceInterpolator = opts.makeUpdateSliceInterpolator; + var makeUpdateTextInterpolator = opts.makeUpdateTextInterpolator; + var prevEntry = opts.prevEntry; + var refRect = {}; + + var fullLayout = gd._fullLayout; + var cd0 = cd[0]; + var trace = cd0.trace; + + var hasLeft = trace.textposition.indexOf('left') !== -1; + var hasRight = trace.textposition.indexOf('right') !== -1; + var hasBottom = trace.textposition.indexOf('bottom') !== -1; + + var noRoomForHeader = (!hasBottom && !trace.marker.pad.t) || (hasBottom && !trace.marker.pad.b); + + // N.B. slice data isn't the calcdata, + // grab corresponding calcdata item in sliceData[i].data.data + var allData = partition(entry, [width, height], { + packing: trace.tiling.packing, + squarifyratio: trace.tiling.squarifyratio, + flipX: trace.tiling.flip.indexOf('x') > -1, + flipY: trace.tiling.flip.indexOf('y') > -1, + pad: { + inner: trace.tiling.pad, + top: trace.marker.pad.t, + left: trace.marker.pad.l, + right: trace.marker.pad.r, + bottom: trace.marker.pad.b, + } + }); + + var sliceData = allData.descendants(); + + slices = slices.data(sliceData, function(pt) { + // hide slices that won't show up on graph + if(pt.depth >= trace._maxDepth) { + pt.x0 = pt.x1 = (pt.x0 + pt.x1) / 2; + pt.y0 = pt.y1 = (pt.y0 + pt.y1) / 2; + } + + return helpers.getPtId(pt); + }); + + slices.enter().append('g') + .classed('slice', true); + + handleSlicesExit(slices, onPathbar, refRect, [width, height], pathSlice); + + slices.order(); + + // next coords of previous entry + var nextOfPrevEntry = null; + if(hasTransition && prevEntry) { + var prevEntryId = helpers.getPtId(prevEntry); + slices.each(function(pt) { + if(nextOfPrevEntry === null && (helpers.getPtId(pt) === prevEntryId)) { + nextOfPrevEntry = { + x0: pt.x0, + x1: pt.x1, + y0: pt.y0, + y1: pt.y1 + }; + } + }); + } + + var getRefRect = function() { + return nextOfPrevEntry || { + x0: 0, + x1: width, + y0: 0, + y1: height + }; + }; + + var updateSlices = slices; + if(hasTransition) { + updateSlices = updateSlices.transition().each('end', function() { + // N.B. gd._transitioning is (still) *true* by the time + // transition updates get here + var sliceTop = d3.select(this); + helpers.setSliceCursor(sliceTop, gd, { + hideOnRoot: true, + hideOnLeaves: false, + isTransitioning: false + }); + }); + } + + updateSlices.each(function(pt) { + var isHeader = helpers.isHeader(pt, trace); + + pt._hoverX = viewX(pt.x1 - trace.marker.pad.r), + pt._hoverY = hasBottom ? + viewY(pt.y1 - trace.marker.pad.b / 2) : + viewY(pt.y0 + trace.marker.pad.t / 2); + + var sliceTop = d3.select(this); + + var slicePath = Lib.ensureSingle(sliceTop, 'path', 'surface', function(s) { + s.style('pointer-events', 'all'); + }); + + if(hasTransition) { + slicePath.transition().attrTween('d', function(pt2) { + var interp = makeUpdateSliceInterpolator(pt2, onPathbar, getRefRect(), [width, height]); + return function(t) { return pathSlice(interp(t)); }; + }); + } else { + slicePath.attr('d', pathSlice); + } + + sliceTop + .call(attachFxHandlers, entry, gd, cd, { + styleOne: styleOne, + eventDataKeys: constants.eventDataKeys, + transitionTime: constants.CLICK_TRANSITION_TIME, + transitionEasing: constants.CLICK_TRANSITION_EASING + }) + .call(helpers.setSliceCursor, gd, { isTransitioning: gd._transitioning }); + + slicePath.call(styleOne, pt, trace, { + hovered: false + }); + + var sliceTextGroup = Lib.ensureSingle(sliceTop, 'g', 'slicetext'); + var sliceText = Lib.ensureSingle(sliceTextGroup, 'text', '', function(s) { + // prohibit tex interpretation until we can handle + // tex and regular text together + s.attr('data-notex', 1); + }); + + var tx; + if(isHeader) { + if(noRoomForHeader) return; + + tx = helpers.getPtLabel(pt); + } else { + tx = formatSliceLabel(pt, entry, trace, cd, fullLayout) || ' '; + } + + sliceText.text(tx) + .classed('slicetext', true) + .attr('text-anchor', hasRight ? 'end' : (hasLeft || isHeader) ? 'start' : 'middle') + .call(Drawing.font, helpers.determineTextFont(trace, pt, fullLayout.font)) + .call(svgTextUtils.convertToTspans, gd); + + pt.textBB = Drawing.bBox(sliceText.node()); + pt.transform = toMoveInsideSlice( + pt.x0, + pt.x1, + pt.y0, + pt.y1, + pt.textBB, + { + isHeader: isHeader + } + ); + + if(helpers.isOutsideText(trace, pt)) { + // consider in/out diff font sizes + pt.transform.targetY -= ( + helpers.getOutsideTextFontKey('size', trace, pt, fullLayout.font) - + helpers.getInsideTextFontKey('size', trace, pt, fullLayout.font) + ); + } + + if(hasTransition) { + sliceText.transition().attrTween('transform', function(pt2) { + var interp = makeUpdateTextInterpolator(pt2, onPathbar, getRefRect(), [width, height]); + return function(t) { return strTransform(interp(t)); }; + }); + } else { + sliceText.attr('transform', strTransform(pt)); + } + }); + + return nextOfPrevEntry; +}; diff --git a/src/traces/treemap/index.js b/src/traces/treemap/index.js new file mode 100644 index 00000000000..28e57f4c644 --- /dev/null +++ b/src/traces/treemap/index.js @@ -0,0 +1,38 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +module.exports = { + moduleType: 'trace', + name: 'treemap', + basePlotModule: require('./base_plot'), + categories: [], + animatable: true, + + attributes: require('./attributes'), + layoutAttributes: require('./layout_attributes'), + supplyDefaults: require('./defaults'), + supplyLayoutDefaults: require('./layout_defaults'), + + calc: require('./calc').calc, + crossTraceCalc: require('./calc').crossTraceCalc, + + plot: require('./plot'), + style: require('./style').style, + + colorbar: require('../scatter/marker_colorbar'), + + meta: { + description: [ + 'Visualize hierarchal data from leaves (and/or outer branches) towards root', + 'with rectangles. The treemap sectors are determined by the entries in', + '*labels* or *ids* and in *parents*.' + ].join(' ') + } +}; diff --git a/src/traces/treemap/layout_attributes.js b/src/traces/treemap/layout_attributes.js new file mode 100644 index 00000000000..93ac90ebaae --- /dev/null +++ b/src/traces/treemap/layout_attributes.js @@ -0,0 +1,39 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +module.exports = { + treemapcolorway: { + valType: 'colorlist', + role: 'style', + editType: 'calc', + description: [ + 'Sets the default treemap slice colors. Defaults to the main', + '`colorway` used for trace colors. If you specify a new', + 'list here it can still be extended with lighter and darker', + 'colors, see `extendtreemapcolors`.' + ].join(' ') + }, + extendtreemapcolors: { + valType: 'boolean', + dflt: true, + role: 'style', + editType: 'calc', + description: [ + 'If `true`, the treemap slice colors (whether given by `treemapcolorway` or', + 'inherited from `colorway`) will be extended to three times its', + 'original length by first repeating every color 20% lighter then', + 'each color 20% darker. This is intended to reduce the likelihood', + 'of reusing the same color when you have many slices, but you can', + 'set `false` to disable.', + 'Colors provided in the trace, using `marker.colors`, are never', + 'extended.' + ].join(' ') + } +}; diff --git a/src/traces/treemap/layout_defaults.js b/src/traces/treemap/layout_defaults.js new file mode 100644 index 00000000000..e1ccbb37c7a --- /dev/null +++ b/src/traces/treemap/layout_defaults.js @@ -0,0 +1,20 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var Lib = require('../../lib'); +var layoutAttributes = require('./layout_attributes'); + +module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) { + function coerce(attr, dflt) { + return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt); + } + coerce('treemapcolorway', layoutOut.colorway); + coerce('extendtreemapcolors'); +}; diff --git a/src/traces/treemap/partition.js b/src/traces/treemap/partition.js new file mode 100644 index 00000000000..182e368cf28 --- /dev/null +++ b/src/traces/treemap/partition.js @@ -0,0 +1,104 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var d3Hierarchy = require('d3-hierarchy'); + +module.exports = function partition(entry, size, opts) { + var flipX = opts.flipX; + var flipY = opts.flipY; + var swapXY = opts.packing === 'dice-slice'; + + var top = opts.pad[flipY ? 'bottom' : 'top']; + var left = opts.pad[flipX ? 'right' : 'left']; + var right = opts.pad[flipX ? 'left' : 'right']; + var bottom = opts.pad[flipY ? 'top' : 'bottom']; + + var tmp; + if(swapXY) { + tmp = left; + left = top; + top = tmp; + + tmp = right; + right = bottom; + bottom = tmp; + } + + var result = d3Hierarchy + .treemap() + .tile(getTilingMethod(opts.packing, opts.squarifyratio)) + .paddingInner(opts.pad.inner) + .paddingLeft(left) + .paddingRight(right) + .paddingTop(top) + .paddingBottom(bottom) + .size( + swapXY ? [size[1], size[0]] : size + )(entry); + + if(swapXY || flipX || flipY) { + flipTree(result, size, { + swapXY: swapXY, + flipX: flipX, + flipY: flipY + }); + } + return result; +}; + +function getTilingMethod(key, squarifyratio) { + switch(key) { + case 'squarify': + return d3Hierarchy.treemapSquarify.ratio(squarifyratio); + case 'binary': + return d3Hierarchy.treemapBinary; + case 'dice': + return d3Hierarchy.treemapDice; + case 'slice': + return d3Hierarchy.treemapSlice; + default: // i.e. 'slice-dice' | 'dice-slice' + return d3Hierarchy.treemapSliceDice; + } +} + +function flipTree(node, size, opts) { + var tmp; + + if(opts.swapXY) { + // swap x0 and y0 + tmp = node.x0; + node.x0 = node.y0; + node.y0 = tmp; + + // swap x1 and y1 + tmp = node.x1; + node.x1 = node.y1; + node.y1 = tmp; + } + + if(opts.flipX) { + tmp = node.x0; + node.x0 = size[0] - node.x1; + node.x1 = size[0] - tmp; + } + + if(opts.flipY) { + tmp = node.y0; + node.y0 = size[1] - node.y1; + node.y1 = size[1] - tmp; + } + + var children = node.children; + if(children) { + for(var i = 0; i < children.length; i++) { + flipTree(children[i], size, opts); + } + } +} diff --git a/src/traces/treemap/plot.js b/src/traces/treemap/plot.js new file mode 100644 index 00000000000..a72f03d6c8c --- /dev/null +++ b/src/traces/treemap/plot.js @@ -0,0 +1,597 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var d3 = require('d3'); + +var hasTransition = require('../sunburst/helpers').hasTransition; +var helpers = require('../sunburst/helpers'); + +var Lib = require('../../lib'); +var TEXTPAD = require('../bar/constants').TEXTPAD; +var toMoveInsideBar = require('../bar/plot').toMoveInsideBar; + +var constants = require('./constants'); +var drawDescendants = require('./draw_descendants'); +var drawAncestors = require('./draw_ancestors'); + +module.exports = function(gd, cdmodule, transitionOpts, makeOnCompleteCallback) { + var fullLayout = gd._fullLayout; + var layer = fullLayout._treemaplayer; + var join, onComplete; + + // If transition config is provided, then it is only a partial replot and traces not + // updated are removed. + var isFullReplot = !transitionOpts; + + join = layer.selectAll('g.trace.treemap') + .data(cdmodule, function(cd) { return cd[0].trace.uid; }); + + join.enter().append('g') + .classed('trace', true) + .classed('treemap', true); + + join.order(); + + if(hasTransition(transitionOpts)) { + if(makeOnCompleteCallback) { + // If it was passed a callback to register completion, make a callback. If + // this is created, then it must be executed on completion, otherwise the + // pos-transition redraw will not execute: + onComplete = makeOnCompleteCallback(); + } + + var transition = d3.transition() + .duration(transitionOpts.duration) + .ease(transitionOpts.easing) + .each('end', function() { onComplete && onComplete(); }) + .each('interrupt', function() { onComplete && onComplete(); }); + + transition.each(function() { + // Must run the selection again since otherwise enters/updates get grouped together + // and these get executed out of order. Except we need them in order! + layer.selectAll('g.trace').each(function(cd) { + plotOne(gd, cd, this, transitionOpts); + }); + }); + } else { + join.each(function(cd) { + plotOne(gd, cd, this, transitionOpts); + }); + } + + if(isFullReplot) { + join.exit().remove(); + } +}; + +function getKey(pt) { + return helpers.isHierarchyRoot(pt) ? + '' : // don't use the dummyId + helpers.getPtId(pt); +} + +function plotOne(gd, cd, element, transitionOpts) { + var fullLayout = gd._fullLayout; + var cd0 = cd[0]; + var trace = cd0.trace; + var hierarchy = cd0.hierarchy; + var hasTransition = helpers.hasTransition(transitionOpts); + var entry = helpers.findEntryWithLevel(hierarchy, trace.level); + var maxDepth = helpers.getMaxDepth(trace); + var hasVisibleDepth = function(pt) { + return pt.data.depth - entry.data.depth < maxDepth; + }; + + var gs = fullLayout._size; + var domain = trace.domain; + + var vpw = gs.w * (domain.x[1] - domain.x[0]); + var vph = gs.h * (domain.y[1] - domain.y[0]); + var barW = vpw; + var barH = trace.pathbar.thickness; + var barPad = trace.marker.line.width + constants.gapWithPathbar; + var barDifY = !trace.pathbar.visible ? 0 : + trace.pathbar.side.indexOf('bottom') > -1 ? vph + barPad : -(barH + barPad); + + var pathbarOrigin = { + x0: barW, // slide to the right + x1: barW, + y0: barDifY, + y1: barDifY + barH + }; + + var findClosestEdge = function(pt, ref, size) { + var e = trace.tiling.pad; + var isLeftOfRect = function(x) { return x - e <= ref.x0; }; + var isRightOfRect = function(x) { return x + e >= ref.x1; }; + var isBottomOfRect = function(y) { return y - e <= ref.y0; }; + var isTopOfRect = function(y) { return y + e >= ref.y1; }; + + return { + x0: isLeftOfRect(pt.x0 - e) ? 0 : isRightOfRect(pt.x0 - e) ? size[0] : pt.x0, + x1: isLeftOfRect(pt.x1 + e) ? 0 : isRightOfRect(pt.x1 + e) ? size[0] : pt.x1, + y0: isBottomOfRect(pt.y0 - e) ? 0 : isTopOfRect(pt.y0 - e) ? size[1] : pt.y0, + y1: isBottomOfRect(pt.y1 + e) ? 0 : isTopOfRect(pt.y1 + e) ? size[1] : pt.y1 + }; + }; + + // stash of 'previous' position data used by tweening functions + var prevEntry = null; + var prevLookupPathbar = {}; + var prevLookupSlices = {}; + var nextOfPrevEntry = null; + var getPrev = function(pt, onPathbar) { + return onPathbar ? + prevLookupPathbar[getKey(pt)] : + prevLookupSlices[getKey(pt)]; + }; + + var getOrigin = function(pt, onPathbar, refRect, size) { + if(onPathbar) { + return prevLookupPathbar[getKey(hierarchy)] || pathbarOrigin; + } else { + var ref = prevLookupSlices[trace.level] || refRect; + + if(hasVisibleDepth(pt)) { // case of an empty object - happens when maxdepth is set + return findClosestEdge(pt, ref, size); + } + } + return {}; + }; + + var isRoot = helpers.isHierarchyRoot(entry); + + trace._entryDepth = entry.data.depth; + if(isRoot) { + trace._entryDepth++; + } + + // N.B. handle multiple-root special case + if(cd0.hasMultipleRoots && isRoot) { + maxDepth++; + } + trace._maxDepth = maxDepth; + + var cenX = -vpw / 2 + gs.l + gs.w * (domain.x[1] + domain.x[0]) / 2; + var cenY = -vph / 2 + gs.t + gs.h * (1 - (domain.y[1] + domain.y[0]) / 2); + + var viewMapX = function(x) { return cenX + x; }; + var viewMapY = function(y) { return cenY + y; }; + + var barY0 = viewMapY(0); + var barX0 = viewMapX(0); + + var viewBarX = function(x) { return barX0 + x; }; + var viewBarY = function(y) { return barY0 + y; }; + + function pos(x, y) { + return x + ',' + y; + } + + var xStart = viewBarX(0); + var limitX0 = function(p) { p.x = Math.max(xStart, p.x); }; + + var edgeshape = trace.pathbar.edgeshape; + + // pathbar(directory) path generation fn + var pathAncestor = function(d) { + var _x0 = viewBarX(Math.max(Math.min(d.x0, d.x0), 0)); + var _x1 = viewBarX(Math.min(Math.max(d.x1, d.x1), barW)); + var _y0 = viewBarY(d.y0); + var _y1 = viewBarY(d.y1); + + var halfH = barH / 2; + + var pL = {}; + var pR = {}; + + pL.x = _x0; + pR.x = _x1; + + pL.y = pR.y = (_y0 + _y1) / 2; + + var pA = {x: _x0, y: _y0}; + var pB = {x: _x1, y: _y0}; + var pC = {x: _x1, y: _y1}; + var pD = {x: _x0, y: _y1}; + + if(edgeshape === '>') { + pA.x -= halfH; + pB.x -= halfH; + pC.x -= halfH; + pD.x -= halfH; + } else if(edgeshape === '/') { + pC.x -= halfH; + pD.x -= halfH; + pL.x -= halfH / 2; + pR.x -= halfH / 2; + } else if(edgeshape === '\\') { + pA.x -= halfH; + pB.x -= halfH; + pL.x -= halfH / 2; + pR.x -= halfH / 2; + } else if(edgeshape === '<') { + pL.x -= halfH; + pR.x -= halfH; + } + + limitX0(pA); + limitX0(pD); + limitX0(pL); + + limitX0(pB); + limitX0(pC); + limitX0(pR); + + return ( + 'M' + pos(pA.x, pA.y) + + 'L' + pos(pB.x, pB.y) + + 'L' + pos(pR.x, pR.y) + + 'L' + pos(pC.x, pC.y) + + 'L' + pos(pD.x, pD.y) + + 'L' + pos(pL.x, pL.y) + + 'Z' + ); + }; + + // slice path generation fn + var pathDescendant = function(d) { + var _x0 = viewMapX(d.x0); + var _x1 = viewMapX(d.x1); + var _y0 = viewMapY(d.y0); + var _y1 = viewMapY(d.y1); + + var dx = _x1 - _x0; + var dy = _y1 - _y0; + if(!dx || !dy) return ''; + + var FILLET = 0; // TODO: may expose this constant + + var r = ( + dx > 2 * FILLET && + dy > 2 * FILLET + ) ? FILLET : 0; + + var arc = function(rx, ry) { return r ? 'a' + pos(r, r) + ' 0 0 1 ' + pos(rx, ry) : ''; }; + + return ( + 'M' + pos(_x0, _y0 + r) + + arc(r, -r) + + 'L' + pos(_x1 - r, _y0) + + arc(r, r) + + 'L' + pos(_x1, _y1 - r) + + arc(-r, r) + + 'L' + pos(_x0 + r, _y1) + + arc(-r, -r) + 'Z' + ); + }; + + var toMoveInsideSlice = function(x0, x1, y0, y1, textBB, opts) { + var hasFlag = function(f) { return trace.textposition.indexOf(f) !== -1; }; + + var hasBottom = hasFlag('bottom'); + var hasTop = hasFlag('top') || (opts.isHeader && !hasBottom); + + var anchor = + hasTop ? 'start' : + hasBottom ? 'end' : 'middle'; + + var hasRight = hasFlag('right'); + var hasLeft = hasFlag('left') || opts.onPathbar; + + var offsetDir = + hasLeft ? 'left' : + hasRight ? 'right' : 'center'; + + if(opts.onPathbar || !opts.isHeader) { + x0 += hasLeft ? TEXTPAD : 0; + x1 -= hasRight ? TEXTPAD : 0; + } + + var pad = trace.marker.pad; + if(opts.isHeader) { + x0 += pad.l - TEXTPAD; + x1 -= pad.r - TEXTPAD; + + // limit the drawing area for headers + var limY; + if(hasBottom) { + limY = y1 - pad.b; + if(y0 < limY && limY < y1) y0 = limY; + } else { + limY = y0 + pad.t; + if(y0 < limY && limY < y1) y1 = limY; + } + } + + // position the text relative to the slice + var transform = toMoveInsideBar(x0, x1, y0, y1, textBB, { + isHorizontal: false, + constrained: true, + angle: 0, + anchor: anchor + }); + + if(offsetDir !== 'center') { + var deltaX = (x1 - x0) / 2 - transform.scale * (textBB.right - textBB.left) / 2; + if(opts.isHeader) deltaX -= TEXTPAD; + + if(offsetDir === 'left') transform.targetX -= deltaX; + else if(offsetDir === 'right') transform.targetX += deltaX; + } + + transform.targetX = viewMapX(transform.targetX); + transform.targetY = viewMapY(transform.targetY); + + if(isNaN(transform.targetX) || isNaN(transform.targetY)) { + return {}; + } + + return { + scale: transform.scale, + rotate: transform.rotate, + textX: transform.textX, + textY: transform.textY, + targetX: transform.targetX, + targetY: transform.targetY + }; + }; + + var interpFromParent = function(pt, onPathbar) { + var parentPrev; + var i = 0; + var Q = pt; + while(!parentPrev && i < maxDepth) { // loop to find a parent/grandParent on the previous graph + i++; + Q = Q.parent; + if(Q) { + parentPrev = getPrev(Q, onPathbar); + } else i = maxDepth; + } + return parentPrev || {}; + }; + + var makeExitSliceInterpolator = function(pt, onPathbar, refRect, size) { + var prev = getPrev(pt, onPathbar); + var next; + + if(onPathbar) { + next = pathbarOrigin; + } else { + var entryPrev = getPrev(entry, onPathbar); + if(entryPrev) { + // 'entryPrev' is here has the previous coordinates of the entry + // node, which corresponds to the last "clicked" node when zooming in + next = findClosestEdge(pt, entryPrev, size); + } else { + // this happens when maxdepth is set, when leaves must + // be removed and the entry is new (i.e. does not have a 'prev' object) + next = {}; + } + } + + return d3.interpolate(prev, next); + }; + + var makeUpdateSliceInterpolator = function(pt, onPathbar, refRect, size) { + var prev0 = getPrev(pt, onPathbar); + var prev; + + if(prev0) { + // if pt already on graph, this is easy + prev = prev0; + } else { + // for new pts: + if(onPathbar) { + prev = pathbarOrigin; + } else { + if(prevEntry) { + // if trace was visible before + if(pt.parent) { + var ref = nextOfPrevEntry || refRect; + + if(ref && !onPathbar) { + prev = findClosestEdge(pt, ref, size); + } else { + // if new leaf (when maxdepth is set), + // grow it from its parent node + prev = {}; + Lib.extendFlat(prev, interpFromParent(pt, onPathbar)); + } + } else { + prev = pt; + } + } else { + prev = {}; + } + } + } + + return d3.interpolate(prev, { + x0: pt.x0, + x1: pt.x1, + y0: pt.y0, + y1: pt.y1 + }); + }; + + var makeUpdateTextInterpolator = function(pt, onPathbar, refRect, size) { + var prev0 = getPrev(pt, onPathbar); + var prev = {}; + var origin = getOrigin(pt, onPathbar, refRect, size); + + Lib.extendFlat(prev, { + transform: toMoveInsideSlice( + origin.x0, + origin.x1, + origin.y0, + origin.y1, + pt.textBB, + { + isHeader: helpers.isHeader(pt, trace) + } + ) + }); + + if(prev0) { + // if pt already on graph, this is easy + prev = prev0; + } else { + // for new pts: + if(pt.parent) { + Lib.extendFlat(prev, interpFromParent(pt, onPathbar)); + } + } + + return d3.interpolate(prev, { + transform: { + scale: pt.transform.scale, + rotate: pt.transform.rotate, + textX: pt.transform.textX, + textY: pt.transform.textY, + targetX: pt.transform.targetX, + targetY: pt.transform.targetY + } + }); + }; + + var handleSlicesExit = function(slices, onPathbar, refRect, size, pathSlice) { + var width = size[0]; + var height = size[1]; + + if(hasTransition) { + slices.exit().transition() + .each(function() { + var sliceTop = d3.select(this); + + var slicePath = sliceTop.select('path.surface'); + slicePath.transition().attrTween('d', function(pt2) { + var interp = makeExitSliceInterpolator(pt2, onPathbar, refRect, [width, height]); + return function(t) { return pathSlice(interp(t)); }; + }); + + var sliceTextGroup = sliceTop.select('g.slicetext'); + sliceTextGroup.attr('opacity', 0); + }) + .remove(); + } else { + slices.exit().remove(); + } + }; + + var strTransform = function(d) { + return Lib.getTextTransform({ + textX: d.transform.textX, + textY: d.transform.textY, + targetX: d.transform.targetX, + targetY: d.transform.targetY, + scale: d.transform.scale, + rotate: d.transform.rotate + }); + }; + + var gTrace = d3.select(element); + var selAncestors = gTrace.selectAll('g.pathbar'); + var selDescendants = gTrace.selectAll('g.slice'); + + if(!entry) { + selAncestors.remove(); + selDescendants.remove(); + return; + } + + if(hasTransition) { + // Important: do this before binding new sliceData! + + selAncestors.each(function(pt) { + prevLookupPathbar[getKey(pt)] = { + x0: pt.x0, + x1: pt.x1, + y0: pt.y0, + y1: pt.y1 + }; + + if(pt.transform) { + prevLookupPathbar[getKey(pt)].transform = { + textX: pt.transform.textX, + textY: pt.transform.textY, + targetX: pt.transform.targetX, + targetY: pt.transform.targetY, + scale: pt.transform.scale, + rotate: pt.transform.rotate + }; + } + }); + + selDescendants.each(function(pt) { + prevLookupSlices[getKey(pt)] = { + x0: pt.x0, + x1: pt.x1, + y0: pt.y0, + y1: pt.y1 + }; + + if(pt.transform) { + prevLookupSlices[getKey(pt)].transform = { + textX: pt.transform.textX, + textY: pt.transform.textY, + targetX: pt.transform.targetX, + targetY: pt.transform.targetY, + scale: pt.transform.scale, + rotate: pt.transform.rotate + }; + } + + if(!prevEntry && helpers.isEntry(pt)) { + prevEntry = pt; + } + }); + } + + nextOfPrevEntry = drawDescendants(gd, cd, entry, selDescendants, { + width: vpw, + height: vph, + + viewX: viewMapX, + viewY: viewMapY, + + pathSlice: pathDescendant, + toMoveInsideSlice: toMoveInsideSlice, + + prevEntry: prevEntry, + makeUpdateSliceInterpolator: makeUpdateSliceInterpolator, + makeUpdateTextInterpolator: makeUpdateTextInterpolator, + + handleSlicesExit: handleSlicesExit, + hasTransition: hasTransition, + strTransform: strTransform + }); + + if(trace.pathbar.visible) { + drawAncestors(gd, cd, entry, selAncestors, { + barDifY: barDifY, + width: barW, + height: barH, + + viewX: viewBarX, + viewY: viewBarY, + + pathSlice: pathAncestor, + toMoveInsideSlice: toMoveInsideSlice, + + makeUpdateSliceInterpolator: makeUpdateSliceInterpolator, + makeUpdateTextInterpolator: makeUpdateTextInterpolator, + + handleSlicesExit: handleSlicesExit, + hasTransition: hasTransition, + strTransform: strTransform + }); + } +} diff --git a/src/traces/treemap/style.js b/src/traces/treemap/style.js new file mode 100644 index 00000000000..cecc78c3c93 --- /dev/null +++ b/src/traces/treemap/style.js @@ -0,0 +1,76 @@ +/** +* Copyright 2012-2019, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var d3 = require('d3'); +var Color = require('../../components/color'); +var Lib = require('../../lib'); +var helpers = require('../sunburst/helpers'); + +function style(gd) { + gd._fullLayout._treemaplayer.selectAll('.trace').each(function(cd) { + var gTrace = d3.select(this); + var cd0 = cd[0]; + var trace = cd0.trace; + + gTrace.style('opacity', trace.opacity); + + gTrace.selectAll('path.surface').each(function(pt) { + d3.select(this).call(styleOne, pt, trace, { + hovered: false + }); + }); + }); +} + +function styleOne(s, pt, trace, opts) { + var hovered = (opts || {}).hovered; + var cdi = pt.data.data; + var ptNumber = cdi.i; + var lineColor; + var lineWidth; + var opacity; + + var depthFade = function(n) { + var base = trace.marker.opacitybase; + var step = trace.marker.opacitystep; + + return n === 0 ? base : + Math.max(0, Math.min(1, n * step)); + }; + + if(hovered) { + lineColor = trace._hovered.marker.line.color; + lineWidth = trace._hovered.marker.line.width; + opacity = trace._hovered.marker.opacity; + } else { + if(helpers.isHierarchyRoot(pt)) { + lineColor = 'rgba(0,0,0,0)'; + lineWidth = 0; + } else { + lineColor = Lib.castOption(trace, ptNumber, 'marker.line.color') || Color.defaultLine; + lineWidth = Lib.castOption(trace, ptNumber, 'marker.line.width') || 0; + } + + opacity = + trace._hasColorscale || helpers.isLeaf(pt) ? 1 : + pt.onPathbar ? trace.pathbar.opacity : + depthFade(pt.data.depth - trace._entryDepth); + } + + s.style('stroke-width', lineWidth) + .call(Color.fill, cdi.color) + .call(Color.stroke, lineColor) + .style('opacity', opacity); +} + +module.exports = { + style: style, + styleOne: styleOne +}; diff --git a/tasks/test_syntax.js b/tasks/test_syntax.js index e3018d5460b..3e77d91e242 100644 --- a/tasks/test_syntax.js +++ b/tasks/test_syntax.js @@ -140,12 +140,15 @@ function assertSrcContents() { } else if(IE_BLACK_LIST.indexOf(lastPart) !== -1) { logs.push(file + ' : contains .' + lastPart + ' (IE failure)'); } else if(IE_SVG_BLACK_LIST.indexOf(lastPart) !== -1) { - // add special case for sunburst where we use 'children' + // add special case for sunburst and treemap where we use 'children' // off the d3-hierarchy output var dirParts = path.dirname(file).split(path.sep); - var isSunburstFile = dirParts[dirParts.length - 1] === 'sunburst'; - var isLinkedToObject = ['pt', 'd', 'parent'].indexOf(parts[parts.length - 2]) !== -1; - if(!(isSunburstFile && isLinkedToObject)) { + var filename = dirParts[dirParts.length - 1]; + var isSunburstOrTreemap = + filename === 'sunburst' || + filename === 'treemap'; + var isLinkedToObject = ['pt', 'd', 'parent', 'node'].indexOf(parts[parts.length - 2]) !== -1; + if(!(isSunburstOrTreemap && isLinkedToObject)) { logs.push(file + ' : contains .' + lastPart + ' (IE failure in SVG)'); } } else if(FF_BLACK_LIST.indexOf(lastPart) !== -1) { diff --git a/test/image/baselines/sunburst_count_branches.png b/test/image/baselines/sunburst_count_branches.png new file mode 100644 index 00000000000..a15651fe553 Binary files /dev/null and b/test/image/baselines/sunburst_count_branches.png differ diff --git a/test/image/baselines/sunburst_first.png b/test/image/baselines/sunburst_first.png index b1ba840f2e8..9e2c4013b62 100644 Binary files a/test/image/baselines/sunburst_first.png and b/test/image/baselines/sunburst_first.png differ diff --git a/test/image/baselines/sunburst_packages_colorscale_novalue.png b/test/image/baselines/sunburst_packages_colorscale_novalue.png new file mode 100644 index 00000000000..02e7bcbbbc7 Binary files /dev/null and b/test/image/baselines/sunburst_packages_colorscale_novalue.png differ diff --git a/test/image/baselines/sunburst_values.png b/test/image/baselines/sunburst_values.png index e3d36289c66..8e7f8b6f8da 100644 Binary files a/test/image/baselines/sunburst_values.png and b/test/image/baselines/sunburst_values.png differ diff --git a/test/image/baselines/sunburst_values_colorscale.png b/test/image/baselines/sunburst_values_colorscale.png new file mode 100644 index 00000000000..94d1e7e69e4 Binary files /dev/null and b/test/image/baselines/sunburst_values_colorscale.png differ diff --git a/test/image/baselines/sunburst_with-without_values.png b/test/image/baselines/sunburst_with-without_values.png new file mode 100644 index 00000000000..80263d41d03 Binary files /dev/null and b/test/image/baselines/sunburst_with-without_values.png differ diff --git a/test/image/baselines/treemap_coffee-maxdepth3.png b/test/image/baselines/treemap_coffee-maxdepth3.png new file mode 100644 index 00000000000..7a3c014df04 Binary files /dev/null and b/test/image/baselines/treemap_coffee-maxdepth3.png differ diff --git a/test/image/baselines/treemap_coffee.png b/test/image/baselines/treemap_coffee.png new file mode 100644 index 00000000000..f6c02683aca Binary files /dev/null and b/test/image/baselines/treemap_coffee.png differ diff --git a/test/image/baselines/treemap_first.png b/test/image/baselines/treemap_first.png new file mode 100644 index 00000000000..e1a0a76d836 Binary files /dev/null and b/test/image/baselines/treemap_first.png differ diff --git a/test/image/baselines/treemap_flare.png b/test/image/baselines/treemap_flare.png new file mode 100644 index 00000000000..6522ebaf127 Binary files /dev/null and b/test/image/baselines/treemap_flare.png differ diff --git a/test/image/baselines/treemap_level-depth.png b/test/image/baselines/treemap_level-depth.png new file mode 100644 index 00000000000..a254f815c17 Binary files /dev/null and b/test/image/baselines/treemap_level-depth.png differ diff --git a/test/image/baselines/treemap_packages_colorscale_allone.png b/test/image/baselines/treemap_packages_colorscale_allone.png new file mode 100644 index 00000000000..46daa70c4ea Binary files /dev/null and b/test/image/baselines/treemap_packages_colorscale_allone.png differ diff --git a/test/image/baselines/treemap_packages_colorscale_novalue.png b/test/image/baselines/treemap_packages_colorscale_novalue.png new file mode 100644 index 00000000000..28261b046df Binary files /dev/null and b/test/image/baselines/treemap_packages_colorscale_novalue.png differ diff --git a/test/image/baselines/treemap_packings.png b/test/image/baselines/treemap_packings.png new file mode 100644 index 00000000000..4664a239293 Binary files /dev/null and b/test/image/baselines/treemap_packings.png differ diff --git a/test/image/baselines/treemap_pad_mirror.png b/test/image/baselines/treemap_pad_mirror.png new file mode 100644 index 00000000000..e7ff59336e6 Binary files /dev/null and b/test/image/baselines/treemap_pad_mirror.png differ diff --git a/test/image/baselines/treemap_pad_transpose.png b/test/image/baselines/treemap_pad_transpose.png new file mode 100644 index 00000000000..b07265c6bc9 Binary files /dev/null and b/test/image/baselines/treemap_pad_transpose.png differ diff --git a/test/image/baselines/treemap_textfit.png b/test/image/baselines/treemap_textfit.png new file mode 100644 index 00000000000..a56cbff85f3 Binary files /dev/null and b/test/image/baselines/treemap_textfit.png differ diff --git a/test/image/baselines/treemap_textposition.png b/test/image/baselines/treemap_textposition.png new file mode 100644 index 00000000000..7ecbc57290f Binary files /dev/null and b/test/image/baselines/treemap_textposition.png differ diff --git a/test/image/baselines/treemap_transpose_nopad.png b/test/image/baselines/treemap_transpose_nopad.png new file mode 100644 index 00000000000..43b9ef13a96 Binary files /dev/null and b/test/image/baselines/treemap_transpose_nopad.png differ diff --git a/test/image/baselines/treemap_values.png b/test/image/baselines/treemap_values.png new file mode 100644 index 00000000000..00dd12be445 Binary files /dev/null and b/test/image/baselines/treemap_values.png differ diff --git a/test/image/baselines/treemap_values_colorscale.png b/test/image/baselines/treemap_values_colorscale.png new file mode 100644 index 00000000000..f89fb5b7fef Binary files /dev/null and b/test/image/baselines/treemap_values_colorscale.png differ diff --git a/test/image/baselines/treemap_with-without_values.png b/test/image/baselines/treemap_with-without_values.png new file mode 100644 index 00000000000..2aaeeba3c73 Binary files /dev/null and b/test/image/baselines/treemap_with-without_values.png differ diff --git a/test/image/baselines/treemap_with-without_values_template.png b/test/image/baselines/treemap_with-without_values_template.png new file mode 100644 index 00000000000..e0552a8717a Binary files /dev/null and b/test/image/baselines/treemap_with-without_values_template.png differ diff --git a/test/image/mocks/sunburst_count_branches.json b/test/image/mocks/sunburst_count_branches.json new file mode 100644 index 00000000000..f4566094ae3 --- /dev/null +++ b/test/image/mocks/sunburst_count_branches.json @@ -0,0 +1,78 @@ +{ + "data": [ + { + "type": "sunburst", + "count": "leaves+branches", + "textinfo": "label+percent parent", + "marker": { + "line": { + "color": "#777" + }, + "colorscale": "Blackbody", + "reversescale": true, + "showscale": true + }, + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ] + } + ], + "layout": { + "width": 800, + "height": 800 + } +} diff --git a/test/image/mocks/sunburst_first.json b/test/image/mocks/sunburst_first.json index 3e5d343c1e0..984de005d9c 100644 --- a/test/image/mocks/sunburst_first.json +++ b/test/image/mocks/sunburst_first.json @@ -2,18 +2,37 @@ "data": [ { "type": "sunburst", + "textinfo": "label+percent parent", "labels": ["Eve", "Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"], "parents": ["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve" ], "domain": {"x": [0, 0.5]} }, { "type": "sunburst", + "textinfo": "label+percent root", "labels": ["Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"], "parents": ["Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve" ], "domain": {"x": [0.5, 1]} } ], "layout": { - + "annotations": [ + { + "showarrow": false, + "text": "percent parent", + "x": 0.25, + "xanchor": "center", + "y": 1, + "yanchor": "bottom" + }, + { + "showarrow": false, + "text": "percent root", + "x": 0.75, + "xanchor": "center", + "y": 1, + "yanchor": "bottom" + } + ] } } diff --git a/test/image/mocks/sunburst_flare.json b/test/image/mocks/sunburst_flare.json index a1429b53aa3..5c396c75132 100644 --- a/test/image/mocks/sunburst_flare.json +++ b/test/image/mocks/sunburst_flare.json @@ -2,6 +2,7 @@ "data": [ { "type": "sunburst", + "hoverinfo": "all", "ids": [ "flare", "flare-analytics", diff --git a/test/image/mocks/sunburst_packages_colorscale_novalue.json b/test/image/mocks/sunburst_packages_colorscale_novalue.json new file mode 100644 index 00000000000..f80181f786f --- /dev/null +++ b/test/image/mocks/sunburst_packages_colorscale_novalue.json @@ -0,0 +1,2328 @@ +{ + "data": [ + { + "type": "sunburst", + "maxdepth": 2, + "textinfo": "label+percent parent", + "marker": { + "line": { + "color": "#777" + }, + "colorscale": [[0, "#FFF"], [0.01, "#FF0"], [0.1, "#F00"], [1, "#000"]], + "showscale": true + }, + "ids": [ + "Plotly.js v1.46.x external module counter", + "1. @plotly/d3-sankey", + "1. alpha-shape", + "1. array-range", + "1. canvas-fit", + "1. color-normalize", + "1. convex-hull", + "1. country-regex", + "1. d3", + "1. d3-force", + "1. d3-hierarchy", + "1. d3-interpolate", + "1. d3-sankey-circular", + "1. delaunay-triangulate", + "1. es6-promise", + "1. fast-isnumeric", + "1. font-atlas-sdf", + "1. gl-cone3d", + "1. gl-contour2d", + "1. gl-error3d", + "1. gl-heatmap2d", + "1. gl-line3d", + "1. gl-mat4", + "1. gl-mesh3d", + "1. gl-plot2d", + "1. gl-plot3d", + "1. gl-pointcloud2d", + "1. gl-scatter3d", + "1. gl-select-box", + "1. gl-spikes2d", + "1. gl-streamtube3d", + "1. gl-surface3d", + "1. gl-text", + "1. glslify", + "1. has-hover", + "1. has-passive-events", + "1. mapbox-gl", + "1. matrix-camera-controller", + "1. mouse-change", + "1. mouse-event-offset", + "1. mouse-wheel", + "1. ndarray", + "1. ndarray-fill", + "1. ndarray-homography", + "1. point-cluster", + "1. polybooljs", + "1. regl", + "1. regl-error2d", + "1. regl-line2d", + "1. regl-scatter2d", + "1. regl-splom", + "1. right-now", + "1. robust-orientation", + "1. sane-topojson", + "1. strongly-connected-components", + "1. superscript-text", + "1. svg-path-sdf", + "1. tinycolor2", + "1. topojson-client", + "1. webgl-context", + "1. world-calendars", + "2. 3d-view", + "2. @mapbox/gl-matrix", + "2. @mapbox/jsonlint-lines-primitives", + "2. @mapbox/mapbox-gl-supported", + "2. @mapbox/point-geometry", + "2. @mapbox/shelf-pack", + "2. @mapbox/tiny-sdf", + "2. @mapbox/unitbezier", + "2. @mapbox/vector-tile", + "2. @mapbox/whoots-js", + "2. a-big-triangle", + "2. affine-hull", + "2. alpha-complex", + "2. array-bounds", + "2. array-normalize", + "2. array-range", + "2. array-rearrange", + "2. barycentric", + "2. binary-search-bounds", + "2. bit-twiddle", + "2. bitmap-sdf", + "2. bl", + "2. brfs", + "2. bubleify", + "2. cdt2d", + "2. clamp", + "2. clean-pslg", + "2. color-alpha", + "2. color-id", + "2. color-normalize", + "2. color-rgba", + "2. colormap", + "2. commander", + "2. concat-stream", + "2. css-font", + "2. csscolorparser", + "2. cwise", + "2. d3-array", + "2. d3-collection", + "2. d3-color", + "2. d3-dispatch", + "2. d3-quadtree", + "2. d3-shape", + "2. d3-timer", + "2. defined", + "2. detect-kerning", + "2. draw-svg-path", + "2. dtype", + "2. dup", + "2. duplexify", + "2. earcut", + "2. element-size", + "2. elementary-circuits-directed-graph", + "2. es6-weak-map", + "2. falafel", + "2. flatten-vertex-data", + "2. font-atlas", + "2. font-measure", + "2. from2", + "2. geojson-rewind", + "2. geojson-vt", + "2. get-canvas-context", + "2. gl-axes3d", + "2. gl-buffer", + "2. gl-fbo", + "2. gl-mat4", + "2. gl-matrix-invert", + "2. gl-select-static", + "2. gl-shader", + "2. gl-spikes3d", + "2. gl-texture2d", + "2. gl-util", + "2. gl-vao", + "2. gl-vec3", + "2. glsl-inverse", + "2. glsl-out-of-range", + "2. glsl-read-float", + "2. glsl-resolve", + "2. glsl-specular-beckmann", + "2. glsl-specular-cook-torrance", + "2. glsl-token-whitespace-trim", + "2. glslify", + "2. glslify-bundle", + "2. glslify-deps", + "2. gray-matter", + "2. grid-index", + "2. has-passive-events", + "2. image-palette", + "2. incremental-convex-hull", + "2. iota-array", + "2. is-browser", + "2. is-buffer", + "2. is-iexplorer", + "2. is-mobile", + "2. is-obj", + "2. is-plain-obj", + "2. is-string-blank", + "2. is-svg-path", + "2. left-pad", + "2. mat4-interpolate", + "2. math-log2", + "2. minimist", + "2. monotone-convex-hull-2d", + "2. mouse-change", + "2. mouse-event", + "2. mouse-event-offset", + "2. mouse-wheel", + "2. ndarray", + "2. ndarray-gradient", + "2. ndarray-ops", + "2. ndarray-pack", + "2. ndarray-scratch", + "2. ndarray-warp", + "2. normals", + "2. object-assign", + "2. optical-properties", + "2. parse-rect", + "2. parse-svg-path", + "2. parse-unit", + "2. pbf", + "2. pick-by-alias", + "2. point-cluster", + "2. polytope-closest-point", + "2. quickselect", + "2. raf", + "2. regl", + "2. regl-scatter2d", + "2. resolve", + "2. right-now", + "2. robust-scale", + "2. robust-subtract", + "2. robust-sum", + "2. rw", + "2. shuffle-seed", + "2. signum", + "2. simplicial-complex-boundary", + "2. simplicial-complex-contour", + "2. sort-object", + "2. stack-trace", + "2. static-eval", + "2. supercluster", + "2. surface-nets", + "2. svg-path-bounds", + "2. text-cache", + "2. through2", + "2. tiny-sdf", + "2. tinyqueue", + "2. to-float32", + "2. to-px", + "2. two-product", + "2. typedarray-pool", + "2. uniq", + "2. update-diff", + "2. vectorize-text", + "2. vt-pbf", + "2. xtend", + "3. @choojs/findup", + "3. @mapbox/geojson-area", + "3. @mapbox/point-geometry", + "3. @mapbox/vector-tile", + "3. abs-svg-path", + "3. acorn", + "3. array-bounds", + "3. big-rat", + "3. binary-search-bounds", + "3. bit-twiddle", + "3. boundary-cells", + "3. box-intersect", + "3. buble", + "3. buffer-from", + "3. cdt2d", + "3. circumradius", + "3. clamp", + "3. clean-pslg", + "3. color-id", + "3. color-parse", + "3. color-space", + "3. concat-stream", + "3. css-font", + "3. css-font-size-keywords", + "3. css-font-stretch-keywords", + "3. css-font-style-keywords", + "3. css-font-weight-keywords", + "3. css-global-keywords", + "3. css-system-font-keywords", + "3. cwise", + "3. cwise-compiler", + "3. cwise-parser", + "3. d", + "3. d3-path", + "3. delaunay-triangulate", + "3. dtype", + "3. dup", + "3. end-of-stream", + "3. es5-ext", + "3. es6-iterator", + "3. es6-symbol", + "3. es6-weak-map", + "3. escodegen", + "3. events", + "3. extend-shallow", + "3. extract-frustum-planes", + "3. foreach", + "3. gl-buffer", + "3. gl-fbo", + "3. gl-format-compiler-error", + "3. gl-mat2", + "3. gl-mat3", + "3. gl-mat4", + "3. gl-shader", + "3. gl-state", + "3. gl-texture2d", + "3. gl-vao", + "3. gl-vec3", + "3. gl-vec4", + "3. glsl-inject-defines", + "3. glsl-resolve", + "3. glsl-specular-beckmann", + "3. glsl-token-defines", + "3. glsl-token-depth", + "3. glsl-token-descope", + "3. glsl-token-scope", + "3. glsl-token-string", + "3. glsl-token-whitespace-trim", + "3. glsl-tokenizer", + "3. glslify", + "3. graceful-fs", + "3. ieee754", + "3. inherits", + "3. is-browser", + "3. is-firefox", + "3. is-plain-obj", + "3. is-svg-path", + "3. isarray", + "3. js-yaml", + "3. kdbush", + "3. kind-of", + "3. lerp", + "3. map-limit", + "3. marching-simplex-table", + "3. mat4-decompose", + "3. mat4-recompose", + "3. matrix-camera-controller", + "3. minimist", + "3. murmurhash-js", + "3. ndarray", + "3. ndarray-extract-contour", + "3. ndarray-linear-interpolate", + "3. ndarray-ops", + "3. ndarray-sort", + "3. nextafter", + "3. normalize-svg-path", + "3. number-is-integer", + "3. numeric", + "3. object-assign", + "3. object-keys", + "3. orbit-camera-controller", + "3. parse-svg-path", + "3. parse-unit", + "3. path-parse", + "3. pbf", + "3. performance-now", + "3. pick-by-alias", + "3. planar-graph-to-polyline", + "3. pxls", + "3. quantize", + "3. quat-slerp", + "3. quote-stream", + "3. rat-vec", + "3. readable-stream", + "3. reduce-simplicial-complex", + "3. resolve", + "3. resolve-protobuf-schema", + "3. robust-in-sphere", + "3. robust-linear-solve", + "3. robust-orientation", + "3. robust-segment-intersect", + "3. safe-buffer", + "3. seedrandom", + "3. shallow-copy", + "3. sharkdown", + "3. simplicial-complex", + "3. simplify-planar-graph", + "3. sort-asc", + "3. sort-desc", + "3. split-polygon", + "3. static-module", + "3. stream-shift", + "3. string-split-by", + "3. strip-bom-string", + "3. strongly-connected-components", + "3. surface-nets", + "3. through2", + "3. triangulate-hypercube", + "3. triangulate-polyline", + "3. turntable-camera-controller", + "3. two-product", + "3. two-sum", + "3. typedarray", + "3. typedarray-pool", + "3. uglify-js", + "3. union-find", + "3. uniq", + "3. unquote", + "3. vectorize-text", + "3. weak-map", + "3. weakmap-shim", + "3. xtend", + "3. zero-crossings", + "4. acorn", + "4. acorn-dynamic-import", + "4. acorn-jsx", + "4. add-line-numbers", + "4. argparse", + "4. arr-flatten", + "4. big-rat", + "4. bit-twiddle", + "4. bn.js", + "4. buffer-equal", + "4. cardinal", + "4. cdt2d", + "4. cell-orientation", + "4. chalk", + "4. circumcenter", + "4. color-name", + "4. commander", + "4. compare-cell", + "4. compare-oriented-cell", + "4. compute-dims", + "4. concat-stream", + "4. convert-source-map", + "4. convex-hull", + "4. core-util-is", + "4. cwise-compiler", + "4. d", + "4. defined", + "4. double-bits", + "4. duplexer2", + "4. edges-to-adjacency-list", + "4. es5-ext", + "4. es6-iterator", + "4. es6-symbol", + "4. escodegen", + "4. esprima", + "4. estraverse", + "4. esutils", + "4. expect.js", + "4. falafel", + "4. filtered-vector", + "4. flip-pixels", + "4. gamma", + "4. gl-constants", + "4. gl-mat4", + "4. gl-quat", + "4. gl-vec3", + "4. glsl-shader-name", + "4. glsl-token-assignments", + "4. glsl-token-depth", + "4. glsl-token-inject-block", + "4. glsl-token-properties", + "4. glsl-token-scope", + "4. glsl-token-string", + "4. glsl-tokenizer", + "4. has", + "4. hsluv", + "4. inherits", + "4. is-browser", + "4. is-buffer", + "4. is-extendable", + "4. is-finite", + "4. is-plain-obj", + "4. isarray", + "4. magic-string", + "4. merge-source-map", + "4. minimist", + "4. mumath", + "4. next-tick", + "4. object-inspect", + "4. once", + "4. optionator", + "4. os-homedir", + "4. parenthesis", + "4. permutation-parity", + "4. permutation-rank", + "4. planar-dual", + "4. point-in-big-polygon", + "4. process-nextick-args", + "4. protocol-buffers-schema", + "4. quote-stream", + "4. readable-stream", + "4. robust-determinant", + "4. robust-dot-product", + "4. robust-orientation", + "4. robust-scale", + "4. robust-subtract", + "4. robust-sum", + "4. safe-buffer", + "4. shallow-copy", + "4. simplicial-complex", + "4. source-map", + "4. split", + "4. sprintf-js", + "4. static-eval", + "4. stream-spigot", + "4. string_decoder", + "4. svg-arc-to-cubic-bezier", + "4. tape", + "4. through", + "4. through2", + "4. to-uint8", + "4. two-product", + "4. typedarray-pool", + "4. uglify-to-browserify", + "4. union-find", + "4. uniq", + "4. util-deprecate", + "4. vlq", + "4. wgs84", + "4. yargs", + "5. acorn", + "5. almost-equal", + "5. ansi-styles", + "5. ansicolors", + "5. arr-flatten", + "5. atob-lite", + "5. binary-search-bounds", + "5. bit-twiddle", + "5. camelcase", + "5. cell-orientation", + "5. clamp", + "5. cliui", + "5. compare-angle", + "5. compare-cell", + "5. core-util-is", + "5. cubic-hermite", + "5. decamelize", + "5. deep-equal", + "5. deep-is", + "5. defined", + "5. dup", + "5. escape-string-regexp", + "5. escodegen", + "5. esprima", + "5. estraverse", + "5. esutils", + "5. fast-levenshtein", + "5. for-each", + "5. function-bind", + "5. gl-mat3", + "5. gl-vec3", + "5. gl-vec4", + "5. glob", + "5. glsl-tokenizer", + "5. has", + "5. inherits", + "5. interval-tree-1d", + "5. invert-permutation", + "5. is-base64", + "5. is-float-array", + "5. isarray", + "5. levn", + "5. minimist", + "5. number-is-nan", + "5. object-inspect", + "5. optionator", + "5. pad-left", + "5. prelude-ls", + "5. readable-stream", + "5. redeyed", + "5. resolve", + "5. resumer", + "5. robust-compress", + "5. robust-linear-solve", + "5. robust-orientation", + "5. robust-scale", + "5. robust-sum", + "5. safe-buffer", + "5. slab-decomposition", + "5. source-map", + "5. sprintf-js", + "5. string.prototype.trim", + "5. string_decoder", + "5. supports-color", + "5. through", + "5. through2", + "5. to-array-buffer", + "5. two-product", + "5. type-check", + "5. typedarray-pool", + "5. union-find", + "5. uniq", + "5. utils-copy", + "5. validate.io-array", + "5. validate.io-matrix-like", + "5. validate.io-ndarray-like", + "5. validate.io-positive-integer", + "5. vlq", + "5. window-size", + "5. wordwrap", + "5. wrappy", + "5. xtend", + "6. amdefine", + "6. binary-search-bounds", + "6. center-align", + "6. color-convert", + "6. const-pinf-float64", + "6. core-util-is", + "6. define-properties", + "6. es-abstract", + "6. esprima", + "6. estraverse", + "6. flatten-vertex-data", + "6. fs.realpath", + "6. function-bind", + "6. functional-red-black-tree", + "6. has-flag", + "6. inflight", + "6. inherits", + "6. is-blob", + "6. is-callable", + "6. isarray", + "6. minimatch", + "6. object-keys", + "6. once", + "6. path-is-absolute", + "6. prelude-ls", + "6. readable-stream", + "6. repeat-string", + "6. right-align", + "6. robust-orientation", + "6. robust-product", + "6. robust-sum", + "6. signum", + "6. source-map", + "6. string-to-arraybuffer", + "6. string_decoder", + "6. through", + "6. two-sum", + "6. type-check", + "6. type-name", + "6. utils-copy-error", + "6. utils-indexof", + "6. utils-regex-from-string", + "6. validate.io-array", + "6. validate.io-buffer", + "6. validate.io-integer", + "6. validate.io-nonnegative-integer", + "6. wordwrap", + "6. xtend" + ], + "parents": [ + "", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "1. @plotly/d3-sankey", + "1. @plotly/d3-sankey", + "1. @plotly/d3-sankey", + "1. alpha-shape", + "1. alpha-shape", + "1. canvas-fit", + "1. color-normalize", + "1. color-normalize", + "1. color-normalize", + "1. convex-hull", + "1. convex-hull", + "1. convex-hull", + "1. d3-force", + "1. d3-force", + "1. d3-force", + "1. d3-force", + "1. d3-interpolate", + "1. d3-sankey-circular", + "1. d3-sankey-circular", + "1. d3-sankey-circular", + "1. d3-sankey-circular", + "1. delaunay-triangulate", + "1. delaunay-triangulate", + "1. fast-isnumeric", + "1. font-atlas-sdf", + "1. font-atlas-sdf", + "1. gl-cone3d", + "1. gl-cone3d", + "1. gl-cone3d", + "1. gl-cone3d", + "1. gl-cone3d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-error3d", + "1. gl-error3d", + "1. gl-error3d", + "1. gl-error3d", + "1. gl-error3d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-pointcloud2d", + "1. gl-pointcloud2d", + "1. gl-pointcloud2d", + "1. gl-pointcloud2d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-select-box", + "1. gl-select-box", + "1. gl-select-box", + "1. gl-streamtube3d", + "1. gl-streamtube3d", + "1. gl-streamtube3d", + "1. gl-streamtube3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. has-hover", + "1. has-passive-events", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. matrix-camera-controller", + "1. matrix-camera-controller", + "1. matrix-camera-controller", + "1. matrix-camera-controller", + "1. mouse-change", + "1. mouse-wheel", + "1. mouse-wheel", + "1. mouse-wheel", + "1. ndarray", + "1. ndarray", + "1. ndarray-fill", + "1. ndarray-homography", + "1. ndarray-homography", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. robust-orientation", + "1. robust-orientation", + "1. robust-orientation", + "1. robust-orientation", + "1. svg-path-sdf", + "1. svg-path-sdf", + "1. svg-path-sdf", + "1. svg-path-sdf", + "1. svg-path-sdf", + "1. topojson-client", + "1. webgl-context", + "1. world-calendars", + "2. d3-shape", + "2. alpha-complex", + "2. alpha-complex", + "2. simplicial-complex-boundary", + "2. simplicial-complex-boundary", + "2. color-rgba", + "2. color-rgba", + "2. color-rgba", + "2. affine-hull", + "2. incremental-convex-hull", + "2. incremental-convex-hull", + "2. monotone-convex-hull-2d", + "2. elementary-circuits-directed-graph", + "2. gl-shader", + "2. gl-shader", + "2. cdt2d", + "2. cdt2d", + "2. cdt2d", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. gl-buffer", + "2. gl-buffer", + "2. gl-buffer", + "2. surface-nets", + "2. surface-nets", + "2. surface-nets", + "2. typedarray-pool", + "2. typedarray-pool", + "2. gl-texture2d", + "2. gl-texture2d", + "2. gl-texture2d", + "2. barycentric", + "2. colormap", + "2. glsl-specular-cook-torrance", + "2. polytope-closest-point", + "2. simplicial-complex-contour", + "2. simplicial-complex-contour", + "2. simplicial-complex-contour", + "2. simplicial-complex-contour", + "2. gl-select-static", + "2. gl-select-static", + "2. gl-select-static", + "2. gl-select-static", + "2. gl-select-static", + "2. text-cache", + "2. 3d-view", + "2. 3d-view", + "2. 3d-view", + "2. a-big-triangle", + "2. a-big-triangle", + "2. a-big-triangle", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-fbo", + "2. gl-spikes3d", + "2. gl-spikes3d", + "2. gl-spikes3d", + "2. gl-spikes3d", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. ndarray-gradient", + "2. ndarray-gradient", + "2. ndarray-ops", + "2. ndarray-pack", + "2. ndarray-pack", + "2. ndarray-scratch", + "2. ndarray-scratch", + "2. ndarray-scratch", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. es6-weak-map", + "2. es6-weak-map", + "2. es6-weak-map", + "2. es6-weak-map", + "2. flatten-vertex-data", + "2. font-atlas", + "2. font-measure", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. parse-rect", + "2. to-px", + "2. bl", + "2. bl", + "2. concat-stream", + "2. concat-stream", + "2. concat-stream", + "2. concat-stream", + "2. duplexify", + "2. duplexify", + "2. duplexify", + "2. duplexify", + "2. falafel", + "2. falafel", + "2. falafel", + "2. falafel", + "2. from2", + "2. from2", + "2. glsl-resolve", + "2. glsl-resolve", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. through2", + "2. through2", + "2. resolve", + "2. static-eval", + "2. @mapbox/vector-tile", + "2. geojson-rewind", + "2. geojson-rewind", + "2. geojson-rewind", + "2. geojson-rewind", + "2. gray-matter", + "2. gray-matter", + "2. gray-matter", + "2. gray-matter", + "2. brfs", + "2. brfs", + "2. brfs", + "2. brfs", + "2. through2", + "2. through2", + "2. pbf", + "2. pbf", + "2. shuffle-seed", + "2. sort-object", + "2. sort-object", + "2. supercluster", + "2. vt-pbf", + "2. vt-pbf", + "2. vt-pbf", + "2. mat4-interpolate", + "2. mat4-interpolate", + "2. mat4-interpolate", + "2. mat4-interpolate", + "2. mat4-interpolate", + "2. cwise", + "2. cwise", + "2. cwise", + "2. cwise", + "2. gl-matrix-invert", + "2. gl-matrix-invert", + "2. gl-matrix-invert", + "2. ndarray-warp", + "2. ndarray-warp", + "2. array-normalize", + "2. bubleify", + "2. color-id", + "2. image-palette", + "2. image-palette", + "2. image-palette", + "2. color-alpha", + "2. raf", + "2. robust-scale", + "2. robust-scale", + "2. bitmap-sdf", + "2. draw-svg-path", + "2. draw-svg-path", + "2. svg-path-bounds", + "2. svg-path-bounds", + "2. svg-path-bounds", + "2. svg-path-bounds", + "3. circumradius", + "3. boundary-cells", + "3. reduce-simplicial-complex", + "3. reduce-simplicial-complex", + "3. reduce-simplicial-complex", + "3. color-parse", + "3. color-parse", + "3. color-parse", + "3. color-space", + "3. color-space", + "3. simplicial-complex", + "3. simplicial-complex", + "3. gl-format-compiler-error", + "3. gl-format-compiler-error", + "3. gl-format-compiler-error", + "3. gl-format-compiler-error", + "3. robust-in-sphere", + "3. robust-in-sphere", + "3. robust-in-sphere", + "3. robust-in-sphere", + "3. big-rat", + "3. big-rat", + "3. big-rat", + "3. box-intersect", + "3. box-intersect", + "3. nextafter", + "3. rat-vec", + "3. robust-segment-intersect", + "3. ndarray-extract-contour", + "3. triangulate-hypercube", + "3. triangulate-hypercube", + "3. triangulate-hypercube", + "3. zero-crossings", + "3. robust-linear-solve", + "3. marching-simplex-table", + "3. ndarray-sort", + "3. orbit-camera-controller", + "3. orbit-camera-controller", + "3. turntable-camera-controller", + "3. turntable-camera-controller", + "3. turntable-camera-controller", + "3. gl-state", + "3. split-polygon", + "3. split-polygon", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. simplify-planar-graph", + "3. simplify-planar-graph", + "3. triangulate-polyline", + "3. cwise-compiler", + "3. string-split-by", + "3. d", + "3. es5-ext", + "3. es5-ext", + "3. es5-ext", + "3. es6-iterator", + "3. es6-iterator", + "3. es6-iterator", + "3. es6-symbol", + "3. es6-symbol", + "3. number-is-integer", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. end-of-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. glsl-inject-defines", + "3. glsl-inject-defines", + "3. glsl-inject-defines", + "3. glsl-token-defines", + "3. glsl-token-descope", + "3. glsl-token-descope", + "3. glsl-token-descope", + "3. glsl-token-descope", + "3. glsl-tokenizer", + "3. @choojs/findup", + "3. map-limit", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. escodegen", + "3. escodegen", + "3. escodegen", + "3. escodegen", + "3. escodegen", + "3. @mapbox/geojson-area", + "3. sharkdown", + "3. sharkdown", + "3. sharkdown", + "3. sharkdown", + "3. sharkdown", + "3. sharkdown", + "3. extend-shallow", + "3. js-yaml", + "3. js-yaml", + "3. quote-stream", + "3. quote-stream", + "3. quote-stream", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. resolve-protobuf-schema", + "3. mat4-decompose", + "3. mat4-decompose", + "3. mat4-recompose", + "3. quat-slerp", + "3. cwise-parser", + "3. cwise-parser", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. uglify-js", + "3. uglify-js", + "3. uglify-js", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. pxls", + "3. pxls", + "3. pxls", + "3. pxls", + "3. pxls", + "3. pxls", + "3. normalize-svg-path", + "4. circumcenter", + "4. circumcenter", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. compare-oriented-cell", + "4. compare-oriented-cell", + "4. mumath", + "4. add-line-numbers", + "4. glsl-shader-name", + "4. glsl-shader-name", + "4. permutation-parity", + "4. permutation-rank", + "4. permutation-rank", + "4. robust-determinant", + "4. robust-determinant", + "4. robust-determinant", + "4. robust-determinant", + "4. filtered-vector", + "4. filtered-vector", + "4. robust-dot-product", + "4. robust-dot-product", + "4. edges-to-adjacency-list", + "4. planar-dual", + "4. planar-dual", + "4. point-in-big-polygon", + "4. point-in-big-polygon", + "4. point-in-big-polygon", + "4. point-in-big-polygon", + "4. simplicial-complex", + "4. simplicial-complex", + "4. is-finite", + "4. string_decoder", + "4. string_decoder", + "4. string_decoder", + "4. once", + "4. string_decoder", + "4. through2", + "4. through2", + "4. once", + "4. string_decoder", + "4. optionator", + "4. optionator", + "4. optionator", + "4. optionator", + "4. optionator", + "4. optionator", + "4. cardinal", + "4. cardinal", + "4. split", + "4. stream-spigot", + "4. argparse", + "4. has", + "4. magic-string", + "4. duplexer2", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. merge-source-map", + "4. string_decoder", + "4. gl-quat", + "4. gl-quat", + "4. gl-quat", + "4. duplexer2", + "4. quote-stream", + "4. quote-stream", + "4. readable-stream", + "4. readable-stream", + "4. readable-stream", + "4. readable-stream", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. static-eval", + "4. through2", + "4. through2", + "4. yargs", + "4. yargs", + "4. yargs", + "4. yargs", + "4. acorn-dynamic-import", + "4. acorn-jsx", + "4. chalk", + "4. chalk", + "4. chalk", + "4. compute-dims", + "4. compute-dims", + "4. compute-dims", + "4. compute-dims", + "4. compute-dims", + "4. to-uint8", + "4. to-uint8", + "4. to-uint8", + "4. to-uint8", + "4. to-uint8" + ], + "labels": [ + "Plotly.js v1.46.x external module counter", + "1. @plotly/d3-sankey", + "1. alpha-shape", + "1. array-range", + "1. canvas-fit", + "1. color-normalize", + "1. convex-hull", + "1. country-regex", + "1. d3", + "1. d3-force", + "1. d3-hierarchy", + "1. d3-interpolate", + "1. d3-sankey-circular", + "1. delaunay-triangulate", + "1. es6-promise", + "1. fast-isnumeric", + "1. font-atlas-sdf", + "1. gl-cone3d", + "1. gl-contour2d", + "1. gl-error3d", + "1. gl-heatmap2d", + "1. gl-line3d", + "1. gl-mat4", + "1. gl-mesh3d", + "1. gl-plot2d", + "1. gl-plot3d", + "1. gl-pointcloud2d", + "1. gl-scatter3d", + "1. gl-select-box", + "1. gl-spikes2d", + "1. gl-streamtube3d", + "1. gl-surface3d", + "1. gl-text", + "1. glslify", + "1. has-hover", + "1. has-passive-events", + "1. mapbox-gl", + "1. matrix-camera-controller", + "1. mouse-change", + "1. mouse-event-offset", + "1. mouse-wheel", + "1. ndarray", + "1. ndarray-fill", + "1. ndarray-homography", + "1. point-cluster", + "1. polybooljs", + "1. regl", + "1. regl-error2d", + "1. regl-line2d", + "1. regl-scatter2d", + "1. regl-splom", + "1. right-now", + "1. robust-orientation", + "1. sane-topojson", + "1. strongly-connected-components", + "1. superscript-text", + "1. svg-path-sdf", + "1. tinycolor2", + "1. topojson-client", + "1. webgl-context", + "1. world-calendars", + "2. d3-array", + "2. d3-collection", + "2. d3-shape", + "2. alpha-complex", + "2. simplicial-complex-boundary", + "2. element-size", + "2. clamp", + "2. color-rgba", + "2. dtype", + "2. affine-hull", + "2. incremental-convex-hull", + "2. monotone-convex-hull-2d", + "2. d3-collection", + "2. d3-dispatch", + "2. d3-quadtree", + "2. d3-timer", + "2. d3-color", + "2. d3-array", + "2. d3-collection", + "2. d3-shape", + "2. elementary-circuits-directed-graph", + "2. incremental-convex-hull", + "2. uniq", + "2. is-string-blank", + "2. optical-properties", + "2. tiny-sdf", + "2. gl-shader", + "2. gl-vec3", + "2. glsl-inverse", + "2. glsl-out-of-range", + "2. glslify", + "2. cdt2d", + "2. clean-pslg", + "2. gl-buffer", + "2. binary-search-bounds", + "2. gl-shader", + "2. glslify", + "2. iota-array", + "2. ndarray", + "2. surface-nets", + "2. gl-buffer", + "2. gl-shader", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glslify", + "2. gl-buffer", + "2. binary-search-bounds", + "2. gl-shader", + "2. glslify", + "2. iota-array", + "2. typedarray-pool", + "2. gl-buffer", + "2. binary-search-bounds", + "2. gl-shader", + "2. gl-texture2d", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glsl-read-float", + "2. glslify", + "2. ndarray", + "2. barycentric", + "2. colormap", + "2. gl-buffer", + "2. gl-mat4", + "2. gl-shader", + "2. gl-texture2d", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glsl-specular-cook-torrance", + "2. glslify", + "2. ndarray", + "2. normals", + "2. polytope-closest-point", + "2. simplicial-complex-contour", + "2. typedarray-pool", + "2. gl-buffer", + "2. binary-search-bounds", + "2. gl-select-static", + "2. gl-shader", + "2. glsl-inverse", + "2. glslify", + "2. text-cache", + "2. 3d-view", + "2. a-big-triangle", + "2. gl-axes3d", + "2. gl-fbo", + "2. gl-mat4", + "2. gl-select-static", + "2. gl-shader", + "2. gl-spikes3d", + "2. glslify", + "2. has-passive-events", + "2. is-mobile", + "2. mouse-change", + "2. mouse-event-offset", + "2. mouse-wheel", + "2. ndarray", + "2. right-now", + "2. gl-buffer", + "2. gl-shader", + "2. glslify", + "2. typedarray-pool", + "2. gl-buffer", + "2. gl-mat4", + "2. gl-shader", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glslify", + "2. is-string-blank", + "2. typedarray-pool", + "2. vectorize-text", + "2. gl-buffer", + "2. gl-shader", + "2. glslify", + "2. gl-vec3", + "2. glsl-inverse", + "2. glsl-out-of-range", + "2. glslify", + "2. bit-twiddle", + "2. colormap", + "2. dup", + "2. gl-buffer", + "2. gl-mat4", + "2. gl-shader", + "2. binary-search-bounds", + "2. gl-texture2d", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glsl-specular-beckmann", + "2. glslify", + "2. ndarray", + "2. ndarray-gradient", + "2. ndarray-ops", + "2. ndarray-pack", + "2. ndarray-scratch", + "2. surface-nets", + "2. typedarray-pool", + "2. bit-twiddle", + "2. color-normalize", + "2. css-font", + "2. detect-kerning", + "2. es6-weak-map", + "2. flatten-vertex-data", + "2. font-atlas", + "2. font-measure", + "2. gl-util", + "2. is-plain-obj", + "2. object-assign", + "2. parse-rect", + "2. parse-unit", + "2. pick-by-alias", + "2. regl", + "2. to-px", + "2. typedarray-pool", + "2. bl", + "2. concat-stream", + "2. duplexify", + "2. falafel", + "2. from2", + "2. glsl-resolve", + "2. glsl-token-whitespace-trim", + "2. glslify-bundle", + "2. glslify-deps", + "2. through2", + "2. minimist", + "2. resolve", + "2. stack-trace", + "2. static-eval", + "2. xtend", + "2. is-browser", + "2. is-browser", + "2. @mapbox/gl-matrix", + "2. @mapbox/jsonlint-lines-primitives", + "2. @mapbox/mapbox-gl-supported", + "2. @mapbox/point-geometry", + "2. @mapbox/shelf-pack", + "2. @mapbox/tiny-sdf", + "2. @mapbox/unitbezier", + "2. @mapbox/vector-tile", + "2. @mapbox/whoots-js", + "2. csscolorparser", + "2. earcut", + "2. geojson-rewind", + "2. geojson-vt", + "2. gray-matter", + "2. grid-index", + "2. brfs", + "2. minimist", + "2. through2", + "2. pbf", + "2. quickselect", + "2. rw", + "2. shuffle-seed", + "2. sort-object", + "2. supercluster", + "2. tinyqueue", + "2. vt-pbf", + "2. binary-search-bounds", + "2. gl-mat4", + "2. gl-vec3", + "2. mat4-interpolate", + "2. mouse-event", + "2. signum", + "2. right-now", + "2. to-px", + "2. iota-array", + "2. is-buffer", + "2. cwise", + "2. gl-matrix-invert", + "2. ndarray-warp", + "2. array-bounds", + "2. array-normalize", + "2. bubleify", + "2. clamp", + "2. dtype", + "2. flatten-vertex-data", + "2. is-obj", + "2. math-log2", + "2. parse-rect", + "2. binary-search-bounds", + "2. array-bounds", + "2. bubleify", + "2. color-normalize", + "2. flatten-vertex-data", + "2. object-assign", + "2. pick-by-alias", + "2. to-float32", + "2. update-diff", + "2. array-bounds", + "2. array-normalize", + "2. bubleify", + "2. color-normalize", + "2. earcut", + "2. es6-weak-map", + "2. flatten-vertex-data", + "2. glslify", + "2. object-assign", + "2. parse-rect", + "2. pick-by-alias", + "2. to-float32", + "2. array-range", + "2. array-rearrange", + "2. clamp", + "2. color-id", + "2. color-normalize", + "2. color-rgba", + "2. flatten-vertex-data", + "2. glslify", + "2. image-palette", + "2. is-iexplorer", + "2. object-assign", + "2. parse-rect", + "2. pick-by-alias", + "2. point-cluster", + "2. to-float32", + "2. update-diff", + "2. array-bounds", + "2. array-range", + "2. bubleify", + "2. color-alpha", + "2. defined", + "2. flatten-vertex-data", + "2. left-pad", + "2. parse-rect", + "2. pick-by-alias", + "2. point-cluster", + "2. raf", + "2. regl-scatter2d", + "2. robust-scale", + "2. robust-subtract", + "2. robust-sum", + "2. two-product", + "2. bitmap-sdf", + "2. draw-svg-path", + "2. is-svg-path", + "2. parse-svg-path", + "2. svg-path-bounds", + "2. commander", + "2. get-canvas-context", + "2. object-assign", + "3. d3-path", + "3. circumradius", + "3. delaunay-triangulate", + "3. boundary-cells", + "3. reduce-simplicial-complex", + "3. clamp", + "3. color-parse", + "3. color-space", + "3. robust-orientation", + "3. robust-orientation", + "3. simplicial-complex", + "3. robust-orientation", + "3. strongly-connected-components", + "3. gl-format-compiler-error", + "3. weakmap-shim", + "3. binary-search-bounds", + "3. robust-in-sphere", + "3. robust-orientation", + "3. big-rat", + "3. box-intersect", + "3. nextafter", + "3. rat-vec", + "3. robust-segment-intersect", + "3. union-find", + "3. uniq", + "3. ndarray", + "3. ndarray-ops", + "3. typedarray-pool", + "3. ndarray-extract-contour", + "3. triangulate-hypercube", + "3. zero-crossings", + "3. bit-twiddle", + "3. dup", + "3. ndarray", + "3. ndarray-ops", + "3. typedarray-pool", + "3. robust-linear-solve", + "3. lerp", + "3. glsl-specular-beckmann", + "3. numeric", + "3. marching-simplex-table", + "3. ndarray", + "3. ndarray-sort", + "3. typedarray-pool", + "3. bit-twiddle", + "3. cwise", + "3. gl-fbo", + "3. ndarray", + "3. typedarray-pool", + "3. vectorize-text", + "3. matrix-camera-controller", + "3. orbit-camera-controller", + "3. turntable-camera-controller", + "3. gl-buffer", + "3. gl-vao", + "3. weak-map", + "3. bit-twiddle", + "3. dup", + "3. extract-frustum-planes", + "3. gl-buffer", + "3. gl-mat4", + "3. gl-shader", + "3. gl-state", + "3. gl-vao", + "3. gl-vec4", + "3. glslify", + "3. robust-orientation", + "3. split-polygon", + "3. vectorize-text", + "3. gl-texture2d", + "3. gl-buffer", + "3. gl-shader", + "3. gl-vao", + "3. glslify", + "3. cdt2d", + "3. clean-pslg", + "3. ndarray", + "3. planar-graph-to-polyline", + "3. simplify-planar-graph", + "3. surface-nets", + "3. triangulate-polyline", + "3. cwise-compiler", + "3. dup", + "3. cwise-compiler", + "3. cwise-compiler", + "3. ndarray", + "3. ndarray", + "3. ndarray-ops", + "3. typedarray-pool", + "3. css-font-size-keywords", + "3. css-font-stretch-keywords", + "3. css-font-style-keywords", + "3. css-font-weight-keywords", + "3. css-global-keywords", + "3. css-system-font-keywords", + "3. pick-by-alias", + "3. string-split-by", + "3. unquote", + "3. d", + "3. es5-ext", + "3. es6-iterator", + "3. es6-symbol", + "3. dtype", + "3. css-font", + "3. css-font", + "3. es6-weak-map", + "3. is-browser", + "3. is-firefox", + "3. is-plain-obj", + "3. number-is-integer", + "3. object-assign", + "3. pick-by-alias", + "3. pick-by-alias", + "3. parse-unit", + "3. readable-stream", + "3. safe-buffer", + "3. buffer-from", + "3. readable-stream", + "3. inherits", + "3. typedarray", + "3. readable-stream", + "3. end-of-stream", + "3. inherits", + "3. stream-shift", + "3. acorn", + "3. foreach", + "3. isarray", + "3. object-keys", + "3. readable-stream", + "3. inherits", + "3. resolve", + "3. xtend", + "3. glsl-inject-defines", + "3. glsl-token-defines", + "3. glsl-token-depth", + "3. glsl-token-descope", + "3. glsl-token-scope", + "3. glsl-token-string", + "3. glsl-token-whitespace-trim", + "3. glsl-tokenizer", + "3. murmurhash-js", + "3. shallow-copy", + "3. @choojs/findup", + "3. events", + "3. glsl-resolve", + "3. glsl-tokenizer", + "3. graceful-fs", + "3. inherits", + "3. map-limit", + "3. resolve", + "3. readable-stream", + "3. xtend", + "3. path-parse", + "3. escodegen", + "3. @mapbox/point-geometry", + "3. @mapbox/geojson-area", + "3. concat-stream", + "3. minimist", + "3. sharkdown", + "3. extend-shallow", + "3. kind-of", + "3. js-yaml", + "3. strip-bom-string", + "3. quote-stream", + "3. static-module", + "3. through2", + "3. resolve", + "3. readable-stream", + "3. xtend", + "3. ieee754", + "3. resolve-protobuf-schema", + "3. seedrandom", + "3. sort-asc", + "3. sort-desc", + "3. kdbush", + "3. @mapbox/point-geometry", + "3. @mapbox/vector-tile", + "3. pbf", + "3. gl-mat4", + "3. gl-vec3", + "3. mat4-decompose", + "3. mat4-recompose", + "3. quat-slerp", + "3. cwise-compiler", + "3. cwise-parser", + "3. static-module", + "3. uglify-js", + "3. gl-mat2", + "3. gl-mat3", + "3. gl-mat4", + "3. cwise", + "3. ndarray-linear-interpolate", + "3. array-bounds", + "3. buble", + "3. clamp", + "3. color-id", + "3. pxls", + "3. quantize", + "3. color-parse", + "3. performance-now", + "3. two-product", + "3. two-sum", + "3. clamp", + "3. abs-svg-path", + "3. normalize-svg-path", + "3. abs-svg-path", + "3. is-svg-path", + "3. parse-svg-path", + "3. normalize-svg-path", + "4. circumcenter", + "4. tape", + "4. cell-orientation", + "4. compare-cell", + "4. compare-oriented-cell", + "4. color-name", + "4. defined", + "4. is-plain-obj", + "4. hsluv", + "4. mumath", + "4. bit-twiddle", + "4. union-find", + "4. add-line-numbers", + "4. gl-constants", + "4. glsl-shader-name", + "4. sprintf-js", + "4. robust-scale", + "4. robust-subtract", + "4. robust-sum", + "4. two-product", + "4. bit-twiddle", + "4. bn.js", + "4. double-bits", + "4. bit-twiddle", + "4. typedarray-pool", + "4. double-bits", + "4. big-rat", + "4. robust-orientation", + "4. typedarray-pool", + "4. gamma", + "4. permutation-parity", + "4. permutation-rank", + "4. cwise-compiler", + "4. robust-determinant", + "4. convex-hull", + "4. typedarray-pool", + "4. filtered-vector", + "4. gl-mat4", + "4. filtered-vector", + "4. gl-mat4", + "4. gl-vec3", + "4. uniq", + "4. robust-dot-product", + "4. robust-sum", + "4. edges-to-adjacency-list", + "4. planar-dual", + "4. point-in-big-polygon", + "4. robust-orientation", + "4. robust-sum", + "4. two-product", + "4. uniq", + "4. robust-orientation", + "4. simplicial-complex", + "4. cdt2d", + "4. uniq", + "4. parenthesis", + "4. es5-ext", + "4. es6-iterator", + "4. es6-symbol", + "4. next-tick", + "4. d", + "4. es5-ext", + "4. es6-symbol", + "4. d", + "4. es5-ext", + "4. is-finite", + "4. isarray", + "4. string_decoder", + "4. core-util-is", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. isarray", + "4. string_decoder", + "4. core-util-is", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. core-util-is", + "4. isarray", + "4. string_decoder", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. once", + "4. core-util-is", + "4. isarray", + "4. string_decoder", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. glsl-token-inject-block", + "4. glsl-token-string", + "4. glsl-tokenizer", + "4. glsl-tokenizer", + "4. glsl-token-assignments", + "4. glsl-token-depth", + "4. glsl-token-properties", + "4. glsl-token-scope", + "4. through2", + "4. commander", + "4. once", + "4. core-util-is", + "4. isarray", + "4. string_decoder", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. esprima", + "4. estraverse", + "4. esutils", + "4. optionator", + "4. source-map", + "4. wgs84", + "4. cardinal", + "4. expect.js", + "4. minimist", + "4. split", + "4. stream-spigot", + "4. through", + "4. is-extendable", + "4. argparse", + "4. esprima", + "4. buffer-equal", + "4. minimist", + "4. through2", + "4. concat-stream", + "4. convert-source-map", + "4. falafel", + "4. has", + "4. magic-string", + "4. duplexer2", + "4. escodegen", + "4. object-inspect", + "4. quote-stream", + "4. readable-stream", + "4. through2", + "4. merge-source-map", + "4. shallow-copy", + "4. static-eval", + "4. core-util-is", + "4. inherits", + "4. isarray", + "4. string_decoder", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. protocol-buffers-schema", + "4. gl-mat4", + "4. gl-vec3", + "4. gl-mat4", + "4. gl-quat", + "4. esprima", + "4. uniq", + "4. concat-stream", + "4. duplexer2", + "4. falafel", + "4. has", + "4. quote-stream", + "4. readable-stream", + "4. shallow-copy", + "4. escodegen", + "4. object-inspect", + "4. static-eval", + "4. through2", + "4. source-map", + "4. uglify-to-browserify", + "4. yargs", + "4. acorn", + "4. acorn-dynamic-import", + "4. acorn-jsx", + "4. vlq", + "4. chalk", + "4. magic-string", + "4. minimist", + "4. os-homedir", + "4. arr-flatten", + "4. compute-dims", + "4. flip-pixels", + "4. is-browser", + "4. is-buffer", + "4. to-uint8", + "4. svg-arc-to-cubic-bezier", + "5. dup", + "5. robust-linear-solve", + "5. deep-equal", + "5. defined", + "5. for-each", + "5. function-bind", + "5. glob", + "5. has", + "5. inherits", + "5. minimist", + "5. object-inspect", + "5. resolve", + "5. resumer", + "5. string.prototype.trim", + "5. through", + "5. cell-orientation", + "5. compare-cell", + "5. almost-equal", + "5. pad-left", + "5. atob-lite", + "5. glsl-tokenizer", + "5. typedarray-pool", + "5. invert-permutation", + "5. typedarray-pool", + "5. robust-compress", + "5. robust-scale", + "5. robust-sum", + "5. two-product", + "5. binary-search-bounds", + "5. cubic-hermite", + "5. robust-sum", + "5. two-product", + "5. uniq", + "5. compare-angle", + "5. dup", + "5. binary-search-bounds", + "5. interval-tree-1d", + "5. robust-orientation", + "5. slab-decomposition", + "5. bit-twiddle", + "5. union-find", + "5. number-is-nan", + "5. safe-buffer", + "5. safe-buffer", + "5. safe-buffer", + "5. wrappy", + "5. safe-buffer", + "5. readable-stream", + "5. xtend", + "5. wrappy", + "5. safe-buffer", + "5. deep-is", + "5. fast-levenshtein", + "5. levn", + "5. prelude-ls", + "5. type-check", + "5. wordwrap", + "5. ansicolors", + "5. redeyed", + "5. through", + "5. readable-stream", + "5. sprintf-js", + "5. function-bind", + "5. vlq", + "5. readable-stream", + "5. esprima", + "5. estraverse", + "5. esutils", + "5. optionator", + "5. source-map", + "5. source-map", + "5. safe-buffer", + "5. gl-mat3", + "5. gl-vec3", + "5. gl-vec4", + "5. readable-stream", + "5. minimist", + "5. through2", + "5. core-util-is", + "5. inherits", + "5. isarray", + "5. string_decoder", + "5. esprima", + "5. estraverse", + "5. esutils", + "5. source-map", + "5. escodegen", + "5. readable-stream", + "5. xtend", + "5. camelcase", + "5. cliui", + "5. decamelize", + "5. window-size", + "5. acorn", + "5. acorn", + "5. ansi-styles", + "5. escape-string-regexp", + "5. supports-color", + "5. utils-copy", + "5. validate.io-array", + "5. validate.io-matrix-like", + "5. validate.io-ndarray-like", + "5. validate.io-positive-integer", + "5. arr-flatten", + "5. clamp", + "5. is-base64", + "5. is-float-array", + "5. to-array-buffer" + ] + } + ], + "layout": { + "width": 800, + "height": 800 + } +} diff --git a/test/image/mocks/sunburst_values.json b/test/image/mocks/sunburst_values.json index 940fe3e2d15..3fa7f87b325 100644 --- a/test/image/mocks/sunburst_values.json +++ b/test/image/mocks/sunburst_values.json @@ -6,6 +6,7 @@ "labels": ["Eve", "Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"], "parents": ["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve" ], "values": [10, 14, 12, 10, 2, 6, 6, 1, 4], + "textinfo": "label+value+percent parent+percent root", "domain": {"x": [0, 0.48]}, "outsidetextfont": {"size": 20, "color": "#377eb8"}, "leaf": {"opacity": 0.4}, @@ -19,6 +20,7 @@ "parents": ["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve" ], "domain": {"x": [0.52, 1]}, "values": [65, 14, 12, 10, 2, 6, 6, 1, 4], + "textinfo": "label+value+percent parent+percent root", "outsidetextfont": {"size": 20, "color": "#377eb8"}, "leaf": {"opacity": 0.4}, "marker": {"line": {"width": 2}} diff --git a/test/image/mocks/sunburst_values_colorscale.json b/test/image/mocks/sunburst_values_colorscale.json new file mode 100644 index 00000000000..920119fc0c8 --- /dev/null +++ b/test/image/mocks/sunburst_values_colorscale.json @@ -0,0 +1,144 @@ +{ + "data": [ + { + "type": "sunburst", + "name": "with branchvalues:remainder", + "labels": [ + "Eve", + "Cain", + "Seth", + "Enos", + "Noam", + "Abel", + "Awan", + "Enoch", + "Azura" + ], + "parents": [ + "", + "Eve", + "Eve", + "Seth", + "Seth", + "Eve", + "Eve", + "Awan", + "Eve" + ], + "values": [ + 10, + 14, + 12, + 10, + 2, + 6, + 6, + 1, + 4 + ], + "domain": { + "x": [ + 0, + 0.48 + ] + }, + "marker": { + "colorscale": "Portland", + "colors": [ + 10, + 14, + 12, + 10, + 2, + 6, + 6, + 1, + 4 + ], + "showscale": true, + "colorbar": { + "title": "trace A", + "x": 0, + "xanchor": "right" + } + } + }, + { + "type": "sunburst", + "name": "with branchvalues:total", + "branchvalues": "total", + "labels": [ + "Eve", + "Cain", + "Seth", + "Enos", + "Noam", + "Abel", + "Awan", + "Enoch", + "Azura" + ], + "parents": [ + "", + "Eve", + "Eve", + "Seth", + "Seth", + "Eve", + "Eve", + "Awan", + "Eve" + ], + "domain": { + "x": [ + 0.52, + 1 + ] + }, + "values": [ + 65, + 14, + 12, + 10, + 2, + 6, + 6, + 1, + 4 + ], + "marker": { + "cmin": 0, + "cmax": 25, + "colorscale": "Electric", + "reversescale": true, + "showscale": true, + "colorbar": { + "title": "trace B" + } + } + } + ], + "layout": { + "width": 800, + "height": 500, + "annotations": [ + { + "showarrow": false, + "text": "branchvalues: remainder", + "x": 0.25, + "xanchor": "center", + "y": 1.1, + "yanchor": "bottom" + }, + { + "showarrow": false, + "text": "branchvalues: total
used as input to marker.color", + "x": 0.75, + "xanchor": "center", + "y": 1.1, + "yanchor": "bottom" + } + ], + "paper_bgcolor": "#d3d3d3" + } +} diff --git a/test/image/mocks/sunburst_with-without_values.json b/test/image/mocks/sunburst_with-without_values.json new file mode 100644 index 00000000000..2f3d1710046 --- /dev/null +++ b/test/image/mocks/sunburst_with-without_values.json @@ -0,0 +1,430 @@ +{ + "data": [ + { + "type": "sunburst", + "textinfo": "label+value+percent parent+percent entry+percent root+text+current path", + "hoverinfo": "all", + "name": "without values", + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "domain": { + "x": [ + 0.01, + 0.33 + ] + } + }, + { + "type": "sunburst", + "textinfo": "label+value+percent parent+percent entry+percent root+text+current path", + "hoverinfo": "all", + "name": "with total values", + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "branchvalues": "total", + "values": [ + 40, + 2, + 38, + 1.5, + 2.5, + 34, + 1, + 2, + 3, + 28, + 1.25, + 1.75, + 2.25, + 2.75, + 20, + 1, + 1.5, + 2, + 2.5, + 3, + 10, + 1, + 1.5, + 2, + 2.5, + 3 + ], + "text": [ + "forty", + "two", + "thirty-eight", + "one and a half", + "two and a half", + "thirty-four", + "one", + "two", + "three", + "twenty-eight", + "one and twenty-five hundredths", + "one and seventy-five hundredths", + "two and twenty-five hundredths", + "two and seventy-five hundredths", + "twenty", + "one", + "one and a half", + "two", + "two and a half", + "three", + "ten", + "one", + "one and a half", + "two", + "two and a half", + "three" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "marker": { + "colorscale": [ + [ + 0, + "#FFF" + ], + [ + 0.01, + "#0FF" + ], + [ + 0.1, + "#00F" + ], + [ + 1, + "#000" + ] + ] + }, + "domain": { + "x": [ + 0.34, + 0.66 + ] + } + }, + { + "type": "sunburst", + "textinfo": "label+value+percent parent+percent entry+percent root+text+current path", + "hoverinfo": "all", + "name": "with remainder values", + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "branchvalues": "remainder", + "values": [ + 0, + 2, + 0, + 1.5, + 2.5, + 0, + 1, + 2, + 3, + 0, + 1.25, + 1.75, + 2.25, + 2.75, + 0, + 1, + 1.5, + 2, + 2.5, + 3, + 0, + 1, + 1.5, + 2, + 2.5, + 3 + ], + "text": [ + "zero", + "two", + "zero", + "one and a half", + "two and a half", + "zero", + "one", + "two", + "three", + "zero", + "one and twenty-five hundredths", + "one and seventy-five hundredths", + "two and twenty-five hundredths", + "two and seventy-five hundredths", + "zero", + "one", + "one and a half", + "two", + "two and a half", + "three", + "zero", + "one", + "one and a half", + "two", + "two and a half", + "three" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "marker": { + "colorscale": [ + [ + 0, + "#FFF" + ], + [ + 0.01, + "#0FF" + ], + [ + 0.1, + "#00F" + ], + [ + 1, + "#000" + ] + ] + }, + "domain": { + "x": [ + 0.67, + 0.99 + ] + } + } + ], + "layout": { + "margin" : { + "t": 50, + "l": 0, + "r": 0, + "b": 25 + }, + "width": 1500, + "height": 600, + "shapes": [ + { + "type": "rect", + "layer": "above", + "x0": 0.01, + "x1": 0.33, + "y0": 0, + "y1": 1 + }, + { + "type": "rect", + "layer": "above", + "x0": 0.34, + "x1": 0.66, + "y0": 0, + "y1": 1 + }, + { + "type": "rect", + "layer": "above", + "x0": 0.67, + "x1": 0.99, + "y0": 0, + "y1": 1 + } + ], + "annotations": [ + { + "showarrow": false, + "text": "with counted leaves
", + "x": 0.17, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "with values and branchvalues: total
", + "x": 0.5, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "with values and branchvalues: remainder
", + "x": 0.83, + "xanchor": "center", + "y": 0, + "yanchor": "top" + } + ] + } +} diff --git a/test/image/mocks/treemap_coffee-maxdepth3.json b/test/image/mocks/treemap_coffee-maxdepth3.json new file mode 100644 index 00000000000..90d45aff3f0 --- /dev/null +++ b/test/image/mocks/treemap_coffee-maxdepth3.json @@ -0,0 +1,314 @@ +{ + "data": [ + { + "type": "treemap", + "pathbar": { + "visible": false + }, + "maxdepth": 3, + "textinfo": "label+percent parent", + "ids": [ + "Aromas", + "Tastes", + "Aromas-Enzymatic", + "Aromas-Sugar Browning", + "Aromas-Dry Distillation", + "Tastes-Bitter", + "Tastes-Salt", + "Tastes-Sweet", + "Tastes-Sour", + "Enzymatic-Flowery", + "Enzymatic-Fruity", + "Enzymatic-Herby", + "Sugar Browning-Nutty", + "Sugar Browning-Carmelly", + "Sugar Browning-Chocolatey", + "Dry Distillation-Resinous", + "Dry Distillation-Spicy", + "Dry Distillation-Carbony", + "Bitter-Pungent", + "Bitter-Harsh", + "Salt-Sharp", + "Salt-Bland", + "Sweet-Mellow", + "Sweet-Acidy", + "Sour-Winey", + "Sour-Soury", + "Flowery-Floral", + "Flowery-Fragrant", + "Fruity-Citrus", + "Fruity-Berry-like", + "Herby-Alliaceous", + "Herby-Leguminous", + "Nutty-Nut-like", + "Nutty-Malt-like", + "Carmelly-Candy-like", + "Carmelly-Syrup-like", + "Chocolatey-Chocolate-like", + "Chocolatey-Vanilla-like", + "Resinous-Turpeny", + "Resinous-Medicinal", + "Spicy-Warming", + "Spicy-Pungent", + "Carbony-Smokey", + "Carbony-Ashy", + "Pungent-Creosol", + "Pungent-Phenolic", + "Harsh-Caustic", + "Harsh-Alkaline", + "Sharp-Astringent", + "Sharp-Rough", + "Bland-Neutral", + "Bland-Soft", + "Mellow-Delicate", + "Mellow-Mild", + "Acidy-Nippy", + "Acidy-Piquant", + "Winey-Tangy", + "Winey-Tart", + "Soury-Hard", + "Soury-Acrid", + "Floral-Coffee Blossom", + "Floral-Tea Rose", + "Fragrant-Cardamon Caraway", + "Fragrant-Coriander Seeds", + "Citrus-Lemon", + "Citrus-Apple", + "Berry-like-Apricot", + "Berry-like-Blackberry", + "Alliaceous-Onion", + "Alliaceous-Garlic", + "Leguminous-Cucumber", + "Leguminous-Garden Peas", + "Nut-like-Roasted Peanuts", + "Nut-like-Walnuts", + "Malt-like-Balsamic Rice", + "Malt-like-Toast", + "Candy-like-Roasted Hazelnut", + "Candy-like-Roasted Almond", + "Syrup-like-Honey", + "Syrup-like-Maple Syrup", + "Chocolate-like-Bakers", + "Chocolate-like-Dark Chocolate", + "Vanilla-like-Swiss", + "Vanilla-like-Butter", + "Turpeny-Piney", + "Turpeny-Blackcurrant-like", + "Medicinal-Camphoric", + "Medicinal-Cineolic", + "Warming-Cedar", + "Warming-Pepper", + "Pungent-Clove", + "Pungent-Thyme", + "Smokey-Tarry", + "Smokey-Pipe Tobacco", + "Ashy-Burnt", + "Ashy-Charred" + ], + "labels": [ + "Aromas", + "Tastes", + "Enzymatic", + "Sugar Browning", + "Dry Distillation", + "Bitter", + "Salt", + "Sweet", + "Sour", + "Flowery", + "Fruity", + "Herby", + "Nutty", + "Carmelly", + "Chocolatey", + "Resinous", + "Spicy", + "Carbony", + "Pungent", + "Harsh", + "Sharp", + "Bland", + "Mellow", + "Acidy", + "Winey", + "Soury", + "Floral", + "Fragrant", + "Citrus", + "Berry-like", + "Alliaceous", + "Leguminous", + "Nut-like", + "Malt-like", + "Candy-like", + "Syrup-like", + "Chocolate-like", + "Vanilla-like", + "Turpeny", + "Medicinal", + "Warming", + "Pungent", + "Smokey", + "Ashy", + "Creosol", + "Phenolic", + "Caustic", + "Alkaline", + "Astringent", + "Rough", + "Neutral", + "Soft", + "Delicate", + "Mild", + "Nippy", + "Piquant", + "Tangy", + "Tart", + "Hard", + "Acrid", + "Coffee Blossom", + "Tea Rose", + "Cardamon Caraway", + "Coriander Seeds", + "Lemon", + "Apple", + "Apricot", + "Blackberry", + "Onion", + "Garlic", + "Cucumber", + "Garden Peas", + "Roasted Peanuts", + "Walnuts", + "Balsamic Rice", + "Toast", + "Roasted Hazelnut", + "Roasted Almond", + "Honey", + "Maple Syrup", + "Bakers", + "Dark Chocolate", + "Swiss", + "Butter", + "Piney", + "Blackcurrant-like", + "Camphoric", + "Cineolic", + "Cedar", + "Pepper", + "Clove", + "Thyme", + "Tarry", + "Pipe Tobacco", + "Burnt", + "Charred" + ], + "parents": [ + "", + "", + "Aromas", + "Aromas", + "Aromas", + "Tastes", + "Tastes", + "Tastes", + "Tastes", + "Aromas-Enzymatic", + "Aromas-Enzymatic", + "Aromas-Enzymatic", + "Aromas-Sugar Browning", + "Aromas-Sugar Browning", + "Aromas-Sugar Browning", + "Aromas-Dry Distillation", + "Aromas-Dry Distillation", + "Aromas-Dry Distillation", + "Tastes-Bitter", + "Tastes-Bitter", + "Tastes-Salt", + "Tastes-Salt", + "Tastes-Sweet", + "Tastes-Sweet", + "Tastes-Sour", + "Tastes-Sour", + "Enzymatic-Flowery", + "Enzymatic-Flowery", + "Enzymatic-Fruity", + "Enzymatic-Fruity", + "Enzymatic-Herby", + "Enzymatic-Herby", + "Sugar Browning-Nutty", + "Sugar Browning-Nutty", + "Sugar Browning-Carmelly", + "Sugar Browning-Carmelly", + "Sugar Browning-Chocolatey", + "Sugar Browning-Chocolatey", + "Dry Distillation-Resinous", + "Dry Distillation-Resinous", + "Dry Distillation-Spicy", + "Dry Distillation-Spicy", + "Dry Distillation-Carbony", + "Dry Distillation-Carbony", + "Bitter-Pungent", + "Bitter-Pungent", + "Bitter-Harsh", + "Bitter-Harsh", + "Salt-Sharp", + "Salt-Sharp", + "Salt-Bland", + "Salt-Bland", + "Sweet-Mellow", + "Sweet-Mellow", + "Sweet-Acidy", + "Sweet-Acidy", + "Sour-Winey", + "Sour-Winey", + "Sour-Soury", + "Sour-Soury", + "Flowery-Floral", + "Flowery-Floral", + "Flowery-Fragrant", + "Flowery-Fragrant", + "Fruity-Citrus", + "Fruity-Citrus", + "Fruity-Berry-like", + "Fruity-Berry-like", + "Herby-Alliaceous", + "Herby-Alliaceous", + "Herby-Leguminous", + "Herby-Leguminous", + "Nutty-Nut-like", + "Nutty-Nut-like", + "Nutty-Malt-like", + "Nutty-Malt-like", + "Carmelly-Candy-like", + "Carmelly-Candy-like", + "Carmelly-Syrup-like", + "Carmelly-Syrup-like", + "Chocolatey-Chocolate-like", + "Chocolatey-Chocolate-like", + "Chocolatey-Vanilla-like", + "Chocolatey-Vanilla-like", + "Resinous-Turpeny", + "Resinous-Turpeny", + "Resinous-Medicinal", + "Resinous-Medicinal", + "Spicy-Warming", + "Spicy-Warming", + "Spicy-Pungent", + "Spicy-Pungent", + "Carbony-Smokey", + "Carbony-Smokey", + "Carbony-Ashy", + "Carbony-Ashy" + ] + } + ], + "layout": { + "margin": {"l": 0, "r": 0, "b": 0, "t": 0}, + "width": 500, + "height": 500, + "shapes": [ + { "type": "rect", "layer": "below", "x0": 0, "x1": 1, "y0": 0, "y1": 1 } + ] + } +} diff --git a/test/image/mocks/treemap_coffee.json b/test/image/mocks/treemap_coffee.json new file mode 100644 index 00000000000..cf9db2ad129 --- /dev/null +++ b/test/image/mocks/treemap_coffee.json @@ -0,0 +1,313 @@ +{ + "data": [ + { + "type": "treemap", + "pathbar": { + "visible": false + }, + "textinfo": "label+percent parent", + "ids": [ + "Aromas", + "Tastes", + "Aromas-Enzymatic", + "Aromas-Sugar Browning", + "Aromas-Dry Distillation", + "Tastes-Bitter", + "Tastes-Salt", + "Tastes-Sweet", + "Tastes-Sour", + "Enzymatic-Flowery", + "Enzymatic-Fruity", + "Enzymatic-Herby", + "Sugar Browning-Nutty", + "Sugar Browning-Carmelly", + "Sugar Browning-Chocolatey", + "Dry Distillation-Resinous", + "Dry Distillation-Spicy", + "Dry Distillation-Carbony", + "Bitter-Pungent", + "Bitter-Harsh", + "Salt-Sharp", + "Salt-Bland", + "Sweet-Mellow", + "Sweet-Acidy", + "Sour-Winey", + "Sour-Soury", + "Flowery-Floral", + "Flowery-Fragrant", + "Fruity-Citrus", + "Fruity-Berry-like", + "Herby-Alliaceous", + "Herby-Leguminous", + "Nutty-Nut-like", + "Nutty-Malt-like", + "Carmelly-Candy-like", + "Carmelly-Syrup-like", + "Chocolatey-Chocolate-like", + "Chocolatey-Vanilla-like", + "Resinous-Turpeny", + "Resinous-Medicinal", + "Spicy-Warming", + "Spicy-Pungent", + "Carbony-Smokey", + "Carbony-Ashy", + "Pungent-Creosol", + "Pungent-Phenolic", + "Harsh-Caustic", + "Harsh-Alkaline", + "Sharp-Astringent", + "Sharp-Rough", + "Bland-Neutral", + "Bland-Soft", + "Mellow-Delicate", + "Mellow-Mild", + "Acidy-Nippy", + "Acidy-Piquant", + "Winey-Tangy", + "Winey-Tart", + "Soury-Hard", + "Soury-Acrid", + "Floral-Coffee Blossom", + "Floral-Tea Rose", + "Fragrant-Cardamon Caraway", + "Fragrant-Coriander Seeds", + "Citrus-Lemon", + "Citrus-Apple", + "Berry-like-Apricot", + "Berry-like-Blackberry", + "Alliaceous-Onion", + "Alliaceous-Garlic", + "Leguminous-Cucumber", + "Leguminous-Garden Peas", + "Nut-like-Roasted Peanuts", + "Nut-like-Walnuts", + "Malt-like-Balsamic Rice", + "Malt-like-Toast", + "Candy-like-Roasted Hazelnut", + "Candy-like-Roasted Almond", + "Syrup-like-Honey", + "Syrup-like-Maple Syrup", + "Chocolate-like-Bakers", + "Chocolate-like-Dark Chocolate", + "Vanilla-like-Swiss", + "Vanilla-like-Butter", + "Turpeny-Piney", + "Turpeny-Blackcurrant-like", + "Medicinal-Camphoric", + "Medicinal-Cineolic", + "Warming-Cedar", + "Warming-Pepper", + "Pungent-Clove", + "Pungent-Thyme", + "Smokey-Tarry", + "Smokey-Pipe Tobacco", + "Ashy-Burnt", + "Ashy-Charred" + ], + "labels": [ + "Aromas", + "Tastes", + "Enzymatic", + "Sugar Browning", + "Dry Distillation", + "Bitter", + "Salt", + "Sweet", + "Sour", + "Flowery", + "Fruity", + "Herby", + "Nutty", + "Carmelly", + "Chocolatey", + "Resinous", + "Spicy", + "Carbony", + "Pungent", + "Harsh", + "Sharp", + "Bland", + "Mellow", + "Acidy", + "Winey", + "Soury", + "Floral", + "Fragrant", + "Citrus", + "Berry-like", + "Alliaceous", + "Leguminous", + "Nut-like", + "Malt-like", + "Candy-like", + "Syrup-like", + "Chocolate-like", + "Vanilla-like", + "Turpeny", + "Medicinal", + "Warming", + "Pungent", + "Smokey", + "Ashy", + "Creosol", + "Phenolic", + "Caustic", + "Alkaline", + "Astringent", + "Rough", + "Neutral", + "Soft", + "Delicate", + "Mild", + "Nippy", + "Piquant", + "Tangy", + "Tart", + "Hard", + "Acrid", + "Coffee Blossom", + "Tea Rose", + "Cardamon Caraway", + "Coriander Seeds", + "Lemon", + "Apple", + "Apricot", + "Blackberry", + "Onion", + "Garlic", + "Cucumber", + "Garden Peas", + "Roasted Peanuts", + "Walnuts", + "Balsamic Rice", + "Toast", + "Roasted Hazelnut", + "Roasted Almond", + "Honey", + "Maple Syrup", + "Bakers", + "Dark Chocolate", + "Swiss", + "Butter", + "Piney", + "Blackcurrant-like", + "Camphoric", + "Cineolic", + "Cedar", + "Pepper", + "Clove", + "Thyme", + "Tarry", + "Pipe Tobacco", + "Burnt", + "Charred" + ], + "parents": [ + "", + "", + "Aromas", + "Aromas", + "Aromas", + "Tastes", + "Tastes", + "Tastes", + "Tastes", + "Aromas-Enzymatic", + "Aromas-Enzymatic", + "Aromas-Enzymatic", + "Aromas-Sugar Browning", + "Aromas-Sugar Browning", + "Aromas-Sugar Browning", + "Aromas-Dry Distillation", + "Aromas-Dry Distillation", + "Aromas-Dry Distillation", + "Tastes-Bitter", + "Tastes-Bitter", + "Tastes-Salt", + "Tastes-Salt", + "Tastes-Sweet", + "Tastes-Sweet", + "Tastes-Sour", + "Tastes-Sour", + "Enzymatic-Flowery", + "Enzymatic-Flowery", + "Enzymatic-Fruity", + "Enzymatic-Fruity", + "Enzymatic-Herby", + "Enzymatic-Herby", + "Sugar Browning-Nutty", + "Sugar Browning-Nutty", + "Sugar Browning-Carmelly", + "Sugar Browning-Carmelly", + "Sugar Browning-Chocolatey", + "Sugar Browning-Chocolatey", + "Dry Distillation-Resinous", + "Dry Distillation-Resinous", + "Dry Distillation-Spicy", + "Dry Distillation-Spicy", + "Dry Distillation-Carbony", + "Dry Distillation-Carbony", + "Bitter-Pungent", + "Bitter-Pungent", + "Bitter-Harsh", + "Bitter-Harsh", + "Salt-Sharp", + "Salt-Sharp", + "Salt-Bland", + "Salt-Bland", + "Sweet-Mellow", + "Sweet-Mellow", + "Sweet-Acidy", + "Sweet-Acidy", + "Sour-Winey", + "Sour-Winey", + "Sour-Soury", + "Sour-Soury", + "Flowery-Floral", + "Flowery-Floral", + "Flowery-Fragrant", + "Flowery-Fragrant", + "Fruity-Citrus", + "Fruity-Citrus", + "Fruity-Berry-like", + "Fruity-Berry-like", + "Herby-Alliaceous", + "Herby-Alliaceous", + "Herby-Leguminous", + "Herby-Leguminous", + "Nutty-Nut-like", + "Nutty-Nut-like", + "Nutty-Malt-like", + "Nutty-Malt-like", + "Carmelly-Candy-like", + "Carmelly-Candy-like", + "Carmelly-Syrup-like", + "Carmelly-Syrup-like", + "Chocolatey-Chocolate-like", + "Chocolatey-Chocolate-like", + "Chocolatey-Vanilla-like", + "Chocolatey-Vanilla-like", + "Resinous-Turpeny", + "Resinous-Turpeny", + "Resinous-Medicinal", + "Resinous-Medicinal", + "Spicy-Warming", + "Spicy-Warming", + "Spicy-Pungent", + "Spicy-Pungent", + "Carbony-Smokey", + "Carbony-Smokey", + "Carbony-Ashy", + "Carbony-Ashy" + ] + } + ], + "layout": { + "margin": {"l": 0, "r": 0, "b": 0, "t": 0}, + "width": 500, + "height": 500, + "shapes": [ + { "type": "rect", "layer": "below", "x0": 0, "x1": 1, "y0": 0, "y1": 1 } + ] + } +} diff --git a/test/image/mocks/treemap_first.json b/test/image/mocks/treemap_first.json new file mode 100644 index 00000000000..a8fb85a2100 --- /dev/null +++ b/test/image/mocks/treemap_first.json @@ -0,0 +1,92 @@ +{ + "data": [ + { + "type": "treemap", + "pathbar": { + "visible": false + }, + "textinfo": "label+percent parent", + "labels": [ + "Eve", + "Cain", + "Seth", + "Enos", + "Noam", + "Abel", + "Awan", + "Enoch", + "Azura" + ], + "parents": [ + "", + "Eve", + "Eve", + "Seth", + "Seth", + "Eve", + "Eve", + "Awan", + "Eve" + ], + "domain": { + "x": [ + 0, + 0.5 + ] + } + }, + { + "type": "treemap", + "pathbar": { + "visible": false + }, + "textinfo": "label+percent entry", + "labels": [ + "Cain", + "Seth", + "Enos", + "Noam", + "Abel", + "Awan", + "Enoch", + "Azura" + ], + "parents": [ + "Eve", + "Eve", + "Seth", + "Seth", + "Eve", + "Eve", + "Awan", + "Eve" + ], + "domain": { + "x": [ + 0.5, + 1 + ] + } + } + ], + "layout": { + "annotations": [ + { + "showarrow": false, + "text": "percent parent", + "x": 0.25, + "xanchor": "center", + "y": 1, + "yanchor": "bottom" + }, + { + "showarrow": false, + "text": "percent entry", + "x": 0.75, + "xanchor": "center", + "y": 1, + "yanchor": "bottom" + } + ] + } +} diff --git a/test/image/mocks/treemap_flare.json b/test/image/mocks/treemap_flare.json new file mode 100644 index 00000000000..f049539cc80 --- /dev/null +++ b/test/image/mocks/treemap_flare.json @@ -0,0 +1,774 @@ +{ + "data": [ + { + "type": "treemap", + "hoverinfo": "all", + "ids": [ + "flare", + "flare-analytics", + "flare-animate", + "flare-data", + "flare-display", + "flare-flex", + "flare-physics", + "flare-query", + "flare-scale", + "flare-util", + "flare-vis", + "analytics-cluster", + "analytics-graph", + "analytics-optimization", + "animate-Easing", + "animate-FunctionSequence", + "animate-interpolate", + "animate-ISchedulable", + "animate-Parallel", + "animate-Pause", + "animate-Scheduler", + "animate-Sequence", + "animate-Transition", + "animate-Transitioner", + "animate-TransitionEvent", + "animate-Tween", + "data-converters", + "data-DataField", + "data-DataSchema", + "data-DataSet", + "data-DataSource", + "data-DataTable", + "data-DataUtil", + "display-DirtySprite", + "display-LineSprite", + "display-RectSprite", + "display-TextSprite", + "flex-FlareVis", + "physics-DragForce", + "physics-GravityForce", + "physics-IForce", + "physics-NBodyForce", + "physics-Particle", + "physics-Simulation", + "physics-Spring", + "physics-SpringForce", + "query-AggregateExpression", + "query-And", + "query-Arithmetic", + "query-Average", + "query-BinaryExpression", + "query-Comparison", + "query-CompositeExpression", + "query-Count", + "query-DateUtil", + "query-Distinct", + "query-Expression", + "query-ExpressionIterator", + "query-Fn", + "query-If", + "query-IsA", + "query-Literal", + "query-Match", + "query-Maximum", + "query-methods", + "query-Minimum", + "query-Not", + "query-Or", + "query-Query", + "query-Range", + "query-StringUtil", + "query-Sum", + "query-Variable", + "query-Variance", + "query-Xor", + "scale-IScaleMap", + "scale-LinearScale", + "scale-LogScale", + "scale-OrdinalScale", + "scale-QuantileScale", + "scale-QuantitativeScale", + "scale-RootScale", + "scale-Scale", + "scale-ScaleType", + "scale-TimeScale", + "util-Arrays", + "util-Colors", + "util-Dates", + "util-Displays", + "util-Filter", + "util-Geometry", + "util-heap", + "util-IEvaluable", + "util-IPredicate", + "util-IValueProxy", + "util-math", + "util-Maths", + "util-Orientation", + "util-palette", + "util-Property", + "util-Shapes", + "util-Sort", + "util-Stats", + "util-Strings", + "vis-axis", + "vis-controls", + "vis-data", + "vis-events", + "vis-legend", + "vis-operator", + "vis-Visualization", + "cluster-AgglomerativeCluster", + "cluster-CommunityStructure", + "cluster-HierarchicalCluster", + "cluster-MergeEdge", + "graph-BetweennessCentrality", + "graph-LinkDistance", + "graph-MaxFlowMinCut", + "graph-ShortestPaths", + "graph-SpanningTree", + "optimization-AspectRatioBanker", + "interpolate-ArrayInterpolator", + "interpolate-ColorInterpolator", + "interpolate-DateInterpolator", + "interpolate-Interpolator", + "interpolate-MatrixInterpolator", + "interpolate-NumberInterpolator", + "interpolate-ObjectInterpolator", + "interpolate-PointInterpolator", + "interpolate-RectangleInterpolator", + "converters-Converters", + "converters-DelimitedTextConverter", + "converters-GraphMLConverter", + "converters-IDataConverter", + "converters-JSONConverter", + "methods-add", + "methods-and", + "methods-average", + "methods-count", + "methods-distinct", + "methods-div", + "methods-eq", + "methods-fn", + "methods-gt", + "methods-gte", + "methods-iff", + "methods-isa", + "methods-lt", + "methods-lte", + "methods-max", + "methods-min", + "methods-mod", + "methods-mul", + "methods-neq", + "methods-not", + "methods-or", + "methods-orderby", + "methods-range", + "methods-select", + "methods-stddev", + "methods-sub", + "methods-sum", + "methods-update", + "methods-variance", + "methods-where", + "methods-xor", + "methods-_", + "heap-FibonacciHeap", + "heap-HeapNode", + "math-DenseMatrix", + "math-IMatrix", + "math-SparseMatrix", + "palette-ColorPalette", + "palette-Palette", + "palette-ShapePalette", + "palette-SizePalette", + "axis-Axes", + "axis-Axis", + "axis-AxisGridLine", + "axis-AxisLabel", + "axis-CartesianAxes", + "controls-AnchorControl", + "controls-ClickControl", + "controls-Control", + "controls-ControlList", + "controls-DragControl", + "controls-ExpandControl", + "controls-HoverControl", + "controls-IControl", + "controls-PanZoomControl", + "controls-SelectionControl", + "controls-TooltipControl", + "data-Data", + "data-DataList", + "data-DataSprite", + "data-EdgeSprite", + "data-NodeSprite", + "data-render", + "data-ScaleBinding", + "data-Tree", + "data-TreeBuilder", + "events-DataEvent", + "events-SelectionEvent", + "events-TooltipEvent", + "events-VisualizationEvent", + "legend-Legend", + "legend-LegendItem", + "legend-LegendRange", + "operator-distortion", + "operator-encoder", + "operator-filter", + "operator-IOperator", + "operator-label", + "operator-layout", + "operator-Operator", + "operator-OperatorList", + "operator-OperatorSequence", + "operator-OperatorSwitch", + "operator-SortOperator", + "render-ArrowType", + "render-EdgeRenderer", + "render-IRenderer", + "render-ShapeRenderer", + "distortion-BifocalDistortion", + "distortion-Distortion", + "distortion-FisheyeDistortion", + "encoder-ColorEncoder", + "encoder-Encoder", + "encoder-PropertyEncoder", + "encoder-ShapeEncoder", + "encoder-SizeEncoder", + "filter-FisheyeTreeFilter", + "filter-GraphDistanceFilter", + "filter-VisibilityFilter", + "label-Labeler", + "label-RadialLabeler", + "label-StackedAreaLabeler", + "layout-AxisLayout", + "layout-BundledEdgeRouter", + "layout-CircleLayout", + "layout-CirclePackingLayout", + "layout-DendrogramLayout", + "layout-ForceDirectedLayout", + "layout-IcicleTreeLayout", + "layout-IndentedTreeLayout", + "layout-Layout", + "layout-NodeLinkTreeLayout", + "layout-PieLayout", + "layout-RadialTreeLayout", + "layout-RandomLayout", + "layout-StackedAreaLayout", + "layout-TreeMapLayout" + ], + "labels": [ + "flare", + "analytics", + "animate", + "data", + "display", + "flex", + "physics", + "query", + "scale", + "util", + "vis", + "cluster", + "graph", + "optimization", + "Easing", + "FunctionSequence", + "interpolate", + "ISchedulable", + "Parallel", + "Pause", + "Scheduler", + "Sequence", + "Transition", + "Transitioner", + "TransitionEvent", + "Tween", + "converters", + "DataField", + "DataSchema", + "DataSet", + "DataSource", + "DataTable", + "DataUtil", + "DirtySprite", + "LineSprite", + "RectSprite", + "TextSprite", + "FlareVis", + "DragForce", + "GravityForce", + "IForce", + "NBodyForce", + "Particle", + "Simulation", + "Spring", + "SpringForce", + "AggregateExpression", + "And", + "Arithmetic", + "Average", + "BinaryExpression", + "Comparison", + "CompositeExpression", + "Count", + "DateUtil", + "Distinct", + "Expression", + "ExpressionIterator", + "Fn", + "If", + "IsA", + "Literal", + "Match", + "Maximum", + "methods", + "Minimum", + "Not", + "Or", + "Query", + "Range", + "StringUtil", + "Sum", + "Variable", + "Variance", + "Xor", + "IScaleMap", + "LinearScale", + "LogScale", + "OrdinalScale", + "QuantileScale", + "QuantitativeScale", + "RootScale", + "Scale", + "ScaleType", + "TimeScale", + "Arrays", + "Colors", + "Dates", + "Displays", + "Filter", + "Geometry", + "heap", + "IEvaluable", + "IPredicate", + "IValueProxy", + "math", + "Maths", + "Orientation", + "palette", + "Property", + "Shapes", + "Sort", + "Stats", + "Strings", + "axis", + "controls", + "data", + "events", + "legend", + "operator", + "Visualization", + "AgglomerativeCluster", + "CommunityStructure", + "HierarchicalCluster", + "MergeEdge", + "BetweennessCentrality", + "LinkDistance", + "MaxFlowMinCut", + "ShortestPaths", + "SpanningTree", + "AspectRatioBanker", + "ArrayInterpolator", + "ColorInterpolator", + "DateInterpolator", + "Interpolator", + "MatrixInterpolator", + "NumberInterpolator", + "ObjectInterpolator", + "PointInterpolator", + "RectangleInterpolator", + "Converters", + "DelimitedTextConverter", + "GraphMLConverter", + "IDataConverter", + "JSONConverter", + "add", + "and", + "average", + "count", + "distinct", + "div", + "eq", + "fn", + "gt", + "gte", + "iff", + "isa", + "lt", + "lte", + "max", + "min", + "mod", + "mul", + "neq", + "not", + "or", + "orderby", + "range", + "select", + "stddev", + "sub", + "sum", + "update", + "variance", + "where", + "xor", + "_", + "FibonacciHeap", + "HeapNode", + "DenseMatrix", + "IMatrix", + "SparseMatrix", + "ColorPalette", + "Palette", + "ShapePalette", + "SizePalette", + "Axes", + "Axis", + "AxisGridLine", + "AxisLabel", + "CartesianAxes", + "AnchorControl", + "ClickControl", + "Control", + "ControlList", + "DragControl", + "ExpandControl", + "HoverControl", + "IControl", + "PanZoomControl", + "SelectionControl", + "TooltipControl", + "Data", + "DataList", + "DataSprite", + "EdgeSprite", + "NodeSprite", + "render", + "ScaleBinding", + "Tree", + "TreeBuilder", + "DataEvent", + "SelectionEvent", + "TooltipEvent", + "VisualizationEvent", + "Legend", + "LegendItem", + "LegendRange", + "distortion", + "encoder", + "filter", + "IOperator", + "label", + "layout", + "Operator", + "OperatorList", + "OperatorSequence", + "OperatorSwitch", + "SortOperator", + "ArrowType", + "EdgeRenderer", + "IRenderer", + "ShapeRenderer", + "BifocalDistortion", + "Distortion", + "FisheyeDistortion", + "ColorEncoder", + "Encoder", + "PropertyEncoder", + "ShapeEncoder", + "SizeEncoder", + "FisheyeTreeFilter", + "GraphDistanceFilter", + "VisibilityFilter", + "Labeler", + "RadialLabeler", + "StackedAreaLabeler", + "AxisLayout", + "BundledEdgeRouter", + "CircleLayout", + "CirclePackingLayout", + "DendrogramLayout", + "ForceDirectedLayout", + "IcicleTreeLayout", + "IndentedTreeLayout", + "Layout", + "NodeLinkTreeLayout", + "PieLayout", + "RadialTreeLayout", + "RandomLayout", + "StackedAreaLayout", + "TreeMapLayout" + ], + "parents": [ + "", + "flare", + "flare", + "flare", + "flare", + "flare", + "flare", + "flare", + "flare", + "flare", + "flare", + "flare-analytics", + "flare-analytics", + "flare-analytics", + "flare-animate", + "flare-animate", + "flare-animate", + "flare-animate", + "flare-animate", + "flare-animate", + "flare-animate", + "flare-animate", + "flare-animate", + "flare-animate", + "flare-animate", + "flare-animate", + "flare-data", + "flare-data", + "flare-data", + "flare-data", + "flare-data", + "flare-data", + "flare-data", + "flare-display", + "flare-display", + "flare-display", + "flare-display", + "flare-flex", + "flare-physics", + "flare-physics", + "flare-physics", + "flare-physics", + "flare-physics", + "flare-physics", + "flare-physics", + "flare-physics", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-query", + "flare-scale", + "flare-scale", + "flare-scale", + "flare-scale", + "flare-scale", + "flare-scale", + "flare-scale", + "flare-scale", + "flare-scale", + "flare-scale", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-util", + "flare-vis", + "flare-vis", + "flare-vis", + "flare-vis", + "flare-vis", + "flare-vis", + "flare-vis", + "analytics-cluster", + "analytics-cluster", + "analytics-cluster", + "analytics-cluster", + "analytics-graph", + "analytics-graph", + "analytics-graph", + "analytics-graph", + "analytics-graph", + "analytics-optimization", + "animate-interpolate", + "animate-interpolate", + "animate-interpolate", + "animate-interpolate", + "animate-interpolate", + "animate-interpolate", + "animate-interpolate", + "animate-interpolate", + "animate-interpolate", + "data-converters", + "data-converters", + "data-converters", + "data-converters", + "data-converters", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "query-methods", + "util-heap", + "util-heap", + "util-math", + "util-math", + "util-math", + "util-palette", + "util-palette", + "util-palette", + "util-palette", + "vis-axis", + "vis-axis", + "vis-axis", + "vis-axis", + "vis-axis", + "vis-controls", + "vis-controls", + "vis-controls", + "vis-controls", + "vis-controls", + "vis-controls", + "vis-controls", + "vis-controls", + "vis-controls", + "vis-controls", + "vis-controls", + "vis-data", + "vis-data", + "vis-data", + "vis-data", + "vis-data", + "vis-data", + "vis-data", + "vis-data", + "vis-data", + "vis-events", + "vis-events", + "vis-events", + "vis-events", + "vis-legend", + "vis-legend", + "vis-legend", + "vis-operator", + "vis-operator", + "vis-operator", + "vis-operator", + "vis-operator", + "vis-operator", + "vis-operator", + "vis-operator", + "vis-operator", + "vis-operator", + "vis-operator", + "data-render", + "data-render", + "data-render", + "data-render", + "operator-distortion", + "operator-distortion", + "operator-distortion", + "operator-encoder", + "operator-encoder", + "operator-encoder", + "operator-encoder", + "operator-encoder", + "operator-filter", + "operator-filter", + "operator-filter", + "operator-label", + "operator-label", + "operator-label", + "operator-layout", + "operator-layout", + "operator-layout", + "operator-layout", + "operator-layout", + "operator-layout", + "operator-layout", + "operator-layout", + "operator-layout", + "operator-layout", + "operator-layout", + "operator-layout", + "operator-layout", + "operator-layout", + "operator-layout" + ] + } + ], + "layout": { + "width": 600, + "height": 600 + } +} diff --git a/test/image/mocks/treemap_level-depth.json b/test/image/mocks/treemap_level-depth.json new file mode 100644 index 00000000000..8cc81a08320 --- /dev/null +++ b/test/image/mocks/treemap_level-depth.json @@ -0,0 +1,562 @@ +{ + "data": [ + { + "type": "treemap", + "maxdepth": 3, + "texttemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "hovertemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "text": [ + "A L P H A", + "B R A V O", + "C H A R L I E", + "D E L T A", + "E C H O", + "F O X T R O T", + "G O L F", + "H O T E L", + "I N D I A", + "J U L I E T", + "K I L O", + "L I M A", + "M I K E", + "N O V E M B E R", + "O S C A R", + "P A P A", + "Q U E B E C", + "R O M E O", + "S I E R R A", + "T A N G O", + "U N I F O R M", + "V I C T O R", + "W H I S K E Y", + "X R A Y", + "Y A N K E E", + "Z U L U", + "" + ], + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu", + 0 + ], + "values": [ + 4000000, + 3000000, + 2000000, + 1000000, + 1000000, + 3000000, + 2000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 2000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 2000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000 + ], + "parents": [ + "", + "", + "", + "", + "", + "Alpha", + "Alpha", + "Alpha", + "Alpha", + "Bravo", + "Bravo", + "Bravo", + "Charlie", + "Charlie", + "Delta", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Golf", + "Golf", + "Hotel", + "Papa", + "Papa", + "Quebec", + "Victor", + "Victor", + "Yankee" + ], + "domain": { + "x": [ + 0, + 0.5 + ], + "y": [ + 0, + 0.3 + ] + } + }, + { + "type": "treemap", + "level": "Victor", + "texttemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "hovertemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "text": [ + "A L P H A", + "B R A V O", + "C H A R L I E", + "D E L T A", + "E C H O", + "F O X T R O T", + "G O L F", + "H O T E L", + "I N D I A", + "J U L I E T", + "K I L O", + "L I M A", + "M I K E", + "N O V E M B E R", + "O S C A R", + "P A P A", + "Q U E B E C", + "R O M E O", + "S I E R R A", + "T A N G O", + "U N I F O R M", + "V I C T O R", + "W H I S K E Y", + "X R A Y", + "Y A N K E E", + "Z U L U", + "" + ], + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu", + 0 + ], + "values": [ + 4000000, + 3000000, + 2000000, + 1000000, + 1000000, + 3000000, + 2000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 2000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 2000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000 + ], + "parents": [ + "", + "", + "", + "", + "", + "Alpha", + "Alpha", + "Alpha", + "Alpha", + "Bravo", + "Bravo", + "Bravo", + "Charlie", + "Charlie", + "Delta", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Golf", + "Golf", + "Hotel", + "Papa", + "Papa", + "Quebec", + "Victor", + "Victor", + "Yankee" + ], + "marker": { + "line": { + "color": "black", + "width": 2 + } + }, + "domain": { + "x": [ + 0.5, + 1 + ], + "y": [ + 0, + 0.3 + ] + } + }, + { + "type": "sunburst", + "maxdepth": 3, + "texttemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "hovertemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "text": [ + "A L P H A", + "B R A V O", + "C H A R L I E", + "D E L T A", + "E C H O", + "F O X T R O T", + "G O L F", + "H O T E L", + "I N D I A", + "J U L I E T", + "K I L O", + "L I M A", + "M I K E", + "N O V E M B E R", + "O S C A R", + "P A P A", + "Q U E B E C", + "R O M E O", + "S I E R R A", + "T A N G O", + "U N I F O R M", + "V I C T O R", + "W H I S K E Y", + "X R A Y", + "Y A N K E E", + "Z U L U", + "" + ], + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu", + 0 + ], + "values": [ + 4000000, + 3000000, + 2000000, + 1000000, + 1000000, + 3000000, + 2000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 2000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 2000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000 + ], + "parents": [ + "", + "", + "", + "", + "", + "Alpha", + "Alpha", + "Alpha", + "Alpha", + "Bravo", + "Bravo", + "Bravo", + "Charlie", + "Charlie", + "Delta", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Golf", + "Golf", + "Hotel", + "Papa", + "Papa", + "Quebec", + "Victor", + "Victor", + "Yankee" + ], + "domain": { + "x": [ + 0, + 0.5 + ], + "y": [ + 0.2, + 1 + ] + } + }, + { + "type": "sunburst", + "level": "Victor", + "texttemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "hovertemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "text": [ + "A L P H A", + "B R A V O", + "C H A R L I E", + "D E L T A", + "E C H O", + "F O X T R O T", + "G O L F", + "H O T E L", + "I N D I A", + "J U L I E T", + "K I L O", + "L I M A", + "M I K E", + "N O V E M B E R", + "O S C A R", + "P A P A", + "Q U E B E C", + "R O M E O", + "S I E R R A", + "T A N G O", + "U N I F O R M", + "V I C T O R", + "W H I S K E Y", + "X R A Y", + "Y A N K E E", + "Z U L U", + "" + ], + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu", + 0 + ], + "values": [ + 4000000, + 3000000, + 2000000, + 1000000, + 1000000, + 3000000, + 2000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 2000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000, + 2000000, + 1000000, + 1000000, + 1000000, + 1000000, + 1000000 + ], + "parents": [ + "", + "", + "", + "", + "", + "Alpha", + "Alpha", + "Alpha", + "Alpha", + "Bravo", + "Bravo", + "Bravo", + "Charlie", + "Charlie", + "Delta", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Golf", + "Golf", + "Hotel", + "Papa", + "Papa", + "Quebec", + "Victor", + "Victor", + "Yankee" + ], + "marker": { + "line": { + "color": "black", + "width": 2 + } + }, + "domain": { + "x": [ + 0.5, + 1 + ], + "y": [ + 0.2, + 1 + ] + } + } + ], + "layout": { + "width": 1200, + "height": 800, + "treemapcolorway": [ + "#8dd3c7", + "#ffffb3", + "#bebada", + "#fb8072", + "#80b1d3" + ], + "sunburstcolorway": [ + "#8dd3c7", + "#ffffb3", + "#bebada", + "#fb8072", + "#80b1d3" + ] + } +} diff --git a/test/image/mocks/treemap_packages_colorscale_allone.json b/test/image/mocks/treemap_packages_colorscale_allone.json new file mode 100644 index 00000000000..e8187fb9661 --- /dev/null +++ b/test/image/mocks/treemap_packages_colorscale_allone.json @@ -0,0 +1,2354 @@ +{ + "data": [ + { + "type": "treemap", + "count": "leaves+branches", + "maxdepth": 3, + "textinfo": "label+percent parent", + "hoverinfo": "all", + "tiling": { + "packing": "slice-dice" + }, + "pathbar": { + "side": "bottom" + }, + "marker": { + "line": { + "color": "#777" + }, + "colorscale": [ + [ + 0, + "#FFF" + ], + [ + 0.01, + "#FF0" + ], + [ + 0.1, + "#F00" + ], + [ + 1, + "#000" + ] + ], + "showscale": true + }, + "level": "1. gl-mesh3d", + "ids": [ + "Plotly.js v1.46.x external module counter", + "1. @plotly/d3-sankey", + "1. alpha-shape", + "1. array-range", + "1. canvas-fit", + "1. color-normalize", + "1. convex-hull", + "1. country-regex", + "1. d3", + "1. d3-force", + "1. d3-hierarchy", + "1. d3-interpolate", + "1. d3-sankey-circular", + "1. delaunay-triangulate", + "1. es6-promise", + "1. fast-isnumeric", + "1. font-atlas-sdf", + "1. gl-cone3d", + "1. gl-contour2d", + "1. gl-error3d", + "1. gl-heatmap2d", + "1. gl-line3d", + "1. gl-mat4", + "1. gl-mesh3d", + "1. gl-plot2d", + "1. gl-plot3d", + "1. gl-pointcloud2d", + "1. gl-scatter3d", + "1. gl-select-box", + "1. gl-spikes2d", + "1. gl-streamtube3d", + "1. gl-surface3d", + "1. gl-text", + "1. glslify", + "1. has-hover", + "1. has-passive-events", + "1. mapbox-gl", + "1. matrix-camera-controller", + "1. mouse-change", + "1. mouse-event-offset", + "1. mouse-wheel", + "1. ndarray", + "1. ndarray-fill", + "1. ndarray-homography", + "1. point-cluster", + "1. polybooljs", + "1. regl", + "1. regl-error2d", + "1. regl-line2d", + "1. regl-scatter2d", + "1. regl-splom", + "1. right-now", + "1. robust-orientation", + "1. sane-topojson", + "1. strongly-connected-components", + "1. superscript-text", + "1. svg-path-sdf", + "1. tinycolor2", + "1. topojson-client", + "1. webgl-context", + "1. world-calendars", + "2. 3d-view", + "2. @mapbox/gl-matrix", + "2. @mapbox/jsonlint-lines-primitives", + "2. @mapbox/mapbox-gl-supported", + "2. @mapbox/point-geometry", + "2. @mapbox/shelf-pack", + "2. @mapbox/tiny-sdf", + "2. @mapbox/unitbezier", + "2. @mapbox/vector-tile", + "2. @mapbox/whoots-js", + "2. a-big-triangle", + "2. affine-hull", + "2. alpha-complex", + "2. array-bounds", + "2. array-normalize", + "2. array-range", + "2. array-rearrange", + "2. barycentric", + "2. binary-search-bounds", + "2. bit-twiddle", + "2. bitmap-sdf", + "2. bl", + "2. brfs", + "2. bubleify", + "2. cdt2d", + "2. clamp", + "2. clean-pslg", + "2. color-alpha", + "2. color-id", + "2. color-normalize", + "2. color-rgba", + "2. colormap", + "2. commander", + "2. concat-stream", + "2. css-font", + "2. csscolorparser", + "2. cwise", + "2. d3-array", + "2. d3-collection", + "2. d3-color", + "2. d3-dispatch", + "2. d3-quadtree", + "2. d3-shape", + "2. d3-timer", + "2. defined", + "2. detect-kerning", + "2. draw-svg-path", + "2. dtype", + "2. dup", + "2. duplexify", + "2. earcut", + "2. element-size", + "2. elementary-circuits-directed-graph", + "2. es6-weak-map", + "2. falafel", + "2. flatten-vertex-data", + "2. font-atlas", + "2. font-measure", + "2. from2", + "2. geojson-rewind", + "2. geojson-vt", + "2. get-canvas-context", + "2. gl-axes3d", + "2. gl-buffer", + "2. gl-fbo", + "2. gl-mat4", + "2. gl-matrix-invert", + "2. gl-select-static", + "2. gl-shader", + "2. gl-spikes3d", + "2. gl-texture2d", + "2. gl-util", + "2. gl-vao", + "2. gl-vec3", + "2. glsl-inverse", + "2. glsl-out-of-range", + "2. glsl-read-float", + "2. glsl-resolve", + "2. glsl-specular-beckmann", + "2. glsl-specular-cook-torrance", + "2. glsl-token-whitespace-trim", + "2. glslify", + "2. glslify-bundle", + "2. glslify-deps", + "2. gray-matter", + "2. grid-index", + "2. has-passive-events", + "2. image-palette", + "2. incremental-convex-hull", + "2. iota-array", + "2. is-browser", + "2. is-buffer", + "2. is-iexplorer", + "2. is-mobile", + "2. is-obj", + "2. is-plain-obj", + "2. is-string-blank", + "2. is-svg-path", + "2. left-pad", + "2. mat4-interpolate", + "2. math-log2", + "2. minimist", + "2. monotone-convex-hull-2d", + "2. mouse-change", + "2. mouse-event", + "2. mouse-event-offset", + "2. mouse-wheel", + "2. ndarray", + "2. ndarray-gradient", + "2. ndarray-ops", + "2. ndarray-pack", + "2. ndarray-scratch", + "2. ndarray-warp", + "2. normals", + "2. object-assign", + "2. optical-properties", + "2. parse-rect", + "2. parse-svg-path", + "2. parse-unit", + "2. pbf", + "2. pick-by-alias", + "2. point-cluster", + "2. polytope-closest-point", + "2. quickselect", + "2. raf", + "2. regl", + "2. regl-scatter2d", + "2. resolve", + "2. right-now", + "2. robust-scale", + "2. robust-subtract", + "2. robust-sum", + "2. rw", + "2. shuffle-seed", + "2. signum", + "2. simplicial-complex-boundary", + "2. simplicial-complex-contour", + "2. sort-object", + "2. stack-trace", + "2. static-eval", + "2. supercluster", + "2. surface-nets", + "2. svg-path-bounds", + "2. text-cache", + "2. through2", + "2. tiny-sdf", + "2. tinyqueue", + "2. to-float32", + "2. to-px", + "2. two-product", + "2. typedarray-pool", + "2. uniq", + "2. update-diff", + "2. vectorize-text", + "2. vt-pbf", + "2. xtend", + "3. @choojs/findup", + "3. @mapbox/geojson-area", + "3. @mapbox/point-geometry", + "3. @mapbox/vector-tile", + "3. abs-svg-path", + "3. acorn", + "3. array-bounds", + "3. big-rat", + "3. binary-search-bounds", + "3. bit-twiddle", + "3. boundary-cells", + "3. box-intersect", + "3. buble", + "3. buffer-from", + "3. cdt2d", + "3. circumradius", + "3. clamp", + "3. clean-pslg", + "3. color-id", + "3. color-parse", + "3. color-space", + "3. concat-stream", + "3. css-font", + "3. css-font-size-keywords", + "3. css-font-stretch-keywords", + "3. css-font-style-keywords", + "3. css-font-weight-keywords", + "3. css-global-keywords", + "3. css-system-font-keywords", + "3. cwise", + "3. cwise-compiler", + "3. cwise-parser", + "3. d", + "3. d3-path", + "3. delaunay-triangulate", + "3. dtype", + "3. dup", + "3. end-of-stream", + "3. es5-ext", + "3. es6-iterator", + "3. es6-symbol", + "3. es6-weak-map", + "3. escodegen", + "3. events", + "3. extend-shallow", + "3. extract-frustum-planes", + "3. foreach", + "3. gl-buffer", + "3. gl-fbo", + "3. gl-format-compiler-error", + "3. gl-mat2", + "3. gl-mat3", + "3. gl-mat4", + "3. gl-shader", + "3. gl-state", + "3. gl-texture2d", + "3. gl-vao", + "3. gl-vec3", + "3. gl-vec4", + "3. glsl-inject-defines", + "3. glsl-resolve", + "3. glsl-specular-beckmann", + "3. glsl-token-defines", + "3. glsl-token-depth", + "3. glsl-token-descope", + "3. glsl-token-scope", + "3. glsl-token-string", + "3. glsl-token-whitespace-trim", + "3. glsl-tokenizer", + "3. glslify", + "3. graceful-fs", + "3. ieee754", + "3. inherits", + "3. is-browser", + "3. is-firefox", + "3. is-plain-obj", + "3. is-svg-path", + "3. isarray", + "3. js-yaml", + "3. kdbush", + "3. kind-of", + "3. lerp", + "3. map-limit", + "3. marching-simplex-table", + "3. mat4-decompose", + "3. mat4-recompose", + "3. matrix-camera-controller", + "3. minimist", + "3. murmurhash-js", + "3. ndarray", + "3. ndarray-extract-contour", + "3. ndarray-linear-interpolate", + "3. ndarray-ops", + "3. ndarray-sort", + "3. nextafter", + "3. normalize-svg-path", + "3. number-is-integer", + "3. numeric", + "3. object-assign", + "3. object-keys", + "3. orbit-camera-controller", + "3. parse-svg-path", + "3. parse-unit", + "3. path-parse", + "3. pbf", + "3. performance-now", + "3. pick-by-alias", + "3. planar-graph-to-polyline", + "3. pxls", + "3. quantize", + "3. quat-slerp", + "3. quote-stream", + "3. rat-vec", + "3. readable-stream", + "3. reduce-simplicial-complex", + "3. resolve", + "3. resolve-protobuf-schema", + "3. robust-in-sphere", + "3. robust-linear-solve", + "3. robust-orientation", + "3. robust-segment-intersect", + "3. safe-buffer", + "3. seedrandom", + "3. shallow-copy", + "3. sharkdown", + "3. simplicial-complex", + "3. simplify-planar-graph", + "3. sort-asc", + "3. sort-desc", + "3. split-polygon", + "3. static-module", + "3. stream-shift", + "3. string-split-by", + "3. strip-bom-string", + "3. strongly-connected-components", + "3. surface-nets", + "3. through2", + "3. triangulate-hypercube", + "3. triangulate-polyline", + "3. turntable-camera-controller", + "3. two-product", + "3. two-sum", + "3. typedarray", + "3. typedarray-pool", + "3. uglify-js", + "3. union-find", + "3. uniq", + "3. unquote", + "3. vectorize-text", + "3. weak-map", + "3. weakmap-shim", + "3. xtend", + "3. zero-crossings", + "4. acorn", + "4. acorn-dynamic-import", + "4. acorn-jsx", + "4. add-line-numbers", + "4. argparse", + "4. arr-flatten", + "4. big-rat", + "4. bit-twiddle", + "4. bn.js", + "4. buffer-equal", + "4. cardinal", + "4. cdt2d", + "4. cell-orientation", + "4. chalk", + "4. circumcenter", + "4. color-name", + "4. commander", + "4. compare-cell", + "4. compare-oriented-cell", + "4. compute-dims", + "4. concat-stream", + "4. convert-source-map", + "4. convex-hull", + "4. core-util-is", + "4. cwise-compiler", + "4. d", + "4. defined", + "4. double-bits", + "4. duplexer2", + "4. edges-to-adjacency-list", + "4. es5-ext", + "4. es6-iterator", + "4. es6-symbol", + "4. escodegen", + "4. esprima", + "4. estraverse", + "4. esutils", + "4. expect.js", + "4. falafel", + "4. filtered-vector", + "4. flip-pixels", + "4. gamma", + "4. gl-constants", + "4. gl-mat4", + "4. gl-quat", + "4. gl-vec3", + "4. glsl-shader-name", + "4. glsl-token-assignments", + "4. glsl-token-depth", + "4. glsl-token-inject-block", + "4. glsl-token-properties", + "4. glsl-token-scope", + "4. glsl-token-string", + "4. glsl-tokenizer", + "4. has", + "4. hsluv", + "4. inherits", + "4. is-browser", + "4. is-buffer", + "4. is-extendable", + "4. is-finite", + "4. is-plain-obj", + "4. isarray", + "4. magic-string", + "4. merge-source-map", + "4. minimist", + "4. mumath", + "4. next-tick", + "4. object-inspect", + "4. once", + "4. optionator", + "4. os-homedir", + "4. parenthesis", + "4. permutation-parity", + "4. permutation-rank", + "4. planar-dual", + "4. point-in-big-polygon", + "4. process-nextick-args", + "4. protocol-buffers-schema", + "4. quote-stream", + "4. readable-stream", + "4. robust-determinant", + "4. robust-dot-product", + "4. robust-orientation", + "4. robust-scale", + "4. robust-subtract", + "4. robust-sum", + "4. safe-buffer", + "4. shallow-copy", + "4. simplicial-complex", + "4. source-map", + "4. split", + "4. sprintf-js", + "4. static-eval", + "4. stream-spigot", + "4. string_decoder", + "4. svg-arc-to-cubic-bezier", + "4. tape", + "4. through", + "4. through2", + "4. to-uint8", + "4. two-product", + "4. typedarray-pool", + "4. uglify-to-browserify", + "4. union-find", + "4. uniq", + "4. util-deprecate", + "4. vlq", + "4. wgs84", + "4. yargs", + "5. acorn", + "5. almost-equal", + "5. ansi-styles", + "5. ansicolors", + "5. arr-flatten", + "5. atob-lite", + "5. binary-search-bounds", + "5. bit-twiddle", + "5. camelcase", + "5. cell-orientation", + "5. clamp", + "5. cliui", + "5. compare-angle", + "5. compare-cell", + "5. core-util-is", + "5. cubic-hermite", + "5. decamelize", + "5. deep-equal", + "5. deep-is", + "5. defined", + "5. dup", + "5. escape-string-regexp", + "5. escodegen", + "5. esprima", + "5. estraverse", + "5. esutils", + "5. fast-levenshtein", + "5. for-each", + "5. function-bind", + "5. gl-mat3", + "5. gl-vec3", + "5. gl-vec4", + "5. glob", + "5. glsl-tokenizer", + "5. has", + "5. inherits", + "5. interval-tree-1d", + "5. invert-permutation", + "5. is-base64", + "5. is-float-array", + "5. isarray", + "5. levn", + "5. minimist", + "5. number-is-nan", + "5. object-inspect", + "5. optionator", + "5. pad-left", + "5. prelude-ls", + "5. readable-stream", + "5. redeyed", + "5. resolve", + "5. resumer", + "5. robust-compress", + "5. robust-linear-solve", + "5. robust-orientation", + "5. robust-scale", + "5. robust-sum", + "5. safe-buffer", + "5. slab-decomposition", + "5. source-map", + "5. sprintf-js", + "5. string.prototype.trim", + "5. string_decoder", + "5. supports-color", + "5. through", + "5. through2", + "5. to-array-buffer", + "5. two-product", + "5. type-check", + "5. typedarray-pool", + "5. union-find", + "5. uniq", + "5. utils-copy", + "5. validate.io-array", + "5. validate.io-matrix-like", + "5. validate.io-ndarray-like", + "5. validate.io-positive-integer", + "5. vlq", + "5. window-size", + "5. wordwrap", + "5. wrappy", + "5. xtend", + "6. amdefine", + "6. binary-search-bounds", + "6. center-align", + "6. color-convert", + "6. const-pinf-float64", + "6. core-util-is", + "6. define-properties", + "6. es-abstract", + "6. esprima", + "6. estraverse", + "6. flatten-vertex-data", + "6. fs.realpath", + "6. function-bind", + "6. functional-red-black-tree", + "6. has-flag", + "6. inflight", + "6. inherits", + "6. is-blob", + "6. is-callable", + "6. isarray", + "6. minimatch", + "6. object-keys", + "6. once", + "6. path-is-absolute", + "6. prelude-ls", + "6. readable-stream", + "6. repeat-string", + "6. right-align", + "6. robust-orientation", + "6. robust-product", + "6. robust-sum", + "6. signum", + "6. source-map", + "6. string-to-arraybuffer", + "6. string_decoder", + "6. through", + "6. two-sum", + "6. type-check", + "6. type-name", + "6. utils-copy-error", + "6. utils-indexof", + "6. utils-regex-from-string", + "6. validate.io-array", + "6. validate.io-buffer", + "6. validate.io-integer", + "6. validate.io-nonnegative-integer", + "6. wordwrap", + "6. xtend" + ], + "parents": [ + "", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "1. @plotly/d3-sankey", + "1. @plotly/d3-sankey", + "1. @plotly/d3-sankey", + "1. alpha-shape", + "1. alpha-shape", + "1. canvas-fit", + "1. color-normalize", + "1. color-normalize", + "1. color-normalize", + "1. convex-hull", + "1. convex-hull", + "1. convex-hull", + "1. d3-force", + "1. d3-force", + "1. d3-force", + "1. d3-force", + "1. d3-interpolate", + "1. d3-sankey-circular", + "1. d3-sankey-circular", + "1. d3-sankey-circular", + "1. d3-sankey-circular", + "1. delaunay-triangulate", + "1. delaunay-triangulate", + "1. fast-isnumeric", + "1. font-atlas-sdf", + "1. font-atlas-sdf", + "1. gl-cone3d", + "1. gl-cone3d", + "1. gl-cone3d", + "1. gl-cone3d", + "1. gl-cone3d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-error3d", + "1. gl-error3d", + "1. gl-error3d", + "1. gl-error3d", + "1. gl-error3d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-pointcloud2d", + "1. gl-pointcloud2d", + "1. gl-pointcloud2d", + "1. gl-pointcloud2d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-select-box", + "1. gl-select-box", + "1. gl-select-box", + "1. gl-streamtube3d", + "1. gl-streamtube3d", + "1. gl-streamtube3d", + "1. gl-streamtube3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. has-hover", + "1. has-passive-events", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. matrix-camera-controller", + "1. matrix-camera-controller", + "1. matrix-camera-controller", + "1. matrix-camera-controller", + "1. mouse-change", + "1. mouse-wheel", + "1. mouse-wheel", + "1. mouse-wheel", + "1. ndarray", + "1. ndarray", + "1. ndarray-fill", + "1. ndarray-homography", + "1. ndarray-homography", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. robust-orientation", + "1. robust-orientation", + "1. robust-orientation", + "1. robust-orientation", + "1. svg-path-sdf", + "1. svg-path-sdf", + "1. svg-path-sdf", + "1. svg-path-sdf", + "1. svg-path-sdf", + "1. topojson-client", + "1. webgl-context", + "1. world-calendars", + "2. d3-shape", + "2. alpha-complex", + "2. alpha-complex", + "2. simplicial-complex-boundary", + "2. simplicial-complex-boundary", + "2. color-rgba", + "2. color-rgba", + "2. color-rgba", + "2. affine-hull", + "2. incremental-convex-hull", + "2. incremental-convex-hull", + "2. monotone-convex-hull-2d", + "2. elementary-circuits-directed-graph", + "2. gl-shader", + "2. gl-shader", + "2. cdt2d", + "2. cdt2d", + "2. cdt2d", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. gl-buffer", + "2. gl-buffer", + "2. gl-buffer", + "2. surface-nets", + "2. surface-nets", + "2. surface-nets", + "2. typedarray-pool", + "2. typedarray-pool", + "2. gl-texture2d", + "2. gl-texture2d", + "2. gl-texture2d", + "2. barycentric", + "2. colormap", + "2. glsl-specular-cook-torrance", + "2. polytope-closest-point", + "2. simplicial-complex-contour", + "2. simplicial-complex-contour", + "2. simplicial-complex-contour", + "2. simplicial-complex-contour", + "2. gl-select-static", + "2. gl-select-static", + "2. gl-select-static", + "2. gl-select-static", + "2. gl-select-static", + "2. text-cache", + "2. 3d-view", + "2. 3d-view", + "2. 3d-view", + "2. a-big-triangle", + "2. a-big-triangle", + "2. a-big-triangle", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-fbo", + "2. gl-spikes3d", + "2. gl-spikes3d", + "2. gl-spikes3d", + "2. gl-spikes3d", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. ndarray-gradient", + "2. ndarray-gradient", + "2. ndarray-ops", + "2. ndarray-pack", + "2. ndarray-pack", + "2. ndarray-scratch", + "2. ndarray-scratch", + "2. ndarray-scratch", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. es6-weak-map", + "2. es6-weak-map", + "2. es6-weak-map", + "2. es6-weak-map", + "2. flatten-vertex-data", + "2. font-atlas", + "2. font-measure", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. parse-rect", + "2. to-px", + "2. bl", + "2. bl", + "2. concat-stream", + "2. concat-stream", + "2. concat-stream", + "2. concat-stream", + "2. duplexify", + "2. duplexify", + "2. duplexify", + "2. duplexify", + "2. falafel", + "2. falafel", + "2. falafel", + "2. falafel", + "2. from2", + "2. from2", + "2. glsl-resolve", + "2. glsl-resolve", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. through2", + "2. through2", + "2. resolve", + "2. static-eval", + "2. @mapbox/vector-tile", + "2. geojson-rewind", + "2. geojson-rewind", + "2. geojson-rewind", + "2. geojson-rewind", + "2. gray-matter", + "2. gray-matter", + "2. gray-matter", + "2. gray-matter", + "2. brfs", + "2. brfs", + "2. brfs", + "2. brfs", + "2. through2", + "2. through2", + "2. pbf", + "2. pbf", + "2. shuffle-seed", + "2. sort-object", + "2. sort-object", + "2. supercluster", + "2. vt-pbf", + "2. vt-pbf", + "2. vt-pbf", + "2. mat4-interpolate", + "2. mat4-interpolate", + "2. mat4-interpolate", + "2. mat4-interpolate", + "2. mat4-interpolate", + "2. cwise", + "2. cwise", + "2. cwise", + "2. cwise", + "2. gl-matrix-invert", + "2. gl-matrix-invert", + "2. gl-matrix-invert", + "2. ndarray-warp", + "2. ndarray-warp", + "2. array-normalize", + "2. bubleify", + "2. color-id", + "2. image-palette", + "2. image-palette", + "2. image-palette", + "2. color-alpha", + "2. raf", + "2. robust-scale", + "2. robust-scale", + "2. bitmap-sdf", + "2. draw-svg-path", + "2. draw-svg-path", + "2. svg-path-bounds", + "2. svg-path-bounds", + "2. svg-path-bounds", + "2. svg-path-bounds", + "3. circumradius", + "3. boundary-cells", + "3. reduce-simplicial-complex", + "3. reduce-simplicial-complex", + "3. reduce-simplicial-complex", + "3. color-parse", + "3. color-parse", + "3. color-parse", + "3. color-space", + "3. color-space", + "3. simplicial-complex", + "3. simplicial-complex", + "3. gl-format-compiler-error", + "3. gl-format-compiler-error", + "3. gl-format-compiler-error", + "3. gl-format-compiler-error", + "3. robust-in-sphere", + "3. robust-in-sphere", + "3. robust-in-sphere", + "3. robust-in-sphere", + "3. big-rat", + "3. big-rat", + "3. big-rat", + "3. box-intersect", + "3. box-intersect", + "3. nextafter", + "3. rat-vec", + "3. robust-segment-intersect", + "3. ndarray-extract-contour", + "3. triangulate-hypercube", + "3. triangulate-hypercube", + "3. triangulate-hypercube", + "3. zero-crossings", + "3. robust-linear-solve", + "3. marching-simplex-table", + "3. ndarray-sort", + "3. orbit-camera-controller", + "3. orbit-camera-controller", + "3. turntable-camera-controller", + "3. turntable-camera-controller", + "3. turntable-camera-controller", + "3. gl-state", + "3. split-polygon", + "3. split-polygon", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. simplify-planar-graph", + "3. simplify-planar-graph", + "3. triangulate-polyline", + "3. cwise-compiler", + "3. string-split-by", + "3. d", + "3. es5-ext", + "3. es5-ext", + "3. es5-ext", + "3. es6-iterator", + "3. es6-iterator", + "3. es6-iterator", + "3. es6-symbol", + "3. es6-symbol", + "3. number-is-integer", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. end-of-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. glsl-inject-defines", + "3. glsl-inject-defines", + "3. glsl-inject-defines", + "3. glsl-token-defines", + "3. glsl-token-descope", + "3. glsl-token-descope", + "3. glsl-token-descope", + "3. glsl-token-descope", + "3. glsl-tokenizer", + "3. @choojs/findup", + "3. map-limit", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. escodegen", + "3. escodegen", + "3. escodegen", + "3. escodegen", + "3. escodegen", + "3. @mapbox/geojson-area", + "3. sharkdown", + "3. sharkdown", + "3. sharkdown", + "3. sharkdown", + "3. sharkdown", + "3. sharkdown", + "3. extend-shallow", + "3. js-yaml", + "3. js-yaml", + "3. quote-stream", + "3. quote-stream", + "3. quote-stream", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. resolve-protobuf-schema", + "3. mat4-decompose", + "3. mat4-decompose", + "3. mat4-recompose", + "3. quat-slerp", + "3. cwise-parser", + "3. cwise-parser", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. uglify-js", + "3. uglify-js", + "3. uglify-js", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. pxls", + "3. pxls", + "3. pxls", + "3. pxls", + "3. pxls", + "3. pxls", + "3. normalize-svg-path", + "4. circumcenter", + "4. circumcenter", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. compare-oriented-cell", + "4. compare-oriented-cell", + "4. mumath", + "4. add-line-numbers", + "4. glsl-shader-name", + "4. glsl-shader-name", + "4. permutation-parity", + "4. permutation-rank", + "4. permutation-rank", + "4. robust-determinant", + "4. robust-determinant", + "4. robust-determinant", + "4. robust-determinant", + "4. filtered-vector", + "4. filtered-vector", + "4. robust-dot-product", + "4. robust-dot-product", + "4. edges-to-adjacency-list", + "4. planar-dual", + "4. planar-dual", + "4. point-in-big-polygon", + "4. point-in-big-polygon", + "4. point-in-big-polygon", + "4. point-in-big-polygon", + "4. simplicial-complex", + "4. simplicial-complex", + "4. is-finite", + "4. string_decoder", + "4. string_decoder", + "4. string_decoder", + "4. once", + "4. string_decoder", + "4. through2", + "4. through2", + "4. once", + "4. string_decoder", + "4. optionator", + "4. optionator", + "4. optionator", + "4. optionator", + "4. optionator", + "4. optionator", + "4. cardinal", + "4. cardinal", + "4. split", + "4. stream-spigot", + "4. argparse", + "4. has", + "4. magic-string", + "4. duplexer2", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. merge-source-map", + "4. string_decoder", + "4. gl-quat", + "4. gl-quat", + "4. gl-quat", + "4. duplexer2", + "4. quote-stream", + "4. quote-stream", + "4. readable-stream", + "4. readable-stream", + "4. readable-stream", + "4. readable-stream", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. static-eval", + "4. through2", + "4. through2", + "4. yargs", + "4. yargs", + "4. yargs", + "4. yargs", + "4. acorn-dynamic-import", + "4. acorn-jsx", + "4. chalk", + "4. chalk", + "4. chalk", + "4. compute-dims", + "4. compute-dims", + "4. compute-dims", + "4. compute-dims", + "4. compute-dims", + "4. to-uint8", + "4. to-uint8", + "4. to-uint8", + "4. to-uint8", + "4. to-uint8" + ], + "labels": [ + "Plotly.js v1.46.x external module counter", + "1. @plotly/d3-sankey", + "1. alpha-shape", + "1. array-range", + "1. canvas-fit", + "1. color-normalize", + "1. convex-hull", + "1. country-regex", + "1. d3", + "1. d3-force", + "1. d3-hierarchy", + "1. d3-interpolate", + "1. d3-sankey-circular", + "1. delaunay-triangulate", + "1. es6-promise", + "1. fast-isnumeric", + "1. font-atlas-sdf", + "1. gl-cone3d", + "1. gl-contour2d", + "1. gl-error3d", + "1. gl-heatmap2d", + "1. gl-line3d", + "1. gl-mat4", + "1. gl-mesh3d", + "1. gl-plot2d", + "1. gl-plot3d", + "1. gl-pointcloud2d", + "1. gl-scatter3d", + "1. gl-select-box", + "1. gl-spikes2d", + "1. gl-streamtube3d", + "1. gl-surface3d", + "1. gl-text", + "1. glslify", + "1. has-hover", + "1. has-passive-events", + "1. mapbox-gl", + "1. matrix-camera-controller", + "1. mouse-change", + "1. mouse-event-offset", + "1. mouse-wheel", + "1. ndarray", + "1. ndarray-fill", + "1. ndarray-homography", + "1. point-cluster", + "1. polybooljs", + "1. regl", + "1. regl-error2d", + "1. regl-line2d", + "1. regl-scatter2d", + "1. regl-splom", + "1. right-now", + "1. robust-orientation", + "1. sane-topojson", + "1. strongly-connected-components", + "1. superscript-text", + "1. svg-path-sdf", + "1. tinycolor2", + "1. topojson-client", + "1. webgl-context", + "1. world-calendars", + "2. d3-array", + "2. d3-collection", + "2. d3-shape", + "2. alpha-complex", + "2. simplicial-complex-boundary", + "2. element-size", + "2. clamp", + "2. color-rgba", + "2. dtype", + "2. affine-hull", + "2. incremental-convex-hull", + "2. monotone-convex-hull-2d", + "2. d3-collection", + "2. d3-dispatch", + "2. d3-quadtree", + "2. d3-timer", + "2. d3-color", + "2. d3-array", + "2. d3-collection", + "2. d3-shape", + "2. elementary-circuits-directed-graph", + "2. incremental-convex-hull", + "2. uniq", + "2. is-string-blank", + "2. optical-properties", + "2. tiny-sdf", + "2. gl-shader", + "2. gl-vec3", + "2. glsl-inverse", + "2. glsl-out-of-range", + "2. glslify", + "2. cdt2d", + "2. clean-pslg", + "2. gl-buffer", + "2. binary-search-bounds", + "2. gl-shader", + "2. glslify", + "2. iota-array", + "2. ndarray", + "2. surface-nets", + "2. gl-buffer", + "2. gl-shader", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glslify", + "2. gl-buffer", + "2. binary-search-bounds", + "2. gl-shader", + "2. glslify", + "2. iota-array", + "2. typedarray-pool", + "2. gl-buffer", + "2. binary-search-bounds", + "2. gl-shader", + "2. gl-texture2d", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glsl-read-float", + "2. glslify", + "2. ndarray", + "2. barycentric", + "2. colormap", + "2. gl-buffer", + "2. gl-mat4", + "2. gl-shader", + "2. gl-texture2d", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glsl-specular-cook-torrance", + "2. glslify", + "2. ndarray", + "2. normals", + "2. polytope-closest-point", + "2. simplicial-complex-contour", + "2. typedarray-pool", + "2. gl-buffer", + "2. binary-search-bounds", + "2. gl-select-static", + "2. gl-shader", + "2. glsl-inverse", + "2. glslify", + "2. text-cache", + "2. 3d-view", + "2. a-big-triangle", + "2. gl-axes3d", + "2. gl-fbo", + "2. gl-mat4", + "2. gl-select-static", + "2. gl-shader", + "2. gl-spikes3d", + "2. glslify", + "2. has-passive-events", + "2. is-mobile", + "2. mouse-change", + "2. mouse-event-offset", + "2. mouse-wheel", + "2. ndarray", + "2. right-now", + "2. gl-buffer", + "2. gl-shader", + "2. glslify", + "2. typedarray-pool", + "2. gl-buffer", + "2. gl-mat4", + "2. gl-shader", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glslify", + "2. is-string-blank", + "2. typedarray-pool", + "2. vectorize-text", + "2. gl-buffer", + "2. gl-shader", + "2. glslify", + "2. gl-vec3", + "2. glsl-inverse", + "2. glsl-out-of-range", + "2. glslify", + "2. bit-twiddle", + "2. colormap", + "2. dup", + "2. gl-buffer", + "2. gl-mat4", + "2. gl-shader", + "2. binary-search-bounds", + "2. gl-texture2d", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glsl-specular-beckmann", + "2. glslify", + "2. ndarray", + "2. ndarray-gradient", + "2. ndarray-ops", + "2. ndarray-pack", + "2. ndarray-scratch", + "2. surface-nets", + "2. typedarray-pool", + "2. bit-twiddle", + "2. color-normalize", + "2. css-font", + "2. detect-kerning", + "2. es6-weak-map", + "2. flatten-vertex-data", + "2. font-atlas", + "2. font-measure", + "2. gl-util", + "2. is-plain-obj", + "2. object-assign", + "2. parse-rect", + "2. parse-unit", + "2. pick-by-alias", + "2. regl", + "2. to-px", + "2. typedarray-pool", + "2. bl", + "2. concat-stream", + "2. duplexify", + "2. falafel", + "2. from2", + "2. glsl-resolve", + "2. glsl-token-whitespace-trim", + "2. glslify-bundle", + "2. glslify-deps", + "2. through2", + "2. minimist", + "2. resolve", + "2. stack-trace", + "2. static-eval", + "2. xtend", + "2. is-browser", + "2. is-browser", + "2. @mapbox/gl-matrix", + "2. @mapbox/jsonlint-lines-primitives", + "2. @mapbox/mapbox-gl-supported", + "2. @mapbox/point-geometry", + "2. @mapbox/shelf-pack", + "2. @mapbox/tiny-sdf", + "2. @mapbox/unitbezier", + "2. @mapbox/vector-tile", + "2. @mapbox/whoots-js", + "2. csscolorparser", + "2. earcut", + "2. geojson-rewind", + "2. geojson-vt", + "2. gray-matter", + "2. grid-index", + "2. brfs", + "2. minimist", + "2. through2", + "2. pbf", + "2. quickselect", + "2. rw", + "2. shuffle-seed", + "2. sort-object", + "2. supercluster", + "2. tinyqueue", + "2. vt-pbf", + "2. binary-search-bounds", + "2. gl-mat4", + "2. gl-vec3", + "2. mat4-interpolate", + "2. mouse-event", + "2. signum", + "2. right-now", + "2. to-px", + "2. iota-array", + "2. is-buffer", + "2. cwise", + "2. gl-matrix-invert", + "2. ndarray-warp", + "2. array-bounds", + "2. array-normalize", + "2. bubleify", + "2. clamp", + "2. dtype", + "2. flatten-vertex-data", + "2. is-obj", + "2. math-log2", + "2. parse-rect", + "2. binary-search-bounds", + "2. array-bounds", + "2. bubleify", + "2. color-normalize", + "2. flatten-vertex-data", + "2. object-assign", + "2. pick-by-alias", + "2. to-float32", + "2. update-diff", + "2. array-bounds", + "2. array-normalize", + "2. bubleify", + "2. color-normalize", + "2. earcut", + "2. es6-weak-map", + "2. flatten-vertex-data", + "2. glslify", + "2. object-assign", + "2. parse-rect", + "2. pick-by-alias", + "2. to-float32", + "2. array-range", + "2. array-rearrange", + "2. clamp", + "2. color-id", + "2. color-normalize", + "2. color-rgba", + "2. flatten-vertex-data", + "2. glslify", + "2. image-palette", + "2. is-iexplorer", + "2. object-assign", + "2. parse-rect", + "2. pick-by-alias", + "2. point-cluster", + "2. to-float32", + "2. update-diff", + "2. array-bounds", + "2. array-range", + "2. bubleify", + "2. color-alpha", + "2. defined", + "2. flatten-vertex-data", + "2. left-pad", + "2. parse-rect", + "2. pick-by-alias", + "2. point-cluster", + "2. raf", + "2. regl-scatter2d", + "2. robust-scale", + "2. robust-subtract", + "2. robust-sum", + "2. two-product", + "2. bitmap-sdf", + "2. draw-svg-path", + "2. is-svg-path", + "2. parse-svg-path", + "2. svg-path-bounds", + "2. commander", + "2. get-canvas-context", + "2. object-assign", + "3. d3-path", + "3. circumradius", + "3. delaunay-triangulate", + "3. boundary-cells", + "3. reduce-simplicial-complex", + "3. clamp", + "3. color-parse", + "3. color-space", + "3. robust-orientation", + "3. robust-orientation", + "3. simplicial-complex", + "3. robust-orientation", + "3. strongly-connected-components", + "3. gl-format-compiler-error", + "3. weakmap-shim", + "3. binary-search-bounds", + "3. robust-in-sphere", + "3. robust-orientation", + "3. big-rat", + "3. box-intersect", + "3. nextafter", + "3. rat-vec", + "3. robust-segment-intersect", + "3. union-find", + "3. uniq", + "3. ndarray", + "3. ndarray-ops", + "3. typedarray-pool", + "3. ndarray-extract-contour", + "3. triangulate-hypercube", + "3. zero-crossings", + "3. bit-twiddle", + "3. dup", + "3. ndarray", + "3. ndarray-ops", + "3. typedarray-pool", + "3. robust-linear-solve", + "3. lerp", + "3. glsl-specular-beckmann", + "3. numeric", + "3. marching-simplex-table", + "3. ndarray", + "3. ndarray-sort", + "3. typedarray-pool", + "3. bit-twiddle", + "3. cwise", + "3. gl-fbo", + "3. ndarray", + "3. typedarray-pool", + "3. vectorize-text", + "3. matrix-camera-controller", + "3. orbit-camera-controller", + "3. turntable-camera-controller", + "3. gl-buffer", + "3. gl-vao", + "3. weak-map", + "3. bit-twiddle", + "3. dup", + "3. extract-frustum-planes", + "3. gl-buffer", + "3. gl-mat4", + "3. gl-shader", + "3. gl-state", + "3. gl-vao", + "3. gl-vec4", + "3. glslify", + "3. robust-orientation", + "3. split-polygon", + "3. vectorize-text", + "3. gl-texture2d", + "3. gl-buffer", + "3. gl-shader", + "3. gl-vao", + "3. glslify", + "3. cdt2d", + "3. clean-pslg", + "3. ndarray", + "3. planar-graph-to-polyline", + "3. simplify-planar-graph", + "3. surface-nets", + "3. triangulate-polyline", + "3. cwise-compiler", + "3. dup", + "3. cwise-compiler", + "3. cwise-compiler", + "3. ndarray", + "3. ndarray", + "3. ndarray-ops", + "3. typedarray-pool", + "3. css-font-size-keywords", + "3. css-font-stretch-keywords", + "3. css-font-style-keywords", + "3. css-font-weight-keywords", + "3. css-global-keywords", + "3. css-system-font-keywords", + "3. pick-by-alias", + "3. string-split-by", + "3. unquote", + "3. d", + "3. es5-ext", + "3. es6-iterator", + "3. es6-symbol", + "3. dtype", + "3. css-font", + "3. css-font", + "3. es6-weak-map", + "3. is-browser", + "3. is-firefox", + "3. is-plain-obj", + "3. number-is-integer", + "3. object-assign", + "3. pick-by-alias", + "3. pick-by-alias", + "3. parse-unit", + "3. readable-stream", + "3. safe-buffer", + "3. buffer-from", + "3. readable-stream", + "3. inherits", + "3. typedarray", + "3. readable-stream", + "3. end-of-stream", + "3. inherits", + "3. stream-shift", + "3. acorn", + "3. foreach", + "3. isarray", + "3. object-keys", + "3. readable-stream", + "3. inherits", + "3. resolve", + "3. xtend", + "3. glsl-inject-defines", + "3. glsl-token-defines", + "3. glsl-token-depth", + "3. glsl-token-descope", + "3. glsl-token-scope", + "3. glsl-token-string", + "3. glsl-token-whitespace-trim", + "3. glsl-tokenizer", + "3. murmurhash-js", + "3. shallow-copy", + "3. @choojs/findup", + "3. events", + "3. glsl-resolve", + "3. glsl-tokenizer", + "3. graceful-fs", + "3. inherits", + "3. map-limit", + "3. resolve", + "3. readable-stream", + "3. xtend", + "3. path-parse", + "3. escodegen", + "3. @mapbox/point-geometry", + "3. @mapbox/geojson-area", + "3. concat-stream", + "3. minimist", + "3. sharkdown", + "3. extend-shallow", + "3. kind-of", + "3. js-yaml", + "3. strip-bom-string", + "3. quote-stream", + "3. static-module", + "3. through2", + "3. resolve", + "3. readable-stream", + "3. xtend", + "3. ieee754", + "3. resolve-protobuf-schema", + "3. seedrandom", + "3. sort-asc", + "3. sort-desc", + "3. kdbush", + "3. @mapbox/point-geometry", + "3. @mapbox/vector-tile", + "3. pbf", + "3. gl-mat4", + "3. gl-vec3", + "3. mat4-decompose", + "3. mat4-recompose", + "3. quat-slerp", + "3. cwise-compiler", + "3. cwise-parser", + "3. static-module", + "3. uglify-js", + "3. gl-mat2", + "3. gl-mat3", + "3. gl-mat4", + "3. cwise", + "3. ndarray-linear-interpolate", + "3. array-bounds", + "3. buble", + "3. clamp", + "3. color-id", + "3. pxls", + "3. quantize", + "3. color-parse", + "3. performance-now", + "3. two-product", + "3. two-sum", + "3. clamp", + "3. abs-svg-path", + "3. normalize-svg-path", + "3. abs-svg-path", + "3. is-svg-path", + "3. parse-svg-path", + "3. normalize-svg-path", + "4. circumcenter", + "4. tape", + "4. cell-orientation", + "4. compare-cell", + "4. compare-oriented-cell", + "4. color-name", + "4. defined", + "4. is-plain-obj", + "4. hsluv", + "4. mumath", + "4. bit-twiddle", + "4. union-find", + "4. add-line-numbers", + "4. gl-constants", + "4. glsl-shader-name", + "4. sprintf-js", + "4. robust-scale", + "4. robust-subtract", + "4. robust-sum", + "4. two-product", + "4. bit-twiddle", + "4. bn.js", + "4. double-bits", + "4. bit-twiddle", + "4. typedarray-pool", + "4. double-bits", + "4. big-rat", + "4. robust-orientation", + "4. typedarray-pool", + "4. gamma", + "4. permutation-parity", + "4. permutation-rank", + "4. cwise-compiler", + "4. robust-determinant", + "4. convex-hull", + "4. typedarray-pool", + "4. filtered-vector", + "4. gl-mat4", + "4. filtered-vector", + "4. gl-mat4", + "4. gl-vec3", + "4. uniq", + "4. robust-dot-product", + "4. robust-sum", + "4. edges-to-adjacency-list", + "4. planar-dual", + "4. point-in-big-polygon", + "4. robust-orientation", + "4. robust-sum", + "4. two-product", + "4. uniq", + "4. robust-orientation", + "4. simplicial-complex", + "4. cdt2d", + "4. uniq", + "4. parenthesis", + "4. es5-ext", + "4. es6-iterator", + "4. es6-symbol", + "4. next-tick", + "4. d", + "4. es5-ext", + "4. es6-symbol", + "4. d", + "4. es5-ext", + "4. is-finite", + "4. isarray", + "4. string_decoder", + "4. core-util-is", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. isarray", + "4. string_decoder", + "4. core-util-is", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. core-util-is", + "4. isarray", + "4. string_decoder", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. once", + "4. core-util-is", + "4. isarray", + "4. string_decoder", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. glsl-token-inject-block", + "4. glsl-token-string", + "4. glsl-tokenizer", + "4. glsl-tokenizer", + "4. glsl-token-assignments", + "4. glsl-token-depth", + "4. glsl-token-properties", + "4. glsl-token-scope", + "4. through2", + "4. commander", + "4. once", + "4. core-util-is", + "4. isarray", + "4. string_decoder", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. esprima", + "4. estraverse", + "4. esutils", + "4. optionator", + "4. source-map", + "4. wgs84", + "4. cardinal", + "4. expect.js", + "4. minimist", + "4. split", + "4. stream-spigot", + "4. through", + "4. is-extendable", + "4. argparse", + "4. esprima", + "4. buffer-equal", + "4. minimist", + "4. through2", + "4. concat-stream", + "4. convert-source-map", + "4. falafel", + "4. has", + "4. magic-string", + "4. duplexer2", + "4. escodegen", + "4. object-inspect", + "4. quote-stream", + "4. readable-stream", + "4. through2", + "4. merge-source-map", + "4. shallow-copy", + "4. static-eval", + "4. core-util-is", + "4. inherits", + "4. isarray", + "4. string_decoder", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. protocol-buffers-schema", + "4. gl-mat4", + "4. gl-vec3", + "4. gl-mat4", + "4. gl-quat", + "4. esprima", + "4. uniq", + "4. concat-stream", + "4. duplexer2", + "4. falafel", + "4. has", + "4. quote-stream", + "4. readable-stream", + "4. shallow-copy", + "4. escodegen", + "4. object-inspect", + "4. static-eval", + "4. through2", + "4. source-map", + "4. uglify-to-browserify", + "4. yargs", + "4. acorn", + "4. acorn-dynamic-import", + "4. acorn-jsx", + "4. vlq", + "4. chalk", + "4. magic-string", + "4. minimist", + "4. os-homedir", + "4. arr-flatten", + "4. compute-dims", + "4. flip-pixels", + "4. is-browser", + "4. is-buffer", + "4. to-uint8", + "4. svg-arc-to-cubic-bezier", + "5. dup", + "5. robust-linear-solve", + "5. deep-equal", + "5. defined", + "5. for-each", + "5. function-bind", + "5. glob", + "5. has", + "5. inherits", + "5. minimist", + "5. object-inspect", + "5. resolve", + "5. resumer", + "5. string.prototype.trim", + "5. through", + "5. cell-orientation", + "5. compare-cell", + "5. almost-equal", + "5. pad-left", + "5. atob-lite", + "5. glsl-tokenizer", + "5. typedarray-pool", + "5. invert-permutation", + "5. typedarray-pool", + "5. robust-compress", + "5. robust-scale", + "5. robust-sum", + "5. two-product", + "5. binary-search-bounds", + "5. cubic-hermite", + "5. robust-sum", + "5. two-product", + "5. uniq", + "5. compare-angle", + "5. dup", + "5. binary-search-bounds", + "5. interval-tree-1d", + "5. robust-orientation", + "5. slab-decomposition", + "5. bit-twiddle", + "5. union-find", + "5. number-is-nan", + "5. safe-buffer", + "5. safe-buffer", + "5. safe-buffer", + "5. wrappy", + "5. safe-buffer", + "5. readable-stream", + "5. xtend", + "5. wrappy", + "5. safe-buffer", + "5. deep-is", + "5. fast-levenshtein", + "5. levn", + "5. prelude-ls", + "5. type-check", + "5. wordwrap", + "5. ansicolors", + "5. redeyed", + "5. through", + "5. readable-stream", + "5. sprintf-js", + "5. function-bind", + "5. vlq", + "5. readable-stream", + "5. esprima", + "5. estraverse", + "5. esutils", + "5. optionator", + "5. source-map", + "5. source-map", + "5. safe-buffer", + "5. gl-mat3", + "5. gl-vec3", + "5. gl-vec4", + "5. readable-stream", + "5. minimist", + "5. through2", + "5. core-util-is", + "5. inherits", + "5. isarray", + "5. string_decoder", + "5. esprima", + "5. estraverse", + "5. esutils", + "5. source-map", + "5. escodegen", + "5. readable-stream", + "5. xtend", + "5. camelcase", + "5. cliui", + "5. decamelize", + "5. window-size", + "5. acorn", + "5. acorn", + "5. ansi-styles", + "5. escape-string-regexp", + "5. supports-color", + "5. utils-copy", + "5. validate.io-array", + "5. validate.io-matrix-like", + "5. validate.io-ndarray-like", + "5. validate.io-positive-integer", + "5. arr-flatten", + "5. clamp", + "5. is-base64", + "5. is-float-array", + "5. to-array-buffer" + ] + } + ], + "layout": { + "width": 800, + "height": 800 + } +} diff --git a/test/image/mocks/treemap_packages_colorscale_novalue.json b/test/image/mocks/treemap_packages_colorscale_novalue.json new file mode 100644 index 00000000000..99d8aa5e21b --- /dev/null +++ b/test/image/mocks/treemap_packages_colorscale_novalue.json @@ -0,0 +1,2329 @@ +{ + "data": [ + { + "type": "treemap", + "maxdepth": 3, + "textinfo": "label+percent parent", + "hoverinfo": "all", + "marker": { + "line": { + "color": "#777" + }, + "colorscale": [[0, "#FFF"], [0.01, "#FF0"], [0.1, "#F00"], [1, "#000"]], + "showscale": true + }, + "ids": [ + "Plotly.js v1.46.x external module counter", + "1. @plotly/d3-sankey", + "1. alpha-shape", + "1. array-range", + "1. canvas-fit", + "1. color-normalize", + "1. convex-hull", + "1. country-regex", + "1. d3", + "1. d3-force", + "1. d3-hierarchy", + "1. d3-interpolate", + "1. d3-sankey-circular", + "1. delaunay-triangulate", + "1. es6-promise", + "1. fast-isnumeric", + "1. font-atlas-sdf", + "1. gl-cone3d", + "1. gl-contour2d", + "1. gl-error3d", + "1. gl-heatmap2d", + "1. gl-line3d", + "1. gl-mat4", + "1. gl-mesh3d", + "1. gl-plot2d", + "1. gl-plot3d", + "1. gl-pointcloud2d", + "1. gl-scatter3d", + "1. gl-select-box", + "1. gl-spikes2d", + "1. gl-streamtube3d", + "1. gl-surface3d", + "1. gl-text", + "1. glslify", + "1. has-hover", + "1. has-passive-events", + "1. mapbox-gl", + "1. matrix-camera-controller", + "1. mouse-change", + "1. mouse-event-offset", + "1. mouse-wheel", + "1. ndarray", + "1. ndarray-fill", + "1. ndarray-homography", + "1. point-cluster", + "1. polybooljs", + "1. regl", + "1. regl-error2d", + "1. regl-line2d", + "1. regl-scatter2d", + "1. regl-splom", + "1. right-now", + "1. robust-orientation", + "1. sane-topojson", + "1. strongly-connected-components", + "1. superscript-text", + "1. svg-path-sdf", + "1. tinycolor2", + "1. topojson-client", + "1. webgl-context", + "1. world-calendars", + "2. 3d-view", + "2. @mapbox/gl-matrix", + "2. @mapbox/jsonlint-lines-primitives", + "2. @mapbox/mapbox-gl-supported", + "2. @mapbox/point-geometry", + "2. @mapbox/shelf-pack", + "2. @mapbox/tiny-sdf", + "2. @mapbox/unitbezier", + "2. @mapbox/vector-tile", + "2. @mapbox/whoots-js", + "2. a-big-triangle", + "2. affine-hull", + "2. alpha-complex", + "2. array-bounds", + "2. array-normalize", + "2. array-range", + "2. array-rearrange", + "2. barycentric", + "2. binary-search-bounds", + "2. bit-twiddle", + "2. bitmap-sdf", + "2. bl", + "2. brfs", + "2. bubleify", + "2. cdt2d", + "2. clamp", + "2. clean-pslg", + "2. color-alpha", + "2. color-id", + "2. color-normalize", + "2. color-rgba", + "2. colormap", + "2. commander", + "2. concat-stream", + "2. css-font", + "2. csscolorparser", + "2. cwise", + "2. d3-array", + "2. d3-collection", + "2. d3-color", + "2. d3-dispatch", + "2. d3-quadtree", + "2. d3-shape", + "2. d3-timer", + "2. defined", + "2. detect-kerning", + "2. draw-svg-path", + "2. dtype", + "2. dup", + "2. duplexify", + "2. earcut", + "2. element-size", + "2. elementary-circuits-directed-graph", + "2. es6-weak-map", + "2. falafel", + "2. flatten-vertex-data", + "2. font-atlas", + "2. font-measure", + "2. from2", + "2. geojson-rewind", + "2. geojson-vt", + "2. get-canvas-context", + "2. gl-axes3d", + "2. gl-buffer", + "2. gl-fbo", + "2. gl-mat4", + "2. gl-matrix-invert", + "2. gl-select-static", + "2. gl-shader", + "2. gl-spikes3d", + "2. gl-texture2d", + "2. gl-util", + "2. gl-vao", + "2. gl-vec3", + "2. glsl-inverse", + "2. glsl-out-of-range", + "2. glsl-read-float", + "2. glsl-resolve", + "2. glsl-specular-beckmann", + "2. glsl-specular-cook-torrance", + "2. glsl-token-whitespace-trim", + "2. glslify", + "2. glslify-bundle", + "2. glslify-deps", + "2. gray-matter", + "2. grid-index", + "2. has-passive-events", + "2. image-palette", + "2. incremental-convex-hull", + "2. iota-array", + "2. is-browser", + "2. is-buffer", + "2. is-iexplorer", + "2. is-mobile", + "2. is-obj", + "2. is-plain-obj", + "2. is-string-blank", + "2. is-svg-path", + "2. left-pad", + "2. mat4-interpolate", + "2. math-log2", + "2. minimist", + "2. monotone-convex-hull-2d", + "2. mouse-change", + "2. mouse-event", + "2. mouse-event-offset", + "2. mouse-wheel", + "2. ndarray", + "2. ndarray-gradient", + "2. ndarray-ops", + "2. ndarray-pack", + "2. ndarray-scratch", + "2. ndarray-warp", + "2. normals", + "2. object-assign", + "2. optical-properties", + "2. parse-rect", + "2. parse-svg-path", + "2. parse-unit", + "2. pbf", + "2. pick-by-alias", + "2. point-cluster", + "2. polytope-closest-point", + "2. quickselect", + "2. raf", + "2. regl", + "2. regl-scatter2d", + "2. resolve", + "2. right-now", + "2. robust-scale", + "2. robust-subtract", + "2. robust-sum", + "2. rw", + "2. shuffle-seed", + "2. signum", + "2. simplicial-complex-boundary", + "2. simplicial-complex-contour", + "2. sort-object", + "2. stack-trace", + "2. static-eval", + "2. supercluster", + "2. surface-nets", + "2. svg-path-bounds", + "2. text-cache", + "2. through2", + "2. tiny-sdf", + "2. tinyqueue", + "2. to-float32", + "2. to-px", + "2. two-product", + "2. typedarray-pool", + "2. uniq", + "2. update-diff", + "2. vectorize-text", + "2. vt-pbf", + "2. xtend", + "3. @choojs/findup", + "3. @mapbox/geojson-area", + "3. @mapbox/point-geometry", + "3. @mapbox/vector-tile", + "3. abs-svg-path", + "3. acorn", + "3. array-bounds", + "3. big-rat", + "3. binary-search-bounds", + "3. bit-twiddle", + "3. boundary-cells", + "3. box-intersect", + "3. buble", + "3. buffer-from", + "3. cdt2d", + "3. circumradius", + "3. clamp", + "3. clean-pslg", + "3. color-id", + "3. color-parse", + "3. color-space", + "3. concat-stream", + "3. css-font", + "3. css-font-size-keywords", + "3. css-font-stretch-keywords", + "3. css-font-style-keywords", + "3. css-font-weight-keywords", + "3. css-global-keywords", + "3. css-system-font-keywords", + "3. cwise", + "3. cwise-compiler", + "3. cwise-parser", + "3. d", + "3. d3-path", + "3. delaunay-triangulate", + "3. dtype", + "3. dup", + "3. end-of-stream", + "3. es5-ext", + "3. es6-iterator", + "3. es6-symbol", + "3. es6-weak-map", + "3. escodegen", + "3. events", + "3. extend-shallow", + "3. extract-frustum-planes", + "3. foreach", + "3. gl-buffer", + "3. gl-fbo", + "3. gl-format-compiler-error", + "3. gl-mat2", + "3. gl-mat3", + "3. gl-mat4", + "3. gl-shader", + "3. gl-state", + "3. gl-texture2d", + "3. gl-vao", + "3. gl-vec3", + "3. gl-vec4", + "3. glsl-inject-defines", + "3. glsl-resolve", + "3. glsl-specular-beckmann", + "3. glsl-token-defines", + "3. glsl-token-depth", + "3. glsl-token-descope", + "3. glsl-token-scope", + "3. glsl-token-string", + "3. glsl-token-whitespace-trim", + "3. glsl-tokenizer", + "3. glslify", + "3. graceful-fs", + "3. ieee754", + "3. inherits", + "3. is-browser", + "3. is-firefox", + "3. is-plain-obj", + "3. is-svg-path", + "3. isarray", + "3. js-yaml", + "3. kdbush", + "3. kind-of", + "3. lerp", + "3. map-limit", + "3. marching-simplex-table", + "3. mat4-decompose", + "3. mat4-recompose", + "3. matrix-camera-controller", + "3. minimist", + "3. murmurhash-js", + "3. ndarray", + "3. ndarray-extract-contour", + "3. ndarray-linear-interpolate", + "3. ndarray-ops", + "3. ndarray-sort", + "3. nextafter", + "3. normalize-svg-path", + "3. number-is-integer", + "3. numeric", + "3. object-assign", + "3. object-keys", + "3. orbit-camera-controller", + "3. parse-svg-path", + "3. parse-unit", + "3. path-parse", + "3. pbf", + "3. performance-now", + "3. pick-by-alias", + "3. planar-graph-to-polyline", + "3. pxls", + "3. quantize", + "3. quat-slerp", + "3. quote-stream", + "3. rat-vec", + "3. readable-stream", + "3. reduce-simplicial-complex", + "3. resolve", + "3. resolve-protobuf-schema", + "3. robust-in-sphere", + "3. robust-linear-solve", + "3. robust-orientation", + "3. robust-segment-intersect", + "3. safe-buffer", + "3. seedrandom", + "3. shallow-copy", + "3. sharkdown", + "3. simplicial-complex", + "3. simplify-planar-graph", + "3. sort-asc", + "3. sort-desc", + "3. split-polygon", + "3. static-module", + "3. stream-shift", + "3. string-split-by", + "3. strip-bom-string", + "3. strongly-connected-components", + "3. surface-nets", + "3. through2", + "3. triangulate-hypercube", + "3. triangulate-polyline", + "3. turntable-camera-controller", + "3. two-product", + "3. two-sum", + "3. typedarray", + "3. typedarray-pool", + "3. uglify-js", + "3. union-find", + "3. uniq", + "3. unquote", + "3. vectorize-text", + "3. weak-map", + "3. weakmap-shim", + "3. xtend", + "3. zero-crossings", + "4. acorn", + "4. acorn-dynamic-import", + "4. acorn-jsx", + "4. add-line-numbers", + "4. argparse", + "4. arr-flatten", + "4. big-rat", + "4. bit-twiddle", + "4. bn.js", + "4. buffer-equal", + "4. cardinal", + "4. cdt2d", + "4. cell-orientation", + "4. chalk", + "4. circumcenter", + "4. color-name", + "4. commander", + "4. compare-cell", + "4. compare-oriented-cell", + "4. compute-dims", + "4. concat-stream", + "4. convert-source-map", + "4. convex-hull", + "4. core-util-is", + "4. cwise-compiler", + "4. d", + "4. defined", + "4. double-bits", + "4. duplexer2", + "4. edges-to-adjacency-list", + "4. es5-ext", + "4. es6-iterator", + "4. es6-symbol", + "4. escodegen", + "4. esprima", + "4. estraverse", + "4. esutils", + "4. expect.js", + "4. falafel", + "4. filtered-vector", + "4. flip-pixels", + "4. gamma", + "4. gl-constants", + "4. gl-mat4", + "4. gl-quat", + "4. gl-vec3", + "4. glsl-shader-name", + "4. glsl-token-assignments", + "4. glsl-token-depth", + "4. glsl-token-inject-block", + "4. glsl-token-properties", + "4. glsl-token-scope", + "4. glsl-token-string", + "4. glsl-tokenizer", + "4. has", + "4. hsluv", + "4. inherits", + "4. is-browser", + "4. is-buffer", + "4. is-extendable", + "4. is-finite", + "4. is-plain-obj", + "4. isarray", + "4. magic-string", + "4. merge-source-map", + "4. minimist", + "4. mumath", + "4. next-tick", + "4. object-inspect", + "4. once", + "4. optionator", + "4. os-homedir", + "4. parenthesis", + "4. permutation-parity", + "4. permutation-rank", + "4. planar-dual", + "4. point-in-big-polygon", + "4. process-nextick-args", + "4. protocol-buffers-schema", + "4. quote-stream", + "4. readable-stream", + "4. robust-determinant", + "4. robust-dot-product", + "4. robust-orientation", + "4. robust-scale", + "4. robust-subtract", + "4. robust-sum", + "4. safe-buffer", + "4. shallow-copy", + "4. simplicial-complex", + "4. source-map", + "4. split", + "4. sprintf-js", + "4. static-eval", + "4. stream-spigot", + "4. string_decoder", + "4. svg-arc-to-cubic-bezier", + "4. tape", + "4. through", + "4. through2", + "4. to-uint8", + "4. two-product", + "4. typedarray-pool", + "4. uglify-to-browserify", + "4. union-find", + "4. uniq", + "4. util-deprecate", + "4. vlq", + "4. wgs84", + "4. yargs", + "5. acorn", + "5. almost-equal", + "5. ansi-styles", + "5. ansicolors", + "5. arr-flatten", + "5. atob-lite", + "5. binary-search-bounds", + "5. bit-twiddle", + "5. camelcase", + "5. cell-orientation", + "5. clamp", + "5. cliui", + "5. compare-angle", + "5. compare-cell", + "5. core-util-is", + "5. cubic-hermite", + "5. decamelize", + "5. deep-equal", + "5. deep-is", + "5. defined", + "5. dup", + "5. escape-string-regexp", + "5. escodegen", + "5. esprima", + "5. estraverse", + "5. esutils", + "5. fast-levenshtein", + "5. for-each", + "5. function-bind", + "5. gl-mat3", + "5. gl-vec3", + "5. gl-vec4", + "5. glob", + "5. glsl-tokenizer", + "5. has", + "5. inherits", + "5. interval-tree-1d", + "5. invert-permutation", + "5. is-base64", + "5. is-float-array", + "5. isarray", + "5. levn", + "5. minimist", + "5. number-is-nan", + "5. object-inspect", + "5. optionator", + "5. pad-left", + "5. prelude-ls", + "5. readable-stream", + "5. redeyed", + "5. resolve", + "5. resumer", + "5. robust-compress", + "5. robust-linear-solve", + "5. robust-orientation", + "5. robust-scale", + "5. robust-sum", + "5. safe-buffer", + "5. slab-decomposition", + "5. source-map", + "5. sprintf-js", + "5. string.prototype.trim", + "5. string_decoder", + "5. supports-color", + "5. through", + "5. through2", + "5. to-array-buffer", + "5. two-product", + "5. type-check", + "5. typedarray-pool", + "5. union-find", + "5. uniq", + "5. utils-copy", + "5. validate.io-array", + "5. validate.io-matrix-like", + "5. validate.io-ndarray-like", + "5. validate.io-positive-integer", + "5. vlq", + "5. window-size", + "5. wordwrap", + "5. wrappy", + "5. xtend", + "6. amdefine", + "6. binary-search-bounds", + "6. center-align", + "6. color-convert", + "6. const-pinf-float64", + "6. core-util-is", + "6. define-properties", + "6. es-abstract", + "6. esprima", + "6. estraverse", + "6. flatten-vertex-data", + "6. fs.realpath", + "6. function-bind", + "6. functional-red-black-tree", + "6. has-flag", + "6. inflight", + "6. inherits", + "6. is-blob", + "6. is-callable", + "6. isarray", + "6. minimatch", + "6. object-keys", + "6. once", + "6. path-is-absolute", + "6. prelude-ls", + "6. readable-stream", + "6. repeat-string", + "6. right-align", + "6. robust-orientation", + "6. robust-product", + "6. robust-sum", + "6. signum", + "6. source-map", + "6. string-to-arraybuffer", + "6. string_decoder", + "6. through", + "6. two-sum", + "6. type-check", + "6. type-name", + "6. utils-copy-error", + "6. utils-indexof", + "6. utils-regex-from-string", + "6. validate.io-array", + "6. validate.io-buffer", + "6. validate.io-integer", + "6. validate.io-nonnegative-integer", + "6. wordwrap", + "6. xtend" + ], + "parents": [ + "", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "Plotly.js v1.46.x external module counter", + "1. @plotly/d3-sankey", + "1. @plotly/d3-sankey", + "1. @plotly/d3-sankey", + "1. alpha-shape", + "1. alpha-shape", + "1. canvas-fit", + "1. color-normalize", + "1. color-normalize", + "1. color-normalize", + "1. convex-hull", + "1. convex-hull", + "1. convex-hull", + "1. d3-force", + "1. d3-force", + "1. d3-force", + "1. d3-force", + "1. d3-interpolate", + "1. d3-sankey-circular", + "1. d3-sankey-circular", + "1. d3-sankey-circular", + "1. d3-sankey-circular", + "1. delaunay-triangulate", + "1. delaunay-triangulate", + "1. fast-isnumeric", + "1. font-atlas-sdf", + "1. font-atlas-sdf", + "1. gl-cone3d", + "1. gl-cone3d", + "1. gl-cone3d", + "1. gl-cone3d", + "1. gl-cone3d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-contour2d", + "1. gl-error3d", + "1. gl-error3d", + "1. gl-error3d", + "1. gl-error3d", + "1. gl-error3d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-heatmap2d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-line3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-mesh3d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot2d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-plot3d", + "1. gl-pointcloud2d", + "1. gl-pointcloud2d", + "1. gl-pointcloud2d", + "1. gl-pointcloud2d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-scatter3d", + "1. gl-select-box", + "1. gl-select-box", + "1. gl-select-box", + "1. gl-streamtube3d", + "1. gl-streamtube3d", + "1. gl-streamtube3d", + "1. gl-streamtube3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-surface3d", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. gl-text", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. glslify", + "1. has-hover", + "1. has-passive-events", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. mapbox-gl", + "1. matrix-camera-controller", + "1. matrix-camera-controller", + "1. matrix-camera-controller", + "1. matrix-camera-controller", + "1. mouse-change", + "1. mouse-wheel", + "1. mouse-wheel", + "1. mouse-wheel", + "1. ndarray", + "1. ndarray", + "1. ndarray-fill", + "1. ndarray-homography", + "1. ndarray-homography", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. point-cluster", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-error2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-line2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-scatter2d", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. regl-splom", + "1. robust-orientation", + "1. robust-orientation", + "1. robust-orientation", + "1. robust-orientation", + "1. svg-path-sdf", + "1. svg-path-sdf", + "1. svg-path-sdf", + "1. svg-path-sdf", + "1. svg-path-sdf", + "1. topojson-client", + "1. webgl-context", + "1. world-calendars", + "2. d3-shape", + "2. alpha-complex", + "2. alpha-complex", + "2. simplicial-complex-boundary", + "2. simplicial-complex-boundary", + "2. color-rgba", + "2. color-rgba", + "2. color-rgba", + "2. affine-hull", + "2. incremental-convex-hull", + "2. incremental-convex-hull", + "2. monotone-convex-hull-2d", + "2. elementary-circuits-directed-graph", + "2. gl-shader", + "2. gl-shader", + "2. cdt2d", + "2. cdt2d", + "2. cdt2d", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. clean-pslg", + "2. gl-buffer", + "2. gl-buffer", + "2. gl-buffer", + "2. surface-nets", + "2. surface-nets", + "2. surface-nets", + "2. typedarray-pool", + "2. typedarray-pool", + "2. gl-texture2d", + "2. gl-texture2d", + "2. gl-texture2d", + "2. barycentric", + "2. colormap", + "2. glsl-specular-cook-torrance", + "2. polytope-closest-point", + "2. simplicial-complex-contour", + "2. simplicial-complex-contour", + "2. simplicial-complex-contour", + "2. simplicial-complex-contour", + "2. gl-select-static", + "2. gl-select-static", + "2. gl-select-static", + "2. gl-select-static", + "2. gl-select-static", + "2. text-cache", + "2. 3d-view", + "2. 3d-view", + "2. 3d-view", + "2. a-big-triangle", + "2. a-big-triangle", + "2. a-big-triangle", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-axes3d", + "2. gl-fbo", + "2. gl-spikes3d", + "2. gl-spikes3d", + "2. gl-spikes3d", + "2. gl-spikes3d", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. vectorize-text", + "2. ndarray-gradient", + "2. ndarray-gradient", + "2. ndarray-ops", + "2. ndarray-pack", + "2. ndarray-pack", + "2. ndarray-scratch", + "2. ndarray-scratch", + "2. ndarray-scratch", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. css-font", + "2. es6-weak-map", + "2. es6-weak-map", + "2. es6-weak-map", + "2. es6-weak-map", + "2. flatten-vertex-data", + "2. font-atlas", + "2. font-measure", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. gl-util", + "2. parse-rect", + "2. to-px", + "2. bl", + "2. bl", + "2. concat-stream", + "2. concat-stream", + "2. concat-stream", + "2. concat-stream", + "2. duplexify", + "2. duplexify", + "2. duplexify", + "2. duplexify", + "2. falafel", + "2. falafel", + "2. falafel", + "2. falafel", + "2. from2", + "2. from2", + "2. glsl-resolve", + "2. glsl-resolve", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-bundle", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. glslify-deps", + "2. through2", + "2. through2", + "2. resolve", + "2. static-eval", + "2. @mapbox/vector-tile", + "2. geojson-rewind", + "2. geojson-rewind", + "2. geojson-rewind", + "2. geojson-rewind", + "2. gray-matter", + "2. gray-matter", + "2. gray-matter", + "2. gray-matter", + "2. brfs", + "2. brfs", + "2. brfs", + "2. brfs", + "2. through2", + "2. through2", + "2. pbf", + "2. pbf", + "2. shuffle-seed", + "2. sort-object", + "2. sort-object", + "2. supercluster", + "2. vt-pbf", + "2. vt-pbf", + "2. vt-pbf", + "2. mat4-interpolate", + "2. mat4-interpolate", + "2. mat4-interpolate", + "2. mat4-interpolate", + "2. mat4-interpolate", + "2. cwise", + "2. cwise", + "2. cwise", + "2. cwise", + "2. gl-matrix-invert", + "2. gl-matrix-invert", + "2. gl-matrix-invert", + "2. ndarray-warp", + "2. ndarray-warp", + "2. array-normalize", + "2. bubleify", + "2. color-id", + "2. image-palette", + "2. image-palette", + "2. image-palette", + "2. color-alpha", + "2. raf", + "2. robust-scale", + "2. robust-scale", + "2. bitmap-sdf", + "2. draw-svg-path", + "2. draw-svg-path", + "2. svg-path-bounds", + "2. svg-path-bounds", + "2. svg-path-bounds", + "2. svg-path-bounds", + "3. circumradius", + "3. boundary-cells", + "3. reduce-simplicial-complex", + "3. reduce-simplicial-complex", + "3. reduce-simplicial-complex", + "3. color-parse", + "3. color-parse", + "3. color-parse", + "3. color-space", + "3. color-space", + "3. simplicial-complex", + "3. simplicial-complex", + "3. gl-format-compiler-error", + "3. gl-format-compiler-error", + "3. gl-format-compiler-error", + "3. gl-format-compiler-error", + "3. robust-in-sphere", + "3. robust-in-sphere", + "3. robust-in-sphere", + "3. robust-in-sphere", + "3. big-rat", + "3. big-rat", + "3. big-rat", + "3. box-intersect", + "3. box-intersect", + "3. nextafter", + "3. rat-vec", + "3. robust-segment-intersect", + "3. ndarray-extract-contour", + "3. triangulate-hypercube", + "3. triangulate-hypercube", + "3. triangulate-hypercube", + "3. zero-crossings", + "3. robust-linear-solve", + "3. marching-simplex-table", + "3. ndarray-sort", + "3. orbit-camera-controller", + "3. orbit-camera-controller", + "3. turntable-camera-controller", + "3. turntable-camera-controller", + "3. turntable-camera-controller", + "3. gl-state", + "3. split-polygon", + "3. split-polygon", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. planar-graph-to-polyline", + "3. simplify-planar-graph", + "3. simplify-planar-graph", + "3. triangulate-polyline", + "3. cwise-compiler", + "3. string-split-by", + "3. d", + "3. es5-ext", + "3. es5-ext", + "3. es5-ext", + "3. es6-iterator", + "3. es6-iterator", + "3. es6-iterator", + "3. es6-symbol", + "3. es6-symbol", + "3. number-is-integer", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. end-of-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. glsl-inject-defines", + "3. glsl-inject-defines", + "3. glsl-inject-defines", + "3. glsl-token-defines", + "3. glsl-token-descope", + "3. glsl-token-descope", + "3. glsl-token-descope", + "3. glsl-token-descope", + "3. glsl-tokenizer", + "3. @choojs/findup", + "3. map-limit", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. escodegen", + "3. escodegen", + "3. escodegen", + "3. escodegen", + "3. escodegen", + "3. @mapbox/geojson-area", + "3. sharkdown", + "3. sharkdown", + "3. sharkdown", + "3. sharkdown", + "3. sharkdown", + "3. sharkdown", + "3. extend-shallow", + "3. js-yaml", + "3. js-yaml", + "3. quote-stream", + "3. quote-stream", + "3. quote-stream", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. readable-stream", + "3. resolve-protobuf-schema", + "3. mat4-decompose", + "3. mat4-decompose", + "3. mat4-recompose", + "3. quat-slerp", + "3. cwise-parser", + "3. cwise-parser", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. static-module", + "3. uglify-js", + "3. uglify-js", + "3. uglify-js", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. buble", + "3. pxls", + "3. pxls", + "3. pxls", + "3. pxls", + "3. pxls", + "3. pxls", + "3. normalize-svg-path", + "4. circumcenter", + "4. circumcenter", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. tape", + "4. compare-oriented-cell", + "4. compare-oriented-cell", + "4. mumath", + "4. add-line-numbers", + "4. glsl-shader-name", + "4. glsl-shader-name", + "4. permutation-parity", + "4. permutation-rank", + "4. permutation-rank", + "4. robust-determinant", + "4. robust-determinant", + "4. robust-determinant", + "4. robust-determinant", + "4. filtered-vector", + "4. filtered-vector", + "4. robust-dot-product", + "4. robust-dot-product", + "4. edges-to-adjacency-list", + "4. planar-dual", + "4. planar-dual", + "4. point-in-big-polygon", + "4. point-in-big-polygon", + "4. point-in-big-polygon", + "4. point-in-big-polygon", + "4. simplicial-complex", + "4. simplicial-complex", + "4. is-finite", + "4. string_decoder", + "4. string_decoder", + "4. string_decoder", + "4. once", + "4. string_decoder", + "4. through2", + "4. through2", + "4. once", + "4. string_decoder", + "4. optionator", + "4. optionator", + "4. optionator", + "4. optionator", + "4. optionator", + "4. optionator", + "4. cardinal", + "4. cardinal", + "4. split", + "4. stream-spigot", + "4. argparse", + "4. has", + "4. magic-string", + "4. duplexer2", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. merge-source-map", + "4. string_decoder", + "4. gl-quat", + "4. gl-quat", + "4. gl-quat", + "4. duplexer2", + "4. quote-stream", + "4. quote-stream", + "4. readable-stream", + "4. readable-stream", + "4. readable-stream", + "4. readable-stream", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. escodegen", + "4. static-eval", + "4. through2", + "4. through2", + "4. yargs", + "4. yargs", + "4. yargs", + "4. yargs", + "4. acorn-dynamic-import", + "4. acorn-jsx", + "4. chalk", + "4. chalk", + "4. chalk", + "4. compute-dims", + "4. compute-dims", + "4. compute-dims", + "4. compute-dims", + "4. compute-dims", + "4. to-uint8", + "4. to-uint8", + "4. to-uint8", + "4. to-uint8", + "4. to-uint8" + ], + "labels": [ + "Plotly.js v1.46.x external module counter", + "1. @plotly/d3-sankey", + "1. alpha-shape", + "1. array-range", + "1. canvas-fit", + "1. color-normalize", + "1. convex-hull", + "1. country-regex", + "1. d3", + "1. d3-force", + "1. d3-hierarchy", + "1. d3-interpolate", + "1. d3-sankey-circular", + "1. delaunay-triangulate", + "1. es6-promise", + "1. fast-isnumeric", + "1. font-atlas-sdf", + "1. gl-cone3d", + "1. gl-contour2d", + "1. gl-error3d", + "1. gl-heatmap2d", + "1. gl-line3d", + "1. gl-mat4", + "1. gl-mesh3d", + "1. gl-plot2d", + "1. gl-plot3d", + "1. gl-pointcloud2d", + "1. gl-scatter3d", + "1. gl-select-box", + "1. gl-spikes2d", + "1. gl-streamtube3d", + "1. gl-surface3d", + "1. gl-text", + "1. glslify", + "1. has-hover", + "1. has-passive-events", + "1. mapbox-gl", + "1. matrix-camera-controller", + "1. mouse-change", + "1. mouse-event-offset", + "1. mouse-wheel", + "1. ndarray", + "1. ndarray-fill", + "1. ndarray-homography", + "1. point-cluster", + "1. polybooljs", + "1. regl", + "1. regl-error2d", + "1. regl-line2d", + "1. regl-scatter2d", + "1. regl-splom", + "1. right-now", + "1. robust-orientation", + "1. sane-topojson", + "1. strongly-connected-components", + "1. superscript-text", + "1. svg-path-sdf", + "1. tinycolor2", + "1. topojson-client", + "1. webgl-context", + "1. world-calendars", + "2. d3-array", + "2. d3-collection", + "2. d3-shape", + "2. alpha-complex", + "2. simplicial-complex-boundary", + "2. element-size", + "2. clamp", + "2. color-rgba", + "2. dtype", + "2. affine-hull", + "2. incremental-convex-hull", + "2. monotone-convex-hull-2d", + "2. d3-collection", + "2. d3-dispatch", + "2. d3-quadtree", + "2. d3-timer", + "2. d3-color", + "2. d3-array", + "2. d3-collection", + "2. d3-shape", + "2. elementary-circuits-directed-graph", + "2. incremental-convex-hull", + "2. uniq", + "2. is-string-blank", + "2. optical-properties", + "2. tiny-sdf", + "2. gl-shader", + "2. gl-vec3", + "2. glsl-inverse", + "2. glsl-out-of-range", + "2. glslify", + "2. cdt2d", + "2. clean-pslg", + "2. gl-buffer", + "2. binary-search-bounds", + "2. gl-shader", + "2. glslify", + "2. iota-array", + "2. ndarray", + "2. surface-nets", + "2. gl-buffer", + "2. gl-shader", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glslify", + "2. gl-buffer", + "2. binary-search-bounds", + "2. gl-shader", + "2. glslify", + "2. iota-array", + "2. typedarray-pool", + "2. gl-buffer", + "2. binary-search-bounds", + "2. gl-shader", + "2. gl-texture2d", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glsl-read-float", + "2. glslify", + "2. ndarray", + "2. barycentric", + "2. colormap", + "2. gl-buffer", + "2. gl-mat4", + "2. gl-shader", + "2. gl-texture2d", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glsl-specular-cook-torrance", + "2. glslify", + "2. ndarray", + "2. normals", + "2. polytope-closest-point", + "2. simplicial-complex-contour", + "2. typedarray-pool", + "2. gl-buffer", + "2. binary-search-bounds", + "2. gl-select-static", + "2. gl-shader", + "2. glsl-inverse", + "2. glslify", + "2. text-cache", + "2. 3d-view", + "2. a-big-triangle", + "2. gl-axes3d", + "2. gl-fbo", + "2. gl-mat4", + "2. gl-select-static", + "2. gl-shader", + "2. gl-spikes3d", + "2. glslify", + "2. has-passive-events", + "2. is-mobile", + "2. mouse-change", + "2. mouse-event-offset", + "2. mouse-wheel", + "2. ndarray", + "2. right-now", + "2. gl-buffer", + "2. gl-shader", + "2. glslify", + "2. typedarray-pool", + "2. gl-buffer", + "2. gl-mat4", + "2. gl-shader", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glslify", + "2. is-string-blank", + "2. typedarray-pool", + "2. vectorize-text", + "2. gl-buffer", + "2. gl-shader", + "2. glslify", + "2. gl-vec3", + "2. glsl-inverse", + "2. glsl-out-of-range", + "2. glslify", + "2. bit-twiddle", + "2. colormap", + "2. dup", + "2. gl-buffer", + "2. gl-mat4", + "2. gl-shader", + "2. binary-search-bounds", + "2. gl-texture2d", + "2. gl-vao", + "2. glsl-out-of-range", + "2. glsl-specular-beckmann", + "2. glslify", + "2. ndarray", + "2. ndarray-gradient", + "2. ndarray-ops", + "2. ndarray-pack", + "2. ndarray-scratch", + "2. surface-nets", + "2. typedarray-pool", + "2. bit-twiddle", + "2. color-normalize", + "2. css-font", + "2. detect-kerning", + "2. es6-weak-map", + "2. flatten-vertex-data", + "2. font-atlas", + "2. font-measure", + "2. gl-util", + "2. is-plain-obj", + "2. object-assign", + "2. parse-rect", + "2. parse-unit", + "2. pick-by-alias", + "2. regl", + "2. to-px", + "2. typedarray-pool", + "2. bl", + "2. concat-stream", + "2. duplexify", + "2. falafel", + "2. from2", + "2. glsl-resolve", + "2. glsl-token-whitespace-trim", + "2. glslify-bundle", + "2. glslify-deps", + "2. through2", + "2. minimist", + "2. resolve", + "2. stack-trace", + "2. static-eval", + "2. xtend", + "2. is-browser", + "2. is-browser", + "2. @mapbox/gl-matrix", + "2. @mapbox/jsonlint-lines-primitives", + "2. @mapbox/mapbox-gl-supported", + "2. @mapbox/point-geometry", + "2. @mapbox/shelf-pack", + "2. @mapbox/tiny-sdf", + "2. @mapbox/unitbezier", + "2. @mapbox/vector-tile", + "2. @mapbox/whoots-js", + "2. csscolorparser", + "2. earcut", + "2. geojson-rewind", + "2. geojson-vt", + "2. gray-matter", + "2. grid-index", + "2. brfs", + "2. minimist", + "2. through2", + "2. pbf", + "2. quickselect", + "2. rw", + "2. shuffle-seed", + "2. sort-object", + "2. supercluster", + "2. tinyqueue", + "2. vt-pbf", + "2. binary-search-bounds", + "2. gl-mat4", + "2. gl-vec3", + "2. mat4-interpolate", + "2. mouse-event", + "2. signum", + "2. right-now", + "2. to-px", + "2. iota-array", + "2. is-buffer", + "2. cwise", + "2. gl-matrix-invert", + "2. ndarray-warp", + "2. array-bounds", + "2. array-normalize", + "2. bubleify", + "2. clamp", + "2. dtype", + "2. flatten-vertex-data", + "2. is-obj", + "2. math-log2", + "2. parse-rect", + "2. binary-search-bounds", + "2. array-bounds", + "2. bubleify", + "2. color-normalize", + "2. flatten-vertex-data", + "2. object-assign", + "2. pick-by-alias", + "2. to-float32", + "2. update-diff", + "2. array-bounds", + "2. array-normalize", + "2. bubleify", + "2. color-normalize", + "2. earcut", + "2. es6-weak-map", + "2. flatten-vertex-data", + "2. glslify", + "2. object-assign", + "2. parse-rect", + "2. pick-by-alias", + "2. to-float32", + "2. array-range", + "2. array-rearrange", + "2. clamp", + "2. color-id", + "2. color-normalize", + "2. color-rgba", + "2. flatten-vertex-data", + "2. glslify", + "2. image-palette", + "2. is-iexplorer", + "2. object-assign", + "2. parse-rect", + "2. pick-by-alias", + "2. point-cluster", + "2. to-float32", + "2. update-diff", + "2. array-bounds", + "2. array-range", + "2. bubleify", + "2. color-alpha", + "2. defined", + "2. flatten-vertex-data", + "2. left-pad", + "2. parse-rect", + "2. pick-by-alias", + "2. point-cluster", + "2. raf", + "2. regl-scatter2d", + "2. robust-scale", + "2. robust-subtract", + "2. robust-sum", + "2. two-product", + "2. bitmap-sdf", + "2. draw-svg-path", + "2. is-svg-path", + "2. parse-svg-path", + "2. svg-path-bounds", + "2. commander", + "2. get-canvas-context", + "2. object-assign", + "3. d3-path", + "3. circumradius", + "3. delaunay-triangulate", + "3. boundary-cells", + "3. reduce-simplicial-complex", + "3. clamp", + "3. color-parse", + "3. color-space", + "3. robust-orientation", + "3. robust-orientation", + "3. simplicial-complex", + "3. robust-orientation", + "3. strongly-connected-components", + "3. gl-format-compiler-error", + "3. weakmap-shim", + "3. binary-search-bounds", + "3. robust-in-sphere", + "3. robust-orientation", + "3. big-rat", + "3. box-intersect", + "3. nextafter", + "3. rat-vec", + "3. robust-segment-intersect", + "3. union-find", + "3. uniq", + "3. ndarray", + "3. ndarray-ops", + "3. typedarray-pool", + "3. ndarray-extract-contour", + "3. triangulate-hypercube", + "3. zero-crossings", + "3. bit-twiddle", + "3. dup", + "3. ndarray", + "3. ndarray-ops", + "3. typedarray-pool", + "3. robust-linear-solve", + "3. lerp", + "3. glsl-specular-beckmann", + "3. numeric", + "3. marching-simplex-table", + "3. ndarray", + "3. ndarray-sort", + "3. typedarray-pool", + "3. bit-twiddle", + "3. cwise", + "3. gl-fbo", + "3. ndarray", + "3. typedarray-pool", + "3. vectorize-text", + "3. matrix-camera-controller", + "3. orbit-camera-controller", + "3. turntable-camera-controller", + "3. gl-buffer", + "3. gl-vao", + "3. weak-map", + "3. bit-twiddle", + "3. dup", + "3. extract-frustum-planes", + "3. gl-buffer", + "3. gl-mat4", + "3. gl-shader", + "3. gl-state", + "3. gl-vao", + "3. gl-vec4", + "3. glslify", + "3. robust-orientation", + "3. split-polygon", + "3. vectorize-text", + "3. gl-texture2d", + "3. gl-buffer", + "3. gl-shader", + "3. gl-vao", + "3. glslify", + "3. cdt2d", + "3. clean-pslg", + "3. ndarray", + "3. planar-graph-to-polyline", + "3. simplify-planar-graph", + "3. surface-nets", + "3. triangulate-polyline", + "3. cwise-compiler", + "3. dup", + "3. cwise-compiler", + "3. cwise-compiler", + "3. ndarray", + "3. ndarray", + "3. ndarray-ops", + "3. typedarray-pool", + "3. css-font-size-keywords", + "3. css-font-stretch-keywords", + "3. css-font-style-keywords", + "3. css-font-weight-keywords", + "3. css-global-keywords", + "3. css-system-font-keywords", + "3. pick-by-alias", + "3. string-split-by", + "3. unquote", + "3. d", + "3. es5-ext", + "3. es6-iterator", + "3. es6-symbol", + "3. dtype", + "3. css-font", + "3. css-font", + "3. es6-weak-map", + "3. is-browser", + "3. is-firefox", + "3. is-plain-obj", + "3. number-is-integer", + "3. object-assign", + "3. pick-by-alias", + "3. pick-by-alias", + "3. parse-unit", + "3. readable-stream", + "3. safe-buffer", + "3. buffer-from", + "3. readable-stream", + "3. inherits", + "3. typedarray", + "3. readable-stream", + "3. end-of-stream", + "3. inherits", + "3. stream-shift", + "3. acorn", + "3. foreach", + "3. isarray", + "3. object-keys", + "3. readable-stream", + "3. inherits", + "3. resolve", + "3. xtend", + "3. glsl-inject-defines", + "3. glsl-token-defines", + "3. glsl-token-depth", + "3. glsl-token-descope", + "3. glsl-token-scope", + "3. glsl-token-string", + "3. glsl-token-whitespace-trim", + "3. glsl-tokenizer", + "3. murmurhash-js", + "3. shallow-copy", + "3. @choojs/findup", + "3. events", + "3. glsl-resolve", + "3. glsl-tokenizer", + "3. graceful-fs", + "3. inherits", + "3. map-limit", + "3. resolve", + "3. readable-stream", + "3. xtend", + "3. path-parse", + "3. escodegen", + "3. @mapbox/point-geometry", + "3. @mapbox/geojson-area", + "3. concat-stream", + "3. minimist", + "3. sharkdown", + "3. extend-shallow", + "3. kind-of", + "3. js-yaml", + "3. strip-bom-string", + "3. quote-stream", + "3. static-module", + "3. through2", + "3. resolve", + "3. readable-stream", + "3. xtend", + "3. ieee754", + "3. resolve-protobuf-schema", + "3. seedrandom", + "3. sort-asc", + "3. sort-desc", + "3. kdbush", + "3. @mapbox/point-geometry", + "3. @mapbox/vector-tile", + "3. pbf", + "3. gl-mat4", + "3. gl-vec3", + "3. mat4-decompose", + "3. mat4-recompose", + "3. quat-slerp", + "3. cwise-compiler", + "3. cwise-parser", + "3. static-module", + "3. uglify-js", + "3. gl-mat2", + "3. gl-mat3", + "3. gl-mat4", + "3. cwise", + "3. ndarray-linear-interpolate", + "3. array-bounds", + "3. buble", + "3. clamp", + "3. color-id", + "3. pxls", + "3. quantize", + "3. color-parse", + "3. performance-now", + "3. two-product", + "3. two-sum", + "3. clamp", + "3. abs-svg-path", + "3. normalize-svg-path", + "3. abs-svg-path", + "3. is-svg-path", + "3. parse-svg-path", + "3. normalize-svg-path", + "4. circumcenter", + "4. tape", + "4. cell-orientation", + "4. compare-cell", + "4. compare-oriented-cell", + "4. color-name", + "4. defined", + "4. is-plain-obj", + "4. hsluv", + "4. mumath", + "4. bit-twiddle", + "4. union-find", + "4. add-line-numbers", + "4. gl-constants", + "4. glsl-shader-name", + "4. sprintf-js", + "4. robust-scale", + "4. robust-subtract", + "4. robust-sum", + "4. two-product", + "4. bit-twiddle", + "4. bn.js", + "4. double-bits", + "4. bit-twiddle", + "4. typedarray-pool", + "4. double-bits", + "4. big-rat", + "4. robust-orientation", + "4. typedarray-pool", + "4. gamma", + "4. permutation-parity", + "4. permutation-rank", + "4. cwise-compiler", + "4. robust-determinant", + "4. convex-hull", + "4. typedarray-pool", + "4. filtered-vector", + "4. gl-mat4", + "4. filtered-vector", + "4. gl-mat4", + "4. gl-vec3", + "4. uniq", + "4. robust-dot-product", + "4. robust-sum", + "4. edges-to-adjacency-list", + "4. planar-dual", + "4. point-in-big-polygon", + "4. robust-orientation", + "4. robust-sum", + "4. two-product", + "4. uniq", + "4. robust-orientation", + "4. simplicial-complex", + "4. cdt2d", + "4. uniq", + "4. parenthesis", + "4. es5-ext", + "4. es6-iterator", + "4. es6-symbol", + "4. next-tick", + "4. d", + "4. es5-ext", + "4. es6-symbol", + "4. d", + "4. es5-ext", + "4. is-finite", + "4. isarray", + "4. string_decoder", + "4. core-util-is", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. isarray", + "4. string_decoder", + "4. core-util-is", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. core-util-is", + "4. isarray", + "4. string_decoder", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. once", + "4. core-util-is", + "4. isarray", + "4. string_decoder", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. glsl-token-inject-block", + "4. glsl-token-string", + "4. glsl-tokenizer", + "4. glsl-tokenizer", + "4. glsl-token-assignments", + "4. glsl-token-depth", + "4. glsl-token-properties", + "4. glsl-token-scope", + "4. through2", + "4. commander", + "4. once", + "4. core-util-is", + "4. isarray", + "4. string_decoder", + "4. inherits", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. esprima", + "4. estraverse", + "4. esutils", + "4. optionator", + "4. source-map", + "4. wgs84", + "4. cardinal", + "4. expect.js", + "4. minimist", + "4. split", + "4. stream-spigot", + "4. through", + "4. is-extendable", + "4. argparse", + "4. esprima", + "4. buffer-equal", + "4. minimist", + "4. through2", + "4. concat-stream", + "4. convert-source-map", + "4. falafel", + "4. has", + "4. magic-string", + "4. duplexer2", + "4. escodegen", + "4. object-inspect", + "4. quote-stream", + "4. readable-stream", + "4. through2", + "4. merge-source-map", + "4. shallow-copy", + "4. static-eval", + "4. core-util-is", + "4. inherits", + "4. isarray", + "4. string_decoder", + "4. process-nextick-args", + "4. safe-buffer", + "4. util-deprecate", + "4. protocol-buffers-schema", + "4. gl-mat4", + "4. gl-vec3", + "4. gl-mat4", + "4. gl-quat", + "4. esprima", + "4. uniq", + "4. concat-stream", + "4. duplexer2", + "4. falafel", + "4. has", + "4. quote-stream", + "4. readable-stream", + "4. shallow-copy", + "4. escodegen", + "4. object-inspect", + "4. static-eval", + "4. through2", + "4. source-map", + "4. uglify-to-browserify", + "4. yargs", + "4. acorn", + "4. acorn-dynamic-import", + "4. acorn-jsx", + "4. vlq", + "4. chalk", + "4. magic-string", + "4. minimist", + "4. os-homedir", + "4. arr-flatten", + "4. compute-dims", + "4. flip-pixels", + "4. is-browser", + "4. is-buffer", + "4. to-uint8", + "4. svg-arc-to-cubic-bezier", + "5. dup", + "5. robust-linear-solve", + "5. deep-equal", + "5. defined", + "5. for-each", + "5. function-bind", + "5. glob", + "5. has", + "5. inherits", + "5. minimist", + "5. object-inspect", + "5. resolve", + "5. resumer", + "5. string.prototype.trim", + "5. through", + "5. cell-orientation", + "5. compare-cell", + "5. almost-equal", + "5. pad-left", + "5. atob-lite", + "5. glsl-tokenizer", + "5. typedarray-pool", + "5. invert-permutation", + "5. typedarray-pool", + "5. robust-compress", + "5. robust-scale", + "5. robust-sum", + "5. two-product", + "5. binary-search-bounds", + "5. cubic-hermite", + "5. robust-sum", + "5. two-product", + "5. uniq", + "5. compare-angle", + "5. dup", + "5. binary-search-bounds", + "5. interval-tree-1d", + "5. robust-orientation", + "5. slab-decomposition", + "5. bit-twiddle", + "5. union-find", + "5. number-is-nan", + "5. safe-buffer", + "5. safe-buffer", + "5. safe-buffer", + "5. wrappy", + "5. safe-buffer", + "5. readable-stream", + "5. xtend", + "5. wrappy", + "5. safe-buffer", + "5. deep-is", + "5. fast-levenshtein", + "5. levn", + "5. prelude-ls", + "5. type-check", + "5. wordwrap", + "5. ansicolors", + "5. redeyed", + "5. through", + "5. readable-stream", + "5. sprintf-js", + "5. function-bind", + "5. vlq", + "5. readable-stream", + "5. esprima", + "5. estraverse", + "5. esutils", + "5. optionator", + "5. source-map", + "5. source-map", + "5. safe-buffer", + "5. gl-mat3", + "5. gl-vec3", + "5. gl-vec4", + "5. readable-stream", + "5. minimist", + "5. through2", + "5. core-util-is", + "5. inherits", + "5. isarray", + "5. string_decoder", + "5. esprima", + "5. estraverse", + "5. esutils", + "5. source-map", + "5. escodegen", + "5. readable-stream", + "5. xtend", + "5. camelcase", + "5. cliui", + "5. decamelize", + "5. window-size", + "5. acorn", + "5. acorn", + "5. ansi-styles", + "5. escape-string-regexp", + "5. supports-color", + "5. utils-copy", + "5. validate.io-array", + "5. validate.io-matrix-like", + "5. validate.io-ndarray-like", + "5. validate.io-positive-integer", + "5. arr-flatten", + "5. clamp", + "5. is-base64", + "5. is-float-array", + "5. to-array-buffer" + ] + } + ], + "layout": { + "width": 800, + "height": 800 + } +} diff --git a/test/image/mocks/treemap_packings.json b/test/image/mocks/treemap_packings.json new file mode 100644 index 00000000000..da40f76decb --- /dev/null +++ b/test/image/mocks/treemap_packings.json @@ -0,0 +1,586 @@ +{ + "data": [ + { + "type": "treemap", + "textinfo": "label", + "hoverinfo": "all", + "name": "binary treemap", + "tiling": { + "packing": "binary" + }, + "pathbar": { + "edgeshape": "/", + "textfont": { + "size": 12, + "family": "Times New Roman" + } + }, + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "marker": { + "colorscale": "Blackbody", + "reversescale": true + }, + "domain": { + "x": [ + 0, + 0.3 + ], + "y": [ + 0, + 0.45 + ] + } + }, + { + "type": "treemap", + "textinfo": "label", + "hoverinfo": "all", + "name": "dice-slice treemap", + "tiling": { + "packing": "dice-slice" + }, + "pathbar": { + "edgeshape": "|", + "textfont": { + "size": 12, + "family": "Times New Roman" + } + }, + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "marker": { + "colorscale": "Blackbody", + "reversescale": true + }, + "domain": { + "x": [ + 0.35, + 0.65 + ], + "y": [ + 0, + 0.45 + ] + } + }, + { + "type": "treemap", + "textinfo": "label", + "hoverinfo": "all", + "name": "squarify treemap", + "tiling": { + "packing": "squarify" + }, + "pathbar": { + "edgeshape": "<", + "textfont": { + "size": 12, + "family": "Times New Roman" + } + }, + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "marker": { + "colorscale": "Blackbody", + "reversescale": true + }, + "domain": { + "x": [ + 0.7, + 1 + ], + "y": [ + 0, + 0.45 + ] + } + }, + { + "type": "treemap", + "textinfo": "label", + "hoverinfo": "all", + "name": "slice treemap", + "tiling": { + "packing": "slice" + }, + "pathbar": { + "edgeshape": ">", + "textfont": { + "size": 12, + "family": "Times New Roman" + } + }, + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "marker": { + "colorscale": "Blackbody", + "reversescale": true + }, + "domain": { + "x": [ + 0, + 0.3 + ], + "y": [ + 0.5, + 0.95 + ] + } + }, + { + "type": "treemap", + "textinfo": "label", + "hoverinfo": "all", + "name": "slice-dice treemap", + "tiling": { + "packing": "slice-dice" + }, + "pathbar": { + "edgeshape": "|", + "textfont": { + "size": 12, + "family": "Times New Roman" + } + }, + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "marker": { + "colorscale": "Blackbody", + "reversescale": true + }, + "domain": { + "x": [ + 0.35, + 0.65 + ], + "y": [ + 0.5, + 0.95 + ] + } + }, + { + "type": "treemap", + "textinfo": "label", + "hoverinfo": "all", + "name": "dice treemap", + "tiling": { + "packing": "dice" + }, + "pathbar": { + "edgeshape": "\\", + "textfont": { + "size": 12, + "family": "Times New Roman" + } + }, + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "marker": { + "colorscale": "Blackbody", + "reversescale": true + }, + "domain": { + "x": [ + 0.7, + 1 + ], + "y": [ + 0.5, + 0.95 + ] + } + } + ], + "layout": { + "width": 1200, + "height": 800, + "annotations": [ + { + "showarrow": false, + "text": "binary treemap
with / edgeshape", + "x": 0.15, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "dice-slice treemap
with | edgeshape", + "x": 0.5, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "squarify treemap
with < edgeshape", + "x": 0.85, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "slice treemap
with > edgeshape", + "x": 0.15, + "xanchor": "center", + "y": 1, + "yanchor": "bottom" + }, + { + "showarrow": false, + "text": "slice-dice treemap
with | edgeshape", + "x": 0.5, + "xanchor": "center", + "y": 1, + "yanchor": "bottom" + }, + { + "showarrow": false, + "text": "dice treemap
with \\ edgeshape", + "x": 0.85, + "xanchor": "center", + "y": 1, + "yanchor": "bottom" + } + ] + } +} diff --git a/test/image/mocks/treemap_pad_mirror.json b/test/image/mocks/treemap_pad_mirror.json new file mode 100644 index 00000000000..f4872947e51 --- /dev/null +++ b/test/image/mocks/treemap_pad_mirror.json @@ -0,0 +1,459 @@ +{ + "data": [ + { + "type": "treemap", + "textinfo": "label", + "textfont": { + "size": 10 + }, + "pathbar": { + "visible": true + }, + "tiling": { + "packing": "slice-dice", + "pad": 0 + }, + "marker": { + "opacitybase": 0.3, + "opacitystep": 0.1, + "pad": { + "t": 16, + "l": 8, + "r": 4, + "b": 2 + } + }, + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "", + "", + "Bravo", + "Bravo", + "Bravo", + "Echo", + "Echo", + "Echo", + "Hotel", + "Hotel", + "Hotel", + "Kilo", + "Kilo", + "Kilo", + "November", + "November", + "November", + "Quebec", + "Quebec", + "Quebec", + "Tango", + "Tango", + "Tango", + "Whiskey", + "Whiskey" + ], + "domain": { + "x": [ + 0.02, + 0.48 + ], + "y": [ + 0, + 0.45 + ] + } + }, + { + "type": "treemap", + "textinfo": "label", + "textfont": { + "size": 10 + }, + "pathbar": { + "visible": true + }, + "tiling": { + "packing": "slice-dice", + "flip": "y", + "pad": 0 + }, + "marker": { + "opacitybase": 0.3, + "opacitystep": 0.1, + "pad": { + "t": 16, + "l": 8, + "r": 4, + "b": 2 + } + }, + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "", + "", + "Bravo", + "Bravo", + "Bravo", + "Echo", + "Echo", + "Echo", + "Hotel", + "Hotel", + "Hotel", + "Kilo", + "Kilo", + "Kilo", + "November", + "November", + "November", + "Quebec", + "Quebec", + "Quebec", + "Tango", + "Tango", + "Tango", + "Whiskey", + "Whiskey" + ], + "domain": { + "x": [ + 0.02, + 0.48 + ], + "y": [ + 0.5, + 0.95 + ] + } + }, + { + "type": "treemap", + "textinfo": "label", + "textfont": { + "size": 10 + }, + "pathbar": { + "visible": true + }, + "tiling": { + "packing": "slice-dice", + "flip": "x", + "pad": 0 + }, + "marker": { + "opacitybase": 0.3, + "opacitystep": 0.1, + "pad": { + "t": 16, + "l": 8, + "r": 4, + "b": 2 + } + }, + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "", + "", + "Bravo", + "Bravo", + "Bravo", + "Echo", + "Echo", + "Echo", + "Hotel", + "Hotel", + "Hotel", + "Kilo", + "Kilo", + "Kilo", + "November", + "November", + "November", + "Quebec", + "Quebec", + "Quebec", + "Tango", + "Tango", + "Tango", + "Whiskey", + "Whiskey" + ], + "domain": { + "x": [ + 0.52, + 0.98 + ], + "y": [ + 0, + 0.45 + ] + } + }, + { + "type": "treemap", + "textinfo": "label", + "textfont": { + "size": 10 + }, + "pathbar": { + "visible": true + }, + "tiling": { + "packing": "slice-dice", + "flip": "x+y", + "pad": 0 + }, + "marker": { + "opacitybase": 0.3, + "opacitystep": 0.1, + "pad": { + "t": 16, + "l": 8, + "r": 4, + "b": 2 + } + }, + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "", + "", + "Bravo", + "Bravo", + "Bravo", + "Echo", + "Echo", + "Echo", + "Hotel", + "Hotel", + "Hotel", + "Kilo", + "Kilo", + "Kilo", + "November", + "November", + "November", + "Quebec", + "Quebec", + "Quebec", + "Tango", + "Tango", + "Tango", + "Whiskey", + "Whiskey" + ], + "domain": { + "x": [ + 0.52, + 0.98 + ], + "y": [ + 0.5, + 0.95 + ] + } + } + ], + "layout": { + "width": 1200, + "height": 800, + "shapes": [ + { + "type": "circle", + "layer": "below", + "x0": 0.075, + "x1": 0.925, + "y0": 0.0, + "y1": 0.8 + }, + { + "type": "rect", + "layer": "below", + "x0": 0.02, + "x1": 0.48, + "y0": 0, + "y1": 0.45 + }, + { + "type": "rect", + "layer": "below", + "x0": 0.02, + "x1": 0.48, + "y0": 0.5, + "y1": 0.95 + }, + { + "type": "rect", + "layer": "below", + "x0": 0.52, + "x1": 0.98, + "y0": 0, + "y1": 0.45 + }, + { + "type": "rect", + "layer": "below", + "x0": 0.52, + "x1": 0.98, + "y0": 0.5, + "y1": 0.95 + } + ], + "annotations": [ + { + "showarrow": false, + "text": "base", + "font": { + "size": 16 + }, + "x": 0.25, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "flip y axis", + "font": { + "size": 16 + }, + "x": 0.25, + "xanchor": "center", + "y": 1, + "yanchor": "bottom" + }, + { + "showarrow": false, + "text": "flip x axis", + "font": { + "size": 16 + }, + "x": 0.75, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "flip both axes", + "font": { + "size": 16 + }, + "x": 0.75, + "xanchor": "center", + "y": 1, + "yanchor": "bottom" + } + ] + } +} diff --git a/test/image/mocks/treemap_pad_transpose.json b/test/image/mocks/treemap_pad_transpose.json new file mode 100644 index 00000000000..55d985431b7 --- /dev/null +++ b/test/image/mocks/treemap_pad_transpose.json @@ -0,0 +1,430 @@ +{ + "data": [ + { + "type": "treemap", + "textinfo": "label", + "textfont": { + "size": 10 + }, + "pathbar": { + "visible": true + }, + "tiling": { + "packing": "dice-slice", + "pad": 0 + }, + "marker": { + "opacitybase": 0.5, + "opacitystep": 0.05, + "pad": { + "t": 16, + "l": 8, + "r": 4, + "b": 2 + } + }, + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "", + "", + "Bravo", + "Bravo", + "Bravo", + "Echo", + "Echo", + "Echo", + "Hotel", + "Hotel", + "Hotel", + "Kilo", + "Kilo", + "Kilo", + "November", + "November", + "November", + "Quebec", + "Quebec", + "Quebec", + "Tango", + "Tango", + "Tango", + "Whiskey", + "Whiskey" + ], + "domain": { + "x": [ + 0.02, + 0.48 + ], + "y": [ + 0, + 0.45 + ] + } + }, + { + "type": "treemap", + "textinfo": "label", + "textfont": { + "size": 10 + }, + "pathbar": { + "visible": true + }, + "tiling": { + "packing": "dice-slice", + "flip": "y", + "pad": 0 + }, + "marker": { + "opacitybase": 0.5, + "opacitystep": 0.05, + "pad": { + "t": 16, + "l": 8, + "r": 4, + "b": 2 + } + }, + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "", + "", + "Bravo", + "Bravo", + "Bravo", + "Echo", + "Echo", + "Echo", + "Hotel", + "Hotel", + "Hotel", + "Kilo", + "Kilo", + "Kilo", + "November", + "November", + "November", + "Quebec", + "Quebec", + "Quebec", + "Tango", + "Tango", + "Tango", + "Whiskey", + "Whiskey" + ], + "domain": { + "x": [ + 0.02, + 0.48 + ], + "y": [ + 0.5, + 0.95 + ] + } + }, + { + "type": "treemap", + "textinfo": "label", + "textfont": { + "size": 10 + }, + "pathbar": { + "visible": true + }, + "tiling": { + "packing": "dice-slice", + "flip": "x", + "pad": 0 + }, + "marker": { + "opacitybase": 0.5, + "opacitystep": 0.05, + "pad": { + "t": 16, + "l": 8, + "r": 4, + "b": 2 + } + }, + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "", + "", + "Bravo", + "Bravo", + "Bravo", + "Echo", + "Echo", + "Echo", + "Hotel", + "Hotel", + "Hotel", + "Kilo", + "Kilo", + "Kilo", + "November", + "November", + "November", + "Quebec", + "Quebec", + "Quebec", + "Tango", + "Tango", + "Tango", + "Whiskey", + "Whiskey" + ], + "domain": { + "x": [ + 0.52, + 0.98 + ], + "y": [ + 0, + 0.45 + ] + } + }, + { + "type": "treemap", + "textinfo": "label", + "textfont": { + "size": 10 + }, + "pathbar": { + "visible": true + }, + "tiling": { + "packing": "dice-slice", + "flip": "x+y", + "pad": 0 + }, + "marker": { + "opacitybase": 0.5, + "opacitystep": 0.05, + "pad": { + "t": 16, + "l": 8, + "r": 4, + "b": 2 + } + }, + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "", + "", + "Bravo", + "Bravo", + "Bravo", + "Echo", + "Echo", + "Echo", + "Hotel", + "Hotel", + "Hotel", + "Kilo", + "Kilo", + "Kilo", + "November", + "November", + "November", + "Quebec", + "Quebec", + "Quebec", + "Tango", + "Tango", + "Tango", + "Whiskey", + "Whiskey" + ], + "domain": { + "x": [ + 0.52, + 0.98 + ], + "y": [ + 0.5, + 0.95 + ] + } + } + ], + "layout": { + "width": 1200, + "height": 800, + "paper_bgcolor": "darkblue", + "treemapcolorway": [ + "#ff0", + "#f00", + "#0f0" + ], + "shapes": [ + { "type": "circle", "layer": "below", "x0": 0.075, "x1": 0.925, "y0": 0.0, "y1": 0.8}, + { "type": "rect", "layer": "below", "x0": 0.02, "x1": 0.48, "y0": 0.0, "y1": 0.45 }, + { "type": "rect", "layer": "below", "x0": 0.02, "x1": 0.48, "y0": 0.5, "y1": 0.95 }, + { "type": "rect", "layer": "below", "x0": 0.52, "x1": 0.98, "y0": 0.0, "y1": 0.45 }, + { "type": "rect", "layer": "below", "x0": 0.52, "x1": 0.98, "y0": 0.5, "y1": 0.95 } + ], + "annotations": [ + { + "showarrow": false, + "text": "base", + "font": { + "size": 16 + }, + "x": 0.25, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "flip y axis", + "font": { + "size": 16 + }, + "x": 0.25, + "xanchor": "center", + "y": 1, + "yanchor": "bottom" + }, + { + "showarrow": false, + "text": "flip x axis", + "font": { + "size": 16 + }, + "x": 0.75, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "flip both axes", + "font": { + "size": 16 + }, + "x": 0.75, + "xanchor": "center", + "y": 1, + "yanchor": "bottom" + } + ] + } +} diff --git a/test/image/mocks/treemap_textfit.json b/test/image/mocks/treemap_textfit.json new file mode 100644 index 00000000000..f9ee8c98f21 --- /dev/null +++ b/test/image/mocks/treemap_textfit.json @@ -0,0 +1,579 @@ +{ + "data": [ + { + "type": "treemap", + "tiling": { + "packing": "squarify", + "pad": 2 + }, + "textfont": { + "size": 256 + }, + "marker": { + "pad": { + "t": 32, + "l": 16, + "r": 8, + "b": 4 + } + }, + "texttemplate": "%{label}
%{text}", + "labels": [ + "Queen - 1973", + "Queen II - 1974", + "Sheer Heart Attack - 1974", + "A Night at the Opera - 1975", + "A Day at the Races - 1976", + "News of the World - 1977", + "Jazz - 1978", + "The Game - 1980", + "Hot Space - 1982", + "The Works - 1984", + "A Kind of Magic - 1986", + "The Miracle - 1989", + "Innuendo - 1991", + "Made in Heaven - 1995", + + "Keep
Yourself
Alive
", + "Doing
All
Right
", + "Great
King
Rat
", + "My
Fairy
King
", + "Liar", + "The
Night
Comes
Down
", + "Modern
Times
Rock
'N'
Roll
", + "Son
and
Daughter
", + "Jesus", + "Seven
Seas
of
Rhye...
", + + "Procession", + "Father
to
Son
", + "White
Queen
", + "Some
Day
One
Day
", + "The
Loser
in
the
End
", + "Ogre
Battle
", + "The
Fairy
Feller's
Master-Stroke
", + "Nevermore", + "The
March
of
the
Black
Queen
", + "Funny
How
Love
Is
", + "Seven
Seas
of
Rhye
", + + "Brighton
Rock
", + "Killer
Queen
", + "Tenement
Funster
", + "Flick
of
the
Wrist
", + "Lily
of
the
Valley
", + "Now
I'm
Here
", + "In
the
Lap
of
the
Gods
", + "Stone
Cold
Crazy
", + "Dear
Friends
", + "Misfire", + "Bring
Back
That
Leroy
Brown
", + "She
Makes
Me
", + "In
the
Lap
of
the
God
-
Revisited
", + + "Death
on
Two
Legs
", + "Lazing
on
a
Sunday
Afternoon
", + "I'm
in
Love
with
My
Car
", + "You're
My
Best
Friend
", + "'39", + "Sweet
Lady
", + "Seaside
Rendezvous
", + "The
Prophet's
Song
", + "Love
of
My
Life
", + "Good
Company
", + "Bohemian
Rhapsody
", + "God
Save
the
Queen
", + + "Tie
Your
Mother
Down
", + "You
Take
My
Breath
Away
", + "Long
Away
", + "The
Millionaire
Waltz
", + "You
and
I
", + "Somebody
to
Love
", + "White
Man
", + "Good
Old-Fashioned
Lover
Boy
", + "Drowse", + "Teo
Torriatte
", + + "We
Will
Rock
You
", + "We
Are
the
Champions
", + "Sheer
Heart
Attack
", + "All
Dead,
All
Dead
", + "Spread
Your
Wings
", + "Fight
from
the
Inside
", + "Get
Down,
Make
Love
", + "Sleeping
on
the
Sidewalk
", + "Who
Needs
You
", + "It's
Late
", + "My
Melancholy
Blues
", + + "Mustapha", + "Fat
Bottomed
Girls
", + "Jealousy", + "Bicycle
Race
", + "If
You
Can't
Beat
Them
", + "Let
Me
Entertain
You
", + "Dead
on
Time
", + "In
Only
Seven
Days
", + "Dreamer's
Ball
", + "Fun
It
", + "Leaving
Home
Ain't
Easy
", + "Don't
Stop
Me
Now
", + "More
of
That
Jazz
", + + "Play
the
Game
", + "Dragon
Attack
", + "Another
One
Bites
the
Dust
", + "Need
Your
Loving
Tonight
", + "Crazy
Little
Thing
Called
Love
", + "Rock
It
", + "Don't
Try
Suicide
", + "Sail
Away
Sweet
Sister
", + "Coming
Soon
", + "Save
Me
", + + "Staying
Power
", + "Dancer", + "Back
Chat
", + "Body
Language
", + "Action
This
Day
", + "Put
Out
the
Fire
", + "Life
Is
Real
", + "Calling
All
Girls
", + "Las
Palabras
de
Amor
", + "Cool
Cat
", + "Under
Pressure
", + + "Radio
Ga
Ga
", + "Tear
It
Up
", + "It's
a
Hard
Life
", + "Man
on
the
Prowl
", + "Back
to
Humans'
", + "I
Want
to
Break
Free
", + "Keep
Passing
the
Open
Windows
", + "Hammer
to
Fall
", + "Is
This
the
World
We
Created?
", + + "One
Vision
", + "A
Kind
of
Magic
", + "One
Year
of
Love
", + "Pain
Is
So
Close
to
Pleasure
", + "Friends
Will
Be
Friends
", + "Who
Wants
to
Live
Forever
", + "Gimme
the
Prize
", + "Don't
Lose
Your
Head
", + "Princes
of
the
Universe
", + + "Party", + "Khashoggi's
Ship
", + "The
Miracle
", + "I
Want
It
All
", + "The
Invisible
Man
", + "Breakthru", + "Rain
Must
Fall
", + "Scandal", + "My
Baby
Does
Me
", + "Was
It
All
Worth
It
", + + "Innuendo", + "I'm
Going
Slightly
Mad
", + "Headlong", + "I
Can't
Live
with
You
", + "Don't
Try
So
Hard
", + "Ride
the
Wild
Wind
", + "All
God's
People
", + "These
Are
the
Days
of
Our
Lives
", + "Delilah", + "The
Hitman
", + "Bijou", + "The
Show
Must
Go
On
", + + "It's
a
Beautiful
Day
", + "Made
in
Heaven
", + "Let
Me
Live
", + "Mother
Love
", + "My
Life
Has
Been
Saved
", + "I
Was
Born
to
Love
You
", + "Heaven
for
Everyone
", + "Too
Much
Love
Will
Kill
You
", + "You
Don't
Fool
Me
", + "A
Winter's
Tale
", + "It's
a
Beautiful
Day
-
Revisited
", + "Yeah", + "13" + ], + "parents": [ + "Queen records", + "Queen records", + "Queen records", + "Queen records", + "Queen records", + "Queen records", + "Queen records", + "Queen records", + "Queen records", + "Queen records", + "Queen records", + "Queen records", + "Queen records", + "Queen records", + + "Queen - 1973", + "Queen - 1973", + "Queen - 1973", + "Queen - 1973", + "Queen - 1973", + "Queen - 1973", + "Queen - 1973", + "Queen - 1973", + "Queen - 1973", + "Queen - 1973", + + "Queen II - 1974", + "Queen II - 1974", + "Queen II - 1974", + "Queen II - 1974", + "Queen II - 1974", + "Queen II - 1974", + "Queen II - 1974", + "Queen II - 1974", + "Queen II - 1974", + "Queen II - 1974", + "Queen II - 1974", + + "Sheer Heart Attack - 1974", + "Sheer Heart Attack - 1974", + "Sheer Heart Attack - 1974", + "Sheer Heart Attack - 1974", + "Sheer Heart Attack - 1974", + "Sheer Heart Attack - 1974", + "Sheer Heart Attack - 1974", + "Sheer Heart Attack - 1974", + "Sheer Heart Attack - 1974", + "Sheer Heart Attack - 1974", + "Sheer Heart Attack - 1974", + "Sheer Heart Attack - 1974", + "Sheer Heart Attack - 1974", + + "A Night at the Opera - 1975", + "A Night at the Opera - 1975", + "A Night at the Opera - 1975", + "A Night at the Opera - 1975", + "A Night at the Opera - 1975", + "A Night at the Opera - 1975", + "A Night at the Opera - 1975", + "A Night at the Opera - 1975", + "A Night at the Opera - 1975", + "A Night at the Opera - 1975", + "A Night at the Opera - 1975", + "A Night at the Opera - 1975", + + "A Day at the Races - 1976", + "A Day at the Races - 1976", + "A Day at the Races - 1976", + "A Day at the Races - 1976", + "A Day at the Races - 1976", + "A Day at the Races - 1976", + "A Day at the Races - 1976", + "A Day at the Races - 1976", + "A Day at the Races - 1976", + "A Day at the Races - 1976", + + "News of the World - 1977", + "News of the World - 1977", + "News of the World - 1977", + "News of the World - 1977", + "News of the World - 1977", + "News of the World - 1977", + "News of the World - 1977", + "News of the World - 1977", + "News of the World - 1977", + "News of the World - 1977", + "News of the World - 1977", + + "Jazz - 1978", + "Jazz - 1978", + "Jazz - 1978", + "Jazz - 1978", + "Jazz - 1978", + "Jazz - 1978", + "Jazz - 1978", + "Jazz - 1978", + "Jazz - 1978", + "Jazz - 1978", + "Jazz - 1978", + "Jazz - 1978", + "Jazz - 1978", + + "The Game - 1980", + "The Game - 1980", + "The Game - 1980", + "The Game - 1980", + "The Game - 1980", + "The Game - 1980", + "The Game - 1980", + "The Game - 1980", + "The Game - 1980", + "The Game - 1980", + + "Hot Space - 1982", + "Hot Space - 1982", + "Hot Space - 1982", + "Hot Space - 1982", + "Hot Space - 1982", + "Hot Space - 1982", + "Hot Space - 1982", + "Hot Space - 1982", + "Hot Space - 1982", + "Hot Space - 1982", + "Hot Space - 1982", + + "The Works - 1984", + "The Works - 1984", + "The Works - 1984", + "The Works - 1984", + "The Works - 1984", + "The Works - 1984", + "The Works - 1984", + "The Works - 1984", + "The Works - 1984", + + "A Kind of Magic - 1986", + "A Kind of Magic - 1986", + "A Kind of Magic - 1986", + "A Kind of Magic - 1986", + "A Kind of Magic - 1986", + "A Kind of Magic - 1986", + "A Kind of Magic - 1986", + "A Kind of Magic - 1986", + "A Kind of Magic - 1986", + + "The Miracle - 1989", + "The Miracle - 1989", + "The Miracle - 1989", + "The Miracle - 1989", + "The Miracle - 1989", + "The Miracle - 1989", + "The Miracle - 1989", + "The Miracle - 1989", + "The Miracle - 1989", + "The Miracle - 1989", + + "Innuendo - 1991", + "Innuendo - 1991", + "Innuendo - 1991", + "Innuendo - 1991", + "Innuendo - 1991", + "Innuendo - 1991", + "Innuendo - 1991", + "Innuendo - 1991", + "Innuendo - 1991", + "Innuendo - 1991", + "Innuendo - 1991", + "Innuendo - 1991", + + "Made in Heaven - 1995", + "Made in Heaven - 1995", + "Made in Heaven - 1995", + "Made in Heaven - 1995", + "Made in Heaven - 1995", + "Made in Heaven - 1995", + "Made in Heaven - 1995", + "Made in Heaven - 1995", + "Made in Heaven - 1995", + "Made in Heaven - 1995", + "Made in Heaven - 1995", + "Made in Heaven - 1995", + "Made in Heaven - 1995" + ], + "text": [ + "38:41", + "40:45", + "38:41", + "43:03", + "44:04", + "39:10", + "44:39", + "35:32", + "43:29", + "37:15", + "40:28", + "41:22", + "53:48", + "70:21", + + "3:46", + "4:10", + "5:41", + "4:07", + "6:26", + "4:24", + "1:48", + "3:24", + "3:45", + "1:10", + + "1:12", + "6:14", + "4:34", + "4:23", + "4:02", + "4:10", + "2:40", + "1:17", + "6:33", + "2:50", + "2:50", + + "5:08", + "3:01", + "2:48", + "3:19", + "1:43", + "4:10", + "3:20", + "2:12", + "1:07", + "1:50", + "2:13", + "4:08", + "3:42", + + "3:43", + "1:08", + "3:05", + "2:50", + "3:30", + "4:01", + "2:13", + "8:21", + "3:38", + "3:26", + "5:57", + "1:11", + + "4:48", + "5:09", + "3:34", + "4:54", + "3:25", + "4:56", + "4:59", + "2:54", + "3:45", + "5:50", + + "2:01", + "2:59", + "3:26", + "3:10", + "4:34", + "3:03", + "3:51", + "3:06", + "3:05", + "6:26", + "3:29", + + "3:03", + "4:14", + "3:14", + "3:04", + "4:15", + "3:01", + "3:23", + "2:30", + "3:30", + "3:29", + "3:15", + "3:29", + "4:12", + + "3:30", + "4:18", + "3:35", + "2:50", + "2:42", + "4:33", + "3:52", + "3:33", + "2:51", + "3:48", + + "4:10", + "3:46", + "4:31", + "4:29", + "3:33", + "3:15", + "3:39", + "3:53", + "4:26", + "3:26", + "4:02", + + "5:48", + "3:28", + "4:08", + "3:28", + "5:10", + "3:20", + "5:21", + "4:28", + "2:13", + + "5:11", + "4:24", + "4:27", + "4:21", + "4:06", + "5:15", + "4:33", + "4:38", + "3:33", + + "2:24", + "2:47", + "5:02", + "4:41", + "3:55", + "4:07", + "4:20", + "4:42", + "3:22", + "5:45", + + "6:31", + "4:22", + "4:38", + "4:33", + "3:39", + "4:42", + "4:21", + "4:15", + "3:35", + "4:56", + "3:36", + "4:35", + + "2:32", + "5:25", + "4:45", + "4:49", + "3:15", + "4:49", + "5:36", + "4:20", + "5:24", + "3:49", + "3:01", + "0:04", + "22:32" + ] + } + ], + "layout": { + "width": 1000, + "height": 1000 + } +} diff --git a/test/image/mocks/treemap_textposition.json b/test/image/mocks/treemap_textposition.json new file mode 100644 index 00000000000..0657347fa51 --- /dev/null +++ b/test/image/mocks/treemap_textposition.json @@ -0,0 +1,982 @@ +{ + "data": [ + { + "type": "treemap", + "textinfo": "label+text+percent parent+percent entry+percent root", + "name": "bottom left textposition", + "textposition": "bottom left", + "pathbar": { + "side": "bottom", + "textfont": { + "size": 12, + "family": "Times New Roman" + } + }, + "text": [ + "A L P H A", + "B R A V O", + "C H A R L I E", + "D E L T A", + "E C H O", + "F O X T R O T", + "G O L F", + "H O T E L", + "I N D I A", + "J U L I E T", + "K I L O", + "L I M A", + "M I K E", + "N O V E M B E R", + "O S C A R", + "P A P A", + "Q U E B E C", + "R O M E O", + "S I E R R A", + "T A N G O", + "U N I F O R M", + "V I C T O R", + "W H I S K E Y", + "X R A Y", + "Y A N K E E", + "Z U L U" + ], + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "domain": { + "x": [ + 0, + 0.3 + ], + "y": [ + 0, + 0.3 + ] + } + }, + { + "type": "treemap", + "textinfo": "label+text+percent parent+percent entry+percent root", + "name": "bottom center textposition", + "textposition": "bottom center", + "pathbar": { + "textfont": { + "size": 12, + "family": "Times New Roman" + } + }, + "text": [ + "A L P H A", + "B R A V O", + "C H A R L I E", + "D E L T A", + "E C H O", + "F O X T R O T", + "G O L F", + "H O T E L", + "I N D I A", + "J U L I E T", + "K I L O", + "L I M A", + "M I K E", + "N O V E M B E R", + "O S C A R", + "P A P A", + "Q U E B E C", + "R O M E O", + "S I E R R A", + "T A N G O", + "U N I F O R M", + "V I C T O R", + "W H I S K E Y", + "X R A Y", + "Y A N K E E", + "Z U L U" + ], + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "level": "Charlie", + "maxdepth": 3, + "domain": { + "x": [ + 0.35, + 0.65 + ], + "y": [ + 0, + 0.3 + ] + } + }, + { + "type": "treemap", + "textinfo": "label+text+percent parent+percent entry+percent root", + "name": "bottom right textposition", + "textposition": "bottom right", + "pathbar": { + "side": "bottom", + "textfont": { + "size": 12, + "family": "Times New Roman" + } + }, + "text": [ + "A L P H A", + "B R A V O", + "C H A R L I E", + "D E L T A", + "E C H O", + "F O X T R O T", + "G O L F", + "H O T E L", + "I N D I A", + "J U L I E T", + "K I L O", + "L I M A", + "M I K E", + "N O V E M B E R", + "O S C A R", + "P A P A", + "Q U E B E C", + "R O M E O", + "S I E R R A", + "T A N G O", + "U N I F O R M", + "V I C T O R", + "W H I S K E Y", + "X R A Y", + "Y A N K E E", + "Z U L U" + ], + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "level": "Foxtrot", + "maxdepth": 3, + "domain": { + "x": [ + 0.7, + 1 + ], + "y": [ + 0, + 0.3 + ] + } + }, + { + "type": "treemap", + "textinfo": "label+text+percent parent+percent entry+percent root", + "name": "middle left textposition", + "textposition": "middle left", + "pathbar": { + "visible": false + }, + "text": [ + "A L P H A", + "B R A V O", + "C H A R L I E", + "D E L T A", + "E C H O", + "F O X T R O T", + "G O L F", + "H O T E L", + "I N D I A", + "J U L I E T", + "K I L O", + "L I M A", + "M I K E", + "N O V E M B E R", + "O S C A R", + "P A P A", + "Q U E B E C", + "R O M E O", + "S I E R R A", + "T A N G O", + "U N I F O R M", + "V I C T O R", + "W H I S K E Y", + "X R A Y", + "Y A N K E E", + "Z U L U" + ], + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "level": "Zulu", + "maxdepth": 3, + "domain": { + "x": [ + 0, + 0.3 + ], + "y": [ + 0.35, + 0.65 + ] + } + }, + { + "type": "treemap", + "textinfo": "label+text+percent parent+percent entry+percent root", + "name": "middle center textposition", + "textposition": "middle center", + "pathbar": { + "visible": false + }, + "text": [ + "A L P H A", + "B R A V O", + "C H A R L I E", + "D E L T A", + "E C H O", + "F O X T R O T", + "G O L F", + "H O T E L", + "I N D I A", + "J U L I E T", + "K I L O", + "L I M A", + "M I K E", + "N O V E M B E R", + "O S C A R", + "P A P A", + "Q U E B E C", + "R O M E O", + "S I E R R A", + "T A N G O", + "U N I F O R M", + "V I C T O R", + "W H I S K E Y", + "X R A Y", + "Y A N K E E", + "Z U L U" + ], + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "level": "Alpha", + "maxdepth": 3, + "domain": { + "x": [ + 0.35, + 0.65 + ], + "y": [ + 0.35, + 0.65 + ] + } + }, + { + "type": "treemap", + "textinfo": "label+text+percent parent+percent entry+percent root", + "name": "middle right textposition", + "textposition": "middle right", + "pathbar": { + "visible": false + }, + "text": [ + "A L P H A", + "B R A V O", + "C H A R L I E", + "D E L T A", + "E C H O", + "F O X T R O T", + "G O L F", + "H O T E L", + "I N D I A", + "J U L I E T", + "K I L O", + "L I M A", + "M I K E", + "N O V E M B E R", + "O S C A R", + "P A P A", + "Q U E B E C", + "R O M E O", + "S I E R R A", + "T A N G O", + "U N I F O R M", + "V I C T O R", + "W H I S K E Y", + "X R A Y", + "Y A N K E E", + "Z U L U" + ], + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "level": "Bravo", + "maxdepth": 3, + "domain": { + "x": [ + 0.7, + 1 + ], + "y": [ + 0.35, + 0.65 + ] + } + }, + { + "type": "treemap", + "textinfo": "label+text+percent parent+percent entry+percent root", + "name": "top left textposition", + "textposition": "top left", + "pathbar": { + "textfont": { + "size": 12, + "family": "Times New Roman" + } + }, + "text": [ + "A L P H A", + "B R A V O", + "C H A R L I E", + "D E L T A", + "E C H O", + "F O X T R O T", + "G O L F", + "H O T E L", + "I N D I A", + "J U L I E T", + "K I L O", + "L I M A", + "M I K E", + "N O V E M B E R", + "O S C A R", + "P A P A", + "Q U E B E C", + "R O M E O", + "S I E R R A", + "T A N G O", + "U N I F O R M", + "V I C T O R", + "W H I S K E Y", + "X R A Y", + "Y A N K E E", + "Z U L U" + ], + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "level": "Juliet", + "maxdepth": 3, + "domain": { + "x": [ + 0, + 0.3 + ], + "y": [ + 0.7, + 1 + ] + } + }, + { + "type": "treemap", + "textinfo": "label+text+percent parent+percent entry+percent root", + "name": "top center textposition", + "textposition": "top center", + "pathbar": { + "side": "bottom", + "textfont": { + "size": 12, + "family": "Times New Roman" + } + }, + "text": [ + "A L P H A", + "B R A V O", + "C H A R L I E", + "D E L T A", + "E C H O", + "F O X T R O T", + "G O L F", + "H O T E L", + "I N D I A", + "J U L I E T", + "K I L O", + "L I M A", + "M I K E", + "N O V E M B E R", + "O S C A R", + "P A P A", + "Q U E B E C", + "R O M E O", + "S I E R R A", + "T A N G O", + "U N I F O R M", + "V I C T O R", + "W H I S K E Y", + "X R A Y", + "Y A N K E E", + "Z U L U" + ], + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "level": "Oscar", + "maxdepth": 3, + "domain": { + "x": [ + 0.35, + 0.65 + ], + "y": [ + 0.7, + 1 + ] + } + }, + { + "type": "treemap", + "textinfo": "label+text+percent parent+percent entry+percent root", + "name": "top right textposition", + "textposition": "top right", + "pathbar": { + "textfont": { + "size": 12, + "family": "Times New Roman" + } + }, + "text": [ + "A L P H A", + "B R A V O", + "C H A R L I E", + "D E L T A", + "E C H O", + "F O X T R O T", + "G O L F", + "H O T E L", + "I N D I A", + "J U L I E T", + "K I L O", + "L I M A", + "M I K E", + "N O V E M B E R", + "O S C A R", + "P A P A", + "Q U E B E C", + "R O M E O", + "S I E R R A", + "T A N G O", + "U N I F O R M", + "V I C T O R", + "W H I S K E Y", + "X R A Y", + "Y A N K E E", + "Z U L U" + ], + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "level": "Uniform", + "maxdepth": 3, + "domain": { + "x": [ + 0.7, + 1 + ], + "y": [ + 0.7, + 1 + ] + } + } + ], + "layout": { + "width": 1200, + "height": 1200, + "paper_bgcolor": "#210" + } +} diff --git a/test/image/mocks/treemap_transpose_nopad.json b/test/image/mocks/treemap_transpose_nopad.json new file mode 100644 index 00000000000..dc22ed0fae3 --- /dev/null +++ b/test/image/mocks/treemap_transpose_nopad.json @@ -0,0 +1,418 @@ +{ + "data": [ + { + "type": "treemap", + "hoverinfo": "all", + "textposition": "middle center", + "textinfo": "label", + "textfont": { + "size": 10 + }, + "pathbar": { + "visible": true + }, + "tiling": { + "packing": "squarify", + "squarifyratio": 1, + "pad": 0 + }, + "marker": { + "pad": { + "t": 0, + "l": 0, + "r": 0, + "b": 0 + } + }, + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "", + "", + "Bravo", + "Bravo", + "Bravo", + "Echo", + "Echo", + "Echo", + "Hotel", + "Hotel", + "Hotel", + "Kilo", + "Kilo", + "Kilo", + "November", + "November", + "November", + "Quebec", + "Quebec", + "Quebec", + "Tango", + "Tango", + "Tango", + "Whiskey", + "Whiskey" + ], + "domain": { + "x": [ + 0.02, + 0.31 + ], + "y": [ + 0, + 0.45 + ] + } + }, + { + "type": "treemap", + "hoverinfo": "all", + "textposition": "middle center", + "textinfo": "label", + "textfont": { + "size": 10 + }, + "pathbar": { + "visible": true + }, + "tiling": { + "packing": "squarify", + "squarifyratio": 1.618034, + "pad": 0 + }, + "marker": { + "pad": { + "t": 0, + "l": 0, + "r": 0, + "b": 0 + } + }, + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "", + "", + "Bravo", + "Bravo", + "Bravo", + "Echo", + "Echo", + "Echo", + "Hotel", + "Hotel", + "Hotel", + "Kilo", + "Kilo", + "Kilo", + "November", + "November", + "November", + "Quebec", + "Quebec", + "Quebec", + "Tango", + "Tango", + "Tango", + "Whiskey", + "Whiskey" + ], + "domain": { + "x": [ + 0.02, + 0.31 + ], + "y": [ + 0.5, + 0.95 + ] + } + }, + { + "type": "treemap", + "hoverinfo": "all", + "textposition": "middle center", + "textinfo": "label", + "textfont": { + "size": 10 + }, + "pathbar": { + "visible": true + }, + "tiling": { + "packing": "squarify", + "squarifyratio": 1, + "pad": 0 + }, + "marker": { + "pad": { + "t": 0, + "l": 0, + "r": 0, + "b": 0 + } + }, + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "", + "", + "Bravo", + "Bravo", + "Bravo", + "Echo", + "Echo", + "Echo", + "Hotel", + "Hotel", + "Hotel", + "Kilo", + "Kilo", + "Kilo", + "November", + "November", + "November", + "Quebec", + "Quebec", + "Quebec", + "Tango", + "Tango", + "Tango", + "Whiskey", + "Whiskey" + ], + "domain": { + "x": [ + 0.35, + 0.98 + ], + "y": [ + 0, + 0.45 + ] + } + }, + { + "type": "treemap", + "hoverinfo": "all", + "textposition": "middle center", + "textinfo": "label", + "textfont": { + "size": 10 + }, + "pathbar": { + "visible": true + }, + "tiling": { + "packing": "squarify", + "squarifyratio": 1.618034, + "pad": 0 + }, + "marker": { + "pad": { + "t": 0, + "l": 0, + "r": 0, + "b": 0 + } + }, + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "", + "", + "Bravo", + "Bravo", + "Bravo", + "Echo", + "Echo", + "Echo", + "Hotel", + "Hotel", + "Hotel", + "Kilo", + "Kilo", + "Kilo", + "November", + "November", + "November", + "Quebec", + "Quebec", + "Quebec", + "Tango", + "Tango", + "Tango", + "Whiskey", + "Whiskey" + ], + "domain": { + "x": [ + 0.35, + 0.98 + ], + "y": [ + 0.5, + 0.95 + ] + } + } + ], + "layout": { + "width": 1200, + "height": 800, + "annotations": [ + { + "showarrow": false, + "text": "square", + "font": { + "size": 16 + }, + "x": 0.17, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "transposed", + "font": { + "size": 16 + }, + "x": 0.17, + "xanchor": "center", + "y": 1, + "yanchor": "bottom" + }, + { + "showarrow": false, + "text": "rectangle", + "font": { + "size": 16 + }, + "x": 0.66, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "transposed rectangle", + "font": { + "size": 16 + }, + "x": 0.66, + "xanchor": "center", + "y": 1, + "yanchor": "bottom" + } + ] + } +} diff --git a/test/image/mocks/treemap_values.json b/test/image/mocks/treemap_values.json new file mode 100644 index 00000000000..81fd7a1a579 --- /dev/null +++ b/test/image/mocks/treemap_values.json @@ -0,0 +1,49 @@ +{ + "data": [ + { + "type": "treemap", + "name": "with branchvalues:remainder", + "labels": ["Eve", "Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"], + "parents": ["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve" ], + "values": [10, 14, 12, 10, 2, 6, 6, 1, 4], + "textinfo": "label+value+percent parent+percent entry", + "domain": {"x": [0, 0.48]}, + "outsidetextfont": {"size": 20, "color": "#377eb8"}, + "marker": {"line": {"width": 2}}, + "pathbar": {"visible": false} + }, + { + "type": "treemap", + "name": "with branchvalues:total", + "branchvalues": "total", + "labels": ["Eve", "Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"], + "parents": ["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve" ], + "domain": {"x": [0.52, 1]}, + "values": [65, 14, 12, 10, 2, 6, 6, 1, 4], + "textinfo": "label+value+percent parent+percent entry", + "outsidetextfont": {"size": 20, "color": "#377eb8"}, + "marker": {"line": {"width": 2}}, + "pathbar": {"visible": false} + } + ], + "layout": { + "annotations": [{ + "showarrow": false, + "text": "branchvalues: remainder", + "x": 0.25, + "xanchor": "center", + "y": 1.1, + "yanchor": "bottom" + + }, { + "showarrow": false, + "text": "branchvalues: total", + "x": 0.75, + "xanchor": "center", + "y": 1.1, + "yanchor": "bottom" + }], + + "paper_bgcolor": "#d3d3d3" + } +} diff --git a/test/image/mocks/treemap_values_colorscale.json b/test/image/mocks/treemap_values_colorscale.json new file mode 100644 index 00000000000..67ed042f626 --- /dev/null +++ b/test/image/mocks/treemap_values_colorscale.json @@ -0,0 +1,184 @@ +{ + "data": [ + { + "type": "treemap", + "name": "with branchvalues:remainder", + "labels": [ + "Eve", + "Cain", + "Seth", + "Enos", + "Noam", + "Abel", + "Awan", + "Enoch", + "Azura" + ], + "parents": [ + "", + "Eve", + "Eve", + "Seth", + "Seth", + "Eve", + "Eve", + "Awan", + "Eve" + ], + "values": [ + 10, + 14, + 12, + 10, + 2, + 6, + 6, + 1, + 4 + ], + "domain": { + "x": [ + 0, + 0.48 + ] + }, + "marker": { + "colorscale": "Portland", + "colors": [ + 10, + 14, + 12, + 10, + 2, + 6, + 6, + 1, + 4 + ], + "showscale": true, + "colorbar": { + "title": "trace A", + "x": 0, + "xanchor": "right" + } + }, + "hovered": { + "marker": { + "line": { + "color": "white" + } + } + }, + "textinfo": "label+value", + "tiling": { + "pad": 4 + }, + "pathbar": { + "thickness": 32, + "color": "black", + "textfont": { + "color": "white", + "size": 28, + "family": "Times New Roman" + } + } + }, + { + "type": "treemap", + "name": "with branchvalues:total", + "branchvalues": "total", + "labels": [ + "Eve", + "Cain", + "Seth", + "Enos", + "Noam", + "Abel", + "Awan", + "Enoch", + "Azura" + ], + "parents": [ + "", + "Eve", + "Eve", + "Seth", + "Seth", + "Eve", + "Eve", + "Awan", + "Eve" + ], + "domain": { + "x": [ + 0.52, + 1 + ] + }, + "values": [ + 65, + 14, + 12, + 10, + 2, + 6, + 6, + 1, + 4 + ], + "text": [ + "sixty five", + "fourteen", + "twelve", + "ten", + "two", + "six", + "six", + "one", + "four" + ], + "marker": { + "cmin": 0, + "cmax": 25, + "colorscale": "Blackbody", + "reversescale": true, + "showscale": true, + "colorbar": { + "title": "trace B" + } + }, + "textinfo": "label+text", + "pathbar": { + "side": "bottom", + "color": "#7F7", + "textfont": { + "size": 20, + "family": "Times New Roman" + } + } + } + ], + "layout": { + "width": 800, + "height": 500, + "annotations": [ + { + "showarrow": false, + "text": "branchvalues: remainder", + "x": 0.25, + "xanchor": "center", + "y": 1.1, + "yanchor": "bottom" + }, + { + "showarrow": false, + "text": "branchvalues: total
used as input to marker.color", + "x": 0.75, + "xanchor": "center", + "y": 1.1, + "yanchor": "bottom" + } + ], + "paper_bgcolor": "#d3d3d3" + } +} diff --git a/test/image/mocks/treemap_with-without_values.json b/test/image/mocks/treemap_with-without_values.json new file mode 100644 index 00000000000..8fe726071c8 --- /dev/null +++ b/test/image/mocks/treemap_with-without_values.json @@ -0,0 +1,430 @@ +{ + "data": [ + { + "type": "treemap", + "textinfo": "label+value+percent parent+percent entry+percent root+text+current path", + "hoverinfo": "all", + "name": "without values", + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "domain": { + "x": [ + 0.01, + 0.33 + ] + } + }, + { + "type": "treemap", + "textinfo": "label+value+percent parent+percent entry+percent root+text+current path", + "hoverinfo": "all", + "name": "with total values", + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "branchvalues": "total", + "values": [ + 40, + 2, + 38, + 1.5, + 2.5, + 34, + 1, + 2, + 3, + 28, + 1.25, + 1.75, + 2.25, + 2.75, + 20, + 1, + 1.5, + 2, + 2.5, + 3, + 10, + 1, + 1.5, + 2, + 2.5, + 3 + ], + "text": [ + "forty", + "two", + "thirty-eight", + "one and a half", + "two and a half", + "thirty-four", + "one", + "two", + "three", + "twenty-eight", + "one and twenty-five hundredths", + "one and seventy-five hundredths", + "two and twenty-five hundredths", + "two and seventy-five hundredths", + "twenty", + "one", + "one and a half", + "two", + "two and a half", + "three", + "ten", + "one", + "one and a half", + "two", + "two and a half", + "three" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "marker": { + "colorscale": [ + [ + 0, + "#FFF" + ], + [ + 0.01, + "#0FF" + ], + [ + 0.1, + "#00F" + ], + [ + 1, + "#000" + ] + ] + }, + "domain": { + "x": [ + 0.34, + 0.66 + ] + } + }, + { + "type": "treemap", + "textinfo": "label+value+percent parent+percent entry+percent root+text+current path", + "hoverinfo": "all", + "name": "with remainder values", + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "branchvalues": "remainder", + "values": [ + 0, + 2, + 0, + 1.5, + 2.5, + 0, + 1, + 2, + 3, + 0, + 1.25, + 1.75, + 2.25, + 2.75, + 0, + 1, + 1.5, + 2, + 2.5, + 3, + 0, + 1, + 1.5, + 2, + 2.5, + 3 + ], + "text": [ + "zero", + "two", + "zero", + "one and a half", + "two and a half", + "zero", + "one", + "two", + "three", + "zero", + "one and twenty-five hundredths", + "one and seventy-five hundredths", + "two and twenty-five hundredths", + "two and seventy-five hundredths", + "zero", + "one", + "one and a half", + "two", + "two and a half", + "three", + "zero", + "one", + "one and a half", + "two", + "two and a half", + "three" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "marker": { + "colorscale": [ + [ + 0, + "#FFF" + ], + [ + 0.01, + "#0FF" + ], + [ + 0.1, + "#00F" + ], + [ + 1, + "#000" + ] + ] + }, + "domain": { + "x": [ + 0.67, + 0.99 + ] + } + } + ], + "layout": { + "margin" : { + "t": 50, + "l": 0, + "r": 0, + "b": 25 + }, + "width": 1500, + "height": 600, + "shapes": [ + { + "type": "rect", + "layer": "above", + "x0": 0.01, + "x1": 0.33, + "y0": 0, + "y1": 1 + }, + { + "type": "rect", + "layer": "above", + "x0": 0.34, + "x1": 0.66, + "y0": 0, + "y1": 1 + }, + { + "type": "rect", + "layer": "above", + "x0": 0.67, + "x1": 0.99, + "y0": 0, + "y1": 1 + } + ], + "annotations": [ + { + "showarrow": false, + "text": "with counted leaves
", + "x": 0.17, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "with values and branchvalues: total
", + "x": 0.5, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "with values and branchvalues: remainder
", + "x": 0.83, + "xanchor": "center", + "y": 0, + "yanchor": "top" + } + ] + } +} diff --git a/test/image/mocks/treemap_with-without_values_template.json b/test/image/mocks/treemap_with-without_values_template.json new file mode 100644 index 00000000000..5aec2b0a3f9 --- /dev/null +++ b/test/image/mocks/treemap_with-without_values_template.json @@ -0,0 +1,434 @@ +{ + "data": [ + { + "type": "treemap", + "texttemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "hovertemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "name": "without values", + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "domain": { + "x": [ + 0.01, + 0.33 + ] + } + }, + { + "type": "treemap", + "texttemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "hovertemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "name": "with total values", + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "branchvalues": "total", + "values": [ + 40, + 2, + 38, + 1.5, + 2.5, + 34, + 1, + 2, + 3, + 28, + 1.25, + 1.75, + 2.25, + 2.75, + 20, + 1, + 1.5, + 2, + 2.5, + 3, + 10, + 1, + 1.5, + 2, + 2.5, + 3 + ], + "text": [ + "forty", + "two", + "thirty-eight", + "one and a half", + "two and a half", + "thirty-four", + "one", + "two", + "three", + "twenty-eight", + "one and twenty-five hundredths", + "one and seventy-five hundredths", + "two and twenty-five hundredths", + "two and seventy-five hundredths", + "twenty", + "one", + "one and a half", + "two", + "two and a half", + "three", + "ten", + "one", + "one and a half", + "two", + "two and a half", + "three" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "marker": { + "colorscale": [ + [ + 0, + "#FFF" + ], + [ + 0.01, + "#FF0" + ], + [ + 0.1, + "#F00" + ], + [ + 1, + "#000" + ] + ] + }, + "domain": { + "x": [ + 0.34, + 0.66 + ] + } + }, + { + "type": "treemap", + "texttemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "hovertemplate": "%{currentPath}%{label}
%{text}
%{value}
%{parent} <=> %{percentParent}
%{entry} <=> %{percentEntry}
%{root} <=> %{percentRoot}", + "name": "with remainder values", + "level": "Oscar", + "labels": [ + "Alpha", + "Bravo", + "Charlie", + "Delta", + "Echo", + "Foxtrot", + "Golf", + "Hotel", + "India", + "Juliet", + "Kilo", + "Lima", + "Mike", + "November", + "Oscar", + "Papa", + "Quebec", + "Romeo", + "Sierra", + "Tango", + "Uniform", + "Victor", + "Whiskey", + "X ray", + "Yankee", + "Zulu" + ], + "branchvalues": "remainder", + "values": [ + 0, + 2, + 0, + 1.5, + 2.5, + 0, + 1, + 2, + 3, + 0, + 1.25, + 1.75, + 2.25, + 2.75, + 0, + 1, + 1.5, + 2, + 2.5, + 3, + 0, + 1, + 1.5, + 2, + 2.5, + 3 + ], + "text": [ + "zero", + "two", + "zero", + "one and a half", + "two and a half", + "zero", + "one", + "two", + "three", + "zero", + "one and twenty-five hundredths", + "one and seventy-five hundredths", + "two and twenty-five hundredths", + "two and seventy-five hundredths", + "zero", + "one", + "one and a half", + "two", + "two and a half", + "three", + "zero", + "one", + "one and a half", + "two", + "two and a half", + "three" + ], + "parents": [ + "", + "Alpha", + "Alpha", + "Charlie", + "Charlie", + "Charlie", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Foxtrot", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Juliet", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Oscar", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform", + "Uniform" + ], + "marker": { + "colorscale": [ + [ + 0, + "#FFF" + ], + [ + 0.01, + "#FF0" + ], + [ + 0.1, + "#F00" + ], + [ + 1, + "#000" + ] + ] + }, + "domain": { + "x": [ + 0.67, + 0.99 + ] + } + } + ], + "layout": { + "treemapcolorway": [ + "#700", + "#077" + ], + "margin" : { + "t": 50, + "l": 0, + "r": 0, + "b": 25 + }, + "width": 1500, + "height": 600, + "shapes": [ + { + "type": "rect", + "layer": "above", + "x0": 0.01, + "x1": 0.33, + "y0": 0, + "y1": 1 + }, + { + "type": "rect", + "layer": "above", + "x0": 0.34, + "x1": 0.66, + "y0": 0, + "y1": 1 + }, + { + "type": "rect", + "layer": "above", + "x0": 0.67, + "x1": 0.99, + "y0": 0, + "y1": 1 + } + ], + "annotations": [ + { + "showarrow": false, + "text": "with counted leaves
", + "x": 0.17, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "with values and branchvalues: total
", + "x": 0.5, + "xanchor": "center", + "y": 0, + "yanchor": "top" + }, + { + "showarrow": false, + "text": "with values and branchvalues: remainder
", + "x": 0.83, + "xanchor": "center", + "y": 0, + "yanchor": "top" + } + ] + } +} diff --git a/test/jasmine/assets/mock_lists.js b/test/jasmine/assets/mock_lists.js index 267ca176811..c72bb86893f 100644 --- a/test/jasmine/assets/mock_lists.js +++ b/test/jasmine/assets/mock_lists.js @@ -33,6 +33,7 @@ var svgMockList = [ ['range_slider_multiple', require('@mocks/range_slider_multiple.json')], ['sankey_energy', require('@mocks/sankey_energy.json')], ['sunburst_coffee', require('@mocks/sunburst_coffee.json')], + ['treemap_coffee', require('@mocks/treemap_coffee.json')], ['parcats_bad-displayindex', require('@mocks/parcats_bad-displayindex.json')], ['scattercarpet', require('@mocks/scattercarpet.json')], ['shapes', require('@mocks/shapes.json')], diff --git a/test/jasmine/tests/plot_api_react_test.js b/test/jasmine/tests/plot_api_react_test.js index 083bd0a83b2..b3e047d1283 100644 --- a/test/jasmine/tests/plot_api_react_test.js +++ b/test/jasmine/tests/plot_api_react_test.js @@ -1901,6 +1901,42 @@ describe('Plotly.react and uirevision attributes', function() { .catch(failTest) .then(done); }); + + it('preserves treemap level changes', function(done) { + function assertLevel(msg, exp) { + expect(gd._fullData[0].level).toBe(exp, msg); + } + + Plotly.react(gd, [{ + type: 'treemap', + labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'], + parents: ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve'], + uirevision: 1 + }]) + .then(function() { + assertLevel('no set level at start', undefined); + }) + .then(function() { + var nodeSeth = d3.select('.slice:nth-child(2)').node(); + mouseEvent('click', 0, 0, {element: nodeSeth}); + }) + .then(function() { + assertLevel('after clicking on Seth sector', 'Seth'); + }) + .then(function() { + return Plotly.react(gd, [{ + type: 'treemap', + labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura', 'Joe'], + parents: ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve', 'Seth'], + uirevision: 1 + }]); + }) + .then(function() { + assertLevel('after reacting with new data, but with same uirevision', 'Seth'); + }) + .catch(failTest) + .then(done); + }); }); describe('Test Plotly.react + interactions under uirevision:', function() { diff --git a/test/jasmine/tests/sunburst_test.js b/test/jasmine/tests/sunburst_test.js index cce6b6034ff..15afa342343 100644 --- a/test/jasmine/tests/sunburst_test.js +++ b/test/jasmine/tests/sunburst_test.js @@ -71,6 +71,18 @@ describe('Test sunburst defaults:', function() { expect(fullData[2].visible).toBe(false, 'no labels'); }); + it('should only coerce *count* when the *values* array is not present', function() { + _supply([ + {labels: [1], parents: ['']}, + {labels: [1], parents: [''], values: []}, + {labels: [1], parents: [''], values: [1]} + ]); + + expect(fullData[0].count).toBe('leaves'); + expect(fullData[1].count).toBe('leaves', 'has empty values'); + expect(fullData[2].count).toBe(undefined, 'has values'); + }); + it('should not coerce *branchvalues* when *values* is not set', function() { _supply([ {labels: [1], parents: [''], values: [1]}, @@ -103,6 +115,16 @@ describe('Test sunburst defaults:', function() { expect(fullData[1].marker.line.color).toBe('#fff', 'dflt'); }); + it('should default *leaf.opacity* depending on having or not having *colorscale*', function() { + _supply([ + {labels: [1], parents: ['']}, + {labels: [1], parents: [''], marker: {colorscale: 'Blues'}} + ]); + + expect(fullData[0].leaf.opacity).toBe(0.7, 'without colorscale'); + expect(fullData[1].leaf.opacity).toBe(1, 'with colorscale'); + }); + it('should include "text" flag in *textinfo* when *text* is set', function() { _supply([ {labels: [1], parents: [''], text: ['A']}, @@ -221,12 +243,16 @@ describe('Test sunburst calc:', function() { var parents = ['', 'Root', 'Root', 'B']; _calc([ - {labels: labels, parents: parents}, + {labels: labels, parents: parents, count: 'leaves+branches'}, + {labels: labels, parents: parents, count: 'branches'}, + {labels: labels, parents: parents}, // N.B. counts 'leaves' in this case {labels: labels, parents: parents, values: [0, 1, 2, 3]}, {labels: labels, parents: parents, values: [30, 20, 10, 5], branchvalues: 'total'} ]); expect(extractPt('value')).toEqual([ + [4, 2, 1, 1], + [2, 1, 0, 0], [2, 1, 1, 1], [6, 5, 1, 3], [30, 20, 10, 5] @@ -245,8 +271,8 @@ describe('Test sunburst calc:', function() { expect(gd.calcdata[0][0].hierarchy).toBe(undefined, 'no computed hierarchy'); expect(Lib.warn).toHaveBeenCalledTimes(2); - expect(Lib.warn.calls.allArgs()[0][0]).toBe('Total value for node Root is smaller than the sum of its children.'); - expect(Lib.warn.calls.allArgs()[1][0]).toBe('Total value for node B is smaller than the sum of its children.'); + expect(Lib.warn.calls.allArgs()[0][0]).toBe('Total value for node Root is smaller than the sum of its children. \nparent value = 0 \nchildren sum = 3'); + expect(Lib.warn.calls.allArgs()[1][0]).toBe('Total value for node B is smaller than the sum of its children. \nparent value = 2 \nchildren sum = 3'); }); it('should warn labels/parents lead to ambiguous hierarchy', function() { @@ -378,7 +404,7 @@ describe('Test sunburst hover:', function() { pos: 4, exp: { label: { - nums: 'Abel\n6', + nums: 'Abel\nEve/\n17% of Eve\n6', name: 'trace 0' }, ptData: { @@ -397,7 +423,7 @@ describe('Test sunburst hover:', function() { pos: 4, exp: { label: { - nums: 'Abel', + nums: 'Abel\nEve/\n17% of Eve', name: 't...' }, ptData: { @@ -945,10 +971,13 @@ describe('Test sunburst tweening:', function() { afterEach(destroyGraphDiv); - function _run(gd, v) { + function _reset() { pathTweenFnLookup = {}; textTweenFnLookup = {}; + } + function _run(gd, v) { + _reset(); click(gd, v)(); // 1 second more than the click transition duration @@ -980,7 +1009,7 @@ describe('Test sunburst tweening:', function() { expect(actual).toBe(trim(exp), msg + ' | node ' + id + ' @t=' + t); } - it('should tween sector exit/update (case: branch, no maxdepth)', function(done) { + it('should tween sector exit/update (case: click on branch, no maxdepth)', function(done) { var mock = { data: [{ type: 'sunburst', @@ -1018,7 +1047,7 @@ describe('Test sunburst tweening:', function() { .then(done); }); - it('should tween sector enter/update (case: entry, no maxdepth)', function(done) { + it('should tween sector enter/update (case: click on entry, no maxdepth)', function(done) { var mock = { data: [{ type: 'sunburst', @@ -1057,7 +1086,7 @@ describe('Test sunburst tweening:', function() { .then(done); }); - it('should tween sector enter/update/exit (case: entry, maxdepth=2)', function(done) { + it('should tween sector enter/update/exit (case: click on entry, maxdepth=2)', function(done) { var mock = { data: [{ type: 'sunburst', @@ -1094,6 +1123,70 @@ describe('Test sunburst tweening:', function() { .catch(failTest) .then(done); }); + + it('should tween sector enter/update/exit (case: click on entry, maxdepth=2, level=B)', function(done) { + var mock = { + data: [{ + type: 'sunburst', + labels: ['Root', 'A', 'B', 'b', 'bb'], + parents: ['', 'Root', 'Root', 'B', 'b'], + maxdepth: 2, + level: 'B' + }] + }; + + Plotly.plot(gd, mock) + .then(_run(gd, 1)) + .then(function() { + _assert('exit b radially outward and to parent sector angle', 'd', 'b', + 'M350,133.75L350,100A135,1350,1,0485,235.00000000000003' + + 'L451.25,235.00000000000003A101.25,101.250,1,1350,133.75Z' + ); + _assert('enter new entry radially outward', 'd', 'Root', + 'M350,235A0,00,1,0350,235A0,00,1,0350,235Z' + + 'M383.75,235A33.75,33.750,1,1316.25,235A33.75,33.750,1,1383.75,235Z' + ); + _assert('enter A counterclockwise', 'd', 'A', + 'M417.5,235L485,235A135,1350,0,0350,100L350,167.5A67.5,67.50,0,1417.5,235Z' + ); + _assert('update B to new position', 'd', 'B', + 'M350,201.25L350,133.75A101.25,101.250,1,0451.25,235.00000000000003' + + 'L383.75,235A33.75,33.750,1,1350,201.25Z' + ); + }) + .catch(failTest) + .then(done); + }); + + /* + it('should tween in sectors from new traces', function(done) { + Plotly.plot(gd, [{type: 'sunburst'}]) + .then(_reset) + .then(function() { + return Plotly.animate(gd, [{ + type: 'sunburst', + labels: ['Root', 'A', 'B', 'b'], + parents: ['', 'Root', 'Root', 'B'] + }]); + }) + .then(function() { + _assert('enter entry from theta=0', 'd', 'Root', + '' + ); + // _assert('enter A from theta=0', 'd', 'A', + // '' + // ); + // _assert('enter B from theta=0', 'd', 'B', + // '' + // ); + // _assert('enter b from theta=0', 'd', 'b', + // '' + // ); + }) + .catch(failTest) + .then(done); + }); + */ }); describe('Test sunburst interactions edge cases', function() { @@ -1239,16 +1332,189 @@ describe('Test sunburst interactions edge cases', function() { }); }); -describe('Test sunburst texttemplate:', function() { +describe('Test sunburst texttemplate without `values` should work at root level:', function() { + checkTextTemplate([{ + type: 'sunburst', + labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'], + parents: ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve' ], + text: ['sixty-five', 'fourteen', 'twelve', 'ten', 'two', 'six', 'six', 'one', 'four'] + }], 'g.slicetext', [ + ['color: %{color}', ['color: rgba(0,0,0,0)', 'color: #1f77b4', 'color: #ff7f0e', 'color: #2ca02c', 'color: #d62728', 'color: #9467bd', 'color: #ff7f0e', 'color: #ff7f0e', 'color: #d62728']], + ['label: %{label}', ['label: Eve', 'label: Cain', 'label: Seth', 'label: Enos', 'label: Noam', 'label: Abel', 'label: Awan', 'label: Enoch', 'label: Azura']], + ['text: %{text}', ['text: sixty-five', 'text: fourteen', 'text: twelve', 'text: ten', 'text: two', 'text: six', 'text: six', 'text: one', 'text: four']], + ['path: %{currentPath}', ['path: /', 'path: Eve/', 'path: Eve/', 'path: Eve/', 'path: Eve/', 'path: Eve', 'path: Eve/Seth', 'path: Eve/Seth/', 'path: Eve/Awan/']], + ['%{percentRoot} of %{root}', ['100% of Eve', '33% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve']], + ['%{percentEntry} of %{entry}', ['100% of Eve', '33% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve']], + ['%{percentParent} of %{parent}', ['%{percentParent} of %{parent}', '100% of Seth', '33% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '50% of Seth', '100% of Awan']], + [ + [ + 'label: %{label}', + 'text: %{text}', + 'value: %{value}', + '%{percentRoot} of %{root}', + '%{percentEntry} of %{entry}', + '%{percentParent} of %{parent}', + '%{percentParent} of %{parent}', + '%{percentParent} of %{parent}', + 'color: %{color}' + ], + [ + 'label: Eve', + 'text: fourteen', + 'value: %{value}', // N.B. there is no `values` array + '17% of Eve', + '17% of Eve', + '17% of Eve', + '17% of Eve', + '100% of Awan', + 'color: #9467bd' + ] + ] + ]); +}); + +describe('Test sunburst texttemplate with *total* `values` should work at root level:', function() { + checkTextTemplate([{ + type: 'sunburst', + branchvalues: 'total', + labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'], + parents: ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve' ], + values: [65, 14, 12, 10, 2, 6, 6, 1, 4], + text: ['sixty-five', 'fourteen', 'twelve', 'ten', 'two', 'six', 'six', 'one', 'four'] + }], 'g.slicetext', [ + ['color: %{color}', ['color: rgba(0,0,0,0)', 'color: #1f77b4', 'color: #ff7f0e', 'color: #2ca02c', 'color: #d62728', 'color: #9467bd', 'color: #ff7f0e', 'color: #ff7f0e', 'color: #d62728']], + ['label: %{label}', ['label: Eve', 'label: Cain', 'label: Seth', 'label: Enos', 'label: Noam', 'label: Abel', 'label: Awan', 'label: Enoch', 'label: Azura']], + ['value: %{value}', ['value: 65', 'value: 14', 'value: 12', 'value: 10', 'value: 2', 'value: 6', 'value: 6', 'value: 1', 'value: 4']], + ['text: %{text}', ['text: sixty-five', 'text: fourteen', 'text: twelve', 'text: ten', 'text: two', 'text: six', 'text: six', 'text: one', 'text: four']], + ['path: %{currentPath}', ['path: /', 'path: Eve/', 'path: Eve/', 'path: Eve/', 'path: Eve/', 'path: Eve', 'path: Eve/Seth', 'path: Eve/Seth/', 'path: Eve/Awan/']], + ['%{percentRoot} of %{root}', ['100% of Eve', '22% of Eve', '18% of Eve', '9% of Eve', '9% of Eve', '6% of Eve', '15% of Eve', '3% of Eve', '2% of Eve']], + ['%{percentEntry} of %{entry}', ['100% of Eve', '22% of Eve', '18% of Eve', '9% of Eve', '9% of Eve', '6% of Eve', '15% of Eve', '3% of Eve', '2% of Eve']], + ['%{percentParent} of %{parent}', ['%{percentParent} of %{parent}', '22% of Eve', '18% of Eve', '9% of Eve', '9% of Eve', '6% of Eve', '83% of Seth', '17% of Seth', '17% of Awan']], + [ + [ + 'label: %{label}', + 'text: %{text}', + 'value: %{value}', + '%{percentRoot} of %{root}', + '%{percentEntry} of %{entry}', + '%{percentParent} of %{parent}', + '%{percentParent} of %{parent}', + '%{percentParent} of %{parent}', + 'color: %{color}' + ], + [ + 'label: Eve', + 'text: fourteen', + 'value: 12', + '9% of Eve', + '15% of Eve', + '3% of Eve', + '6% of Eve', + '17% of Awan', + 'color: #9467bd' + ] + ] + ]); +}); + +describe('Test sunburst texttemplate with *remainder* `values` should work at root level:', function() { checkTextTemplate([{ type: 'sunburst', - labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Esther'], - values: [11, 12, 13, 14, 15], - text: ['1', '2', '3', '4', '5'], - parents: ['', 'Eve', 'Eve', 'Seth', 'Seth' ] + branchvalues: 'remainder', + labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'], + parents: ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve' ], + values: [65, 14, 12, 10, 2, 6, 6, 1, 4], + text: ['sixty-five', 'fourteen', 'twelve', 'ten', 'two', 'six', 'six', 'one', 'four'] }], 'g.slicetext', [ - ['txt: %{label}', ['txt: Eve', 'txt: Cain', 'txt: Seth', 'txt: Enos', 'txt: Esther']], - [['txt: %{label}', '%{text}', 'value: %{value}'], ['txt: Eve', '2', 'value: 13', '', '']], - ['%{color}', ['rgba(0,0,0,0)', '#1f77b4', '#ff7f0e', '#1f77b4', '#1f77b4']] + ['color: %{color}', ['color: rgba(0,0,0,0)', 'color: #1f77b4', 'color: #ff7f0e', 'color: #2ca02c', 'color: #d62728', 'color: #9467bd', 'color: #ff7f0e', 'color: #ff7f0e', 'color: #d62728']], + ['label: %{label}', ['label: Eve', 'label: Cain', 'label: Seth', 'label: Enos', 'label: Noam', 'label: Abel', 'label: Awan', 'label: Enoch', 'label: Azura']], + ['value: %{value}', ['value: 65', 'value: 14', 'value: 12', 'value: 10', 'value: 2', 'value: 6', 'value: 6', 'value: 1', 'value: 4']], + ['text: %{text}', ['text: sixty-five', 'text: fourteen', 'text: twelve', 'text: ten', 'text: two', 'text: six', 'text: six', 'text: one', 'text: four']], + ['path: %{currentPath}', ['path: /', 'path: Eve/', 'path: Eve/', 'path: Eve/', 'path: Eve/', 'path: Eve', 'path: Eve/Seth', 'path: Eve/Seth/', 'path: Eve/Awan/']], + ['%{percentRoot} of %{root}', ['100% of Eve', '20% of Eve', '12% of Eve', '6% of Eve', '5% of Eve', '3% of Eve', '8% of Eve', '2% of Eve', '1% of Eve']], + ['%{percentEntry} of %{entry}', ['100% of Eve', '20% of Eve', '12% of Eve', '6% of Eve', '5% of Eve', '3% of Eve', '8% of Eve', '2% of Eve', '1% of Eve']], + ['%{percentParent} of %{parent}', ['%{percentParent} of %{parent}', '20% of Eve', '12% of Eve', '6% of Eve', '5% of Eve', '3% of Eve', '42% of Seth', '8% of Seth', '14% of Awan']], + [ + [ + 'label: %{label}', + 'text: %{text}', + 'value: %{value}', + '%{percentRoot} of %{root}', + '%{percentEntry} of %{entry}', + '%{percentParent} of %{parent}', + '%{percentParent} of %{parent}', + '%{percentParent} of %{parent}', + 'color: %{color}' + ], + [ + 'label: Eve', + 'text: fourteen', + 'value: 12', + '6% of Eve', + '5% of Eve', + '8% of Eve', + '2% of Eve', + '14% of Awan', + 'color: #9467bd' + ] + ] ]); }); + +describe('Test sunburst texttemplate without `values` should work when *level* is set:', function() { + checkTextTemplate([{ + type: 'sunburst', + level: 'Seth', + labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'], + parents: ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve' ], + text: ['sixty-five', 'fourteen', 'twelve', 'ten', 'two', 'six', 'six', 'one', 'four'] + }], 'g.slicetext', [ + ['color: %{color}', ['color: #1f77b4', 'color: #1f77b4', 'color: #1f77b4']], + ['label: %{label}', ['label: Seth', 'label: Enos', 'label: Noam']], + ['text: %{text}', ['text: twelve', 'text: ten', 'text: two']], + ['path: %{currentPath}', ['path: Eve/', 'path: Eve/Seth', 'path: Eve/Seth/']], + ['%{percentRoot} of %{root}', ['33% of Eve', '17% of Eve', '17% of Eve']], + ['%{percentEntry} of %{entry}', ['100% of Seth', '50% of Seth', '50% of Seth']], + ['%{percentParent} of %{parent}', ['33% of Eve', '50% of Seth', '50% of Seth']], + ], /* skipEtra */ true); +}); + +describe('Test sunburst texttemplate with *total* `values` should work when *level* is set:', function() { + checkTextTemplate([{ + type: 'sunburst', + level: 'Seth', + branchvalues: 'total', + labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'], + parents: ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve' ], + values: [65, 14, 12, 10, 2, 6, 6, 1, 4], + text: ['sixty-five', 'fourteen', 'twelve', 'ten', 'two', 'six', 'six', 'one', 'four'] + }], 'g.slicetext', [ + ['color: %{color}', ['color: #ff7f0e', 'color: #ff7f0e', 'color: #ff7f0e']], + ['label: %{label}', ['label: Seth', 'label: Enos', 'label: Noam']], + ['text: %{text}', ['text: twelve', 'text: ten', 'text: two']], + ['path: %{currentPath}', ['path: Eve/', 'path: Eve/Seth', 'path: Eve/Seth/']], + ['%{percentRoot} of %{root}', ['18% of Eve', '15% of Eve', '3% of Eve']], + ['%{percentEntry} of %{entry}', ['100% of Seth', '83% of Seth', '17% of Seth']], + ['%{percentParent} of %{parent}', ['18% of Eve', '83% of Seth', '17% of Seth']], + ], /* skipEtra */ true); +}); + +describe('Test sunburst texttemplate with *remainder* `values` should work when *level* is set:', function() { + checkTextTemplate([{ + type: 'sunburst', + level: 'Seth', + branchvalues: 'remainder', + labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'], + parents: ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve' ], + values: [65, 14, 12, 10, 2, 6, 6, 1, 4], + text: ['sixty-five', 'fourteen', 'twelve', 'ten', 'two', 'six', 'six', 'one', 'four'] + }], 'g.slicetext', [ + ['color: %{color}', ['color: #1f77b4', 'color: #1f77b4', 'color: #1f77b4']], + ['label: %{label}', ['label: Seth', 'label: Enos', 'label: Noam']], + ['text: %{text}', ['text: twelve', 'text: ten', 'text: two']], + ['path: %{currentPath}', ['path: Eve/', 'path: Eve/Seth', 'path: Eve/Seth/']], + ['%{percentRoot} of %{root}', ['20% of Eve', '8% of Eve', '2% of Eve']], + ['%{percentEntry} of %{entry}', ['100% of Seth', '42% of Seth', '8% of Seth']], + ['%{percentParent} of %{parent}', ['20% of Eve', '42% of Seth', '8% of Seth']], + ], /* skipEtra */ true); +}); diff --git a/test/jasmine/tests/treemap_test.js b/test/jasmine/tests/treemap_test.js new file mode 100644 index 00000000000..b812e58b282 --- /dev/null +++ b/test/jasmine/tests/treemap_test.js @@ -0,0 +1,1487 @@ +var Plotly = require('@lib'); +var Plots = require('@src/plots/plots'); +var Lib = require('@src/lib'); +var Drawing = require('@src/components/drawing'); +var constants = require('@src/traces/treemap/constants'); + +var d3 = require('d3'); +var supplyAllDefaults = require('../assets/supply_defaults'); +var createGraphDiv = require('../assets/create_graph_div'); +var destroyGraphDiv = require('../assets/destroy_graph_div'); +var mouseEvent = require('../assets/mouse_event'); +var delay = require('../assets/delay'); +var failTest = require('../assets/fail_test'); + +var customAssertions = require('../assets/custom_assertions'); +var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle; +var assertHoverLabelContent = customAssertions.assertHoverLabelContent; +var checkTextTemplate = require('../assets/check_texttemplate'); + +function _mouseEvent(type, gd, v) { + return function() { + if(Array.isArray(v)) { + // px-based position + mouseEvent(type, v[0], v[1]); + } else { + // position from slice number + var gd3 = d3.select(gd); + var el = gd3.select('.slice:nth-child(' + v + ')').node(); + mouseEvent(type, 0, 0, {element: el}); + } + }; +} + +function hover(gd, v) { + return _mouseEvent('mouseover', gd, v); +} + +function unhover(gd, v) { + return _mouseEvent('mouseout', gd, v); +} + +function click(gd, v) { + return _mouseEvent('click', gd, v); +} + +describe('Test treemap defaults:', function() { + var gd; + var fullData; + + function _supply(opts, layout) { + gd = {}; + opts = Array.isArray(opts) ? opts : [opts]; + + gd.data = opts.map(function(o) { + return Lib.extendFlat({type: 'treemap'}, o || {}); + }); + gd.layout = layout || {}; + + supplyAllDefaults(gd); + fullData = gd._fullData; + } + + it('should set *visible:false* when *labels* or *parents* is missing', function() { + _supply([ + {labels: [1], parents: ['']}, + {labels: [1]}, + {parents: ['']} + ]); + + expect(fullData[0].visible).toBe(true, 'base'); + expect(fullData[1].visible).toBe(false, 'no parents'); + expect(fullData[2].visible).toBe(false, 'no labels'); + }); + + it('should only coerce *count* when the *values* array is not present', function() { + _supply([ + {labels: [1], parents: ['']}, + {labels: [1], parents: [''], values: []}, + {labels: [1], parents: [''], values: [1]} + ]); + + expect(fullData[0].count).toBe('leaves'); + expect(fullData[1].count).toBe('leaves', 'has empty values'); + expect(fullData[2].count).toBe(undefined, 'has values'); + }); + + it('should not coerce *branchvalues* when *values* is not set', function() { + _supply([ + {labels: [1], parents: [''], values: [1]}, + {labels: [1], parents: ['']}, + ]); + + expect(fullData[0].branchvalues).toBe('remainder', 'base'); + expect(fullData[1].branchvalues).toBe(undefined, 'no values'); + }); + + it('should use *paper_bgcolor* as *marker.line.color* default', function() { + _supply([ + {labels: [1], parents: [''], marker: {line: {color: 'red'}}}, + {labels: [1], parents: ['']} + ], { + paper_bgcolor: 'orange' + }); + + expect(fullData[0].marker.line.color).toBe('red', 'set color'); + expect(fullData[1].marker.line.color).toBe('orange', 'using dflt'); + }); + + it('should not coerce *marker.line.color* when *marker.line.width* is 0', function() { + _supply([ + {labels: [1], parents: [''], marker: {line: {width: 0}}}, + {labels: [1], parents: ['']} + ]); + + expect(fullData[0].marker.line.color).toBe(undefined, 'not coerced'); + expect(fullData[1].marker.line.color).toBe('#fff', 'dflt'); + }); + + it('should not coerce *marker.opacitybase*, *marker.opacitybase* and *pathbar.opacity* when having *colorscale*', function() { + _supply([ + {labels: [1], parents: ['']}, + {labels: [1], parents: [''], marker: {colorscale: 'Blues'}} + ]); + + expect(fullData[0].marker.opacitybase).toBe(0.5); + expect(fullData[0].marker.opacitystep).toBe(0.5); + expect(fullData[0].pathbar.opacity).toBe(0.5); + expect(fullData[1].marker.opacitybase).toBe(undefined, 'not coerced'); + expect(fullData[1].marker.opacitystep).toBe(undefined, 'not coerced'); + expect(fullData[1].pathbar.opacity).toBe(undefined, 'not coerced'); + }); + + it('should use *textfont.size* to adjust top, bottom , left and right *marker.pad* defaults', function() { + _supply([ + {labels: [1], parents: ['']}, + {labels: [1], parents: [''], textfont: {size: 24}}, + {labels: [1], parents: [''], textposition: 'bottom left'}, + {labels: [1], parents: [''], textposition: 'bottom center'}, + {labels: [1], parents: [''], textposition: 'bottom right'}, + {labels: [1], parents: [''], textposition: 'middle left'}, + {labels: [1], parents: [''], textposition: 'middle center'}, + {labels: [1], parents: [''], textposition: 'middle right'}, + {labels: [1], parents: [''], textposition: 'top left'}, + {labels: [1], parents: [''], textposition: 'tpo center'}, + {labels: [1], parents: [''], textposition: 'top right'} + ]); + + expect(fullData[0].textfont.size).toBe(12); + expect(fullData[0].marker.pad.t).toBe(24, 'twice of default textfont.size'); + expect(fullData[0].marker.pad.l).toBe(6, 'half of default textfont.size'); + expect(fullData[0].marker.pad.r).toBe(6, 'half of default textfont.size'); + expect(fullData[0].marker.pad.b).toBe(6, 'half of default textfont.size'); + + expect(fullData[1].textfont.size).toBe(24); + expect(fullData[1].marker.pad.t).toBe(48, 'twice of increased textfont.size'); + expect(fullData[1].marker.pad.l).toBe(12, 'half of increased textfont.size'); + expect(fullData[1].marker.pad.r).toBe(12, 'half of increased textfont.size'); + expect(fullData[1].marker.pad.b).toBe(12, 'half of increased textfont.size'); + + var i; + for(i = 0 + 2; i < 3 + 2; i++) { + expect(fullData[i].marker.pad.t).toBe(6, 'half of default textfont.size', 'with textposition:' + fullData[i].textposition); + expect(fullData[i].marker.pad.l).toBe(6, 'half of default textfont.size', 'with textposition:' + fullData[i].textposition); + expect(fullData[i].marker.pad.r).toBe(6, 'half of default textfont.size', 'with textposition:' + fullData[i].textposition); + expect(fullData[i].marker.pad.b).toBe(24, 'twice of default textfont.size', 'with textposition:' + fullData[i].textposition); + } + for(i = 0 + 5; i < 6 + 5; i++) { + expect(fullData[i].marker.pad.t).toBe(24, 'twice of default textfont.size', 'with textposition:' + fullData[i].textposition); + expect(fullData[i].marker.pad.l).toBe(6, 'half of default textfont.size', 'with textposition:' + fullData[i].textposition); + expect(fullData[i].marker.pad.r).toBe(6, 'half of default textfont.size', 'with textposition:' + fullData[i].textposition); + expect(fullData[i].marker.pad.b).toBe(6, 'half of default textfont.size', 'with textposition:' + fullData[i].textposition); + } + }); + + it('should not include "text" flag in *textinfo* when *text* is set', function() { + _supply([ + {labels: [1], parents: [''], text: ['A']}, + {labels: [1], parents: ['']} + ]); + + expect(fullData[0].textinfo).toBe('text+label', 'with text'); + expect(fullData[1].textinfo).toBe('label', 'no text'); + }); + + it('should use *layout.colorway* as dflt for *treemapcolorway*', function() { + _supply([ + {labels: [1], parents: ['']} + ], { + colorway: ['red', 'blue', 'green'] + }); + expect(gd._fullLayout.treemapcolorway) + .toEqual(['red', 'blue', 'green'], 'dflt to layout colorway'); + + _supply([ + {labels: [1], parents: ['']} + ], { + colorway: ['red', 'blue', 'green'], + treemapcolorway: ['cyan', 'yellow', 'black'] + }); + expect(gd._fullLayout.treemapcolorway) + .toEqual(['cyan', 'yellow', 'black'], 'user-defined value'); + }); + + it('should only coerce *squarifyratio* when *tiling.packing* is *squarify*', function() { + _supply([ + {labels: [1], parents: ['']}, + {labels: [1], parents: [''], tiling: {packing: 'binary'}}, + {labels: [1], parents: [''], tiling: {packing: 'slice'}}, + {labels: [1], parents: [''], tiling: {packing: 'dice'}}, + {labels: [1], parents: [''], tiling: {packing: 'slice-dice'}}, + {labels: [1], parents: [''], tiling: {packing: 'dice-slice'}} + ]); + + expect(fullData[0].tiling.squarifyratio).toBe(1); + expect(fullData[1].tiling.squarifyratio).toBe(undefined, 'no squarify'); + expect(fullData[2].tiling.squarifyratio).toBe(undefined, 'no squarify'); + expect(fullData[3].tiling.squarifyratio).toBe(undefined, 'no squarify'); + expect(fullData[4].tiling.squarifyratio).toBe(undefined, 'no squarify'); + expect(fullData[5].tiling.squarifyratio).toBe(undefined, 'no squarify'); + }); + + it('should not coerce *pathbar* attributes when *pathbar.visible* is false', function() { + _supply([ + {labels: [1], parents: [''], pathbar: {visible: false}} + ]); + + expect(fullData[0].pathbar.visible).toBe(false); + expect(fullData[0].pathbar.textfont).toBe(undefined); + expect(fullData[0].pathbar.thickness).toBe(undefined); + expect(fullData[0].pathbar.side).toBe(undefined); + expect(fullData[0].pathbar.edgeshape).toBe(undefined); + }); + + it('should set *pathbar.visible* to true by default', function() { + _supply([ + {labels: [1], parents: ['']} + ]); + + expect(fullData[0].pathbar.visible).toBe(true); + }); + + it('should set *pathbar.visible* to true by default', function() { + _supply([ + {labels: [1], parents: ['']} + ]); + + expect(fullData[0].pathbar.textfont.family).toBe('"Open Sans", verdana, arial, sans-serif'); + expect(fullData[0].pathbar.textfont.color).toBe('#444'); + expect(fullData[0].pathbar.textfont.size).toBe(12); + expect(fullData[0].pathbar.thickness).toBe(18); + expect(fullData[0].pathbar.side).toBe('top'); + expect(fullData[0].pathbar.edgeshape).toBe('>'); + }); + + it('should default *pathbar* sizes and styles to layout', function() { + _supply([ + {labels: [1], parents: ['']} + ], { + font: {family: 'Times New Romans', color: '#ABC', size: 24} + }); + + expect(fullData[0].pathbar.textfont.family).toBe('Times New Romans'); + expect(fullData[0].pathbar.textfont.color).toBe('#ABC'); + expect(fullData[0].pathbar.textfont.size).toBe(24); + expect(fullData[0].pathbar.thickness).toBe(30); + }); +}); + +describe('Test treemap calc:', function() { + var gd; + + beforeEach(function() { + spyOn(Lib, 'warn'); + }); + + function _calc(opts, layout) { + gd = {}; + opts = Array.isArray(opts) ? opts : [opts]; + + gd.data = opts.map(function(o) { + return Lib.extendFlat({type: 'treemap'}, o || {}); + }); + gd.layout = layout || {}; + + supplyAllDefaults(gd); + Plots.doCalcdata(gd); + } + + function extract(k) { + var out = gd.calcdata.map(function(cd) { + return cd.map(function(pt) { return pt[k]; }); + }); + return out.length > 1 ? out : out[0]; + } + + function extractPt(k) { + var out = gd.calcdata.map(function(cd) { + return cd[0].hierarchy.descendants().map(function(pt) { + return pt[k]; + }); + }); + return out.length > 1 ? out : out[0]; + } + + it('should generate *id* when it can', function() { + _calc({ + labels: ['Root', 'A', 'B', 'b'], + parents: ['', 'Root', 'Root', 'B'] + }); + + expect(extract('id')).toEqual(['Root', 'A', 'B', 'b']); + expect(Lib.warn).toHaveBeenCalledTimes(0); + }); + + it('should generate "implied root" when it can', function() { + _calc({ + labels: [ 'A', 'B', 'b'], + parents: ['Root', 'Root', 'B'] + }); + + expect(extract('id')).toEqual(['Root', 'A', 'B', 'b']); + expect(extract('pid')).toEqual(['', 'Root', 'Root', 'B']); + expect(extract('label')).toEqual(['Root', 'A', 'B', 'b']); + expect(Lib.warn).toHaveBeenCalledTimes(0); + }); + + it('should warn when there are multiple implied roots', function() { + _calc({ + labels: [ 'A', 'B', 'b'], + parents: ['Root1', 'Root22', 'B'] + }); + + expect(Lib.warn).toHaveBeenCalledTimes(1); + expect(Lib.warn).toHaveBeenCalledWith('Multiple implied roots, cannot build treemap hierarchy.'); + }); + + it('should generate "root of roots" when it can', function() { + spyOn(Lib, 'randstr').and.callFake(function() { + return 'dummy'; + }); + + _calc({ + labels: [ 'A', 'B', 'b'], + parents: ['', '', 'B'] + }); + + expect(extract('id')).toEqual(['dummy', 'A', 'B', 'b']); + expect(extract('pid')).toEqual(['', 'dummy', 'dummy', 'B']); + expect(extract('label')).toEqual([undefined, 'A', 'B', 'b']); + }); + + it('should compute hierarchy values', function() { + var labels = ['Root', 'A', 'B', 'b']; + var parents = ['', 'Root', 'Root', 'B']; + + _calc([ + {labels: labels, parents: parents, count: 'leaves+branches'}, + {labels: labels, parents: parents, count: 'branches'}, + {labels: labels, parents: parents}, // N.B. counts 'leaves' in this case + {labels: labels, parents: parents, values: [0, 1, 2, 3]}, + {labels: labels, parents: parents, values: [30, 20, 10, 5], branchvalues: 'total'} + ]); + + expect(extractPt('value')).toEqual([ + [4, 2, 1, 1], + [2, 1, 0, 0], + [2, 1, 1, 1], + [6, 5, 1, 3], + [30, 20, 10, 5] + ]); + expect(Lib.warn).toHaveBeenCalledTimes(0); + }); + + it('should warn when values under *branchvalues:total* do not add up and not show trace', function() { + _calc({ + labels: ['Root', 'A', 'B', 'b'], + parents: ['', 'Root', 'Root', 'B'], + values: [0, 1, 2, 3], + branchvalues: 'total' + }); + + expect(gd.calcdata[0][0].hierarchy).toBe(undefined, 'no computed hierarchy'); + + expect(Lib.warn).toHaveBeenCalledTimes(2); + expect(Lib.warn.calls.allArgs()[0][0]).toBe('Total value for node Root is smaller than the sum of its children. \nparent value = 0 \nchildren sum = 3'); + expect(Lib.warn.calls.allArgs()[1][0]).toBe('Total value for node B is smaller than the sum of its children. \nparent value = 2 \nchildren sum = 3'); + }); + + it('should warn labels/parents lead to ambiguous hierarchy', function() { + _calc({ + labels: ['Root', 'A', 'A', 'B'], + parents: ['', 'Root', 'Root', 'A'] + }); + + expect(Lib.warn).toHaveBeenCalledTimes(1); + expect(Lib.warn).toHaveBeenCalledWith('Failed to build treemap hierarchy. Error: ambiguous: A'); + }); + + it('should warn ids/parents lead to ambiguous hierarchy', function() { + _calc({ + labels: ['label 1', 'label 2', 'label 3', 'label 4'], + ids: ['a', 'b', 'b', 'c'], + parents: ['', 'a', 'a', 'b'] + }); + + expect(Lib.warn).toHaveBeenCalledTimes(1); + expect(Lib.warn).toHaveBeenCalledWith('Failed to build treemap hierarchy. Error: ambiguous: b'); + }); + + it('should accept numbers (even `0`) are ids/parents items', function() { + _calc({ + labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'], + ids: [0, 1, 2, 3, 4, 5, 6, 7, 8], + parents: ['', 0, 0, 2, 2, 0, 0, 6, 0] + }); + + expect(extract('id')).toEqual(['0', '1', '2', '3', '4', '5', '6', '7', '8']); + expect(extract('pid')).toEqual(['', '0', '0', '2', '2', '0', '0', '6', '0']); + }); + + it('should accept mix typed are ids/parents items', function() { + _calc({ + labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'], + ids: [true, 1, '2', 3, 4, 5, 6, 7, 8], + parents: ['', true, true, 2, 2, 'true', 'true', '6', true] + }); + + expect(extract('id')).toEqual(['true', '1', '2', '3', '4', '5', '6', '7', '8']); + expect(extract('pid')).toEqual(['', 'true', 'true', '2', '2', 'true', 'true', '6', 'true']); + }); +}); + +describe('Test treemap hover:', function() { + var gd; + + var labels0 = ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura']; + var parents0 = ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve']; + var values0 = [10, 14, 12, 10, 2, 6, 6, 1, 4]; + + afterEach(destroyGraphDiv); + + function run(spec) { + gd = createGraphDiv(); + + var data = (spec.traces || [{}]).map(function(t) { + t.type = 'treemap'; + if(!t.labels) t.labels = labels0.slice(); + if(!t.parents) t.parents = parents0.slice(); + return t; + }); + + var layout = Lib.extendFlat({ + width: 500, + height: 500, + margin: {t: 0, b: 0, l: 0, r: 0, pad: 0} + }, spec.layout || {}); + + var exp = spec.exp || {}; + var ptData = null; + + return Plotly.plot(gd, data, layout) + .then(function() { + gd.once('plotly_hover', function(d) { ptData = d.points[0]; }); + }) + .then(hover(gd, spec.pos)) + .then(function() { + assertHoverLabelContent(exp.label); + + for(var k in exp.ptData) { + expect(ptData[k]).toBe(exp.ptData[k], 'pt event data key ' + k); + } + + if(exp.style) { + var gd3 = d3.select(gd); + assertHoverLabelStyle(gd3.select('.hovertext'), exp.style); + } + }); + } + + [{ + desc: 'base', + pos: 2, + exp: { + label: { + nums: 'Seth', + }, + ptData: { + curveNumber: 0, + pointNumber: 2, + label: 'Seth', + parent: 'Eve' + } + } + }, { + desc: 'with scalar hovertext', + traces: [{ hovertext: 'A' }], + pos: 3, + exp: { + label: { + nums: 'Cain\nA', + }, + ptData: { + curveNumber: 0, + pointNumber: 1, + label: 'Cain', + parent: 'Eve' + } + } + }, { + desc: 'with array hovertext', + traces: [{ + hovertext: values0, + hoverinfo: 'all' + }], + pos: 4, + exp: { + label: { + nums: 'Abel\nEve/\n17% of Eve\n6', + name: 'trace 0' + }, + ptData: { + curveNumber: 0, + pointNumber: 5, + label: 'Abel', + parent: 'Eve' + } + } + }, { + desc: 'with hoverlabel.namelength set ', + traces: [{ + hoverlabel: {namelength: 4}, + hoverinfo: 'all' + }], + pos: 4, + exp: { + label: { + nums: 'Abel\nEve/\n17% of Eve', + name: 't...' + }, + ptData: { + curveNumber: 0, + pointNumber: 5, + label: 'Abel', + parent: 'Eve' + } + } + }, { + desc: 'with values', + traces: [{ + values: values0, + hoverinfo: 'value' + }], + pos: 5, + exp: { + label: { + nums: '6' + }, + ptData: { + curveNumber: 0, + pointNumber: 5, + label: 'Abel', + parent: 'Eve', + value: 6 + } + } + }, { + desc: 'with values and hovertemplate', + traces: [{ + values: values0, + hovertemplate: '%{label} :: %{value:.2f}N.B.' + }], + pos: 5, + exp: { + label: { + nums: 'Abel :: 6.00', + name: 'N.B.' + }, + ptData: { + curveNumber: 0, + pointNumber: 5, + label: 'Abel', + parent: 'Eve', + value: 6 + } + } + }, { + desc: 'with array hovertemplate and label styling', + traces: [{ + hovertemplate: parents0.map(function(p) { + return p ? + '%{label} -| %{parent}' : + '%{label}THE ROOT'; + }), + hoverlabel: { + bgcolor: 'red', + bordercolor: 'blue', + font: { + size: 20, + family: 'Roboto', + color: 'orange' + } + } + }], + pos: 1, + exp: { + label: { + nums: 'Eve', + name: 'THE ROOT' + }, + style: { + bgcolor: 'rgb(255, 0, 0)', + bordercolor: 'rgb(0, 0, 255)', + fontSize: 20, + fontFamily: 'Roboto', + fontColor: 'rgb(255, 165, 0)' + }, + ptData: { + curveNumber: 0, + pointNumber: 0, + label: 'Eve', + parent: '' + } + } + }] + .forEach(function(spec) { + it('should generate correct hover labels and event data - ' + spec.desc, function(done) { + run(spec).catch(failTest).then(done); + }); + }); +}); + +describe('Test treemap hover lifecycle:', function() { + var gd; + var hoverData; + var unhoverData; + var hoverCnt; + var unhoverCnt; + + beforeEach(function() { gd = createGraphDiv(); }); + + afterEach(destroyGraphDiv); + + function setupListeners() { + hoverData = null; + unhoverData = null; + hoverCnt = 0; + unhoverCnt = 0; + + return function() { + gd.on('plotly_hover', function(d) { + hoverData = d; + hoverCnt++; + }); + gd.on('plotly_unhover', function(d) { + unhoverData = d; + unhoverCnt++; + }); + }; + } + + it('should fire the correct events', function(done) { + var mock = Lib.extendDeep({}, require('@mocks/treemap_first.json')); + + Plotly.plot(gd, mock) + .then(setupListeners()) + .then(hover(gd, 1)) + .then(function() { + if(hoverCnt === 1) { + expect(hoverData.event).toBeDefined(); + expect(hoverData.points[0].label).toBe('Eve'); + } else { + fail('did not trigger correct # of plotly_hover events'); + } + + if(unhoverCnt) { + fail('should not have triggered plotly_unhover'); + } + }) + .then(unhover(gd, 1)) + .then(hover(gd, 2)) + .then(function() { + if(hoverCnt === 2) { + expect(hoverData.event).toBeDefined(); + expect(hoverData.points[0].label).toBe('Seth'); + } else { + fail('did not trigger correct # of plotly_hover events'); + } + + if(unhoverCnt === 1) { + expect(unhoverData.event).toBeDefined(); + expect(unhoverData.points[0].label).toBe('Eve'); + } else { + fail('did not trigger correct # of plotly_unhover events'); + } + }) + .catch(failTest) + .then(done); + }); +}); + +describe('Test treemap clicks:', function() { + var gd; + var trackers; + + beforeEach(function() { + gd = createGraphDiv(); + trackers = {}; + }); + + afterEach(destroyGraphDiv); + + function setupListeners(opts) { + opts = opts || {}; + + trackers.treemapclick = []; + trackers.click = []; + trackers.animating = []; + + // use `.unshift` that way to latest event data object + // will be in entry [0], which is easier to pick out + + return function() { + gd.on('plotly_treemapclick', function(d) { + trackers.treemapclick.unshift(d); + if(opts.turnOffAnimation) return false; + }); + gd.on('plotly_click', function(d) { + trackers.click.unshift(d); + }); + gd.on('plotly_animating', function() { + // N.B. does not emit event data + trackers.animating.unshift(true); + }); + }; + } + + it('should trigger animation when clicking on branches', function(done) { + var mock = Lib.extendDeep({}, require('@mocks/treemap_first.json')); + + Plotly.plot(gd, mock) + .then(setupListeners()) + .then(click(gd, 2)) + .then(function() { + if(trackers.treemapclick.length === 1) { + expect(trackers.treemapclick[0].event).toBeDefined(); + expect(trackers.treemapclick[0].points[0].label).toBe('Seth'); + } else { + fail('incorrect plotly_treemapclick triggering'); + } + + if(trackers.click.length) { + fail('incorrect plotly_click triggering'); + } + + if(trackers.animating.length !== 1) { + fail('incorrect plotly_animating triggering'); + } + }) + .catch(failTest) + .then(done); + }); + + it('should trigger plotly_click event when clicking on leaf node', function(done) { + var mock = Lib.extendDeep({}, require('@mocks/treemap_first.json')); + + Plotly.plot(gd, mock) + .then(setupListeners()) + .then(click(gd, 8)) + .then(function() { + if(trackers.treemapclick.length === 1) { + expect(trackers.treemapclick[0].event).toBeDefined(); + expect(trackers.treemapclick[0].points[0].label).toBe('Noam'); + } else { + fail('incorrect plotly_treemapclick triggering'); + } + + if(trackers.click.length === 1) { + expect(trackers.click[0].event).toBeDefined(); + expect(trackers.click[0].points[0].label).toBe('Noam'); + } + }) + .catch(failTest) + .then(done); + }); + + it('should not trigger animation when graph is transitioning', function(done) { + var mock = Lib.extendDeep({}, require('@mocks/treemap_first.json')); + + // should be same before and after 2nd click + function _assertCommon(msg) { + if(trackers.click.length) { + fail('incorrect plotly_click triggering - ' + msg); + } + if(trackers.animating.length !== 1) { + fail('incorrect plotly_animating triggering - ' + msg); + } + } + + Plotly.plot(gd, mock) + .then(setupListeners()) + .then(click(gd, 2)) + .then(function() { + var msg = 'after 1st click'; + + if(trackers.treemapclick.length === 1) { + expect(trackers.treemapclick[0].event).toBeDefined(msg); + expect(trackers.treemapclick[0].points[0].label).toBe('Seth', msg); + } else { + fail('incorrect plotly_treemapclick triggering - ' + msg); + } + + _assertCommon(msg); + }) + .then(click(gd, 4)) + .then(function() { + var msg = 'after 2nd click'; + + // should trigger plotly_treemapclick twice, but not additional + // plotly_click nor plotly_animating + + if(trackers.treemapclick.length === 2) { + expect(trackers.treemapclick[0].event).toBeDefined(msg); + expect(trackers.treemapclick[0].points[0].label).toBe('Awan', msg); + } else { + fail('incorrect plotly_treemapclick triggering - ' + msg); + } + + _assertCommon(msg); + }) + .catch(failTest) + .then(done); + }); + + it('should be able to override default click behavior using plotly_treemapclick handler ()', function(done) { + var mock = Lib.extendDeep({}, require('@mocks/treemap_first.json')); + + Plotly.plot(gd, mock) + .then(setupListeners({turnOffAnimation: true})) + .then(click(gd, 2)) + .then(function() { + if(trackers.treemapclick.length === 1) { + expect(trackers.treemapclick[0].event).toBeDefined(); + expect(trackers.treemapclick[0].points[0].label).toBe('Seth'); + } else { + fail('incorrect plotly_treemapclick triggering'); + } + + if(trackers.click.length === 1) { + expect(trackers.click[0].event).toBeDefined(); + expect(trackers.click[0].points[0].label).toBe('Seth'); + } else { + fail('incorrect plotly_click triggering'); + } + + if(trackers.animating.length !== 0) { + fail('incorrect plotly_animating triggering'); + } + }) + .catch(failTest) + .then(done); + }); +}); + +describe('Test treemap restyle:', function() { + var gd; + + beforeEach(function() { gd = createGraphDiv(); }); + + afterEach(destroyGraphDiv); + + function _restyle(updateObj) { + return function() { return Plotly.restyle(gd, updateObj); }; + } + + it('should be able to toggle visibility', function(done) { + var mock = Lib.extendDeep({}, require('@mocks/treemap_first.json')); + + function _assert(msg, exp) { + return function() { + var layer = d3.select(gd).select('.treemaplayer'); + expect(layer.selectAll('.trace').size()).toBe(exp, msg); + }; + } + + Plotly.plot(gd, mock) + .then(_assert('base', 2)) + .then(_restyle({'visible': false})) + .then(_assert('both visible:false', 0)) + .then(_restyle({'visible': true})) + .then(_assert('back to visible:true', 2)) + .catch(failTest) + .then(done); + }); + + it('should be able to restyle *maxdepth* and *level* w/o recomputing the hierarchy', function(done) { + var mock = Lib.extendDeep({}, require('@mocks/treemap_coffee.json')); + + function _assert(msg, exp) { + return function() { + var layer = d3.select(gd).select('.treemaplayer'); + + expect(layer.selectAll('.slice').size()).toBe(exp, msg); + + // editType:plot + if(msg !== 'base') { + expect(Plots.doCalcdata).toHaveBeenCalledTimes(0); + } + }; + } + + Plotly.plot(gd, mock) + .then(_assert('base', 97)) + .then(function() { + spyOn(Plots, 'doCalcdata').and.callThrough(); + }) + .then(_restyle({maxdepth: 3})) + .then(_assert('with maxdepth:3', 97)) + .then(_restyle({level: 'Aromas'})) + .then(_assert('with non-root level', 67)) + .then(_restyle({maxdepth: null, level: null})) + .then(_assert('back to first view', 97)) + .catch(failTest) + .then(done); + }); + + it('should be able to restyle *marker.opacitybase* and *marker.opacitystep*', function(done) { + var mock = { + data: [{ + type: 'treemap', pathbar: { visible: false }, + labels: ['Root', 'A', 'B', 'b', 'b2', 'b3'], + parents: ['', 'Root', 'Root', 'B', 'b', 'b2'] + }] + }; + + function _assert(msg, exp) { + return function() { + var layer = d3.select(gd).select('.treemaplayer'); + + var opacities = []; + layer.selectAll('path.surface').each(function() { + opacities.push(this.style.opacity); + }); + + expect(opacities).toEqual(exp, msg); + + // editType:style + if(msg !== 'base') { + expect(Plots.doCalcdata).toHaveBeenCalledTimes(0); + expect(gd._fullData[0]._module.plot).toHaveBeenCalledTimes(0); + } + }; + } + + Plotly.plot(gd, mock) + .then(_assert('base', ['0', '1', '0.5', '0.5', '1', '1'])) + .then(function() { + spyOn(Plots, 'doCalcdata').and.callThrough(); + spyOn(gd._fullData[0]._module, 'plot').and.callThrough(); + }) + .then(_restyle({'marker.opacitybase': 0.2})) + .then(_assert('lower marker.opacitybase', ['0', '1', '0.2', '0.5', '1', '1'])) + .then(_restyle({'marker.opacitystep': 0.1})) + .then(_assert('lower marker.opacitystep', ['0', '1', '0.2', '0.1', '0.2', '1'])) + .then(_restyle({'marker.opacitybase': 0.8})) + .then(_assert('raise marker.opacitybase', ['0', '1', '0.8', '0.1', '0.2', '1'])) + .then(_restyle({'marker.opacitybase': null})) + .then(_assert('back to dflt', ['0', '1', '0.5', '0.1', '0.2', '1'])) + .then(_restyle({'marker.opacitystep': null})) + .then(_assert('back to dflt', ['0', '1', '0.5', '0.5', '1', '1'])) + .catch(failTest) + .then(done); + }); + + it('should be able to restyle *pathbar.opacity*', function(done) { + var mock = { + data: [{ + type: 'treemap', + labels: ['Root', 'A', 'B', 'b', 'b2', 'b3'], + parents: ['', 'Root', 'Root', 'B', 'b', 'b2'], + level: 'b' + }] + }; + + function _assert(msg, exp) { + return function() { + var layer = d3.select(gd).select('.treemaplayer'); + + var opacities = []; + layer.selectAll('path.surface').each(function() { + opacities.push(this.style.opacity); + }); + + expect(opacities).toEqual(exp, msg); + + // editType:style + if(msg !== 'base') { + expect(Plots.doCalcdata).toHaveBeenCalledTimes(0); + expect(gd._fullData[0]._module.plot).toHaveBeenCalledTimes(0); + } + }; + } + + Plotly.plot(gd, mock) + .then(_assert('base', ['0.5', '0.5', '1', '0.5', '0.5'])) + .then(function() { + spyOn(Plots, 'doCalcdata').and.callThrough(); + spyOn(gd._fullData[0]._module, 'plot').and.callThrough(); + }) + .then(_restyle({'pathbar.opacity': 0.2})) + .then(_assert('lower pathbar.opacity', ['0.5', '0.5', '1', '0.2', '0.2'])) + .then(_restyle({'pathbar.opacity': 0.8})) + .then(_assert('raise pathbar.opacity', ['0.5', '0.5', '1', '0.8', '0.8'])) + .then(_restyle({'pathbar.opacity': null})) + .then(_assert('back to dflt', ['0.5', '0.5', '1', '0.5', '0.5'])) + .catch(failTest) + .then(done); + }); + + it('should be able to restyle *textinfo*', function(done) { + var mock = { + data: [{ + type: 'treemap', + labels: ['Root', 'A', 'B', 'b'], + parents: ['', 'Root', 'Root', 'B'], + text: ['node0', 'node1', 'node2', 'node3'], + values: [0, 1, 2, 3], + pathbar: { visible: false } + }] + }; + + function _assert(msg, exp) { + return function() { + var layer = d3.select(gd).select('.treemaplayer'); + var tx = []; + + layer.selectAll('text.slicetext').each(function() { + var lines = d3.select(this).selectAll('tspan'); + + if(lines.size()) { + var t = []; + lines.each(function() { + t.push(this.innerHTML); + }); + tx.push(t.join('\n')); + } else { + tx.push(this.innerHTML); + } + }); + + expect(tx).toEqual(exp, msg); + + // editType:plot + if(msg !== 'base') { + expect(Plots.doCalcdata).toHaveBeenCalledTimes(0); + } + }; + } + + Plotly.plot(gd, mock) + .then(_assert('base', ['Root', 'B', 'A\nnode1', 'b\nnode3'])) + .then(function() { + spyOn(Plots, 'doCalcdata').and.callThrough(); + }) + .then(_restyle({textinfo: 'label'})) + .then(_assert('just label', ['Root', 'B', 'A', 'b'])) + .then(_restyle({textinfo: 'value'})) + .then(_assert('show input values', ['Root', 'B', '1', '3'])) + .then(_restyle({textinfo: 'none'})) + .then(_assert('no textinfo', ['Root', 'B', ' ', ' '])) // N.B. replaced empty string with space character for better transitions + .then(_restyle({textinfo: 'label+text+value'})) + .then(_assert('show everything', ['Root', 'B', 'A\n1\nnode1', 'b\n3\nnode3'])) + .then(_restyle({textinfo: null})) + .then(_assert('back to dflt', ['Root', 'B', 'A\nnode1', 'b\nnode3'])) + .catch(failTest) + .then(done); + }); +}); + +describe('Test treemap tweening:', function() { + var gd; + var pathTweenFnLookup; + var textTweenFnLookup; + + beforeEach(function() { + gd = createGraphDiv(); + + // hacky way to track tween functions + spyOn(d3.transition.prototype, 'attrTween').and.callFake(function(attrName, fn) { + var lookup = {d: pathTweenFnLookup, transform: textTweenFnLookup}[attrName]; + var pt = this[0][0].__data__; + var id = pt.data.data.id; + + // we should never tween the same node twice on a given sector click + lookup[id] = lookup[id] ? null : fn(pt); + }); + }); + + afterEach(destroyGraphDiv); + + function _reset() { + pathTweenFnLookup = {}; + textTweenFnLookup = {}; + } + + function _run(gd, v) { + _reset(); + click(gd, v)(); + + // 1 second more than the click transition duration + return delay(constants.CLICK_TRANSITION_TIME + 1); + } + + function trim(s) { + return s.replace(/\s/g, ''); + } + + + function _assert(msg, attrName, id, exp) { + var lookup = {d: pathTweenFnLookup, transform: textTweenFnLookup}[attrName]; + var fn = lookup[id]; + // normalize time in [0, 1] where we'll assert the tweening fn output, + // asserting at the mid point *should be* representative enough + var t = 0.5; + var actual = trim(fn(t)); + var msg2 = msg + ' | node ' + id + ' @t=' + t; + + if(attrName === 'transform') { + var fake = {attr: function() { return actual; }}; + var xy = Drawing.getTranslate(fake); + expect([xy.x, xy.y]).toBeWithinArray(exp, 1, msg2); + } else { + // we could maybe to bring in: + // https://github.com/hughsk/svg-path-parser + // to make these assertions more readable + expect(actual).toBe(trim(exp), msg2); + } + } + + it('should tween sector exit/update (case: click on branch, no maxdepth)', function(done) { + var mock = { + data: [{ + type: 'treemap', pathbar: { visible: false }, + labels: ['Root', 'A', 'B', 'b'], + parents: ['', 'Root', 'Root', 'B'] + }] + }; + + Plotly.plot(gd, mock) + .then(_run(gd, 3)) + .then(function() { + _assert('exit entry', 'd', 'Root', + 'M80,100L620,100L620,370L80,370Z' + ); + _assert('update A to new position', 'd', 'A', + 'M83,112L214.25,112L214.25,367L83,367Z' + ); + _assert('update B to new position', 'd', 'B', + 'M215.75,112L617,112L617,367L215.75,367Z' + ); + _assert('update b to new position', 'd', 'b', + 'M221.75,136L611,136L611,361L221.75,361Z' + ); + _assert('move B text to new position', 'transform', 'B', [221.75126, 0]); + _assert('move b text to new position', 'transform', 'b', [224.75150, 0]); + }) + .catch(failTest) + .then(done); + }); + + it('should tween sector enter/update (case: click on entry, no maxdepth)', function(done) { + var mock = { + data: [{ + type: 'treemap', pathbar: { visible: false }, + labels: ['Root', 'A', 'B', 'b'], + parents: ['', 'Root', 'Root', 'B'], + level: 'B' + }] + }; + + Plotly.plot(gd, mock) + .then(_run(gd, 1)) + .then(function() { + _assert('enter new entry', 'd', 'Root', + 'M80,100L620,100L620,370L80,370Z' + ); + _assert('update A to new position', 'd', 'A', + 'M83,112L214.25,112L214.25,367L83,367Z' + ); + _assert('update B to new position', 'd', 'B', + 'M215.75,112L617,112L617,367L215.75,367Z' + ); + _assert('update b to new position', 'd', 'b', + 'M221.75,136L611,136L611,361L221.75,361Z' + ); + _assert('move B text to new position', 'transform', 'B', [221.75126, 0]); + _assert('move b text to new position', 'transform', 'b', [224.75150, 0]); + }) + .catch(failTest) + .then(done); + }); + + it('should tween sector enter/update/exit (case: click on entry, maxdepth=2)', function(done) { + var mock = { + data: [{ + type: 'treemap', pathbar: { visible: false }, + labels: ['Root', 'A', 'B', 'b'], + parents: ['', 'Root', 'Root', 'B'], + maxdepth: 2 + }] + }; + + Plotly.plot(gd, mock) + .then(_run(gd, 3)) + .then(function() { + _assert('exit entry', 'd', 'Root', + 'M80,100L620,100L620,370L80,370Z' + ); + _assert('update A to new position', 'd', 'A', + 'M83,112L214.25,112L214.25,367L83,367Z' + ); + _assert('update B to new position', 'd', 'B', + 'M215.75,112L617,112L617,367L215.75,367Z' + ); + _assert('enter b for parent position', 'd', 'b', + 'M284.375,188.5L548.375,188.5L548.375,308.5L284.375,308.5Z' + ); + _assert('move B text to new position', 'transform', 'B', [220.25126, 0]); + _assert('enter b text to new position', 'transform', 'b', [287.375195, 5]); + }) + .catch(failTest) + .then(done); + }); + + it('should tween sector enter/update/exit (case: click on entry, maxdepth=2, level=B)', function(done) { + var mock = { + data: [{ + type: 'treemap', pathbar: { visible: false }, + labels: ['Root', 'A', 'B', 'b', 'bb'], + parents: ['', 'Root', 'Root', 'B', 'b'], + maxdepth: 2, + level: 'B' + }] + }; + + Plotly.plot(gd, mock) + .then(_run(gd, 1)) + .then(function() { + _assert('exit b', 'd', 'b', + 'M284.375,188.5L548.375,188.5L548.375,308.5L284.375,308.5Z' + ); + _assert('enter new entry', 'd', 'Root', + 'M80,100L620,100L620,370L80,370Z' + ); + _assert('enter A counterclockwise', 'd', 'A', + 'M83,112L214.25,112L214.25,367L83,367Z' + ); + _assert('update B to new position', 'd', 'B', + 'M215.75,112L617,112L617,367L215.75,367Z' + ); + }) + .catch(failTest) + .then(done); + }); +}); + +describe('Test treemap interactions edge cases', function() { + var gd; + + beforeEach(function() { gd = createGraphDiv(); }); + + afterEach(destroyGraphDiv); + + it('should keep tracking hover labels and hover events after *calc* edits', function(done) { + var mock = Lib.extendFlat({}, require('@mocks/treemap_first.json')); + var hoverCnt = 0; + var unhoverCnt = 0; + + // see https://github.com/plotly/plotly.js/issues/3618 + + function _assert(msg, exp) { + expect(hoverCnt).toBe(exp.hoverCnt, msg + ' - hover cnt'); + expect(unhoverCnt).toBe(exp.unhoverCnt, msg + ' - unhover cnt'); + + var label = d3.select(gd).select('g.hovertext'); + expect(label.size()).toBe(exp.hoverLabel, msg + ' - hover label cnt'); + + hoverCnt = 0; + unhoverCnt = 0; + } + + Plotly.plot(gd, mock) + .then(function() { + gd.on('plotly_hover', function() { + hoverCnt++; + // N.B. trigger a 'plot' edit + Plotly.restyle(gd, 'textinfo', 'none'); + }); + gd.on('plotly_unhover', function() { + unhoverCnt++; + // N.B. trigger a 'plot' edit + Plotly.restyle(gd, 'textinfo', null); + }); + }) + .then(hover(gd, 1)) + .then(function() { + _assert('after hovering on first sector', { + hoverCnt: 1, + unhoverCnt: 0, + hoverLabel: 1 + }); + }) + .then(unhover(gd, 1)) + .then(function() { + _assert('after un-hovering from first sector', { + hoverCnt: 0, + unhoverCnt: 1, + hoverLabel: 0 + }); + }) + .then(hover(gd, 2)) + .then(function() { + _assert('after hovering onto second sector', { + hoverCnt: 1, + unhoverCnt: 0, + hoverLabel: 1 + }); + }) + .catch(failTest) + .then(done); + }); + + it('should show falsy zero text', function(done) { + Plotly.plot(gd, { + data: [{ + type: 'treemap', + parents: ['', 'A', 'B', 'C', 'D', 'E', 'F'], + labels: ['A', 'B', 'C', 'D', 'E', 'F', 'G'], + values: [7, 6, 5, 4, 3, 2, 1], + text: [null, '', '0', 0, 1, true, false], + textinfo: 'label+text+value' + }], + layout: { + width: 400, + height: 400 + } + }) + .then(hover(gd, 4)) + .then(function() { + assertHoverLabelContent({ nums: 'D\n4\n0' }); + }) + .then(done); + }); + + it('should transition treemap traces only', function(done) { + var mock = Lib.extendDeep({}, require('@mocks/display-text_zero-number.json')); + mock.data[0].visible = false; + mock.data[1].type = 'treemap'; + mock.data[1].name = 'treemap'; + + function _assert(msg, exp) { + var gd3 = d3.select(gd); + expect(gd3.select('.cartesianlayer').selectAll('.trace').size()) + .toBe(exp.cartesianTraceCnt, '# of cartesian traces'); + expect(gd3.select('.pielayer').selectAll('.trace').size()) + .toBe(exp.pieTraceCnt, '# of pie traces'); + expect(gd3.select('.treemaplayer').selectAll('.trace').size()) + .toBe(exp.treemapTraceCnt, '# of treemap traces'); + } + + Plotly.plot(gd, mock) + .then(function() { + _assert('base', { + cartesianTraceCnt: 2, + pieTraceCnt: 0, + treemapTraceCnt: 1 + }); + }) + .then(click(gd, 2)) + .then(delay(constants.CLICK_TRANSITION_TIME + 1)) + .then(function() { + _assert('after treemap click', { + cartesianTraceCnt: 2, + pieTraceCnt: 0, + treemapTraceCnt: 1 + }); + }) + .catch(failTest) + .then(done); + }); + + it('should be able to transition treemap traces via `Plotly.react`', function(done) { + var mock = Lib.extendDeep({}, require('@mocks/display-text_zero-number.json')); + mock.data[1].type = 'treemap'; + mock.data[1].name = 'treemap'; + + mock.layout.transition = {duration: 200}; + + spyOn(Plots, 'transitionFromReact').and.callThrough(); + + Plotly.plot(gd, mock) + .then(function() { + gd.data[1].level = 'B'; + return Plotly.react(gd, gd.data, gd.layout); + }) + .then(delay(202)) + .then(function() { + expect(Plots.transitionFromReact).toHaveBeenCalledTimes(1); + }) + .catch(failTest) + .then(done); + }); +}); + +describe('Test treemap texttemplate without `values` should work:', function() { + checkTextTemplate([{ + type: 'treemap', pathbar: { visible: false }, + labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'], + parents: ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve' ], + text: ['sixty-five', 'fourteen', 'twelve', 'ten', 'two', 'six', 'six', 'one', 'four'] + }], 'g.slicetext', [ + ['color: %{color}', ['Eve', 'color: #1f77b4', 'Seth', 'color: #2ca02c', 'color: #d62728', 'color: #9467bd', 'Awan', 'color: #ff7f0e', 'color: #d62728']], + ['label: %{label}', ['Eve', 'label: Cain', 'Seth', 'label: Enos', 'label: Noam', 'label: Abel', 'Awan', 'label: Enoch', 'label: Azura']], + ['text: %{text}', ['Eve', 'text: fourteen', 'Seth', 'text: ten', 'text: two', 'text: six', 'Awan', 'text: one', 'text: four']], + ['path: %{currentPath}', ['Eve', 'path: Eve/', 'Seth', 'path: Eve/', 'path: Eve/', 'path: Eve/Seth/', 'Awan', 'path: Eve/Seth/', 'path: Eve/Awan/']], + ['%{percentRoot} of %{root}', ['Eve', '33% of Eve', 'Seth', '17% of Eve', '17% of Eve', '17% of Eve', 'Awan', '17% of Eve', '17% of Eve']], + ['%{percentEntry} of %{entry}', ['Eve', '33% of Eve', 'Seth', '17% of Eve', '17% of Eve', '17% of Eve', 'Awan', '17% of Eve', '17% of Eve']], + ['%{percentParent} of %{parent}', ['Eve', '100% of Seth', 'Seth', '17% of Eve', '17% of Eve', '17% of Eve', 'Awan', '50% of Seth', '100% of Awan']], + [ + [ + 'color: %{color}', + 'label: %{label}, text: %{text}', + 'text: %{text}', + 'value: %{value}', + '%{percentRoot} of %{root}', + '%{percentEntry} of %{entry}', + '%{percentParent} of %{parent}', + '%{percentParent} of %{parent}', + '%{percentParent} of %{parent}' + ], + [ + 'Eve', + 'label: Cain, text: fourteen', + 'Seth', + 'value: %{value}', // N.B. there is no `values` array + '17% of Eve', + '17% of Eve', + 'Awan', + '17% of Eve', + '100% of Awan' + ] + ] + ], /* skipEtra */ true); +}); + +describe('Test treemap texttemplate with *total* `values` should work:', function() { + checkTextTemplate([{ + type: 'treemap', pathbar: { visible: false }, + branchvalues: 'total', + labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'], + parents: ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve' ], + values: [65, 14, 12, 10, 2, 6, 6, 1, 4], + text: ['sixty-five', 'fourteen', 'twelve', 'ten', 'two', 'six', 'six', 'one', 'four'] + }], 'g.slicetext', [ + ['color: %{color}', ['Eve', 'color: #1f77b4', 'Seth', 'color: #2ca02c', 'color: #d62728', 'color: #9467bd', 'Awan', 'color: #ff7f0e', 'color: #d62728']], + ['label: %{label}', ['Eve', 'label: Cain', 'Seth', 'label: Enos', 'label: Noam', 'label: Abel', 'Awan', 'label: Enoch', 'label: Azura']], + ['value: %{value}', ['Eve', 'value: 14', 'Seth', 'value: 10', 'value: 2', 'value: 6', 'Awan', 'value: 1', 'value: 4']], + ['text: %{text}', ['Eve', 'text: fourteen', 'Seth', 'text: ten', 'text: two', 'text: six', 'Awan', 'text: one', 'text: four']], + ['path: %{currentPath}', ['Eve', 'path: Eve/', 'Seth', 'path: Eve/', 'path: Eve/', 'path: Eve/Seth/', 'Awan', 'path: Eve/Seth/', 'path: Eve/Awan/']] + ], /* skipEtra */ true); +}); + +describe('Test treemap texttemplate with *remainder* `values` should work:', function() { + checkTextTemplate([{ + type: 'treemap', pathbar: { visible: false }, + branchvalues: 'remainder', + labels: ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'], + parents: ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve' ], + values: [65, 14, 12, 10, 2, 6, 6, 1, 4], + text: ['sixty-five', 'fourteen', 'twelve', 'ten', 'two', 'six', 'six', 'one', 'four'] + }], 'g.slicetext', [ + ['color: %{color}', ['Eve', 'color: #1f77b4', 'Seth', 'color: #2ca02c', 'color: #d62728', 'color: #9467bd', 'Awan', 'color: #ff7f0e', 'color: #d62728']], + ['label: %{label}', ['Eve', 'label: Cain', 'Seth', 'label: Enos', 'label: Noam', 'label: Abel', 'Awan', 'label: Enoch', 'label: Azura']], + ['value: %{value}', ['Eve', 'value: 14', 'Seth', 'value: 10', 'value: 2', 'value: 6', 'Awan', 'value: 1', 'value: 4']], + ['text: %{text}', ['Eve', 'text: fourteen', 'Seth', 'text: ten', 'text: two', 'text: six', 'Awan', 'text: one', 'text: four']], + ['path: %{currentPath}', ['Eve', 'path: Eve/', 'Seth', 'path: Eve/', 'path: Eve/', 'path: Eve/Seth/', 'Awan', 'path: Eve/Seth/', 'path: Eve/Awan/']] + ], /* skipEtra */ true); +});