diff --git a/draftlogs/7240_remove.md b/draftlogs/7240_remove.md new file mode 100644 index 00000000000..5c6c224b70f --- /dev/null +++ b/draftlogs/7240_remove.md @@ -0,0 +1 @@ + - Drop transforms from the API [[#7240](https://github.com/plotly/plotly.js/pull/7240)] diff --git a/src/components/calendars/index.js b/src/components/calendars/index.js index 21dbfbac2e2..7cf4e9a550c 100644 --- a/src/components/calendars/index.js +++ b/src/components/calendars/index.js @@ -232,21 +232,6 @@ module.exports = { polar: { radialaxis: {calendar: axisAttrs} } - }, - transforms: { - filter: { - valuecalendar: makeAttrs([ - 'WARNING: All transforms are deprecated and may be removed from the API in next major version.', - 'Sets the calendar system to use for `value`, if it is a date.' - ].join(' ')), - targetcalendar: makeAttrs([ - 'WARNING: All transforms are deprecated and may be removed from the API in next major version.', - 'Sets the calendar system to use for `target`, if it is an', - 'array of dates. If `target` is a string (eg *x*) we use the', - 'corresponding trace attribute (eg `xcalendar`) if it exists,', - 'even if `targetcalendar` is provided.' - ].join(' ')) - } } }, diff --git a/src/components/legend/draw.js b/src/components/legend/draw.js index 8e7abcf29fa..0c15194a713 100644 --- a/src/components/legend/draw.js +++ b/src/components/legend/draw.js @@ -484,7 +484,7 @@ function clickOrDoubleClick(gd, legend, legendItem, numClicks, evt) { event: evt, node: legendItem.node(), curveNumber: trace.index, - expandedIndex: trace._expandedIndex, + expandedIndex: trace.index, data: gd.data, layout: gd.layout, frames: gd._transitionData._frames, @@ -559,18 +559,7 @@ function drawTexts(g, gd, legendObj) { var fullInput = legendItem.trace._fullInput || {}; var update = {}; - if(Registry.hasTransform(fullInput, 'groupby')) { - var groupbyIndices = Registry.getTransformIndices(fullInput, 'groupby'); - var _index = groupbyIndices[groupbyIndices.length - 1]; - - var kcont = Lib.keyedContainer(fullInput, 'transforms[' + _index + '].styles', 'target', 'value.name'); - - kcont.set(legendItem.trace._group, newName); - - update = kcont.constructUpdate(); - } else { - update.name = newName; - } + update.name = newName; if(fullInput._isShape) { return Registry.call('_guiRelayout', gd, 'shapes[' + trace.index + '].name', update.name); diff --git a/src/components/legend/handle_click.js b/src/components/legend/handle_click.js index 5c83154201c..6c2b7b81b45 100644 --- a/src/components/legend/handle_click.js +++ b/src/components/legend/handle_click.js @@ -91,42 +91,15 @@ module.exports = function handleClick(g, gd, numClicks) { var index = fullInput.index; if(index === undefined) index = fullInput._index; - if(Registry.hasTransform(fullInput, 'groupby')) { - var kcont = carrs[index]; - if(!kcont) { - var groupbyIndices = Registry.getTransformIndices(fullInput, 'groupby'); - var lastGroupbyIndex = groupbyIndices[groupbyIndices.length - 1]; - kcont = Lib.keyedContainer(fullInput, 'transforms[' + lastGroupbyIndex + '].styles', 'target', 'value.visible'); - carrs[index] = kcont; - } - - var curState = kcont.get(fullTrace._group); - - // If not specified, assume visible. This happens if there are other style - // properties set for a group but not the visibility. There are many similar - // ways to do this (e.g. why not just `curState = fullTrace.visible`??? The - // answer is: because it breaks other things like groupby trace names in - // subtle ways.) - if(curState === undefined) { - curState = true; - } + // false -> false (not possible since will not be visible in legend) + // true -> legendonly + // legendonly -> true + var nextVisibility = fullInput.visible === false ? false : visibility; - if(curState !== false) { - // true -> legendonly. All others toggle to true: - kcont.set(fullTrace._group, visibility); - } - carrIdx[index] = insertDataUpdate(index, fullInput.visible === false ? false : true); + if(isShape) { + insertShapesUpdate(index, nextVisibility); } else { - // false -> false (not possible since will not be visible in legend) - // true -> legendonly - // legendonly -> true - var nextVisibility = fullInput.visible === false ? false : visibility; - - if(isShape) { - insertShapesUpdate(index, nextVisibility); - } else { - insertDataUpdate(index, nextVisibility); - } + insertDataUpdate(index, nextVisibility); } } diff --git a/src/components/selections/select.js b/src/components/selections/select.js index 985a79b090a..e44734665ad 100644 --- a/src/components/selections/select.js +++ b/src/components/selections/select.js @@ -597,8 +597,8 @@ function newPointNumTester(pointSelectionDef) { ymax: 0, pts: [], contains: function(pt, omitFirstEdge, pointNumber, searchInfo) { - var idxWantedTrace = pointSelectionDef.searchInfo.cd[0].trace._expandedIndex; - var idxActualTrace = searchInfo.cd[0].trace._expandedIndex; + var idxWantedTrace = pointSelectionDef.searchInfo.cd[0].trace.index; + var idxActualTrace = searchInfo.cd[0].trace.index; return idxActualTrace === idxWantedTrace && pointNumber === pointSelectionDef.pointNumber; }, @@ -844,7 +844,7 @@ function extractClickedPtInfo(hoverData, searchTraces) { for(i = 0; i < searchTraces.length; i++) { searchInfo = searchTraces[i]; - if(hoverDatum.fullData._expandedIndex === searchInfo.cd[0].trace._expandedIndex) { + if(hoverDatum.fullData.index === searchInfo.cd[0].trace.index) { // Special case for box (and violin) if(hoverDatum.hoverOnBox === true) { break; diff --git a/src/plot_api/helpers.js b/src/plot_api/helpers.js index 636d9617e19..d57be1bc622 100644 --- a/src/plot_api/helpers.js +++ b/src/plot_api/helpers.js @@ -270,51 +270,6 @@ exports.cleanData = function(data) { } } - // transforms backward compatibility fixes - if(Array.isArray(trace.transforms)) { - var transforms = trace.transforms; - - for(i = 0; i < transforms.length; i++) { - var transform = transforms[i]; - - if(!Lib.isPlainObject(transform)) continue; - - switch(transform.type) { - case 'filter': - if(transform.filtersrc) { - transform.target = transform.filtersrc; - delete transform.filtersrc; - } - - if(transform.calendar) { - if(!transform.valuecalendar) { - transform.valuecalendar = transform.calendar; - } - delete transform.calendar; - } - break; - - case 'groupby': - // Name has changed from `style` to `styles`, so use `style` but prefer `styles`: - transform.styles = transform.styles || transform.style; - - if(transform.styles && !Array.isArray(transform.styles)) { - var prevStyles = transform.styles; - var styleKeys = Object.keys(prevStyles); - - transform.styles = []; - for(var j = 0; j < styleKeys.length; j++) { - transform.styles.push({ - target: styleKeys[j], - value: prevStyles[styleKeys[j]] - }); - } - } - break; - } - } - } - // prune empty containers made before the new nestedProperty if(emptyContainer(trace, 'line')) delete trace.line; if('marker' in trace) { diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 8a332b88d5d..39f9bc93496 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -2782,7 +2782,6 @@ function diffData(gd, oldFullData, newFullData, immutable, transition, newDataRe for(i = 0; i < oldFullData.length; i++) { if(newFullData[i]) { trace = newFullData[i]._fullInput; - if(Plots.hasMakesDataTransform(trace)) trace = newFullData[i]; if(seenUIDs[trace.uid]) continue; seenUIDs[trace.uid] = 1; diff --git a/src/plot_api/plot_config.js b/src/plot_api/plot_config.js index 56ea308acae..453dcc9fcf1 100644 --- a/src/plot_api/plot_config.js +++ b/src/plot_api/plot_config.js @@ -427,15 +427,6 @@ var configAttributes = { description: 'Sets the length of the undo/redo queue.' }, - globalTransforms: { - valType: 'any', - dflt: [], - description: [ - 'Set global transform to be applied to all traces with no', - 'specification needed' - ].join(' ') - }, - locale: { valType: 'string', dflt: 'en-US', diff --git a/src/plot_api/plot_schema.js b/src/plot_api/plot_schema.js index 2d83a807887..56cf2901a56 100644 --- a/src/plot_api/plot_schema.js +++ b/src/plot_api/plot_schema.js @@ -34,7 +34,6 @@ exports.UNDERSCORE_ATTRS = UNDERSCORE_ATTRS; * - defs * - traces * - layout - * - transforms * - frames * - animations * - config @@ -46,12 +45,6 @@ exports.get = function() { traces[type] = getTraceAttributes(type); }); - var transforms = {}; - - Object.keys(Registry.transformsRegistry).forEach(function(type) { - transforms[type] = getTransformAttributes(type); - }); - return { defs: { valObjects: valObjectMeta, @@ -83,8 +76,6 @@ exports.get = function() { traces: traces, layout: getLayoutAttributes(), - transforms: transforms, - frames: getFramesAttributes(), animation: formatAttributes(animationAttributes), @@ -218,21 +209,6 @@ exports.findArrayAttributes = function(trace) { exports.crawl(trace._module.attributes, callback); } - var transforms = trace.transforms; - if(transforms) { - for(var i = 0; i < transforms.length; i++) { - var transform = transforms[i]; - var module = transform._module; - - if(module) { - baseAttrName = 'transforms[' + i + '].'; - baseContainer = transform; - - exports.crawl(module.attributes, callback); - } - } - } - return arrayAttributes; }; @@ -256,41 +232,26 @@ exports.getTraceValObject = function(trace, parts) { var i = 1; // index to start recursing from var moduleAttrs, valObject; - if(head === 'transforms') { - if(parts.length === 1) { - return baseAttributes.transforms; - } - var transforms = trace.transforms; - if(!Array.isArray(transforms) || !transforms.length) return false; - var tNum = parts[1]; - if(!isIndex(tNum) || tNum >= transforms.length) { - return false; - } - moduleAttrs = (Registry.transformsRegistry[transforms[tNum].type] || {}).attributes; - valObject = moduleAttrs && moduleAttrs[parts[2]]; - i = 3; // start recursing only inside the transform - } else { - // first look in the module for this trace - // components have already merged their trace attributes in here - var _module = trace._module; - if(!_module) _module = (Registry.modules[trace.type || baseAttributes.type.dflt] || {})._module; - if(!_module) return false; - - moduleAttrs = _module.attributes; - valObject = moduleAttrs && moduleAttrs[head]; - - // then look in the subplot attributes - if(!valObject) { - var subplotModule = _module.basePlotModule; - if(subplotModule && subplotModule.attributes) { - valObject = subplotModule.attributes[head]; - } - } + // first look in the module for this trace + // components have already merged their trace attributes in here + var _module = trace._module; + if(!_module) _module = (Registry.modules[trace.type || baseAttributes.type.dflt] || {})._module; + if(!_module) return false; + + moduleAttrs = _module.attributes; + valObject = moduleAttrs && moduleAttrs[head]; - // finally look in the global attributes - if(!valObject) valObject = baseAttributes[head]; + // then look in the subplot attributes + if(!valObject) { + var subplotModule = _module.basePlotModule; + if(subplotModule && subplotModule.attributes) { + valObject = subplotModule.attributes[head]; + } } + // finally look in the global attributes + if(!valObject) valObject = baseAttributes[head]; + return recurseIntoValObject(valObject, parts, i); }; @@ -567,26 +528,6 @@ function getLayoutAttributes() { }; } -function getTransformAttributes(type) { - var _module = Registry.transformsRegistry[type]; - var attributes = extendDeepAll({}, _module.attributes); - - // add registered components transform attributes - Object.keys(Registry.componentsRegistry).forEach(function(k) { - var _module = Registry.componentsRegistry[k]; - - if(_module.schema && _module.schema.transforms && _module.schema.transforms[type]) { - Object.keys(_module.schema.transforms[type]).forEach(function(v) { - insertAttrs(attributes, _module.schema.transforms[type][v], v); - }); - } - }); - - return { - attributes: formatAttributes(attributes) - }; -} - function getFramesAttributes() { var attrs = { frames: extendDeepAll({}, frameAttributes) diff --git a/src/plot_api/template_api.js b/src/plot_api/template_api.js index 4157e6c7b93..cb80162222c 100644 --- a/src/plot_api/template_api.js +++ b/src/plot_api/template_api.js @@ -347,7 +347,7 @@ exports.validateTemplate = function(figureIn, template) { // the template errorList.push({ code: 'missing', - index: fullTrace._fullInput.index, + index: fullTrace.index, traceType: traceType }); } diff --git a/src/plot_api/validate.js b/src/plot_api/validate.js index a1d692b684f..45be7d7bbc4 100644 --- a/src/plot_api/validate.js +++ b/src/plot_api/validate.js @@ -94,39 +94,6 @@ module.exports = function validate(data, layout) { } crawl(traceIn, traceOut, traceSchema, errorList, base); - - var transformsIn = traceIn.transforms; - var transformsOut = traceOut.transforms; - - if(transformsIn) { - if(!isArray(transformsIn)) { - errorList.push(format('array', base, ['transforms'])); - } - - base.push('transforms'); - - for(var j = 0; j < transformsIn.length; j++) { - var path = ['transforms', j]; - var transformType = transformsIn[j].type; - - if(!isPlainObject(transformsIn[j])) { - errorList.push(format('object', base, path)); - continue; - } - - var transformSchema = schema.transforms[transformType] ? - schema.transforms[transformType].attributes : - {}; - - // add 'type' to transform schema to validate the transform type - transformSchema.type = { - valType: 'enumerated', - values: Object.keys(schema.transforms) - }; - - crawl(transformsIn[j], transformsOut[j], transformSchema, errorList, base, path); - } - } } var layoutOut = gd._fullLayout; @@ -146,9 +113,6 @@ function crawl(objIn, objOut, schema, list, base, path) { for(var i = 0; i < keys.length; i++) { var k = keys[i]; - // transforms are handled separately - if(k === 'transforms') continue; - var p = path.slice(); p.push(k); diff --git a/src/plots/attributes.js b/src/plots/attributes.js index d297f69d5f1..bad077693c3 100644 --- a/src/plots/attributes.js +++ b/src/plots/attributes.js @@ -214,15 +214,6 @@ module.exports = { }, editType: 'calc' }, - transforms: { - _isLinkedToArray: 'transform', - editType: 'calc', - description: [ - 'WARNING: All transforms are deprecated and may be removed from the API in next major version.', - 'An array of operations that manipulate the trace data,', - 'for example filtering or sorting the data arrays.' - ].join(' ') - }, uirevision: { valType: 'any', editType: 'none', diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 90f7b288de5..84ebe5b3bb1 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -245,7 +245,6 @@ var getDataConversions = axes.getDataConversions = function(gd, trace, target, t ax.d2c(targetArray[i]); } } - // TODO what to do for transforms? } else { ax = axes.getFromTrace(gd, trace, d2cTarget); } diff --git a/src/plots/cartesian/layout_defaults.js b/src/plots/cartesian/layout_defaults.js index cee585392fb..90351ecfa1b 100644 --- a/src/plots/cartesian/layout_defaults.js +++ b/src/plots/cartesian/layout_defaults.js @@ -143,7 +143,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { function newAxLayoutOut() { var traces = ax2traces[axName] || []; - axLayoutOut._traceIndices = traces.map(function(t) { return t._expandedIndex; }); + axLayoutOut._traceIndices = traces.map(function(t) { return t.index; }); axLayoutOut._annIndices = []; axLayoutOut._shapeIndices = []; axLayoutOut._selectionIndices = []; diff --git a/src/plots/geo/layout_defaults.js b/src/plots/geo/layout_defaults.js index 54b4d49bda4..a5d64e2e9f8 100644 --- a/src/plots/geo/layout_defaults.js +++ b/src/plots/geo/layout_defaults.js @@ -21,7 +21,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce, opts) { var subplotData = getSubplotData(opts.fullData, 'geo', opts.id); - var traceIndices = subplotData.map(function(t) { return t._expandedIndex; }); + var traceIndices = subplotData.map(function(t) { return t.index; }); var resolution = coerce('resolution'); var scope = coerce('scope'); diff --git a/src/plots/plots.js b/src/plots/plots.js index ed6b7dab1b8..9415c598ae8 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -35,8 +35,6 @@ plots.attributes.type.values = plots.allTypes; plots.fontAttrs = require('./font_attributes'); plots.layoutAttributes = require('./layout_attributes'); -var transformsRegistry = plots.transformsRegistry; - var commandModule = require('./command'); plots.executeAPICommand = commandModule.executeAPICommand; plots.computeAPICommandBindings = commandModule.computeAPICommandBindings; @@ -252,9 +250,7 @@ var extraFormatKeys = [ * @param {object} opts * @param {boolean} opts.skipUpdateCalc: normally if the existing gd.calcdata looks * compatible with the new gd._fullData we finish by linking the new _fullData traces - * to the old gd.calcdata, so it's correctly set if we're not going to recalc. But also, - * if there are calcTransforms on the trace, we first remap data arrays from the old full - * trace into the new one. Use skipUpdateCalc to defer this (needed by Plotly.react) + * to the old gd.calcdata, so it's correctly set if we're not going to recalc. * * gd.data, gd.layout: * are precisely what the user specified (except as modified by cleanData/cleanLayout), @@ -397,7 +393,6 @@ plots.supplyDefaults = function(gd, opts) { newFullLayout._traceUids = getTraceUids(oldFullData, newData); // then do the data - newFullLayout._globalTransforms = (gd._context || {}).globalTransforms; plots.supplyDataDefaults(newData, newFullData, newLayout, newFullLayout); // redo grid size defaults with info about splom x/y axes, @@ -1093,59 +1088,9 @@ plots.supplyDataDefaults = function(dataIn, dataOut, layout, fullLayout) { fullTrace.index = i; fullTrace._input = trace; - fullTrace._expandedIndex = cnt; - - if(fullTrace.transforms && fullTrace.transforms.length) { - var sdInvisible = trace.visible !== false && fullTrace.visible === false; - - var expandedTraces = applyTransforms(fullTrace, dataOut, layout, fullLayout); - - for(var j = 0; j < expandedTraces.length; j++) { - var expandedTrace = expandedTraces[j]; - - // No further templating during transforms. - var fullExpandedTrace = { - _template: fullTrace._template, - type: fullTrace.type, - // set uid using parent uid and expanded index - // to promote consistency between update calls - uid: fullTrace.uid + j - }; - - // If the first supplyDefaults created `visible: false`, - // clear it before running supplyDefaults a second time, - // because sometimes there are items we still want to coerce - // inside trace modules before determining that the trace is - // again `visible: false`, for example partial visibilities - // in `splom` traces. - if(sdInvisible && expandedTrace.visible === false) { - delete expandedTrace.visible; - } - - plots.supplyTraceDefaults(expandedTrace, fullExpandedTrace, cnt, fullLayout, i); - - // relink private (i.e. underscore) keys expanded trace to full expanded trace so - // that transform supply-default methods can set _ keys for future use. - relinkPrivateKeys(fullExpandedTrace, expandedTrace); - - // add info about parent data trace - fullExpandedTrace.index = i; - fullExpandedTrace._input = trace; - fullExpandedTrace._fullInput = fullTrace; - - // add info about the expanded data - fullExpandedTrace._expandedIndex = cnt; - fullExpandedTrace._expandedInput = expandedTrace; + fullTrace._fullInput = fullTrace; - pushModule(fullExpandedTrace); - } - } else { - // add identify refs for consistency with transformed traces - fullTrace._fullInput = fullTrace; - fullTrace._expandedInput = fullTrace; - - pushModule(fullTrace); - } + pushModule(fullTrace); if(Registry.traceIs(fullTrace, 'carpetAxis')) { carpetIndex[fullTrace.carpet] = fullTrace; @@ -1350,106 +1295,11 @@ plots.supplyTraceDefaults = function(traceIn, traceOut, colorIndex, layout, trac traceOut.selectedpoints = Array.from(selectedpoints); } } - - plots.supplyTransformDefaults(traceIn, traceOut, layout); } return traceOut; }; -/** - * hasMakesDataTransform: does this trace have a transform that makes its own - * data, either by grabbing it from somewhere else or by creating it from input - * parameters? If so, we should still keep going with supplyDefaults - * even if the trace is invisible, which may just be because it has no data yet. - */ -function hasMakesDataTransform(trace) { - var transforms = trace.transforms; - if(Array.isArray(transforms) && transforms.length) { - for(var i = 0; i < transforms.length; i++) { - var ti = transforms[i]; - var _module = ti._module || transformsRegistry[ti.type]; - if(_module && _module.makesData) return true; - } - } - return false; -} - -plots.hasMakesDataTransform = hasMakesDataTransform; - -plots.supplyTransformDefaults = function(traceIn, traceOut, layout) { - // For now we only allow transforms on 1D traces, ie those that specify a _length. - // If we were to implement 2D transforms, we'd need to have each transform - // describe its own applicability and disable itself when it doesn't apply. - // Also allow transforms that make their own data, but not in globalTransforms - if(!(traceOut._length || hasMakesDataTransform(traceIn))) return; - - var globalTransforms = layout._globalTransforms || []; - var transformModules = layout._transformModules || []; - - if(!Array.isArray(traceIn.transforms) && globalTransforms.length === 0) return; - - var containerIn = traceIn.transforms || []; - var transformList = globalTransforms.concat(containerIn); - var containerOut = traceOut.transforms = []; - - for(var i = 0; i < transformList.length; i++) { - var transformIn = transformList[i]; - var type = transformIn.type; - var _module = transformsRegistry[type]; - var transformOut; - - /* - * Supply defaults may run twice. First pass runs all supply defaults steps - * and adds the _module to any output transforms. - * If transforms exist another pass is run so that any generated traces also - * go through supply defaults. This has the effect of rerunning - * supplyTransformDefaults. If the transform does not have a `transform` - * function it could not have generated any new traces and the second stage - * is unnecessary. We detect this case with the following variables. - */ - var isFirstStage = !(transformIn._module && transformIn._module === _module); - var doLaterStages = _module && typeof _module.transform === 'function'; - - if(!_module) Lib.warn('Unrecognized transform type ' + type + '.'); - - if(_module && _module.supplyDefaults && (isFirstStage || doLaterStages)) { - transformOut = _module.supplyDefaults(transformIn, traceOut, layout, traceIn); - transformOut.type = type; - transformOut._module = _module; - - Lib.pushUnique(transformModules, _module); - } else { - transformOut = Lib.extendFlat({}, transformIn); - } - - containerOut.push(transformOut); - } -}; - -function applyTransforms(fullTrace, fullData, layout, fullLayout) { - var container = fullTrace.transforms; - var dataOut = [fullTrace]; - - for(var i = 0; i < container.length; i++) { - var transform = container[i]; - var _module = transformsRegistry[transform.type]; - - if(_module && _module.transform) { - dataOut = _module.transform(dataOut, { - transform: transform, - fullTrace: fullTrace, - fullData: fullData, - layout: layout, - fullLayout: fullLayout, - transformIndex: i - }); - } - } - - return dataOut; -} - plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut, formatObj) { function coerce(attr, dflt) { return Lib.coerce(layoutIn, layoutOut, plots.layoutAttributes, attr, dflt); @@ -2509,7 +2359,7 @@ plots.recomputeFrameHash = function(gd) { * * This exists so that we can extendDeepNoArrays and avoid stepping into data * arrays without knowledge of the plot schema, but so that we may also manually - * recurse into known container arrays, such as transforms. + * recurse into known container arrays. * * See extendTrace and extendLayout below for usage. */ diff --git a/src/plots/polar/layout_defaults.js b/src/plots/polar/layout_defaults.js index 7b4b9507ca6..97ed8b3380c 100644 --- a/src/plots/polar/layout_defaults.js +++ b/src/plots/polar/layout_defaults.js @@ -48,7 +48,7 @@ function handleDefaults(contIn, contOut, coerce, opts) { var axOut = Template.newContainer(contOut, axName); axOut._id = axOut._name = axName; axOut._attr = opts.id + '.' + axName; - axOut._traceIndices = subplotData.map(function(t) { return t._expandedIndex; }); + axOut._traceIndices = subplotData.map(function(t) { return t.index; }); var dataAttr = constants.axisName2dataArray[axName]; var axType = handleAxisTypeDefaults(axIn, axOut, coerceAxis, subplotData, dataAttr, opts); diff --git a/src/plots/smith/layout_defaults.js b/src/plots/smith/layout_defaults.js index 17c8ac71b3e..f0a72bc514f 100644 --- a/src/plots/smith/layout_defaults.js +++ b/src/plots/smith/layout_defaults.js @@ -48,7 +48,7 @@ function handleDefaults(contIn, contOut, coerce, opts) { var axOut = Template.newContainer(contOut, axName); axOut._id = axOut._name = axName; axOut._attr = opts.id + '.' + axName; - axOut._traceIndices = subplotData.map(function(t) { return t._expandedIndex; }); + axOut._traceIndices = subplotData.map(function(t) { return t.index; }); var visible = coerceAxis('visible'); diff --git a/src/registry.js b/src/registry.js index 253f850043e..499abf2457b 100644 --- a/src/registry.js +++ b/src/registry.js @@ -17,7 +17,6 @@ exports.modules = {}; exports.allCategories = {}; exports.allTypes = []; exports.subplotsRegistry = {}; -exports.transformsRegistry = {}; exports.componentsRegistry = {}; exports.layoutArrayContainers = []; exports.layoutArrayRegexes = []; @@ -146,47 +145,6 @@ exports.traceIs = function(traceType, category) { return !!_module.categories[category]; }; -/** - * Determine if this trace has a transform of the given type and return - * array of matching indices. - * - * @param {object} data - * a trace object (member of data or fullData) - * @param {string} type - * type of trace to test - * @return {array} - * array of matching indices. If none found, returns [] - */ -exports.getTransformIndices = function(data, type) { - var indices = []; - var transforms = data.transforms || []; - for(var i = 0; i < transforms.length; i++) { - if(transforms[i].type === type) { - indices.push(i); - } - } - return indices; -}; - -/** - * Determine if this trace has a transform of the given type - * - * @param {object} data - * a trace object (member of data or fullData) - * @param {string} type - * type of trace to test - * @return {boolean} - */ -exports.hasTransform = function(data, type) { - var transforms = data.transforms || []; - for(var i = 0; i < transforms.length; i++) { - if(transforms[i].type === type) { - return true; - } - } - return false; -}; - /** * Retrieve component module method. Falls back on noop if either the * module or the method is missing, so the result can always be safely called @@ -331,10 +289,6 @@ function registerComponentModule(_module) { mergeComponentAttrsToSubplot(name, subplotName); } - for(var transformType in exports.transformsRegistry) { - mergeComponentAttrsToTransform(name, transformType); - } - if(_module.schema && _module.schema.layout) { extendDeepAll(baseLayoutAttributes, _module.schema.layout); } @@ -365,12 +319,6 @@ function registerTransformModule(_module) { if(typeof _module.supplyDefaults !== 'function') { Loggers.log(prefix + ' registered without a *supplyDefaults* method.'); } - - exports.transformsRegistry[_module.name] = _module; - - for(var componentName in exports.componentsRegistry) { - mergeComponentAttrsToTransform(componentName, _module.name); - } } function registerLocale(_module) { @@ -430,16 +378,6 @@ function mergeComponentAttrsToTrace(componentName, traceType) { } } -function mergeComponentAttrsToTransform(componentName, transformType) { - var componentSchema = exports.componentsRegistry[componentName].schema; - if(!componentSchema || !componentSchema.transforms) return; - - var transformAttrs = componentSchema.transforms[transformType]; - if(transformAttrs) { - extendDeepAll(exports.transformsRegistry[transformType].attributes, transformAttrs); - } -} - function mergeComponentAttrsToSubplot(componentName, subplotName) { var componentSchema = exports.componentsRegistry[componentName].schema; if(!componentSchema || !componentSchema.subplots) return; diff --git a/src/traces/carpet/attributes.js b/src/traces/carpet/attributes.js index e6ff6442a33..7150e67cb61 100644 --- a/src/traces/carpet/attributes.js +++ b/src/traces/carpet/attributes.js @@ -115,6 +115,5 @@ module.exports = { 'Individual pieces can override this.' ].join(' ') }, - transforms: undefined, zorder: zorder }; diff --git a/src/traces/cone/attributes.js b/src/traces/cone/attributes.js index 7d78371f226..c85ce94c8c6 100644 --- a/src/traces/cone/attributes.js +++ b/src/traces/cone/attributes.js @@ -183,6 +183,4 @@ attrs.hoverinfo = extendFlat({}, baseAttrs.hoverinfo, { dflt: 'x+y+z+norm+text+name' }); -attrs.transforms = undefined; - module.exports = attrs; diff --git a/src/traces/contourcarpet/attributes.js b/src/traces/contourcarpet/attributes.js index d938f5554d7..341913b34df 100644 --- a/src/traces/contourcarpet/attributes.js +++ b/src/traces/contourcarpet/attributes.js @@ -71,7 +71,6 @@ module.exports = extendFlat({ }, zorder: contourAttrs.zorder, - transforms: undefined }, colorScaleAttrs('', { diff --git a/src/traces/heatmap/attributes.js b/src/traces/heatmap/attributes.js index 4802521a090..60cd9204297 100644 --- a/src/traces/heatmap/attributes.js +++ b/src/traces/heatmap/attributes.js @@ -134,8 +134,6 @@ module.exports = extendFlat({ showlegend: extendFlat({}, baseAttrs.showlegend, {dflt: false}), zorder: scatterAttrs.zorder -}, { - transforms: undefined }, colorScaleAttrs('', {cLetter: 'z', autoColorDflt: false}) ); diff --git a/src/traces/image/attributes.js b/src/traces/image/attributes.js index 8b33b5ebec1..a1ee867d323 100644 --- a/src/traces/image/attributes.js +++ b/src/traces/image/attributes.js @@ -135,5 +135,4 @@ module.exports = extendFlat({ }), zorder: zorder, - transforms: undefined }); diff --git a/src/traces/isosurface/attributes.js b/src/traces/isosurface/attributes.js index cb00ecbef76..cd1be7240e0 100644 --- a/src/traces/isosurface/attributes.js +++ b/src/traces/isosurface/attributes.js @@ -233,4 +233,3 @@ colorScaleAttrs('', { attrs.flatshading.dflt = true; attrs.lighting.facenormalsepsilon.dflt = 0; attrs.x.editType = attrs.y.editType = attrs.z.editType = attrs.value.editType = 'calc+clearAxisTypes'; -attrs.transforms = undefined; diff --git a/src/traces/mesh3d/attributes.js b/src/traces/mesh3d/attributes.js index 6614a4bf4b2..b9b134ccbd9 100644 --- a/src/traces/mesh3d/attributes.js +++ b/src/traces/mesh3d/attributes.js @@ -177,7 +177,6 @@ module.exports = extendFlat({ 'Overrides *color* and *vertexcolor*.' ].join(' ') }, - transforms: undefined }, colorScaleAttrs('', { diff --git a/src/traces/parcoords/plot.js b/src/traces/parcoords/plot.js index 9b9215e3796..f2d2a0b0832 100644 --- a/src/traces/parcoords/plot.js +++ b/src/traces/parcoords/plot.js @@ -40,7 +40,7 @@ var exports = module.exports = function plot(gd, cdModule) { cdModule.forEach(function(d, i) { var trace = d[0].trace; fullIndices[i] = trace.index; - var iIn = inputIndices[i] = trace._fullInput.index; + var iIn = inputIndices[i] = trace.index; currentDims[i] = gd.data[iIn].dimensions; initialDims[i] = gd.data[iIn].dimensions.slice(); }); diff --git a/src/traces/sankey/attributes.js b/src/traces/sankey/attributes.js index a681e2bf384..98a04b99db2 100644 --- a/src/traces/sankey/attributes.js +++ b/src/traces/sankey/attributes.js @@ -286,4 +286,3 @@ var attrs = module.exports = overrideAll({ description: 'The links of the Sankey plot.', } }, 'calc', 'nested'); -attrs.transforms = undefined; diff --git a/src/traces/scatter/calc.js b/src/traces/scatter/calc.js index a7471c0d85b..619d3b83a44 100644 --- a/src/traces/scatter/calc.js +++ b/src/traces/scatter/calc.js @@ -36,7 +36,7 @@ function calc(gd, trace) { var yAttr = 'y'; var posAttr; if(stackGroupOpts) { - Lib.pushUnique(stackGroupOpts.traceIndices, trace._expandedIndex); + Lib.pushUnique(stackGroupOpts.traceIndices, trace.index); isV = stackGroupOpts.orientation === 'v'; // size, like we use for bar diff --git a/src/traces/streamtube/attributes.js b/src/traces/streamtube/attributes.js index 46f5a7f1f9f..b9c0a4663d5 100644 --- a/src/traces/streamtube/attributes.js +++ b/src/traces/streamtube/attributes.js @@ -157,6 +157,4 @@ attrs.hoverinfo = extendFlat({}, baseAttrs.hoverinfo, { dflt: 'x+y+z+norm+text+name' }); -attrs.transforms = undefined; - module.exports = attrs; diff --git a/src/traces/surface/attributes.js b/src/traces/surface/attributes.js index c8f9c6e036b..5713887146c 100644 --- a/src/traces/surface/attributes.js +++ b/src/traces/surface/attributes.js @@ -293,4 +293,3 @@ colorScaleAttrs('', { }), 'calc', 'nested'); attrs.x.editType = attrs.y.editType = attrs.z.editType = 'calc+clearAxisTypes'; -attrs.transforms = undefined; diff --git a/src/traces/table/attributes.js b/src/traces/table/attributes.js index 47642318b56..fda21f724d1 100644 --- a/src/traces/table/attributes.js +++ b/src/traces/table/attributes.js @@ -165,4 +165,3 @@ var attrs = module.exports = overrideAll({ font: extendFlat({}, fontAttrs({arrayOk: true})) } }, 'calc', 'from-root'); -attrs.transforms = undefined; diff --git a/src/traces/volume/attributes.js b/src/traces/volume/attributes.js index 95c72146458..f54948f84fb 100644 --- a/src/traces/volume/attributes.js +++ b/src/traces/volume/attributes.js @@ -70,4 +70,3 @@ colorScaleAttrs('', { }), 'calc', 'nested'); attrs.x.editType = attrs.y.editType = attrs.z.editType = attrs.value.editType = 'calc+clearAxisTypes'; -attrs.transforms = undefined; diff --git a/tasks/test_mock.mjs b/tasks/test_mock.mjs index 3b6be238a5b..ae9bef8fcdd 100644 --- a/tasks/test_mock.mjs +++ b/tasks/test_mock.mjs @@ -80,12 +80,6 @@ function assert(name, v) { function notBlackListed(name) { return [ - // has transforms See https://github.com/plotly/plotly.js/issues/4759 - 'gl2d_transforms', - 'polar_transforms', - 'smith_transforms', - 'transforms', - // has contourcarpet See https://github.com/plotly/plotly.js/issues/5669 'airfoil', 'h-colorbar_airfoil', diff --git a/test/image/baselines/gl2d_point-selection.png b/test/image/baselines/gl2d_point-selection.png index 80ca7e073e4..c8695c33b61 100644 Binary files a/test/image/baselines/gl2d_point-selection.png and b/test/image/baselines/gl2d_point-selection.png differ diff --git a/test/image/baselines/gl2d_transforms.png b/test/image/baselines/gl2d_transforms.png deleted file mode 100644 index a1c63c28fbc..00000000000 Binary files a/test/image/baselines/gl2d_transforms.png and /dev/null differ diff --git a/test/image/baselines/icicle_textposition.png b/test/image/baselines/icicle_textposition.png index 57f5c6e3ca6..1c1fbfc12a8 100644 Binary files a/test/image/baselines/icicle_textposition.png and b/test/image/baselines/icicle_textposition.png differ diff --git a/test/image/baselines/pattern_bars.png b/test/image/baselines/pattern_bars.png index 69a0826e27c..077c05cf164 100644 Binary files a/test/image/baselines/pattern_bars.png and b/test/image/baselines/pattern_bars.png differ diff --git a/test/image/baselines/pattern_fgcolor_overlay_fillmode.png b/test/image/baselines/pattern_fgcolor_overlay_fillmode.png index 6c6b5fbb821..af59862d58a 100644 Binary files a/test/image/baselines/pattern_fgcolor_overlay_fillmode.png and b/test/image/baselines/pattern_fgcolor_overlay_fillmode.png differ diff --git a/test/image/baselines/point-selection.png b/test/image/baselines/point-selection.png index 62aedb925f3..4164d472d86 100644 Binary files a/test/image/baselines/point-selection.png and b/test/image/baselines/point-selection.png differ diff --git a/test/image/baselines/polar_transforms.png b/test/image/baselines/polar_transforms.png deleted file mode 100644 index 45bacfcf856..00000000000 Binary files a/test/image/baselines/polar_transforms.png and /dev/null differ diff --git a/test/image/baselines/smith_transforms.png b/test/image/baselines/smith_transforms.png deleted file mode 100644 index de9db8ffcef..00000000000 Binary files a/test/image/baselines/smith_transforms.png and /dev/null differ diff --git a/test/image/baselines/stacked_area_groupby.png b/test/image/baselines/stacked_area_groupby.png index 83ea6c3ac63..5c3a817a752 100644 Binary files a/test/image/baselines/stacked_area_groupby.png and b/test/image/baselines/stacked_area_groupby.png differ diff --git a/test/image/baselines/transforms.png b/test/image/baselines/transforms.png deleted file mode 100644 index c1148e64bd8..00000000000 Binary files a/test/image/baselines/transforms.png and /dev/null differ diff --git a/test/image/baselines/treemap_packages_colorscale_novalue.png b/test/image/baselines/treemap_packages_colorscale_novalue.png index 5efd24ef2d9..0ec48aa585b 100644 Binary files a/test/image/baselines/treemap_packages_colorscale_novalue.png and b/test/image/baselines/treemap_packages_colorscale_novalue.png differ diff --git a/test/image/baselines/treemap_sunburst_marker_colors.png b/test/image/baselines/treemap_sunburst_marker_colors.png index 3a45878bbec..209427c1b2a 100644 Binary files a/test/image/baselines/treemap_sunburst_marker_colors.png and b/test/image/baselines/treemap_sunburst_marker_colors.png differ diff --git a/test/image/baselines/treemap_textfit.png b/test/image/baselines/treemap_textfit.png index 1ead0015787..b9b0a41090d 100644 Binary files a/test/image/baselines/treemap_textfit.png and b/test/image/baselines/treemap_textfit.png differ diff --git a/test/image/baselines/uniformtext_sunburst_treemap.png b/test/image/baselines/uniformtext_sunburst_treemap.png index d99afe65a59..31adc8ab71e 100644 Binary files a/test/image/baselines/uniformtext_sunburst_treemap.png and b/test/image/baselines/uniformtext_sunburst_treemap.png differ diff --git a/test/image/baselines/world-cals.png b/test/image/baselines/world-cals.png index ce82b2cafa9..9549610192a 100644 Binary files a/test/image/baselines/world-cals.png and b/test/image/baselines/world-cals.png differ diff --git a/test/image/mocks/gl2d_point-selection.json b/test/image/mocks/gl2d_point-selection.json index 661095ca616..de267366f30 100644 --- a/test/image/mocks/gl2d_point-selection.json +++ b/test/image/mocks/gl2d_point-selection.json @@ -27,15 +27,7 @@ "color": "green", "opacity": 0.5 } - }, - "transforms": [ - { - "type": "filter", - "target": "x", - "operation": "][", - "value": [3.5, 4.5] - } - ] + } }, { "type": "scattergl", @@ -60,15 +52,7 @@ "color": "blue", "opacity": 0.5 } - }, - "transforms": [ - { - "type": "filter", - "target": "x", - "operation": "][", - "value": [3.5, 4.5] - } - ] + } } ], "layout": { diff --git a/test/image/mocks/gl2d_transforms.json b/test/image/mocks/gl2d_transforms.json deleted file mode 100644 index bf6b45fcef2..00000000000 --- a/test/image/mocks/gl2d_transforms.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "data": [ - { - "type": "scattergl", - "mode": "lines+markers", - "x": [1, -1, -2, 0, 1, 3, 3], - "y": [2, 1, 0, 1, 3, 4, 3], - "transforms": [ - { - "type": "groupby", - "groups": ["a", "a", "b", "a", "b", "b", "a"], - "styles": [ - { "target": "a", "value": { "marker": { "color": "orange" } } }, - { "target": "b", "value": { "marker": { "color": "blue" } } } - ] - }, - { - "type": "filter", - "target": "x", - "operation": ">=", - "value": 0, - "preservegaps": true - } - ], - "name": "Groupby+filter" - }, - { - "type": "scattergl", - "x": [1, 2, 3, 4, -3], - "y": [1.1, 2.2, 3.3, 4.4, 5.5], - "marker": { - "size": [0.3, 0.2, 0.1, 0.4, 0.5], - "sizeref": 0.01, - "color": [2, 4, 6, 10, 8], - "opacity": [0.9, 0.6, 0.2, 0.8, 1.0], - "line": { - "color": [2.2, 3.3, 4.4, 5.5, 1.1] - } - }, - "transforms": [ - { - "type": "aggregate", - "groups": ["a", "b", "a", "a", "a"], - "aggregations": [ - { "target": "x", "func": "sum" }, - { "target": "y", "func": "avg" }, - { "target": "marker.size", "func": "min" }, - { "target": "marker.color", "func": "max" }, - { "target": "marker.line.color", "func": "last" }, - { "target": "marker.line.width", "func": "count" } - ] - } - ], - "name": "Aggregate" - }, - { - "type": "scattergl", - "x": [1, 2, 3, 4, 5, 6], - "y": [1, 4, 2, 6, 5, 3], - "transforms": [ - { - "type": "sort", - "target": [1, 6, 2, 5, 3, 4] - } - ], - "name": "Sort" - }, - { - "type": "scattergl", - "x": [4, 5, 6, 4, 5, 6], - "y": [1, 1, 1, 2, 2, 2], - "marker": { "color": [1, 2, 3, -1, -2, -3], "size": 20 }, - "mode": "lines+markers", - "transforms": [{ "type": "groupby", "groups": [1, 1, 1, 2, 2, 2] }] - } - ], - "layout": { - "width": 600, - "height": 400, - "title": { "text": "Transforms on scattergl traces" } - } -} diff --git a/test/image/mocks/point-selection.json b/test/image/mocks/point-selection.json index 2326c035fa3..cb65b3b4df2 100644 --- a/test/image/mocks/point-selection.json +++ b/test/image/mocks/point-selection.json @@ -23,15 +23,7 @@ "color": "green", "opacity": 0.5 } - }, - "transforms": [ - { - "type": "filter", - "target": "x", - "operation": "][", - "value": [3.5, 4.5] - } - ] + } }, { "mode": "lines+markers+text", @@ -55,15 +47,7 @@ "color": "blue", "opacity": 0.5 } - }, - "transforms": [ - { - "type": "filter", - "target": "x", - "operation": "][", - "value": [3.5, 4.5] - } - ] + } } ], "layout": { diff --git a/test/image/mocks/polar_transforms.json b/test/image/mocks/polar_transforms.json deleted file mode 100644 index 738514c9ef2..00000000000 --- a/test/image/mocks/polar_transforms.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "data": [ - { - "type": "scatterpolar", - "mode": "lines+markers", - "r": [1, -1, -2, 0, 1, 3, 3], - "theta": [2, 1, 0, 1, 3, 4, 3], - "thetaunit": "radians", - "transforms": [ - { - "type": "groupby", - "groups": ["a", "a", "b", "a", "b", "b", "a"], - "styles": [ - { "target": "a", "value": { "marker": { "color": "orange" } } }, - { "target": "b", "value": { "marker": { "color": "blue" } } } - ] - }, - { - "type": "filter", - "target": "r", - "operation": ">=", - "value": 0, - "preservegaps": true - } - ], - "name": "Groupby+filter" - }, - { - "type": "scatterpolar", - "r": [1, 2, 3, 4, -3], - "theta": [1.1, 2.2, 3.3, 4.4, 5.5], - "thetaunit": "radians", - "marker": { - "size": [0.3, 0.2, 0.1, 0.4, 0.5], - "sizeref": 0.01, - "color": [2, 4, 6, 10, 8], - "opacity": [0.9, 0.6, 0.2, 0.8, 1.0], - "line": { - "color": [2.2, 3.3, 4.4, 5.5, 1.1] - } - }, - "transforms": [ - { - "type": "aggregate", - "groups": ["a", "b", "a", "a", "a"], - "aggregations": [ - { "target": "r", "func": "sum" }, - { "target": "theta", "func": "avg" }, - { "target": "marker.size", "func": "min" }, - { "target": "marker.color", "func": "max" }, - { "target": "marker.line.color", "func": "last" }, - { "target": "marker.line.width", "func": "count" } - ] - } - ], - "name": "Aggregate" - }, - { - "type": "scatterpolar", - "r": [1, 2, 3, 4, 5, 6], - "theta": [1, 4, 2, 6, 5, 3], - "thetaunit": "radians", - "transforms": [ - { - "type": "sort", - "target": [1, 6, 2, 5, 3, 4] - } - ], - "name": "Sort" - }, - { - "type": "scatterpolar", - "r": [4, 5, 6, 4, 5, 6], - "theta": [1, 1, 1, 2, 2, 2], - "thetaunit": "radians", - "marker": { "color": [1, 2, 3, -1, -2, -3], "size": 12 }, - "mode": "lines+markers", - "transforms": [{ "type": "groupby", "groups": [1, 1, 1, 2, 2, 2] }] - } - ], - "layout": { - "width": 600, - "height": 400, - "title": { "text": "Transforms on polar subplot" } - } -} diff --git a/test/image/mocks/smith_transforms.json b/test/image/mocks/smith_transforms.json deleted file mode 100644 index a9b7de7b6ed..00000000000 --- a/test/image/mocks/smith_transforms.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "data": [ - { - "type": "scattersmith", - "mode": "lines+markers", - "real": [1, -1, -2, 0, 1, 3, 3], - "imag": [2, 1, 0, 1, 3, 4, 3], - "transforms": [ - { - "type": "groupby", - "groups": ["a", "a", "b", "a", "b", "b", "a"], - "styles": [ - { "target": "a", "value": { "marker": { "color": "orange" } } }, - { "target": "b", "value": { "marker": { "color": "blue" } } } - ] - }, - { - "type": "filter", - "target": "real", - "operation": ">=", - "value": 0, - "preservegaps": true - } - ], - "name": "Groupby+filter" - }, - { - "type": "scattersmith", - "real": [1, 2, 3, 4, -3], - "imag": [1.1, 2.2, 3.3, 4.4, 5.5], - "marker": { - "size": [0.3, 0.2, 0.1, 0.4, 0.5], - "sizeref": 0.01, - "color": [2, 4, 6, 10, 8], - "opacity": [0.9, 0.6, 0.2, 0.8, 1.0], - "line": { - "color": [2.2, 3.3, 4.4, 5.5, 1.1] - } - }, - "transforms": [ - { - "type": "aggregate", - "groups": ["a", "b", "a", "a", "a"], - "aggregations": [ - { "target": "real", "func": "sum" }, - { "target": "imag", "func": "avg" }, - { "target": "marker.size", "func": "min" }, - { "target": "marker.color", "func": "max" }, - { "target": "marker.line.color", "func": "last" }, - { "target": "marker.line.width", "func": "count" } - ] - } - ], - "name": "Aggregate" - }, - { - "type": "scattersmith", - "real": [1, 2, 3, 4, 5, 6], - "imag": [1, 4, 2, 6, 5, 3], - "transforms": [ - { - "type": "sort", - "target": [1, 6, 2, 5, 3, 4] - } - ], - "name": "Sort" - }, - { - "type": "scattersmith", - "real": [4, 5, 6, 4, 5, 6], - "imag": [1, 1, 1, 2, 2, 2], - "marker": { "color": [1, 2, 3, -1, -2, -3], "size": 12 }, - "mode": "lines+markers", - "transforms": [{ "type": "groupby", "groups": [1, 1, 1, 2, 2, 2] }] - } - ], - "layout": { - "legend": { - "orientation": "h" - }, - "width": 500, - "height": 500, - "title": { "text": "Transforms on smith subplot" } - } -} diff --git a/test/image/mocks/stacked_area_groupby.json b/test/image/mocks/stacked_area_groupby.json deleted file mode 100644 index f28aafe99e9..00000000000 --- a/test/image/mocks/stacked_area_groupby.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "data": [ - { - "x": [1, 1, 2, 2, 3, 3], - "y": [1, 1, 2, 2, 3, 3], - "stackgroup": 1, - "transforms": [ - { - "type": "groupby", - "groups": ["a", "b", "a", "b", "a", "b"] - } - ] - } - ], - "layout": { - "width": 400 - } -} diff --git a/test/image/mocks/transforms.json b/test/image/mocks/transforms.json deleted file mode 100644 index 4b6e6b8d964..00000000000 --- a/test/image/mocks/transforms.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "data": [ - { - "mode": "lines+markers", - "x": [1, -1, -2, 0, 1, 3, 3], - "y": [2, 1, 0, 1, 3, 4, 3], - "transforms": [ - { - "type": "groupby", - "groups": ["a", "a", "b", "a", "b", "b", "a"], - "styles": [ - { "target": "a", "value": { "marker": { "color": "orange" } } }, - { "target": "b", "value": { "marker": { "color": "blue" } } } - ] - }, - { - "type": "filter", - "target": "x", - "operation": ">=", - "value": 0, - "preservegaps": true - } - ], - "name": "Groupby+filter" - }, - { - "x": [1, 2, 3, 4, -3], - "y": [1.1, 2.2, 3.3, 4.4, 5.5], - "marker": { - "size": [0.3, 0.2, 0.1, 0.4, 0.5], - "sizeref": 0.01, - "color": [2, 4, 6, 10, 8], - "opacity": [0.9, 0.6, 0.2, 0.8, 1.0], - "line": { - "color": [2.2, 3.3, 4.4, 5.5, 1.1] - } - }, - "transforms": [ - { - "type": "aggregate", - "groups": ["a", "b", "a", "a", "a"], - "aggregations": [ - { "target": "x", "func": "sum" }, - { "target": "y", "func": "avg" }, - { "target": "marker.size", "func": "min" }, - { "target": "marker.color", "func": "max" }, - { "target": "marker.line.color", "func": "last" }, - { "target": "marker.line.width", "func": "count" } - ] - } - ], - "name": "Aggregate" - }, - { - "x": [1, 2, 3, 4, 5, 6], - "y": [1, 4, 2, 6, 5, 3], - "transforms": [ - { - "type": "sort", - "target": [1, 6, 2, 5, 3, 4] - } - ], - "name": "Sort" - }, - { - "x": [4, 5, 6, 4, 5, 6], - "y": [1, 1, 1, 2, 2, 2], - "marker": { "color": [1, 2, 3, -1, -2, -3], "size": 20 }, - "mode": "lines+markers", - "transforms": [{ "type": "groupby", "groups": [1, 1, 1, 2, 2, 2] }] - } - ], - "layout": { - "width": 600, - "height": 400, - "title": { "text": "Transforms" } - } -} diff --git a/test/image/mocks/world-cals.json b/test/image/mocks/world-cals.json index 543aec84abf..1942bbfe1f1 100644 --- a/test/image/mocks/world-cals.json +++ b/test/image/mocks/world-cals.json @@ -183,16 +183,7 @@ "xaxis": "x2", "yaxis": "y2", "ycalendar": "hebrew", - "name": "hebrew histogram
jalali filtered", - "transforms": [ - { - "type": "filter", - "operation": "[]", - "valuecalendar": "jalali", - "value": ["0818-08", "0819-06"], - "target": "y" - } - ], + "name": "hebrew histogram", "ybins": { "start": "5200-12-29 12:00", "end": "5200-01-03 12:00", diff --git a/test/jasmine/assets/check_component.js b/test/jasmine/assets/check_component.js index 32f34c41572..7480af5c7c2 100644 --- a/test/jasmine/assets/check_component.js +++ b/test/jasmine/assets/check_component.js @@ -9,7 +9,7 @@ var destroyGraphDiv = require('../assets/destroy_graph_div'); * but the test is that they may have been registered in any order */ module.exports = function checkComponent(Plotly) { - describe('core (svg 2d, scatter) and registered (bar) traces and transforms', function() { + describe('core (svg 2d, scatter) and registered (bar) traces', function() { var gd; var mock = { @@ -23,15 +23,6 @@ module.exports = function checkComponent(Plotly) { x: ['2001-01-01', '2002-01-01', '2003-01-01'], y: [1, 3, 5], type: 'bar', - transforms: [{ - type: 'filter', - operation: '<', - target: 'y', - value: '4', - // need an explicit calendar, as filter uses a default of null - // the rest of them get the default calendar filled in - valuecalendar: 'nepali' - }] } ] }; @@ -59,7 +50,6 @@ module.exports = function checkComponent(Plotly) { expect(nodes.size()).toEqual(1); expect(gd._fullData[1].xcalendar).toBe('gregorian'); - expect(gd._fullData[1].transforms[0].valuecalendar).toBe('nepali'); }); }); diff --git a/test/jasmine/assets/mock_lists.js b/test/jasmine/assets/mock_lists.js index fc6e76c3346..05375108c8d 100644 --- a/test/jasmine/assets/mock_lists.js +++ b/test/jasmine/assets/mock_lists.js @@ -44,7 +44,6 @@ var svgMockList = [ ['table_wrapped_birds', require('../../image/mocks/table_wrapped_birds.json')], ['ternary_fill', require('../../image/mocks/ternary_fill.json')], ['text_chart_arrays', require('../../image/mocks/text_chart_arrays.json')], - ['transforms', require('../../image/mocks/transforms.json')], ['updatemenus', require('../../image/mocks/updatemenus.json')], ['violin_side-by-side', require('../../image/mocks/violin_side-by-side.json')], ['world-cals', require('../../image/mocks/world-cals.json')], diff --git a/test/jasmine/bundle_tests/component_first_test.js b/test/jasmine/bundle_tests/component_first_test.js index 4bdb2208e5b..0d48da8ef86 100644 --- a/test/jasmine/bundle_tests/component_first_test.js +++ b/test/jasmine/bundle_tests/component_first_test.js @@ -6,7 +6,7 @@ var Calendars = require('../../../lib/calendars'); var checkComponent = require('../assets/check_component'); -describe('Bundle with a component loaded before traces and transforms', function() { +describe('Bundle with a component loaded before traces', function() { 'use strict'; Plotly.register([Calendars, Filter, Scatter3d, Bar]); diff --git a/test/jasmine/bundle_tests/component_last_test.js b/test/jasmine/bundle_tests/component_last_test.js index 4508e1eb777..f3b3841f5b0 100644 --- a/test/jasmine/bundle_tests/component_last_test.js +++ b/test/jasmine/bundle_tests/component_last_test.js @@ -6,7 +6,7 @@ var Calendars = require('../../../lib/calendars'); var checkComponent = require('../assets/check_component'); -describe('Bundle with a component loaded after traces and transforms', function() { +describe('Bundle with a component loaded after traces', function() { 'use strict'; Plotly.register([Bar, Scatter3d, Filter, Calendars]); diff --git a/test/jasmine/bundle_tests/finance_test.js b/test/jasmine/bundle_tests/finance_test.js index 0291f54c39f..a449464d1e3 100644 --- a/test/jasmine/bundle_tests/finance_test.js +++ b/test/jasmine/bundle_tests/finance_test.js @@ -14,12 +14,6 @@ describe('Bundle with finance trace type', function() { var mock = require('../../image/mocks/finance_style.json'); - it('should not register transforms anymore', function() { - var transformModules = Object.keys(Plots.transformsRegistry); - - expect(transformModules).toEqual([]); - }); - it('should register the correct trace modules for the generated traces', function() { var traceModules = Object.keys(Plots.modules); diff --git a/test/jasmine/bundle_tests/plotschema_test.js b/test/jasmine/bundle_tests/plotschema_test.js index 7ce54c5771c..7a89f628bce 100644 --- a/test/jasmine/bundle_tests/plotschema_test.js +++ b/test/jasmine/bundle_tests/plotschema_test.js @@ -36,14 +36,6 @@ describe('plot schema', function() { }); } - function assertTransformSchema(callback) { - var transforms = plotSchema.transforms; - - Object.keys(transforms).forEach(function(transformName) { - Plotly.PlotSchema.crawl(transforms[transformName].attributes, callback, 0, transformName); - }); - } - function assertLayoutSchema(callback) { Plotly.PlotSchema.crawl(plotSchema.layout.layoutAttributes, callback, 0, 'layout'); @@ -60,7 +52,6 @@ describe('plot schema', function() { function assertPlotSchema(callback) { assertTraceSchema(callback); assertLayoutSchema(callback); - assertTransformSchema(callback); } it('all attributes should have a valid `valType`', function() { @@ -271,13 +262,6 @@ describe('plot schema', function() { } }); - assertTransformSchema(function(attr, attrName, attrs, level, attrString) { - if(shouldHaveEditType(attr, attrName)) { - expect(Lib.validate(attr.editType, editType.traces)) - .toBe(true, attrString + ': ' + JSON.stringify(attr.editType)); - } - }); - assertLayoutSchema(function(attr, attrName, attrs, level, attrString) { if(shouldHaveEditType(attr, attrName)) { expect(Lib.validate(attr.editType, editType.layout)) @@ -286,34 +270,6 @@ describe('plot schema', function() { }); }); - it('should work with registered transforms', function() { - var valObjects = plotSchema.transforms.filter.attributes; - var attrNames = Object.keys(valObjects); - - ['operation', 'value', 'target'].forEach(function(k) { - expect(attrNames).toContain(k); - }); - }); - - it('should work with registered transforms (2)', function() { - var valObjects = plotSchema.transforms.groupby.attributes; - var items = valObjects.styles.items || {}; - - expect(Object.keys(items)).toEqual(['style']); - }); - - it('should work with registered components', function() { - expect(plotSchema.traces.scatter.attributes.xcalendar.valType).toEqual('enumerated'); - expect(plotSchema.traces.scatter3d.attributes.zcalendar.valType).toEqual('enumerated'); - - expect(plotSchema.layout.layoutAttributes.calendar.valType).toEqual('enumerated'); - expect(plotSchema.layout.layoutAttributes.xaxis.calendar.valType).toEqual('enumerated'); - expect(plotSchema.layout.layoutAttributes.scene.xaxis.calendar.valType).toEqual('enumerated'); - - expect(plotSchema.transforms.filter.attributes.valuecalendar.valType).toEqual('enumerated'); - expect(plotSchema.transforms.filter.attributes.targetcalendar.valType).toEqual('enumerated'); - }); - it('should list correct defs', function() { expect(plotSchema.defs.valObjects).toBeDefined(); @@ -440,34 +396,6 @@ describe('getTraceValObject', function() { .toBe(surface.attributes.zcalendar); }); - it('supports transform attributes', function() { - var mockTrace = {transforms: [ - {type: 'filter'}, - {type: 'groupby'} - ]}; - - var filterAttrs = require('../../../lib/filter').attributes; - expect(getTraceValObject(mockTrace, ['transforms', 0, 'operation'])) - .toBe(filterAttrs.operation); - // check a component-provided attr - expect(getTraceValObject(mockTrace, ['transforms', 0, 'valuecalendar'])) - .toBe(filterAttrs.valuecalendar); - - expect(getTraceValObject(mockTrace, ['transforms', 1, 'styles', 13, 'value', 'line', 'color'])) - .toBe(require('../../../lib/groupby').attributes.styles.value); - - [ - ['transforms', 0], - ['transforms', 0, 'nameformat'], - ['transforms', 2, 'enabled'], - ['transforms', '0', 'operation'] - ].forEach(function(attrArray) { - expect(getTraceValObject(mockTrace, attrArray)).toBe(false, attrArray); - }); - - expect(getTraceValObject({}, ['transforms', 0, 'operation'])).toBe(false); - }); - it('does not return attribute properties', function() { // it still returns the attribute itself - but maybe we should only do this // for valType: any? (or data_array/arrayOk with just an index) diff --git a/test/jasmine/karma.conf.js b/test/jasmine/karma.conf.js index 90f0c696d5c..e069438e5c9 100644 --- a/test/jasmine/karma.conf.js +++ b/test/jasmine/karma.conf.js @@ -278,7 +278,7 @@ func.defaultConfig = { // // Although not recommended, some tests "depend" on other // tests to pass (e.g. the Plotly.react tests check that - // all available traces and transforms are tested). Tag these + // all available traces are tested). Tag these // with @noCIdep, so that // - $ npm run test-jasmine -- tags=noCI,noCIdep // can pass. diff --git a/test/jasmine/tests/animate_test.js b/test/jasmine/tests/animate_test.js index cba22278fcc..f70f99e0ab2 100644 --- a/test/jasmine/tests/animate_test.js +++ b/test/jasmine/tests/animate_test.js @@ -974,28 +974,6 @@ describe('animating scatter traces', function() { }).then(done, done.fail); }); - it('computes calcdata correctly when transforms are present', function(done) { - Plotly.newPlot(gd, { - data: [{ - x: [1, 2, 3], - y: [1, 2, 3], - mode: 'markers', - transforms: [{ - type: 'sort', - target: [1, 3, 2] - }] - }], - frames: [ - {name: 'frame1', data: [{y: [1, 2, 3]}]}, - {name: 'frame2', data: [{y: [3, 1, 2]}]} - ] - }).then(function() { - return Plotly.animate(gd, ['frame2'], {frame: {duration: 200, redraw: false}}); - }).then(function() { - expect(gd.calcdata[0][0].y).toEqual(3); - }).then(done, done.fail); - }); - it('@flaky should animate axis ranges using the less number of steps', function(done) { // sanity-check that scatter points and bars are still there function _assertNodeCnt() { diff --git a/test/jasmine/tests/finance_test.js b/test/jasmine/tests/finance_test.js index f57ffb3a16c..bf0bc8ef3fd 100644 --- a/test/jasmine/tests/finance_test.js +++ b/test/jasmine/tests/finance_test.js @@ -55,67 +55,6 @@ describe('finance charts defaults:', function() { expect(out._fullData.length).toEqual(2); }); - it('should not mutate user data', function() { - var trace0 = Lib.extendDeep({}, mock0, { - type: 'ohlc' - }); - - var trace1 = Lib.extendDeep({}, mock1, { - type: 'candlestick' - }); - - var out = _supply([trace0, trace1]); - expect(out.data[0]).toBe(trace0); - expect(out.data[0].transforms).toBeUndefined(); - expect(out.data[1]).toBe(trace1); - expect(out.data[1].transforms).toBeUndefined(); - - // ... and in an idempotent way - - var out2 = _supply(out.data); - expect(out2.data[0]).toBe(trace0); - expect(out2.data[0].transforms).toBeUndefined(); - expect(out2.data[1]).toBe(trace1); - expect(out2.data[1].transforms).toBeUndefined(); - }); - - it('should work with transforms', function() { - var trace0 = Lib.extendDeep({}, mock1, { - type: 'ohlc', - transforms: [{ - type: 'filter' - }] - }); - - var trace1 = Lib.extendDeep({}, mock0, { - type: 'candlestick', - transforms: [{ - type: 'filter' - }] - }); - - var out = _supply([trace0, trace1]); - - expect(out.data.length).toEqual(2); - expect(out._fullData.length).toEqual(2); - - var transformTypesIn = out.data.map(function(trace) { - return trace.transforms.map(function(opts) { - return opts.type; - }); - }); - - expect(transformTypesIn).toEqual([ ['filter'], ['filter'] ]); - - var transformTypesOut = out._fullData.map(function(fullTrace) { - return fullTrace.transforms.map(function(opts) { - return opts.type; - }); - }); - - expect(transformTypesOut).toEqual([ ['filter'], ['filter'] ]); - }); - it('should not slice data arrays but record minimum supplied length', function() { function assertDataLength(trace, fullTrace, len) { expect(fullTrace.visible).toBe(true); @@ -446,110 +385,6 @@ describe('finance charts calc', function() { expect(mapGet(out[1], 'empty')).toEqual(empties); }); - it('should work with *filter* transforms', function() { - var trace0 = Lib.extendDeep({}, mock1, { - type: 'ohlc', - tickwidth: 0.05, - transforms: [{ - type: 'filter', - operation: '>', - target: 'open', - value: 33 - }] - }); - - var trace1 = Lib.extendDeep({}, mock1, { - type: 'candlestick', - transforms: [{ - type: 'filter', - operation: '{}', - target: 'x', - value: ['2016-09-01', '2016-09-10'] - }] - }); - - var out = _calc([trace0, trace1]); - - expect(out.length).toEqual(2); - - expect(out[0].x).toEqual([ - '2016-09-01', '2016-09-02', '2016-09-03', '2016-09-05', '2016-09-06', '2016-09-07', '2016-09-10' - ]); - expect(out[0].open).toEqual([ - 33.01, 33.31, 33.50, 34.12, 33.05, 33.31, 33.50 - ]); - - expect(out[1].x).toEqual([ - '2016-09-01', '2016-09-10' - ]); - expect(out[1].close).toEqual([ - 34.10, 33.70 - ]); - }); - - it('should work with *groupby* transforms (ohlc)', function() { - var opts = { - type: 'groupby', - groups: ['b', 'b', 'b', 'a'], - }; - - var trace0 = Lib.extendDeep({}, mock1, { - type: 'ohlc', - tickwidth: 0.05, - transforms: [opts] - }); - - var out = _calc([trace0]); - - expect(out.length).toBe(2); - - expect(out[0].name).toBe('b'); - expect(out[0].x).toEqual([ - '2016-09-01', '2016-09-02', '2016-09-03' - ]); - expect(out[0].open).toEqual([ - 33.01, 33.31, 33.5 - ]); - - expect(out[1].name).toBe('a'); - expect(out[1].x).toEqual([ - '2016-09-04' - ]); - expect(out[1].open).toEqual([ - 32.06 - ]); - }); - - it('should work with *groupby* transforms (candlestick)', function() { - var opts = { - type: 'groupby', - groups: ['a', 'b', 'b', 'a'], - }; - - var trace0 = Lib.extendDeep({}, mock1, { - type: 'candlestick', - transforms: [opts] - }); - - var out = _calc([trace0]); - - expect(out[0].name).toEqual('a'); - expect(out[0].x).toEqual([ - '2016-09-01', '2016-09-04' - ]); - expect(out[0].open).toEqual([ - 33.01, 32.06 - ]); - - expect(out[1].name).toEqual('b'); - expect(out[1].x).toEqual([ - '2016-09-02', '2016-09-03' - ]); - expect(out[1].open).toEqual([ - 33.31, 33.5 - ]); - }); - it('should use the smallest trace minimum x difference to convert *tickwidth* to data coords for all traces attached to a given x-axis', function() { var trace0 = Lib.extendDeep({}, mock1, { type: 'ohlc' diff --git a/test/jasmine/tests/funnel_test.js b/test/jasmine/tests/funnel_test.js index b28642fe560..03812bf82ba 100644 --- a/test/jasmine/tests/funnel_test.js +++ b/test/jasmine/tests/funnel_test.js @@ -1093,35 +1093,6 @@ describe('A funnel plot', function() { .then(done, done.fail); }); - it('should be able to deal with transform that empty out the data coordinate arrays', function(done) { - Plotly.newPlot(gd, { - data: [{ - type: 'funnel', - x: [1, 2, 3], - xsrc: 'ints', - transforms: [{ - type: 'filter', - target: [1, 2, 3], - targetsrc: 'ints', - operation: '<', - value: 0 - }] - }], - layout: { - funnelmode: 'group' - } - }) - .then(function() { - var traceNodes = getAllTraceNodes(gd); - expect(traceNodes.length).toBe(0); - - expect(gd.calcdata[0][0].x).toEqual(NaN); - expect(gd.calcdata[0][0].y).toEqual(NaN); - expect(gd.calcdata[0][0].isBlank).toBe(undefined); - }) - .then(done, done.fail); - }); - it('should coerce text-related attributes', function(done) { var data = [{ y: [10, 20, 30, 40], diff --git a/test/jasmine/tests/legend_test.js b/test/jasmine/tests/legend_test.js index ded26277656..70b5317397e 100644 --- a/test/jasmine/tests/legend_test.js +++ b/test/jasmine/tests/legend_test.js @@ -1603,107 +1603,6 @@ describe('legend interaction', function() { }); }); - describe('editable mode interactions', function() { - var gd; - - var mock = { - data: [{ - x: [1, 2, 3], - y: [5, 4, 3] - }, { - x: [1, 2, 3, 4, 5, 6, 7, 8], - y: [1, 3, 2, 4, 3, 5, 4, 6], - transforms: [{ - type: 'groupby', - groups: [1, 2, 1, 2, 3, 4, 3, 4] - }] - }], - config: {editable: true} - }; - - beforeEach(function(done) { - gd = createGraphDiv(); - Plotly.newPlot(gd, Lib.extendDeep({}, mock)).then(done); - }); - - afterEach(destroyGraphDiv); - - function _setValue(index, str) { - var item = d3SelectAll('text.legendtext')[0][index || 0]; - item.dispatchEvent(new MouseEvent('click')); - return delay(20)().then(function() { - var input = d3Select('.plugin-editable.editable'); - input.text(str); - input.node().dispatchEvent(new KeyboardEvent('blur')); - }).then(delay(20)); - } - - function assertLabels(expected) { - var labels = []; - d3SelectAll('text.legendtext').each(function() { - labels.push(this.textContent); - }); - expect(labels).toEqual(expected); - } - - it('sets and unsets trace group names', function(done) { - assertLabels(['trace 0', '1 (trace 1)', '2 (trace 1)', '3 (trace 1)', '4 (trace 1)']); - // Set the name of the first trace: - _setValue(0, 'foo').then(function() { - expect(gd.data[0].name).toEqual('foo'); - // labels shorter than half the longest get padded with spaces to match the longest length - assertLabels(['foo ', '1 (trace 1)', '2 (trace 1)', '3 (trace 1)', '4 (trace 1)']); - - // Set the name of the third legend item: - return _setValue(3, 'barbar'); - }).then(function() { - expect(gd.data[1].transforms[0].styles).toEqual([ - {value: {name: 'barbar'}, target: 3} - ]); - assertLabels(['foo ', '1 (trace 1)', '2 (trace 1)', 'barbar', '4 (trace 1)']); - - return _setValue(2, 'asdf'); - }).then(function() { - expect(gd.data[1].transforms[0].styles).toEqual([ - {value: {name: 'barbar'}, target: 3}, - {value: {name: 'asdf'}, target: 2} - ]); - assertLabels(['foo ', '1 (trace 1)', 'asdf ', 'barbar', '4 (trace 1)']); - - // Clear the group names: - return _setValue(3, ''); - }).then(function() { - assertLabels(['foo ', '1 (trace 1)', 'asdf ', ' ', '4 (trace 1)']); - return _setValue(2, ''); - }).then(function() { - // Verify the group names have been cleared: - expect(gd.data[1].transforms[0].styles).toEqual([ - {target: 3, value: {name: ''}}, - {target: 2, value: {name: ''}} - ]); - assertLabels(['foo ', '1 (trace 1)', ' ', ' ', '4 (trace 1)']); - - return _setValue(0, ''); - }).then(function() { - expect(gd.data[0].name).toEqual(''); - assertLabels([' ', '1 (trace 1)', ' ', ' ', '4 (trace 1)']); - - return _setValue(0, 'boo~~~'); - }).then(function() { - expect(gd.data[0].name).toEqual('boo~~~'); - assertLabels(['boo~~~', '1 (trace 1)', ' ', ' ', '4 (trace 1)']); - - return _setValue(2, 'hoo'); - }).then(function() { - expect(gd.data[1].transforms[0].styles).toEqual([ - {target: 3, value: {name: ''}}, - {target: 2, value: {name: 'hoo'}} - ]); - assertLabels(['boo~~~', '1 (trace 1)', 'hoo ', ' ', '4 (trace 1)']); - }).then(done, done.fail); - }); - }); - describe('editable mode interactions for shape legends', function() { var gd; @@ -2151,84 +2050,6 @@ describe('legend interaction', function() { }); }); - describe('legend visibility toggles with groupby', function() { - beforeEach(function(done) { - Plotly.newPlot(gd, [{ - x: [1, 2], - y: [3, 4], - visible: false - }, { - x: [1, 2, 3, 4], - y: [0, 1, 2, 3] - }, { - x: [1, 2, 3, 4], - y: [1, 3, 2, 4], - transforms: [{ - type: 'groupby', - groups: ['a', 'b', 'c', 'c'] - }] - }, { - x: [1, 2, 3, 4], - y: [1, 3, 2, 4], - transforms: [{ - type: 'groupby', - groups: ['a', 'b', 'c', 'c'] - }] - }]).then(done); - }); - - it('computes the initial visibility correctly', function(done) { - Promise.resolve() - .then(assertVisible([false, true, true, true, true, true, true, true])) - .then(done, done.fail); - }); - - it('toggles the visibility of a non-groupby trace in the presence of groupby traces', function(done) { - Promise.resolve() - .then(click(1)) - .then(assertVisible([false, true, 'legendonly', true, true, true, true, true])) - .then(click(1)) - .then(assertVisible([false, true, true, true, true, true, true, true])) - .then(done, done.fail); - }); - - it('toggles the visibility of the first group in a groupby trace', function(done) { - Promise.resolve() - .then(click(0)) - .then(assertVisible([false, 'legendonly', true, true, true, true, true, true])) - .then(click(0)) - .then(assertVisible([false, true, true, true, true, true, true, true])) - .then(done, done.fail); - }); - - it('toggles the visibility of the third group in a groupby trace', function(done) { - Promise.resolve() - .then(click(3)) - .then(assertVisible([false, true, true, true, 'legendonly', true, true, true])) - .then(click(3)) - .then(assertVisible([false, true, true, true, true, true, true, true])) - .then(done, done.fail); - }); - - it('double-clicking isolates a non-groupby trace', function(done) { - Promise.resolve() - .then(click(0, 2)) - .then(assertVisible([false, true, 'legendonly', 'legendonly', 'legendonly', 'legendonly', 'legendonly', 'legendonly'])) - .then(click(0, 2)) - .then(assertVisible([false, true, true, true, true, true, true, true])) - .then(done, done.fail); - }); - - it('double-clicking isolates a groupby trace', function(done) { - Promise.resolve() - .then(click(1, 2)) - .then(assertVisible([false, 'legendonly', true, 'legendonly', 'legendonly', 'legendonly', 'legendonly', 'legendonly'])) - .then(click(1, 2)) - .then(assertVisible([false, true, true, true, true, true, true, true])) - .then(done, done.fail); - }); - }); - describe('legend visibility with *showlegend:false* traces', function() { beforeEach(function(done) { Plotly.newPlot(gd, [ @@ -2453,34 +2274,6 @@ describe('legend interaction', function() { .then(done, done.fail); }); - it('should have correct keys (groupby case)', function(done) { - Plotly.newPlot(gd, [{ - x: [1, 2, 3, 4, 5], - y: [1, 2, 1, 2, 3], - transforms: [{ - type: 'groupby', - groups: ['a', 'b', 'b', 'a', 'b'] - }] - }, { - x: [1, 2, 3, 4, 5], - y: [1, 2, 1, 2, 3], - }]) - .then(function() { - return clickAndCheck([1, 1], { - curveNumber: 0, - expandedIndex: 1, - group: 'b' - }); - }) - .then(function() { - return clickAndCheck([2, 2], { - curveNumber: 1, - expandedIndex: 2 - }); - }) - .then(done, done.fail); - }); - it('should have correct keys (pie case)', function(done) { Plotly.newPlot(gd, [{ type: 'pie', diff --git a/test/jasmine/tests/plot_api_react_test.js b/test/jasmine/tests/plot_api_react_test.js index 5ef740f05e9..e858a52e8ad 100644 --- a/test/jasmine/tests/plot_api_react_test.js +++ b/test/jasmine/tests/plot_api_react_test.js @@ -782,7 +782,6 @@ describe('@noCIdep Plotly.react', function() { var typesTested = {}; var itemType; for(itemType in Registry.modules) { typesTested[itemType] = 0; } - for(itemType in Registry.transformsRegistry) { typesTested[itemType] = 0; } function _runReactMock(mockSpec, done) { var mock = mockSpec[1]; @@ -849,12 +848,6 @@ describe('@noCIdep Plotly.react', function() { } typesTested[trace.type]++; - - if(trace.transforms) { - trace.transforms.forEach(function(transform) { - typesTested[transform.type]++; - }); - } }); Plotly.newPlot(gd, mock) @@ -1156,7 +1149,7 @@ describe('Plotly.react and uirevision attributes', function() { dataKeys.forEach(function(traceKeys, i) { var trace = gd.data[i]; var fullTrace = gd._fullData.filter(function(ft) { - return ft._fullInput.index === i; + return ft.index === i; })[0]._fullInput; for(var key in traceKeys) { @@ -1534,55 +1527,6 @@ describe('Plotly.react and uirevision attributes', function() { _run(fig, hideSome, checkAllVisible, checkSomeHidden).then(done); }); - it('preserves groupby group visibility', function(done) { - // TODO: there's a known problem if the groups change... unlike - // traces we will keep visibility by group in order, not by group value - - function fig(mainRev, legendRev) { - return { - data: [{ - y: [1, 2, 3, 4, 5, 6], - transforms: [{ - type: 'groupby', - groups: ['a', 'b', 'c', 'a', 'b', 'c'] - }] - }, { - y: [7, 8] - }], - layout: { - uirevision: mainRev, - legend: {uirevision: legendRev} - } - }; - } - - function hideSome() { - return Registry.call('_guiRestyle', gd, { - 'transforms[0].styles[0].value.visible': 'legendonly', - 'transforms[0].styles[2].value.visible': 'legendonly' - }, [0]) - .then(function() { - return Registry.call('_guiRestyle', gd, 'visible', 'legendonly', [1]); - }); - } - - function checkVisible(groups, extraTrace) { - var trace0edits = {}; - groups.forEach(function(visi, i) { - var attr = 'transforms[0].styles[' + i + '].value.visible'; - trace0edits[attr] = visi ? undefined : 'legendonly'; - }); - return checkState([ - trace0edits, - {visible: extraTrace ? [undefined, true] : 'legendonly'} - ]); - } - var checkAllVisible = checkVisible([true, true, true], true); - var checkSomeHidden = checkVisible([false, true, false], false); - - _run(fig, hideSome, checkAllVisible, checkSomeHidden).then(done, done.fail); - }); - it('@gl preserves modebar interactions using modebar.uirevision', function(done) { function fig(mainRev, modebarRev) { return { @@ -1772,46 +1716,6 @@ describe('Plotly.react and uirevision attributes', function() { _run(fig, editSelection, checkNoSelection, checkSelection).then(done, done.fail); }); - it('preserves selectedpoints using selectedrevision (groupby case)', function(done) { - function fig(mainRev, selectionRev) { - return { - data: [{ - x: [1, 2, 3, 1, 2, 3, 1, 2, 3], - y: [1, 1, 1, 2, 2, 2, 3, 3, 3], - mode: 'markers', - marker: {size: 20}, - transforms: [{ - type: 'groupby', - groups: [1, 2, 3, 2, 3, 1, 3, 1, 2] - }] - }], - layout: { - uirevision: mainRev, - selectionrevision: selectionRev, - dragmode: 'select', - width: 400, - height: 400, - margin: {l: 100, t: 100, r: 100, b: 100} - } - }; - } - - function editSelection() { - // drag across the upper right quadrant, so we'll select - // curve 0 point 1 and curve 1 point 2 - return drag({node: document.querySelector('.nsewdrag'), dpos: [148, 148], pos0: [150, 102]}); - } - - var checkNoSelection = checkState([{selectedpoints: undefined}]); - // the funny point order here is from the grouping: - // points 5 & 7 come first as they're in group 1 - // point 8 is next, in group 2 - // point 4 is last, in group 3 - var checkSelection = checkState([{selectedpoints: [[5, 7, 8, 4]]}]); - - _run(fig, editSelection, checkNoSelection, checkSelection).then(done, done.fail); - }); - it('preserves polar view changes using polar.uirevision', function(done) { // polar you can control either at the subplot or the axis level function fig(mainRev, polarRev) { diff --git a/test/jasmine/tests/plot_api_test.js b/test/jasmine/tests/plot_api_test.js index 988c7763364..5af80966015 100644 --- a/test/jasmine/tests/plot_api_test.js +++ b/test/jasmine/tests/plot_api_test.js @@ -1403,31 +1403,6 @@ describe('Test plot api', function() { .then(done, done.fail); }); - it('sets heatmap xtype/ytype even when data/fullData indices mismatch', function(done) { - Plotly.newPlot(gd, [ - { - // importantly, this is NOT a heatmap trace, so _fullData[1] - // will not have the same attributes as data[1] - x: [1, -1, -2, 0], - y: [1, 2, 3, 1], - transforms: [{type: 'groupby', groups: ['a', 'b', 'a', 'b']}] - }, - {type: 'heatmap', z: [[0, 1], [2, 3]]} - ]) - .then(function() { - checkScaling(undefined, undefined, 1, 2); - return Plotly.restyle(gd, {x: [[2, 4]], y: [[3, 5]]}, [1]); - }) - .then(function() { - checkScaling('array', 'array', 1, 2); - return Plotly.restyle(gd, {x0: 1, dy: 3}, [1]); - }) - .then(function() { - checkScaling('scaled', 'scaled', 1, 2); - }) - .then(done, done.fail); - }); - it('sets colorbar.tickmode to linear when editing colorbar.tick0/dtick', function(done) { // note: this *should* apply to marker.colorbar etc too but currently that's not implemented // once we get this all in the schema it will work though. @@ -2450,65 +2425,6 @@ describe('Test plot api', function() { expect(gd.data[1].contours).toBeUndefined(); }); - it('should rename *filtersrc* to *target* in filter transforms', function() { - var data = [{ - transforms: [{ - type: 'filter', - filtersrc: 'y' - }, { - type: 'filter', - operation: '<' - }] - }, { - transforms: [{ - type: 'filter', - target: 'y' - }] - }]; - - Plotly.newPlot(gd, data); - - var trace0 = gd.data[0]; - var trace1 = gd.data[1]; - - expect(trace0.transforms.length).toEqual(2); - expect(trace0.transforms[0].filtersrc).toBeUndefined(); - expect(trace0.transforms[0].target).toEqual('y'); - - expect(trace1.transforms.length).toEqual(1); - expect(trace1.transforms[0].target).toEqual('y'); - }); - - it('should rename *calendar* to *valuecalendar* in filter transforms', function() { - var data = [{ - transforms: [{ - type: 'filter', - target: 'y', - calendar: 'hebrew' - }, { - type: 'filter', - operation: '<' - }] - }, { - transforms: [{ - type: 'filter', - valuecalendar: 'jalali' - }] - }]; - - Plotly.newPlot(gd, data); - - var trace0 = gd.data[0]; - var trace1 = gd.data[1]; - - expect(trace0.transforms.length).toEqual(2); - expect(trace0.transforms[0].calendar).toBeUndefined(); - expect(trace0.transforms[0].valuecalendar).toEqual('hebrew'); - - expect(trace1.transforms.length).toEqual(1); - expect(trace1.transforms[0].valuecalendar).toEqual('jalali'); - }); - it('should cleanup annotations / shapes refs', function() { var data = [{}]; diff --git a/test/jasmine/tests/plots_test.js b/test/jasmine/tests/plots_test.js index 92ba8c2abe5..9b96329af9c 100644 --- a/test/jasmine/tests/plots_test.js +++ b/test/jasmine/tests/plots_test.js @@ -131,17 +131,11 @@ describe('Test Plots', function() { expect(gd._fullData[0].index).toEqual(0); expect(gd._fullData[1].index).toEqual(1); - expect(gd._fullData[0]._expandedIndex).toEqual(0); - expect(gd._fullData[1]._expandedIndex).toEqual(1); - expect(gd._fullData[0]._input).toBe(trace0); expect(gd._fullData[1]._input).toBe(trace1); expect(gd._fullData[0]._fullInput).toBe(gd._fullData[0]); expect(gd._fullData[1]._fullInput).toBe(gd._fullData[1]); - - expect(gd._fullData[0]._expandedInput).toBe(gd._fullData[0]); - expect(gd._fullData[1]._expandedInput).toBe(gd._fullData[1]); }); function testSanitizeMarginsHasBeenCalledOnlyOnce(gd) { @@ -310,20 +304,6 @@ describe('Test Plots', function() { }); }); - describe('Plots.supplyTransformDefaults', function() { - it('should accept an empty layout when transforms present', function() { - var traceOut = {y: [1], _length: 1}; - Plots.supplyTransformDefaults({}, traceOut, { - _globalTransforms: [{ type: 'filter'}] - }); - - // This isn't particularly interesting. More relevant is that - // the above supplyTransformDefaults call didn't fail due to - // missing transformModules data. - expect(traceOut.transforms.length).toEqual(1); - }); - }); - describe('Plots.resize:', function() { var gd; diff --git a/test/jasmine/tests/registry_test.js b/test/jasmine/tests/registry_test.js index a0e8ab9f496..21a99c6402b 100644 --- a/test/jasmine/tests/registry_test.js +++ b/test/jasmine/tests/registry_test.js @@ -5,7 +5,6 @@ var Loggers = require('../../../src/lib/loggers'); describe('Test Register:', function() { beforeAll(function() { this.modulesKeys = Object.keys(Registry.modules); - this.allTransformsKeys = Object.keys(Registry.transformsRegistry); this.allCategoriesKeys = Object.keys(Registry.allCategories); this.allTypes = Registry.allTypes.slice(); }); @@ -26,7 +25,6 @@ describe('Test Register:', function() { } revertObj(Registry.modules, this.modulesKeys); - revertObj(Registry.transformsRegistry, this.allTransformsKeys); revertObj(Registry.allCategories, this.allCategoriesKeys); revertArray(Registry.allTypes, this.allTypes); }); @@ -86,76 +84,6 @@ describe('Test Register:', function() { expect(function() { Plotly.register([invalidTrace]); }).toThrowError(Error, 'Invalid module was attempted to be registered!'); - - expect(Registry.transformsRegistry['mah-transform']).toBeUndefined(); - }); - - it('should throw when if transform module is invalid (1)', function() { - var missingTransformName = { - moduleType: 'transform' - }; - - expect(function() { - Plotly.register(missingTransformName); - }).toThrowError(Error, 'Transform module *name* must be a string.'); - - expect(Registry.transformsRegistry['mah-transform']).toBeUndefined(); - }); - - it('should throw when if transform module is invalid (2)', function() { - var missingTransformFunc = { - moduleType: 'transform', - name: 'mah-transform' - }; - - expect(function() { - Plotly.register(missingTransformFunc); - }).toThrowError(Error, 'Transform module mah-transform is missing a *transform* or *calcTransform* method.'); - - expect(Registry.transformsRegistry['mah-transform']).toBeUndefined(); - }); - - it('should not throw when transform module is valid (1)', function() { - var transformModule = { - moduleType: 'transform', - name: 'mah-transform', - transform: function() {} - }; - - expect(function() { - Plotly.register(transformModule); - }).not.toThrow(); - - expect(Registry.transformsRegistry['mah-transform']).toBeDefined(); - }); - - it('should not throw when transform module is valid (2)', function() { - var transformModule = { - moduleType: 'transform', - name: 'mah-transform', - calcTransform: function() {} - }; - - expect(function() { - Plotly.register(transformModule); - }).not.toThrow(); - - expect(Registry.transformsRegistry['mah-transform']).toBeDefined(); - }); - - it('should not throw when transform module is valid (3)', function() { - var transformModule = { - moduleType: 'transform', - name: 'mah-transform', - transform: function() {}, - calcTransform: function() {} - }; - - expect(function() { - Plotly.register(transformModule); - }).not.toThrow(); - - expect(Registry.transformsRegistry['mah-transform']).toBeDefined(); }); it('should not reregister a trace module', function() { @@ -212,62 +140,4 @@ describe('Test Register:', function() { expect(Loggers.log).toHaveBeenCalled(); }); }); - - describe('Registry.getTransformIndices & Registry.hasTransform:', function() { - var transformModule = { - moduleType: 'transform', - name: 'mah-transform', - transform: function() {} - }; - - beforeEach(function() { - Plotly.register(transformModule); - }); - - it('getTransformIndices returns an empty array if no transforms present', function() { - expect(Registry.getTransformIndices({}, 'groupby')).toEqual([]); - }); - - it('getTransformIndices returns an empty array if none present', function() { - expect(Registry.getTransformIndices({ - transforms: [ - {type: 'filter'}, - {type: 'groupby'} - ] - }, 'degauss')).toEqual([]); - }); - - it('getTransformIndices returns a array of indices if transform is present', function() { - expect(Registry.getTransformIndices({ - transforms: [ - {type: 'filter'}, - {type: 'groupby'}, - {type: 'groupby'} - ] - }, 'groupby')).toEqual([1, 2]); - }); - - it('hasTransform returns false if no transforms present', function() { - expect(Registry.hasTransform({}, 'groupby')).toBe(false); - }); - - it('hasTransform returns false if none present', function() { - expect(Registry.hasTransform({ - transforms: [ - {type: 'filter'}, - {type: 'groupby'} - ] - }, 'degauss')).toBe(false); - }); - - it('hasTransform returns true if transform is present', function() { - expect(Registry.hasTransform({ - transforms: [ - {type: 'filter'}, - {type: 'groupby'}, - {type: 'groupby'} - ] - }, 'groupby')).toBe(true); - }); - }); }); diff --git a/test/jasmine/tests/scatter_test.js b/test/jasmine/tests/scatter_test.js index f07536631ce..8a3739d0d69 100644 --- a/test/jasmine/tests/scatter_test.js +++ b/test/jasmine/tests/scatter_test.js @@ -852,90 +852,6 @@ describe('end-to-end scatter tests', function() { }); } - it('should reorder point and text nodes even when linked to ids (shuffle case)', function(done) { - Plotly.newPlot(gd, [{ - x: [150, 350, 650], - y: [100, 300, 600], - text: ['apple', 'banana', 'clementine'], - ids: ['A', 'B', 'C'], - mode: 'markers+text', - marker: { - color: ['rgb(255, 0, 0)', 'rgb(0, 255, 0)', 'rgb(0, 0, 255)'] - }, - transforms: [{ - type: 'sort', - enabled: false, - target: [0, 1, 0] - }] - }]) - .then(function() { - _assertNodes( - ['rgb(255, 0, 0)', 'rgb(0, 255, 0)', 'rgb(0, 0, 255)'], - ['apple', 'banana', 'clementine'] - ); - - return Plotly.restyle(gd, 'transforms[0].enabled', true); - }) - .then(function() { - _assertNodes( - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)', 'rgb(0, 255, 0)'], - ['apple', 'clementine', 'banana'] - ); - - return Plotly.restyle(gd, 'transforms[0].enabled', false); - }) - .then(function() { - _assertNodes( - ['rgb(255, 0, 0)', 'rgb(0, 255, 0)', 'rgb(0, 0, 255)'], - ['apple', 'banana', 'clementine'] - ); - }) - .then(done, done.fail); - }); - - it('should reorder point and text nodes even when linked to ids (add/remove case)', function(done) { - Plotly.newPlot(gd, [{ - x: [150, 350, null, 600], - y: [100, 300, null, 700], - text: ['apple', 'banana', null, 'clementine'], - ids: ['A', 'B', null, 'C'], - mode: 'markers+text', - marker: { - color: ['rgb(255, 0, 0)', 'rgb(0, 255, 0)', null, 'rgb(0, 0, 255)'] - }, - transforms: [{ - type: 'filter', - enabled: false, - target: [1, 0, 0, 1], - operation: '=', - value: 1 - }] - }]) - .then(function() { - _assertNodes( - ['rgb(255, 0, 0)', 'rgb(0, 255, 0)', 'rgb(0, 0, 255)'], - ['apple', 'banana', 'clementine'] - ); - - return Plotly.restyle(gd, 'transforms[0].enabled', true); - }) - .then(function() { - _assertNodes( - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - ['apple', 'clementine'] - ); - - return Plotly.restyle(gd, 'transforms[0].enabled', false); - }) - .then(function() { - _assertNodes( - ['rgb(255, 0, 0)', 'rgb(0, 255, 0)', 'rgb(0, 0, 255)'], - ['apple', 'banana', 'clementine'] - ); - }) - .then(done, done.fail); - }); - it('should smoothly add/remove nodes tags with *ids* during animations', function(done) { Plotly.newPlot(gd, { data: [{ diff --git a/test/jasmine/tests/scattergl_select_test.js b/test/jasmine/tests/scattergl_select_test.js index 06f073ee227..a929cd87625 100644 --- a/test/jasmine/tests/scattergl_select_test.js +++ b/test/jasmine/tests/scattergl_select_test.js @@ -185,28 +185,6 @@ describe('Test gl2d lasso/select:', function() { .then(done, done.fail); }); - it('@gl should work on trace with enabled transforms', function(done) { - var fig = Lib.extendDeep({}, require('../../image/mocks/gl2d_transforms.json')); - fig.layout.dragmode = 'select'; - fig.layout.margin = {t: 0, b: 0, l: 0, r: 0}; - fig.layout.height = 500; - fig.layout.width = 500; - gd = createGraphDiv(); - - _newPlot(gd, fig) - .then(delay(20)) - .then(function() { return select(gd, [[100, 100], [250, 250]]); }) - .then(function(eventData) { - assertEventData(eventData, { - points: [ - { x: 3, y: 4 }, - { x: 2, y: 4 } - ] - }); - }) - .then(done, done.fail); - }); - it('@gl should work on gl text charts', function(done) { var fig = Lib.extendDeep({}, require('../../image/mocks/gl2d_text_chart_basic.json')); fig.layout.dragmode = 'select'; diff --git a/test/jasmine/tests/scattergl_test.js b/test/jasmine/tests/scattergl_test.js index 505d9e02646..c17fad2f96f 100644 --- a/test/jasmine/tests/scattergl_test.js +++ b/test/jasmine/tests/scattergl_test.js @@ -430,70 +430,6 @@ describe('end-to-end scattergl tests', function() { .then(done, done.fail); }); - it('@gl should handle transform traces properly (calcTransform case)', function(done) { - spyOn(ScatterGl, 'calc').and.callThrough(); - - Plotly.newPlot(gd, [{ - type: 'scattergl', - x: [1, 2, 3], - y: [1, 2, 1], - transforms: [{ - type: 'filter', - target: 'x', - operation: '>', - value: 1 - }] - }]) - .then(function() { - expect(ScatterGl.calc).toHaveBeenCalledTimes(2); - - var opts = gd.calcdata[0][0].t._scene.markerOptions; - // length === 2 before #2677 - expect(opts.length).toBe(1); - - return Plotly.restyle(gd, 'selectedpoints', [[1]]); - }) - .then(function() { - // was === 1 before #2677 - var scene = gd.calcdata[0][0].t._scene; - expect(scene.selectBatch[0]).toEqual([0]); - }) - .then(done, done.fail); - }); - - it('@gl should handle transform traces properly (default transform case)', function(done) { - spyOn(ScatterGl, 'calc').and.callThrough(); - - Plotly.newPlot(gd, [{ - type: 'scattergl', - x: [1, 2, 3], - y: [1, 2, 1], - transforms: [{ - type: 'groupby', - groups: ['a', 'b', 'a'] - }] - }]) - .then(function() { - // twice per 'expanded' trace - expect(ScatterGl.calc).toHaveBeenCalledTimes(4); - - // 'scene' from opts0 and opts1 is linked to the same object, - // which has two items, one for each 'expanded' trace - var opts0 = gd.calcdata[0][0].t._scene.markerOptions; - expect(opts0.length).toBe(2); - - var opts1 = gd.calcdata[1][0].t._scene.markerOptions; - expect(opts1.length).toBe(2); - - return Plotly.restyle(gd, 'selectedpoints', [[1]]); - }) - .then(function() { - var scene = gd.calcdata[0][0].t._scene; - expect(scene.selectBatch).toEqual([[], [0]]); - }) - .then(done, done.fail); - }); - it('@gl should not cause infinite loops when coordinate arrays start/end with NaN', function(done) { function _assertPositions(msg, cont, exp) { var pos = gd._fullLayout._plots.xy._scene[cont] diff --git a/test/jasmine/tests/select_test.js b/test/jasmine/tests/select_test.js index 12a4aecf67e..3d345c63a3a 100644 --- a/test/jasmine/tests/select_test.js +++ b/test/jasmine/tests/select_test.js @@ -3355,52 +3355,6 @@ describe('Test select box and lasso per trace:', function() { }); }); - [false, true].forEach(function(hasCssTransform) { - it('should work on traces with enabled transforms, hasCssTransform: ' + hasCssTransform, function(done) { - var assertSelectedPoints = makeAssertSelectedPoints(); - - _newPlot(gd, [{ - x: [1, 2, 3, 4, 5], - y: [2, 3, 1, 7, 9], - marker: {size: [10, 20, 20, 20, 10]}, - transforms: [{ - type: 'filter', - operation: '>', - value: 2, - target: 'y' - }, { - type: 'aggregate', - groups: 'marker.size', - aggregations: [ - // 20: 6, 10: 5 - {target: 'x', func: 'sum'}, - // 20: 5, 10: 9 - {target: 'y', func: 'avg'} - ] - }] - }], { - dragmode: 'select', - showlegend: false, - width: 400, - height: 400, - margin: {l: 0, t: 0, r: 0, b: 0} - }) - .then(function() { - if(hasCssTransform) transformPlot(gd, cssTransform); - - return _run(hasCssTransform, - [[5, 5], [395, 395]], - function() { - assertSelectedPoints({0: [1, 3, 4]}); - }, - [380, 180], - BOXEVENTS, 'transformed trace select (all points selected)' - ); - }) - .then(done, done.fail); - }); - }); - [false, true].forEach(function(hasCssTransform) { it('should work on scatter/bar traces with text nodes, hasCssTransform: ' + hasCssTransform, function(done) { var assertSelectedPoints = makeAssertSelectedPoints(); diff --git a/test/jasmine/tests/splom_test.js b/test/jasmine/tests/splom_test.js index b85c14882bd..44cede6e3fe 100644 --- a/test/jasmine/tests/splom_test.js +++ b/test/jasmine/tests/splom_test.js @@ -75,32 +75,6 @@ describe('Test splom trace defaults:', function() { expect(gd._fullData[0].diagonal.visible).toBe(false); }); - it('still coerces partial visibilities even if all are false with transforms', function() { - _supply({ - dimensions: [{ - values: [1, 2, 3] - }], - showupperhalf: false, - showlowerhalf: false, - diagonal: {visible: false}, - transforms: [{ - type: 'filter', - target: 'dimensions[0].values', - operation: '>', - value: 2 - }] - }); - - expect(gd._fullData[0].visible).toBe(false); - - expect(gd._fullData[0].transforms[0].enabled).toBe(true); - - // make sure these are still coerced - so you can get back via GUI! - expect(gd._fullData[0].showupperhalf).toBe(false); - expect(gd._fullData[0].showlowerhalf).toBe(false); - expect(gd._fullData[0].diagonal.visible).toBe(false); - }); - it('should set `visible: false` to values-less dimensions', function() { _supply({ dimensions: [ diff --git a/test/jasmine/tests/transform_aggregate_test.js b/test/jasmine/tests/transform_aggregate_test.js deleted file mode 100644 index 58e2f018d36..00000000000 --- a/test/jasmine/tests/transform_aggregate_test.js +++ /dev/null @@ -1,408 +0,0 @@ -var Plotly = require('../../../lib/index'); - -var createGraphDiv = require('../assets/create_graph_div'); -var destroyGraphDiv = require('../assets/destroy_graph_div'); - - -describe('aggregate', function() { - var gd; - - beforeEach(function() { gd = createGraphDiv(); }); - - afterEach(destroyGraphDiv); - - it('handles all funcs for numeric data', function(done) { - // throw in some non-numbers, they should get discarded except first/last - Plotly.newPlot(gd, [{ - x: [1, 2, 3, 4, 'fail'], - y: [1.1, 2.2, 3.3, 'nope', 5.5], - customdata: [4, 'nope', 3, 2, 1], - marker: { - size: ['2001-01-01', 0.2, 0.1, 0.4, 0.5], - color: [2, 4, '', 10, 8], - opacity: [0.6, 'boo', 0.2, 0.8, 1.0], - line: { - color: [2.2, 3.3, 4.4, 5.5, 'the end'] - } - }, - transforms: [{ - type: 'aggregate', - groups: ['a', 'b', 'a', 'a', 'a'], - aggregations: [ - // missing array - the entry is ignored - {target: '', func: 'avg'}, - // disabled explicitly - {target: 'x', func: 'avg', enabled: false}, - {target: 'x', func: 'sum'}, - // non-numerics will not count toward numerator or denominator for avg - {target: 'y', func: 'avg'}, - {target: 'customdata', func: 'change'}, - {target: 'marker.size', func: 'min'}, - {target: 'marker.color', func: 'max'}, - // marker.opacity doesn't have an entry, but it will default to first - // as if it were {target: 'marker.opacity', func: 'first'}, - {target: 'marker.line.color', func: 'last'}, - // not present in data, but that's OK for count - {target: 'marker.line.width', func: 'count'}, - // duplicate entry - discarded - {target: 'x', func: 'min'} - ] - }] - }], { - // log axis doesn't change how sum (or avg but not tested) works - xaxis: {type: 'log'} - }) - .then(function() { - var traceOut = gd._fullData[0]; - - expect(traceOut.x).toEqual([8, 2]); - expect(traceOut.y).toBeCloseToArray([3.3, 2.2], 5); - expect(traceOut.customdata).toEqual([-3, undefined]); - expect(traceOut.marker.size).toEqual([0.1, 0.2]); - expect(traceOut.marker.color).toEqual([10, 4]); - expect(traceOut.marker.opacity).toEqual([0.6, 'boo']); - expect(traceOut.marker.line.color).toEqual(['the end', 3.3]); - expect(traceOut.marker.line.width).toEqual([4, 1]); - - var transform = traceOut.transforms[0]; - var inverseMapping = transform._indexToPoints; - expect(inverseMapping).toEqual({0: [0, 2, 3, 4], 1: [1]}); - }) - .then(done, done.fail); - }); - - it('handles all funcs except sum for date data', function(done) { - // weird cases handled in another test - Plotly.newPlot(gd, [{ - x: ['2001-01-01', '', '2001-01-03', '2001-01-05', '2001-01-07'], - y: ['1995-01-15', '2005-03-15', '1990-12-23', '2001-01-01', 'not a date'], - text: ['2001-01-01 12:34', '2001-01-01 12:35', '2001-01-01 12:36', '2001-01-01 12:37', ''], - hovertext: ['a', '2001-01-02', '2001-01-03', '2001-01-04', '2001-01-05'], - customdata: ['2001-01', 'b', '2001-03', '2001-04', '2001-05'], - transforms: [{ - type: 'aggregate', - // groups can be any type, but until we implement binning they - // will always compare as strings = so 1 === '1' === 1.0 !== '1.0' - groups: [1, 2, '1', 1.0, 1], - aggregations: [ - {target: 'x', func: 'avg'}, - {target: 'y', func: 'min'}, - {target: 'text', func: 'max'}, - // hovertext doesn't have a func, default to first - {target: 'hovertext'}, - {target: 'customdata', func: 'last'}, - // not present in data, but that's OK for count - {target: 'marker.line.width', func: 'count'}, - // duplicate entry - discarded - {target: 'x', func: 'min'} - ] - }] - }]) - .then(function() { - var traceOut = gd._fullData[0]; - - expect(traceOut.x).toEqual(['2001-01-04', undefined]); - expect(traceOut.y).toEqual(['1990-12-23', '2005-03-15']); - expect(traceOut.text).toEqual(['2001-01-01 12:37', '2001-01-01 12:35']); - expect(traceOut.hovertext).toEqual(['a', '2001-01-02']); - expect(traceOut.customdata).toEqual(['2001-05', 'b']); - expect(traceOut.marker.line.width).toEqual([4, 1]); - }) - .then(done, done.fail); - }); - - it('handles all funcs except sum and avg for category data', function(done) { - // weird cases handled in another test - Plotly.newPlot(gd, [{ - x: ['a', 'b', 'c', 'aa', 'd'], - y: ['q', 'w', 'e', 'r', 't'], - text: ['b', 'b', 'a', 'b', 'a'], - hovertext: ['c', 'b', 'a', 'b', 'a'], - transforms: [{ - type: 'aggregate', - groups: [1, 2, 1, 1, 1], - aggregations: [ - {target: 'x', func: 'min'}, - {target: 'y', func: 'max'}, - {target: 'text', func: 'last'}, - // hovertext doesn't have an entry, but it will default to first - // not present in data, but that's OK for count - {target: 'marker.line.width', func: 'count'}, - // duplicate entry - discarded - {target: 'x', func: 'max'} - ] - }] - }], { - xaxis: {categoryarray: ['aaa', 'aa', 'a', 'b', 'c']} - }) - .then(function() { - var traceOut = gd._fullData[0]; - - // explicit order (only possible for axis data) - expect(traceOut.x).toEqual(['aa', 'b']); - // implied order from data - expect(traceOut.y).toEqual(['t', 'w']); - expect(traceOut.text).toEqual(['a', 'b']); - expect(traceOut.hovertext).toEqual(['c', 'b']); - expect(traceOut.marker.line.width).toEqual([4, 1]); - }) - .then(done, done.fail); - }); - - it('allows date and category sums, and category avg, with weird output', function(done) { - // this test is more of an FYI than anything else - it doesn't break but - // these results are usually meaningless. - - Plotly.newPlot(gd, [{ - x: ['2001-01-01', '2001-01-02', '2001-01-03', '2001-01-04'], - y: ['a', 'b', 'b', 'c'], - text: ['a', 'b', 'a', 'c'], - transforms: [{ - type: 'aggregate', - groups: [1, 1, 2, 2], - aggregations: [ - {target: 'x', func: 'sum'}, - {target: 'y', func: 'sum'}, - {target: 'text', func: 'avg'} - ] - }] - }]) - .then(function() { - var traceOut = gd._fullData[0]; - - // date sums: 1970-01-01 is "zero", there are shifts due to # of leap years - // without that shift these would be 2032-01-02 and 2032-01-06 - expect(traceOut.x).toEqual(['2032-01-03', '2032-01-07']); - // category sums: can go off the end of the category array -> gives undefined - expect(traceOut.y).toEqual(['b', undefined]); - // category average: can result in fractional categories -> rounds (0.5 rounds to 1) - expect(traceOut.text).toEqual(['b', 'b']); - - var transform = traceOut.transforms[0]; - var inverseMapping = transform._indexToPoints; - expect(inverseMapping).toEqual({0: [0, 1], 1: [2, 3]}); - }) - .then(done, done.fail); - }); - - it('can aggregate on an existing data array', function(done) { - Plotly.newPlot(gd, [{ - x: [1, 2, 3, 4, 5], - y: [2, 4, 6, 8, 10], - marker: {size: [10, 10, 20, 20, 10]}, - transforms: [{ - type: 'aggregate', - groups: 'marker.size', - aggregations: [ - {target: 'x', func: 'sum'}, - {target: 'y', func: 'avg'} - ] - }] - }]) - .then(function() { - var traceOut = gd._fullData[0]; - - expect(traceOut.x).toEqual([8, 7]); - expect(traceOut.y).toBeCloseToArray([16 / 3, 7], 5); - expect(traceOut.marker.size).toEqual([10, 20]); - - var transform = traceOut.transforms[0]; - var inverseMapping = transform._indexToPoints; - expect(inverseMapping).toEqual({0: [0, 1, 4], 1: [2, 3]}); - }) - .then(done, done.fail); - }); - - it('can handle case where aggregation array is missing', function(done) { - Plotly.newPlot(gd, [{ - x: [1, 2, 3, 4, 5], - y: [2, 4, 6, 8, 10], - marker: {size: [10, 10, 20, 20, 10]}, - transforms: [{ - type: 'aggregate', - groups: 'marker.size' - }] - }]) - .then(function() { - var traceOut = gd._fullData[0]; - - expect(traceOut.x).toEqual([1, 3]); - expect(traceOut.y).toEqual([2, 6]); - expect(traceOut.marker.size).toEqual([10, 20]); - - var transform = traceOut.transforms[0]; - var inverseMapping = transform._indexToPoints; - expect(inverseMapping).toEqual({0: [0, 1, 4], 1: [2, 3]}); - }) - .then(done, done.fail); - }); - - it('handles median, mode, rms, stddev, change & range for numeric data', function(done) { - // again, nothing is going to barf with non-numeric data, but sometimes it - // won't make much sense. - - Plotly.newPlot(gd, [{ - x: [1, 1, 2, 2, 1], - y: [1, 2, 3, 4, 5], - customdata: [5, 4, 3, 2, 1], - marker: { - size: [1, 2, 3, 4, 5], - opacity: [0.6, 0.5, 0.2, 0.8, 1.0], - line: {width: [1, 1, 2, 2, 1]}, - color: [1, 1, 2, 2, 1] - }, - transforms: [{ - type: 'aggregate', - groups: [1, 2, 1, 1, 1], - aggregations: [ - {target: 'x', func: 'mode'}, - {target: 'y', func: 'median'}, - {target: 'customdata', func: 'change'}, - {target: 'marker.size', func: 'rms'}, - {target: 'marker.opacity', func: 'range'}, - {target: 'marker.line.width', func: 'stddev', funcmode: 'population'}, - {target: 'marker.color', func: 'stddev'} - ] - }] - }]) - .then(function() { - var traceOut = gd._fullData[0]; - - // 1 and 2 both have count of 2 in the first group, - // but 2 gets to that count first - expect(traceOut.x).toEqual([2, 1]); - expect(traceOut.y).toBeCloseToArray([3.5, 2], 5); - expect(traceOut.customdata).toEqual([-4, 0]); - expect(traceOut.marker.size).toBeCloseToArray([Math.sqrt(51 / 4), 2], 5); - expect(traceOut.marker.opacity).toEqual([0.8, 0]); - expect(traceOut.marker.line.width).toBeCloseToArray([0.5, 0], 5); - expect(traceOut.marker.color).toBeCloseToArray([Math.sqrt(1 / 3), 0], 5); - }) - .then(done, done.fail); - }); - - it('handles ragged data - extra groups are ignored', function(done) { - Plotly.newPlot(gd, [{ - x: [1, 1, 2, 2, 1, 3, 4], - y: [1, 2, 3, 4, 5], // shortest array controls all - transforms: [{ - type: 'aggregate', - groups: [1, 2, 1, 1, 1, 3, 3, 4, 4, 5], - aggregations: [ - {target: 'x', func: 'mode'}, - {target: 'y', func: 'median'}, - ] - }] - }]) - .then(function() { - var traceOut = gd._fullData[0]; - - expect(traceOut.x).toEqual([2, 1]); - expect(traceOut.y).toBeCloseToArray([3.5, 2], 5); - }) - .then(done, done.fail); - }); - - it('handles ragged data - groups is the shortest, others are ignored', function(done) { - Plotly.newPlot(gd, [{ - x: [1, 1, 2, 2, 1, 3, 4], - y: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], - transforms: [{ - type: 'aggregate', - groups: [1, 2, 1, 1, 1], // shortest array controls all - aggregations: [ - {target: 'x', func: 'mode'}, - {target: 'y', func: 'median'}, - ] - }] - }]) - .then(function() { - var traceOut = gd._fullData[0]; - - expect(traceOut.x).toEqual([2, 1]); - expect(traceOut.y).toBeCloseToArray([3.5, 2], 5); - }) - .then(done, done.fail); - }); - - it('links fullData aggregations to userData via _index', function(done) { - Plotly.newPlot(gd, [{ - x: [1, 2, 3, 4, 5], - y: [2, 4, 6, 8, 10], - marker: { - size: [10, 10, 20, 20, 10], - color: ['red', 'green', 'blue', 'yellow', 'white'] - }, - transforms: [{ - type: 'aggregate', - groups: 'marker.size', - aggregations: [ - {target: 'x', func: 'sum'}, - {target: 'x', func: 'avg'}, - {target: 'y', func: 'avg'} - ] - }] - }]) - .then(function() { - var traceOut = gd._fullData[0]; - var fullAggregation = traceOut.transforms[0]; - var fullAggregations = fullAggregation.aggregations; - var enabledAggregations = fullAggregations.filter(function(agg) { - return agg.enabled; - }); - - expect(enabledAggregations[0].target).toEqual('x'); - expect(enabledAggregations[0]._index).toEqual(0); - - expect(enabledAggregations[1].target).toEqual('y'); - expect(enabledAggregations[1]._index).toEqual(2); - - expect(enabledAggregations[2].target).toEqual('marker.color'); - expect(enabledAggregations[2]._index).toEqual(-1); - }) - .then(done, done.fail); - }); - - it('does not error out on bad *group* value', function(done) { - Plotly.newPlot(gd, [{ - y: [16.99, 10.34, 11.01, 23.68, 24.59], - transforms: [{ - type: 'aggregate', - groups: null - }] - }]) - .then(function() { - var tOut = gd._fullData[0].transforms[0]; - expect(tOut.type).toBe('aggregate', 'transform type'); - expect(tOut.groups).toBe('x', 'the *groups* default'); - expect(tOut.enabled).toBe(false, 'should not be *enabled*'); - }) - .then(done, done.fail); - }); - - it('use numeric sort function for median', function(done) { - var subject = ['M', 'M', 'M']; - var score = [2, 10, 11]; - - var data = [{ - type: 'scatter', - x: subject, - y: score, - mode: 'markers', - transforms: [{ - type: 'aggregate', - groups: subject, - aggregations: [ - { target: 'y', func: 'median' }, - ] - }] - }]; - - Plotly.newPlot(gd, data) - .then(function() { - var traceOut = gd._fullData[0]; - expect(traceOut.y[0]).toBe(10); - }) - .then(done, done.fail); - }); -}); diff --git a/test/jasmine/tests/transform_filter_test.js b/test/jasmine/tests/transform_filter_test.js deleted file mode 100644 index b2aa6af410f..00000000000 --- a/test/jasmine/tests/transform_filter_test.js +++ /dev/null @@ -1,1427 +0,0 @@ -var Plotly = require('../../../lib/index'); -var Filter = require('../../../src/transforms/filter'); - -var Plots = require('../../../src/plots/plots'); -var Lib = require('../../../src/lib'); - -var createGraphDiv = require('../assets/create_graph_div'); -var destroyGraphDiv = require('../assets/destroy_graph_div'); -var customAssertions = require('../assets/custom_assertions'); -var supplyAllDefaults = require('../assets/supply_defaults'); - - -var assertDims = customAssertions.assertDims; -var assertStyle = customAssertions.assertStyle; - -describe('filter transforms defaults:', function() { - var fullLayout = { - _transformModules: [], - _subplots: {cartesian: ['xy'], xaxis: ['x'], yaxis: ['y']} - }; - - var traceIn, traceOut; - - it('supplyTraceDefaults should coerce all attributes', function() { - traceIn = { - x: [1, 2, 3], - transforms: [{ - type: 'filter', - value: 0 - }] - }; - - traceOut = Plots.supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, fullLayout); - - expect(traceOut.transforms).toEqual([{ - type: 'filter', - enabled: true, - preservegaps: false, - operation: '=', - value: 0, - target: 'x', - _module: Filter - }]); - }); - - it('supplyTraceDefaults should not coerce attributes if enabled: false', function() { - traceIn = { - x: [1, 2, 3], - transforms: [{ - enabled: false, - type: 'filter', - value: 0 - }] - }; - - traceOut = Plots.supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, fullLayout); - - expect(traceOut.transforms).toEqual([{ - type: 'filter', - enabled: false, - _module: Filter - }]); - }); - - it('supplyTraceDefaults should coerce *target* as a strict / noBlank string', function() { - traceIn = { - x: [1, 2, 3], - transforms: [{ - type: 'filter' - }, { - type: 'filter', - target: 0 - }, { - type: 'filter', - target: '' - }, { - type: 'filter', - target: 'marker.color' - }] - }; - - traceOut = Plots.supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, fullLayout); - - expect(traceOut.transforms[0].target).toEqual('x'); - expect(traceOut.transforms[1].target).toEqual('x'); - expect(traceOut.transforms[2].target).toEqual('x'); - expect(traceOut.transforms[3].target).toEqual('marker.color'); - }); - - it('supplyTraceDefaults should set *enabled:false* and return early when *target* is an empty array', function() { - // see https://github.com/plotly/plotly.js/issues/2908 - // this solves multiple problems downstream - - traceIn = { - x: [1, 2, 3], - transforms: [{ - type: 'filter', - target: [] - }] - }; - traceOut = Plots.supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, fullLayout); - expect(traceOut.transforms[0].target).toEqual([]); - expect(traceOut.transforms[0].enabled).toBe(false, 'set to false!'); - - traceIn = { - x: new Float32Array([1, 2, 3]), - transforms: [{ - type: 'filter', - target: new Float32Array() - }] - }; - traceOut = Plots.supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, fullLayout); - expect(traceOut.transforms[0].target).toEqual(new Float32Array()); - expect(traceOut.transforms[0].enabled).toBe(false, 'set to false!'); - }); -}); - -describe('filter transforms calc:', function() { - 'use strict'; - - function calcDatatoTrace(calcTrace) { - return calcTrace[0].trace; - } - - function _transform(data, layout) { - var gd = { - data: data, - layout: layout || {} - }; - - supplyAllDefaults(gd); - Plots.doCalcdata(gd); - - return gd.calcdata.map(calcDatatoTrace); - } - - var base = { - x: [-2, -1, -2, 0, 1, 2, 3], - y: [1, 2, 3, 1, 2, 3, 1], - ids: ['n0', 'n1', 'n2', 'z', 'p1', 'p2', 'p3'], - marker: { - color: [0.1, 0.2, 0.3, 0.1, 0.2, 0.3, 0.4], - size: 20 - }, - transforms: [{ type: 'filter' }] - }; - - it('filters should skip if *target* isn\'t present in trace', function() { - var out = _transform([Lib.extendDeep({}, base, { - transforms: [{ - type: 'filter', - operation: '>', - value: 0, - target: 'z' - }] - })]); - - expect(out[0].x).toEqual(base.x); - expect(out[0].y).toEqual(base.y); - }); - - it('filters should handle 3D *z* data', function() { - var out = _transform([Lib.extendDeep({}, base, { - type: 'scatter3d', - z: ['2015-07-20', '2016-08-01', '2016-09-01', '2016-10-21', '2016-12-02'], - transforms: [{ - type: 'filter', - operation: '>', - value: '2016-10-01', - target: 'z' - }] - })]); - - expect(out[0].x).toEqual([0, 1]); - expect(out[0].y).toEqual([1, 2]); - expect(out[0].z).toEqual(['2016-10-21', '2016-12-02']); - expect(out[0].transforms[0]._indexToPoints).toEqual({0: [3], 1: [4]}); - }); - - it('should use the calendar from the target attribute if target is a string', function() { - // this is the same data as in "filters should handle 3D *z* data" - // but with different calendars - var out = _transform([Lib.extendDeep({}, base, { - type: 'scatter3d', - // the same array as above but in nanakshahi dates - z: ['0547-05-05', '0548-05-17', '0548-06-17', '0548-08-07', '0548-09-19'], - zcalendar: 'nanakshahi', - transforms: [{ - type: 'filter', - operation: '>', - value: '5776-06-28', - valuecalendar: 'hebrew', - target: 'z', - // targetcalendar is ignored! - targetcalendar: 'taiwan' - }] - })]); - - expect(out[0].x).toEqual([0, 1]); - expect(out[0].y).toEqual([1, 2]); - expect(out[0].z).toEqual(['0548-08-07', '0548-09-19']); - }); - - it('should use targetcalendar anyway if there is no matching calendar attribute', function() { - // this is the same data as in "filters should handle 3D *z* data" - // but with different calendars - var out = _transform([Lib.extendDeep({}, base, { - type: 'scatter', - // the same array as above but in taiwanese dates - text: ['0104-07-20', '0105-08-01', '0105-09-01', '0105-10-21', '0105-12-02'], - transforms: [{ - type: 'filter', - operation: '>', - value: '5776-06-28', - valuecalendar: 'hebrew', - target: 'text', - targetcalendar: 'taiwan' - }] - })]); - - expect(out[0].x).toEqual([0, 1]); - expect(out[0].y).toEqual([1, 2]); - expect(out[0].text).toEqual(['0105-10-21', '0105-12-02']); - }); - - it('should use targetcalendar if target is an array', function() { - // this is the same data as in "filters should handle 3D *z* data" - // but with different calendars - var out = _transform([Lib.extendDeep({}, base, { - type: 'scatter3d', - // the same array as above but in nanakshahi dates - z: ['0547-05-05', '0548-05-17', '0548-06-17', '0548-08-07', '0548-09-19'], - zcalendar: 'nanakshahi', - transforms: [{ - type: 'filter', - operation: '>', - value: '5776-06-28', - valuecalendar: 'hebrew', - target: ['0104-07-20', '0105-08-01', '0105-09-01', '0105-10-21', '0105-12-02'], - targetcalendar: 'taiwan' - }] - })]); - - expect(out[0].x).toEqual([0, 1]); - expect(out[0].y).toEqual([1, 2]); - expect(out[0].z).toEqual(['0548-08-07', '0548-09-19']); - }); - - it('filters should handle geographical *lon* data', function() { - var trace0 = { - type: 'scattergeo', - lon: [-90, -40, 100, 120, 130], - lat: [-50, -40, 10, 20, 30], - transforms: [{ - type: 'filter', - operation: '>', - value: 0, - target: 'lon' - }] - }; - - var trace1 = { - type: 'scattermapbox', - lon: [-90, -40, 100, 120, 130], - lat: [-50, -40, 10, 20, 30], - transforms: [{ - type: 'filter', - operation: '<', - value: 0, - target: 'lat' - }] - }; - - var out = _transform([trace0, trace1]); - - expect(out[0].lon).toEqual([100, 120, 130]); - expect(out[0].lat).toEqual([10, 20, 30]); - - expect(out[1].lon).toEqual([-90, -40]); - expect(out[1].lat).toEqual([-50, -40]); - }); - - it('filters should handle geographical *lon* data', function() { - var trace0 = { - type: 'scattergeo', - lon: [-90, -40, 100, 120, 130], - lat: [-50, -40, 10, 20, 30], - transforms: [{ - type: 'filter', - operation: '>', - value: 0, - target: 'lon' - }] - }; - - var trace1 = { - type: 'scattermap', - lon: [-90, -40, 100, 120, 130], - lat: [-50, -40, 10, 20, 30], - transforms: [{ - type: 'filter', - operation: '<', - value: 0, - target: 'lat' - }] - }; - - var out = _transform([trace0, trace1]); - - expect(out[0].lon).toEqual([100, 120, 130]); - expect(out[0].lat).toEqual([10, 20, 30]); - - expect(out[1].lon).toEqual([-90, -40]); - expect(out[1].lat).toEqual([-50, -40]); - }); - - it('filters should handle nested attributes', function() { - var out = _transform([Lib.extendDeep({}, base, { - transforms: [{ - type: 'filter', - operation: '>', - value: 0.2, - target: 'marker.color' - }] - })]); - - expect(out[0].x).toEqual([-2, 2, 3]); - expect(out[0].y).toEqual([3, 3, 1]); - expect(out[0].marker.color).toEqual([0.3, 0.3, 0.4]); - expect(out[0].transforms[0]._indexToPoints).toEqual({0: [2], 1: [5], 2: [6]}); - }); - - it('filters should handle array on base trace attributes', function() { - var out = _transform([Lib.extendDeep({}, base, { - hoverinfo: ['x', 'y', 'text', 'name', 'none', 'skip', 'all'], - hoverlabel: { - bgcolor: ['red', 'green', 'blue', 'black', 'yellow', 'cyan', 'pink'] - }, - transforms: [{ - type: 'filter', - operation: '>', - value: 0 - }] - })]); - - expect(out[0].x).toEqual([1, 2, 3]); - expect(out[0].y).toEqual([2, 3, 1]); - expect(out[0].hoverinfo).toEqual(['none', 'skip', 'all']); - expect(out[0].hoverlabel.bgcolor).toEqual(['yellow', 'cyan', 'pink']); - }); - - it('filters should skip if *enabled* is false', function() { - var out = _transform([Lib.extendDeep({}, base, { - transforms: [{ - type: 'filter', - enabled: false, - operation: '>', - value: 0, - target: 'x' - }] - })]); - - expect(out[0].x).toEqual(base.x); - expect(out[0].y).toEqual(base.y); - }); - - it('filters should chain as AND (case 1)', function() { - var out = _transform([Lib.extendDeep({}, base, { - transforms: [{ - type: 'filter', - operation: '>', - value: 0, - target: 'x' - }, { - type: 'filter', - operation: '<', - value: 3, - target: 'x' - }] - })]); - - expect(out[0].x).toEqual([1, 2]); - expect(out[0].y).toEqual([2, 3]); - expect(out[0].transforms[0]._indexToPoints).toEqual({0: [4], 1: [5], 2: [6]}); - expect(out[0].transforms[1]._indexToPoints).toEqual({0: [4], 1: [5]}); - }); - - it('filters should chain as AND (case 2)', function() { - var out = _transform([Lib.extendDeep({}, base, { - transforms: [{ - type: 'filter', - operation: '>', - value: 0, - target: 'x' - }, { - type: 'filter', - enabled: false, - operation: '>', - value: 2, - target: 'y' - }, { - type: 'filter', - operation: '<', - value: 2, - target: 'y' - }] - })]); - - expect(out[0].x).toEqual([3]); - expect(out[0].y).toEqual([1]); - expect(out[0].transforms[0]._indexToPoints).toEqual({0: [4], 1: [5], 2: [6]}); - expect(out[0].transforms[2]._indexToPoints).toEqual({0: [6]}); - }); - - it('should preserve gaps in data when `preservegaps` is turned on', function() { - var out = _transform([Lib.extendDeep({}, base, { - transforms: [{ - type: 'filter', - preservegaps: true, - operation: '>', - value: 0, - target: 'x' - }] - })]); - - expect(out[0].x).toEqual([undefined, undefined, undefined, undefined, 1, 2, 3]); - expect(out[0].y).toEqual([undefined, undefined, undefined, undefined, 2, 3, 1]); - expect(out[0].marker.color).toEqual([undefined, undefined, undefined, undefined, 0.2, 0.3, 0.4]); - expect(out[0].transforms[0]._indexToPoints).toEqual({4: [4], 5: [5], 6: [6]}); - }); - - it('two filter transforms with `preservegaps: true` should commute', function() { - var transform0 = { - type: 'filter', - preservegaps: true, - operation: '>', - value: -1, - target: 'x' - }; - - var transform1 = { - type: 'filter', - preservegaps: true, - operation: '<', - value: 2, - target: 'x' - }; - - var out0 = _transform([Lib.extendDeep({}, base, { - transforms: [transform0, transform1] - })]); - - var out1 = _transform([Lib.extendDeep({}, base, { - transforms: [transform1, transform0] - })]); - // _indexToPoints differs in the first transform but matches in the second - expect(out0[0].transforms[0]._indexToPoints).toEqual({3: [3], 4: [4], 5: [5], 6: [6]}); - expect(out1[0].transforms[0]._indexToPoints).toEqual({0: [0], 1: [1], 2: [2], 3: [3], 4: [4]}); - expect(out0[0].transforms[1]._indexToPoints).toEqual({3: [3], 4: [4]}); - expect(out1[0].transforms[1]._indexToPoints).toEqual({3: [3], 4: [4]}); - - ['x', 'y', 'ids', 'marker.color', 'marker.size'].forEach(function(k) { - var v0 = Lib.nestedProperty(out0[0], k).get(); - var v1 = Lib.nestedProperty(out1[0], k).get(); - expect(v0).toEqual(v1); - }); - }); - - it('two filter transforms with `preservegaps: false` should commute', function() { - var transform0 = { - type: 'filter', - preservegaps: false, - operation: '>', - value: -1, - target: 'x' - }; - - var transform1 = { - type: 'filter', - preservegaps: false, - operation: '<', - value: 2, - target: 'x' - }; - - var out0 = _transform([Lib.extendDeep({}, base, { - transforms: [transform0, transform1] - })]); - - var out1 = _transform([Lib.extendDeep({}, base, { - transforms: [transform1, transform0] - })]); - - // _indexToPoints differs in the first transform but matches in the second - expect(out0[0].transforms[0]._indexToPoints).toEqual({0: [3], 1: [4], 2: [5], 3: [6]}); - expect(out1[0].transforms[0]._indexToPoints).toEqual({0: [0], 1: [1], 2: [2], 3: [3], 4: [4]}); - expect(out0[0].transforms[1]._indexToPoints).toEqual({0: [3], 1: [4]}); - expect(out1[0].transforms[1]._indexToPoints).toEqual({0: [3], 1: [4]}); - - ['x', 'y', 'ids', 'marker.color', 'marker.size'].forEach(function(k) { - var v0 = Lib.nestedProperty(out0[0], k).get(); - var v1 = Lib.nestedProperty(out1[0], k).get(); - expect(v0).toEqual(v1); - }); - }); - - it('two filter transforms with different `preservegaps` values should not necessarily commute', function() { - var transform0 = { - type: 'filter', - preservegaps: true, - operation: '>', - value: -1, - target: 'x' - }; - - var transform1 = { - type: 'filter', - preservegaps: false, - operation: '<', - value: 2, - target: 'x' - }; - - var out0 = _transform([Lib.extendDeep({}, base, { - transforms: [transform0, transform1] - })]); - - expect(out0[0].x).toEqual([0, 1]); - expect(out0[0].y).toEqual([1, 2]); - expect(out0[0].marker.color).toEqual([0.1, 0.2]); - - var out1 = _transform([Lib.extendDeep({}, base, { - transforms: [transform1, transform0] - })]); - - expect(out1[0].x).toEqual([undefined, undefined, undefined, 0, 1]); - expect(out1[0].y).toEqual([undefined, undefined, undefined, 1, 2]); - expect(out1[0].marker.color).toEqual([undefined, undefined, undefined, 0.1, 0.2]); - }); - - describe('filters should handle numeric values', function() { - var _base = Lib.extendDeep({}, base); - - function _assert(out, x, y, markerColor) { - expect(out[0].x).toEqual(x, '- x coords'); - expect(out[0].y).toEqual(y, '- y coords'); - expect(out[0].marker.color).toEqual(markerColor, '- marker.color arrayOk'); - expect(out[0].marker.size).toEqual(20, '- marker.size style'); - } - - it('with operation *[]*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '[]', - value: [-1, 1], - target: 'x' - }] - })]); - - _assert(out, - [-1, 0, 1], - [2, 1, 2], - [0.2, 0.1, 0.2] - ); - }); - - it('with operation *[)*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '[)', - value: [-1, 1], - target: 'x' - }] - })]); - - _assert(out, [-1, 0], [2, 1], [0.2, 0.1]); - }); - - it('with operation *(]*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '(]', - value: [-1, 1], - target: 'x' - }] - })]); - - _assert(out, [0, 1], [1, 2], [0.1, 0.2]); - }); - - it('with operation *()*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '()', - value: [-1, 1], - target: 'x' - }] - })]); - - _assert(out, [0], [1], [0.1]); - }); - - it('with operation *)(*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: ')(', - value: [-1, 1], - target: 'x' - }] - })]); - - _assert(out, - [-2, -2, 2, 3], - [1, 3, 3, 1], - [0.1, 0.3, 0.3, 0.4] - ); - }); - - it('with operation *)[*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: ')[', - value: [-1, 1], - target: 'x' - }] - })]); - - _assert(out, - [-2, -2, 1, 2, 3], - [1, 3, 2, 3, 1], - [0.1, 0.3, 0.2, 0.3, 0.4] - ); - }); - - it('with operation *](*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '](', - value: [-1, 1], - target: 'x' - }] - })]); - - _assert(out, - [-2, -1, -2, 2, 3], - [1, 2, 3, 3, 1], - [0.1, 0.2, 0.3, 0.3, 0.4] - ); - }); - - it('with operation *][*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '][', - value: [-1, 1], - target: 'x' - }] - })]); - - _assert(out, - [-2, -1, -2, 1, 2, 3], - [1, 2, 3, 2, 3, 1], - [0.1, 0.2, 0.3, 0.2, 0.3, 0.4] - ); - }); - - it('with operation *{}*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '{}', - value: [-2, 0], - target: 'x' - }] - })]); - - _assert(out, - [-2, -2, 0], - [1, 3, 1], - [0.1, 0.3, 0.1] - ); - }); - - it('with operation *}{*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '}{', - value: [-2, 0], - target: 'x' - }] - })]); - - _assert(out, - [-1, 1, 2, 3], - [2, 2, 3, 1], - [0.2, 0.2, 0.3, 0.4] - ); - }); - - it('should honored set axis type', function() { - var out = _transform([Lib.extendDeep({}, _base, { - x: [1, 2, 3, 0, -1, -2, -3], - transforms: [{ - operation: '>', - value: -1, - target: 'x' - }] - })], { - xaxis: { type: 'category' } - }); - - _assert(out, [-2, -3], [3, 1], [0.3, 0.4]); - }); - }); - - describe('filters should handle categories', function() { - var _base = { - x: ['a', 'b', 'c', 'd'], - y: [1, 2, 3, 4], - marker: { - color: 'red', - size: ['0', '1', '2', '0'] - }, - transforms: [{ type: 'filter' }] - }; - - function _assert(out, x, y, markerSize) { - expect(out[0].x).toEqual(x, '- x coords'); - expect(out[0].y).toEqual(y, '- y coords'); - expect(out[0].marker.size).toEqual(markerSize, '- marker.size arrayOk'); - expect(out[0].marker.color).toEqual('red', '- marker.color style'); - } - - it('with operation *()*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '()', - value: ['a', 'c'], - target: 'x' - }] - })]); - - _assert(out, ['b'], [2], ['1']); - }); - - it('with operation *)(*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: ')(', - value: ['a', 'c'], - target: 'x' - }] - })]); - - _assert(out, ['d'], [4], ['0']); - }); - - it('with operation *{}*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '{}', - value: ['b', 'd'], - target: 'x' - }] - })]); - - _assert(out, ['b', 'd'], [2, 4], ['1', '0']); - }); - - it('with operation *}{*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '}{', - value: ['b', 'd'], - target: 'x' - }] - })]); - - _assert(out, ['a', 'c'], [1, 3], ['0', '2']); - }); - }); - - describe('filters should handle dates', function() { - var _base = { - x: ['2015-07-20', '2016-08-01', '2016-09-01', '2016-10-21', '2016-12-02'], - y: [1, 2, 3, 1, 5], - marker: { - line: { - color: [0.1, 0.2, 0.3, 0.1, 0.2], - width: 2.5 - } - }, - transforms: [{ type: 'filter' }] - }; - - function _assert(out, x, y, markerLineColor) { - expect(out[0].x).toEqual(x, '- x coords'); - expect(out[0].y).toEqual(y, '- y coords'); - expect(out[0].marker.line.color).toEqual(markerLineColor, '- marker.line.color arrayOk'); - expect(out[0].marker.line.width).toEqual(2.5, '- marker.line.width style'); - } - - it('with operation *=*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '=', - value: ['2015-07-20'], - target: 'x' - }] - })]); - - _assert(out, ['2015-07-20'], [1], [0.1]); - }); - - it('with operation *!=*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '!=', - value: '2015-07-20', - target: 'x' - }] - })]); - - _assert( - out, - ['2016-08-01', '2016-09-01', '2016-10-21', '2016-12-02'], - [2, 3, 1, 5], - [0.2, 0.3, 0.1, 0.2] - ); - }); - - it('with operation *<*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '<', - value: '2016-01-01', - target: 'x' - }] - })]); - - _assert(out, ['2015-07-20'], [1], [0.1]); - }); - - it('with operation *>*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '>=', - value: '2016-08-01', - target: 'x' - }] - })]); - - _assert(out, - ['2016-08-01', '2016-09-01', '2016-10-21', '2016-12-02'], - [2, 3, 1, 5], - [0.2, 0.3, 0.1, 0.2] - ); - }); - - it('with operation *[]*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '[]', - value: ['2016-08-01', '2016-10-01'], - target: 'x' - }] - })]); - - _assert(out, ['2016-08-01', '2016-09-01'], [2, 3], [0.2, 0.3]); - }); - - it('with operation *)(*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: ')(', - value: ['2016-08-01', '2016-10-01'], - target: 'x' - }] - })]); - - _assert(out, ['2015-07-20', '2016-10-21', '2016-12-02'], [1, 1, 5], [0.1, 0.1, 0.2]); - }); - - it('with operation *{}*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '{}', - value: '2015-07-20', - target: 'x' - }] - })]); - - _assert(out, ['2015-07-20'], [1], [0.1]); - }); - - it('with operation *}{*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - operation: '}{', - value: ['2016-08-01', '2016-09-01', '2016-10-21', '2016-12-02'], - target: 'x' - }] - })]); - - _assert(out, ['2015-07-20'], [1], [0.1]); - }); - }); - - it('filters should handle ids', function() { - var out = _transform([Lib.extendDeep({}, base, { - transforms: [{ - operation: '{}', - value: ['p1', 'p2', 'n1'], - target: 'ids' - }] - })]); - - expect(out[0].x).toEqual([-1, 1, 2]); - expect(out[0].y).toEqual([2, 2, 3]); - expect(out[0].ids).toEqual(['n1', 'p1', 'p2']); - }); - - describe('filters should handle array *target* values', function() { - var _base = Lib.extendDeep({}, base); - - function _assert(out, x, y, markerColor) { - expect(out[0].x).toEqual(x, '- x coords'); - expect(out[0].y).toEqual(y, '- y coords'); - expect(out[0].marker.color).toEqual(markerColor, '- marker.color arrayOk'); - expect(out[0].marker.size).toEqual(20, '- marker.size style'); - } - - it('with numeric items', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - target: [1, 1, 0, 0, 1, 0, 1], - operation: '{}', - value: 0 - }] - })]); - - _assert(out, [-2, 0, 2], [3, 1, 3], [0.3, 0.1, 0.3]); - expect(out[0].transforms[0].target).toEqual([0, 0, 0]); - }); - - it('with ragged items - longer target', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - target: [1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1], - operation: '{}', - value: 0 - }] - })]); - - _assert(out, [-2, 0, 2], [3, 1, 3], [0.3, 0.1, 0.3]); - expect(out[0].transforms[0].target).toEqual([0, 0, 0]); - }); - - it('with ragged items - longer data', function() { - var out = _transform([Lib.extendDeep({}, _base, { - x: _base.x.concat(_base.x), - y: _base.y.concat(_base.y), - ids: _base.ids.concat(['a1', 'a2', 'a3', 'a4']), - marker: {color: _base.marker.color.concat(_base.marker.color)}, - transforms: [{ - target: [1, 1, 0, 0, 1, 0, 1], - operation: '{}', - value: 0 - }] - })]); - - _assert(out, [-2, 0, 2], [3, 1, 3], [0.3, 0.1, 0.3]); - expect(out[0].transforms[0].target).toEqual([0, 0, 0]); - }); - - it('with categorical items and *{}*', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - target: ['a', 'a', 'b', 'b', 'a', 'b', 'a'], - operation: '{}', - value: 'b' - }] - })]); - - _assert(out, [-2, 0, 2], [3, 1, 3], [0.3, 0.1, 0.3]); - expect(out[0].transforms[0].target).toEqual(['b', 'b', 'b']); - }); - - it('with categorical items and *<* and *>=*', function() { - var out = _transform([{ - x: [1, 2, 3], - y: [10, 20, 30], - transforms: [{ - type: 'filter', - operation: '<', - target: ['a', 'b', 'c'], - value: 'c' - }] - }, { - x: [1, 2, 3], - y: [30, 20, 10], - transforms: [{ - type: 'filter', - operation: '>=', - target: ['a', 'b', 'c'], - value: 'b' - }] - }]); - - expect(out[0].x).toEqual([1, 2]); - expect(out[0].y).toEqual([10, 20]); - expect(out[0].transforms[0].target).toEqual(['a', 'b']); - - expect(out[1].x).toEqual([2, 3]); - expect(out[1].y).toEqual([20, 10]); - expect(out[1].transforms[0].target).toEqual(['b', 'c']); - }); - - it('with categorical items and *[]*, *][*, *()* and *)(*', function() { - var out = _transform([{ - x: [1, 2, 3], - y: [10, 20, 30], - transforms: [{ - type: 'filter', - operation: '[]', - target: ['a', 'b', 'c'], - value: ['a', 'b'] - }] - }, { - x: [1, 2, 3], - y: [10, 20, 30], - transforms: [{ - type: 'filter', - operation: '()', - target: ['a', 'b', 'c'], - value: ['a', 'b'] - }] - }, { - x: [1, 2, 3], - y: [30, 20, 10], - transforms: [{ - type: 'filter', - operation: '][', - target: ['a', 'b', 'c'], - value: ['a', 'b'] - }] - }, { - x: [1, 2, 3], - y: [30, 20, 10], - transforms: [{ - type: 'filter', - operation: ')(', - target: ['a', 'b', 'c'], - value: ['a', 'b'] - }] - }]); - - expect(out[0].x).toEqual([1, 2]); - expect(out[0].y).toEqual([10, 20]); - expect(out[0].transforms[0].target).toEqual(['a', 'b']); - - expect(out[1].x).toEqual([]); - expect(out[1].y).toEqual([]); - expect(out[1].transforms[0].target).toEqual([]); - - expect(out[2].x).toEqual([1, 2, 3]); - expect(out[2].y).toEqual([30, 20, 10]); - expect(out[2].transforms[0].target).toEqual(['a', 'b', 'c']); - - expect(out[3].x).toEqual([3]); - expect(out[3].y).toEqual([10]); - expect(out[3].transforms[0].target).toEqual(['c']); - }); - - it('with dates items', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - target: ['2015-07-20', '2016-08-01', '2016-09-01', '2016-10-21', '2016-12-02'], - operation: '<', - value: '2016-01-01' - }] - })]); - - _assert(out, [-2], [1], [0.1]); - expect(out[0].transforms[0].target).toEqual(['2015-07-20']); - }); - - it('with multiple transforms (dates) ', function() { - var out = _transform([Lib.extendDeep({}, _base, { - transforms: [{ - target: ['2015-07-20', '2016-08-01', '2016-09-01', '2016-10-21', '2016-12-02'], - operation: '>', - value: '2016-01-01' - }, { - type: 'filter', - target: ['2015-07-20', '2016-08-01', '2016-09-01', '2016-10-21', '2016-12-02'], - operation: '<', - value: '2016-09-01' - }] - })]); - - _assert(out, [-1], [2], [0.2]); - expect(out[0].transforms[0].target).toEqual(['2016-08-01']); - }); - }); -}); - -describe('filter transforms interactions', function() { - 'use strict'; - - var mockData0 = [{ - x: [-2, -1, -2, 0, 1, 2, 3], - y: [1, 2, 3, 1, 2, 3, 1], - text: ['a', 'b', 'c', 'd', 'e', 'f', 'g'], - transforms: [{ - type: 'filter', - operation: '>' - }] - }]; - - var mockData1 = [Lib.extendDeep({}, mockData0[0]), { - x: [20, 11, 12, 0, 1, 2, 3], - y: [1, 2, 3, 2, 5, 2, 0], - text: ['A', 'B', 'C', 'D', 'E', 'F', 'G'], - transforms: [{ - type: 'filter', - operation: '<', - value: 10 - }] - }]; - - afterEach(destroyGraphDiv); - - it('Plotly.newPlot should plot the transform trace', function(done) { - var data = Lib.extendDeep([], mockData0); - - Plotly.newPlot(createGraphDiv(), data).then(function(gd) { - assertDims([3]); - - var uid = gd._fullData[0]._fullInput.uid; - expect(gd._fullData[0].uid).toEqual(uid + '0'); - }) - .then(done, done.fail); - }); - - it('Plotly.restyle should work', function(done) { - var data = Lib.extendDeep([], mockData0); - data[0].marker = { color: 'red' }; - - var gd = createGraphDiv(); - var dims = [3]; - - var uid; - function assertUid(gd) { - expect(gd._fullData[0].uid) - .toBe(uid + '0', 'should preserve uid on restyle'); - } - - Plotly.newPlot(gd, data).then(function() { - uid = gd._fullData[0]._fullInput.uid; - - expect(gd._fullData[0].marker.color).toEqual('red'); - assertUid(gd); - assertStyle(dims, ['rgb(255, 0, 0)'], [1]); - - expect(gd._fullLayout.xaxis.range).toBeCloseToArray([0.87, 3.13]); - expect(gd._fullLayout.yaxis.range).toBeCloseToArray([0.85, 3.15]); - - return Plotly.restyle(gd, 'marker.color', 'blue'); - }).then(function() { - expect(gd._fullData[0].marker.color).toEqual('blue'); - assertUid(gd); - assertStyle(dims, ['rgb(0, 0, 255)'], [1]); - - return Plotly.restyle(gd, 'marker.color', 'red'); - }).then(function() { - expect(gd._fullData[0].marker.color).toEqual('red'); - assertUid(gd); - assertStyle(dims, ['rgb(255, 0, 0)'], [1]); - - return Plotly.restyle(gd, 'transforms[0].value', 2.5); - }).then(function() { - assertUid(gd); - assertStyle([1], ['rgb(255, 0, 0)'], [1]); - - expect(gd._fullLayout.xaxis.range).toBeCloseToArray([2, 4]); - expect(gd._fullLayout.yaxis.range).toBeCloseToArray([0, 2]); - }) - .then(done, done.fail); - }); - - it('Plotly.extendTraces should work', function(done) { - var data = Lib.extendDeep([], mockData0); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data[0].x.length).toEqual(7); - expect(gd._fullData[0].x.length).toEqual(3); - - assertDims([3]); - - return Plotly.extendTraces(gd, { - x: [ [-3, 4, 5] ], - y: [ [1, -2, 3] ] - }, [0]); - }).then(function() { - expect(gd.data[0].x.length).toEqual(10); - expect(gd._fullData[0].x.length).toEqual(5); - - assertDims([5]); - }) - .then(done, done.fail); - }); - - it('Plotly.deleteTraces should work', function(done) { - var data = Lib.extendDeep([], mockData1); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - assertDims([3, 4]); - - return Plotly.deleteTraces(gd, [1]); - }).then(function() { - assertDims([3]); - - return Plotly.deleteTraces(gd, [0]); - }).then(function() { - assertDims([]); - }) - .then(done, done.fail); - }); - - it('toggling trace visibility should work', function(done) { - var data = Lib.extendDeep([], mockData1); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - assertDims([3, 4]); - - return Plotly.restyle(gd, 'visible', 'legendonly', [1]); - }).then(function() { - assertDims([3]); - - return Plotly.restyle(gd, 'visible', false, [0]); - }).then(function() { - assertDims([]); - - return Plotly.restyle(gd, 'visible', [true, true], [0, 1]); - }).then(function() { - assertDims([3, 4]); - }) - .then(done, done.fail); - }); - - it('zooming in/out should not change filtered data', function(done) { - var data = Lib.extendDeep([], mockData1); - - var gd = createGraphDiv(); - - function getTx(p) { return p.tx; } - - Plotly.newPlot(gd, data).then(function() { - expect(gd.calcdata[0].map(getTx)).toEqual(['e', 'f', 'g']); - expect(gd.calcdata[1].map(getTx)).toEqual(['D', 'E', 'F', 'G']); - - return Plotly.relayout(gd, 'xaxis.range', [-1, 1]); - }) - .then(function() { - expect(gd.calcdata[0].map(getTx)).toEqual(['e', 'f', 'g']); - expect(gd.calcdata[1].map(getTx)).toEqual(['D', 'E', 'F', 'G']); - - return Plotly.relayout(gd, 'xaxis.autorange', true); - }) - .then(function() { - expect(gd.calcdata[0].map(getTx)).toEqual(['e', 'f', 'g']); - expect(gd.calcdata[1].map(getTx)).toEqual(['D', 'E', 'F', 'G']); - }) - .then(done, done.fail); - }); - - it('should update axis categories', function(done) { - var data = [{ - type: 'bar', - x: ['a', 'b', 'c', 'd', 'e', 'f', 'g'], - y: [1, 10, 100, 25, 50, -25, 100], - transforms: [{ - type: 'filter', - operation: '<', - value: 10, - target: [1, 10, 100, 25, 50, -25, 100] - }] - }]; - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd._fullLayout.xaxis._categories).toEqual(['a', 'f']); - expect(gd._fullLayout.yaxis._categories).toEqual([]); - - return Plotly.addTraces(gd, [{ - type: 'bar', - x: ['h', 'i'], - y: [2, 1], - transforms: [{ - type: 'filter', - operation: '=', - value: 'i' - }] - }]); - }) - .then(function() { - expect(gd._fullLayout.xaxis._categories).toEqual(['a', 'f', 'i']); - expect(gd._fullLayout.yaxis._categories).toEqual([]); - - return Plotly.deleteTraces(gd, [0]); - }) - .then(function() { - expect(gd._fullLayout.xaxis._categories).toEqual(['i']); - expect(gd._fullLayout.yaxis._categories).toEqual([]); - }) - .then(done, done.fail); - }); - - it('should clear indexToPoints on removal', function(done) { - var gd = createGraphDiv(); - - Plotly.react(gd, [{ - y: [1, 2, 3, 1, 2, 3], - transforms: [{ - type: 'filter', - target: 'y', - operation: '<', - value: 3 - }] - }]) - .then(function() { - expect(gd._fullData[0]._indexToPoints).toEqual({0: [0], 1: [1], 2: [3], 3: [4]}); - return Plotly.react(gd, [{ y: [1, 2, 3, 1, 2, 3] }]); - }) - .then(function() { - expect(gd._fullData[0]._indexToPoints).toBeUndefined(); - }) - .then(done, done.fail); - }); -}); - -describe('filter resulting in empty coordinate arrays', function() { - var gd; - - afterEach(function(done) { - Plotly.purge(gd); - setTimeout(function() { - destroyGraphDiv(); - done(); - }, 200); - }); - - function filter2empty(mock) { - var fig = Lib.extendDeep({}, mock); - var data = fig.data || []; - - data.forEach(function(trace) { - trace.transforms = [{ - type: 'filter', - target: [null] - }]; - }); - - return fig; - } - - describe('svg mocks', function() { - var mockList = require('../assets/mock_lists').svg; - - mockList.forEach(function(d) { - it(d[0], function(done) { - gd = createGraphDiv(); - var fig = filter2empty(d[1]); - Plotly.newPlot(gd, fig).then(done, done.fail); - }); - }); - }); - - describe('gl mocks', function() { - var mockList = require('../assets/mock_lists').gl; - - mockList.forEach(function(d) { - it('@gl ' + d[0], function(done) { - gd = createGraphDiv(); - var fig = filter2empty(d[1]); - Plotly.newPlot(gd, fig).then(done, done.fail); - }); - }); - }); - - describe('mapbox mocks', function() { - var mockList = require('../assets/mock_lists').mapbox; - - Plotly.setPlotConfig({ - mapboxAccessToken: require('../../../build/credentials.json').MAPBOX_ACCESS_TOKEN - }); - - mockList.forEach(function(d) { - it('@gl' + d[0], function(done) { - gd = createGraphDiv(); - var fig = filter2empty(d[1]); - Plotly.newPlot(gd, fig).then(done, done.fail); - }); - }); - }); - - describe('map mocks', function() { - var mockList = require('../assets/mock_lists').map; - - Plotly.setPlotConfig({}); - - mockList.forEach(function(d) { - it('@gl' + d[0], function(done) { - gd = createGraphDiv(); - var fig = filter2empty(d[1]); - Plotly.newPlot(gd, fig).then(done, done.fail); - }); - }); - }); -}); diff --git a/test/jasmine/tests/transform_groupby_test.js b/test/jasmine/tests/transform_groupby_test.js deleted file mode 100644 index 3618344d66d..00000000000 --- a/test/jasmine/tests/transform_groupby_test.js +++ /dev/null @@ -1,822 +0,0 @@ -var Plotly = require('../../../lib/index'); -var Plots = require('../../../src/plots/plots'); -var Lib = require('../../../src/lib'); - -var createGraphDiv = require('../assets/create_graph_div'); -var destroyGraphDiv = require('../assets/destroy_graph_div'); -var customAssertions = require('../assets/custom_assertions'); - - -var assertDims = customAssertions.assertDims; -var assertStyle = customAssertions.assertStyle; - - -function supplyDataDefaults(dataIn, dataOut) { - return Plots.supplyDataDefaults(dataIn, dataOut, {}, { - _subplots: {cartesian: ['xy'], xaxis: ['x'], yaxis: ['y']}, - _modules: [], - _visibleModules: [], - _basePlotModules: [], - _traceUids: dataIn.map(function() { return Lib.randstr(); }) - }); -} - -describe('groupby', function() { - describe('one-to-many transforms:', function() { - 'use strict'; - - var mockData0 = [{ - mode: 'markers', - x: [1, -1, -2, 0, 1, 2, 3], - y: [1, 2, 3, 1, 2, 3, 1], - transforms: [{ - type: 'groupby', - groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'], - styles: [ - {target: 'a', value: {marker: {color: 'red'}}}, - {target: 'b', value: {marker: {color: 'blue'}}} - ] - }] - }]; - - var mockData1 = [Lib.extendDeep({}, mockData0[0]), { - mode: 'markers', - x: [20, 11, 12, 0, 1, 2, 3], - y: [1, 2, 3, 2, 5, 2, 0], - transforms: [{ - type: 'groupby', - groups: ['b', 'a', 'b', 'b', 'b', 'a', 'a'], - styles: [ - {target: 'a', value: {marker: {color: 'green'}}}, - {target: 'b', value: {marker: {color: 'black'}}} - ] - }] - }]; - - var mockDataWithTypedArrayGroups = [{ - mode: 'markers', - x: [20, 11, 12, 0, 1, 2, 3], - y: [1, 2, 3, 2, 5, 2, 0], - transforms: [{ - type: 'groupby', - groups: new Uint8Array([2, 1, 2, 2, 2, 1, 1]), - styles: [ - {target: 1, value: {marker: {color: 'green'}}}, - {target: 2, value: {marker: {color: 'black'}}} - ] - }] - }]; - - afterEach(destroyGraphDiv); - - it('Plotly.newPlot should plot the transform traces', function(done) { - var data = Lib.extendDeep([], mockData0); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data.length).toEqual(1); - expect(gd.data[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd.data[0].y).toEqual([1, 2, 3, 1, 2, 3, 1]); - - expect(gd._fullData.length).toEqual(2); - expect(gd._fullData[0].x).toEqual([1, -1, 0, 3]); - expect(gd._fullData[0].y).toEqual([1, 2, 1, 1]); - expect(gd._fullData[0].transforms[0]._indexToPoints).toEqual({0: [0], 1: [1], 2: [3], 3: [6]}); - expect(gd._fullData[1].x).toEqual([-2, 1, 2]); - expect(gd._fullData[1].y).toEqual([3, 2, 3]); - expect(gd._fullData[1].transforms[0]._indexToPoints).toEqual({0: [2], 1: [4], 2: [5]}); - - assertDims([4, 3]); - }) - .then(done, done.fail); - }); - - it('Accepts deprecated object notation for styles', function(done) { - var oldStyleMockData = [{ - mode: 'markers', - x: [1, -1, -2, 0, 1, 2, 3], - y: [1, 2, 3, 1, 2, 3, 1], - transforms: [{ - type: 'groupby', - groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'], - styles: { - a: {marker: {color: 'red'}}, - b: {marker: {color: 'blue'}} - } - }] - }]; - var data = Lib.extendDeep([], oldStyleMockData); - data[0].marker = { size: 20 }; - - var gd = createGraphDiv(); - var dims = [4, 3]; - - Plotly.newPlot(gd, data).then(function() { - assertStyle(dims, - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [1, 1] - ); - - return Plotly.restyle(gd, 'marker.opacity', 0.4); - }).then(function() { - assertStyle(dims, - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [0.4, 0.4] - ); - - expect(gd._fullData[0].marker.opacity).toEqual(0.4); - expect(gd._fullData[1].marker.opacity).toEqual(0.4); - - return Plotly.restyle(gd, 'marker.opacity', 1); - }).then(function() { - assertStyle(dims, - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [1, 1] - ); - - expect(gd._fullData[0].marker.opacity).toEqual(1); - expect(gd._fullData[1].marker.opacity).toEqual(1); - }) - .then(done, done.fail); - - // The final test for restyle updates using deprecated syntax - // is omitted since old style syntax is *only* sanitized on - // initial plot, *not* on restyle. - }); - - it('Plotly.restyle should work', function(done) { - var data = Lib.extendDeep([], mockData0); - data[0].marker = { size: 20 }; - - var gd = createGraphDiv(); - var dims = [4, 3]; - - Plotly.newPlot(gd, data).then(function() { - assertStyle(dims, - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [1, 1] - ); - - return Plotly.restyle(gd, 'marker.opacity', 0.4); - }).then(function() { - assertStyle(dims, - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [0.4, 0.4] - ); - - expect(gd._fullData[0].marker.opacity).toEqual(0.4); - expect(gd._fullData[1].marker.opacity).toEqual(0.4); - - return Plotly.restyle(gd, 'marker.opacity', 1); - }).then(function() { - assertStyle(dims, - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [1, 1] - ); - - expect(gd._fullData[0].marker.opacity).toEqual(1); - expect(gd._fullData[1].marker.opacity).toEqual(1); - - return Plotly.restyle(gd, { - 'transforms[0].styles': [[ - {target: 'a', value: {marker: {color: 'green'}}}, - {target: 'b', value: {marker: {color: 'red'}}} - ]], - 'marker.opacity': 0.4 - }); - }).then(function() { - assertStyle(dims, - ['rgb(0, 128, 0)', 'rgb(255, 0, 0)'], - [0.4, 0.4] - ); - }) - .then(done, done.fail); - }); - - it('Plotly.react should work', function(done) { - var data = Lib.extendDeep([], mockData0); - data[0].marker = { size: 20 }; - - var gd = createGraphDiv(); - var dims = [4, 3]; - - Plotly.newPlot(gd, data).then(function() { - assertStyle(dims, - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [1, 1] - ); - - gd.data[0].marker.opacity = 0.4; - // contrived test of relinkPrivateKeys - // we'll have to do better if we refactor it to opt-in instead of catchall - gd._fullData[0].marker._boo = 'here I am'; - return Plotly.react(gd, gd.data, gd.layout); - }).then(function() { - assertStyle(dims, - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [0.4, 0.4] - ); - - expect(gd._fullData[0].marker.opacity).toEqual(0.4); - expect(gd._fullData[1].marker.opacity).toEqual(0.4); - expect(gd._fullData[0].marker._boo).toBe('here I am'); - - gd.data[0].marker.opacity = 1; - return Plotly.react(gd, gd.data, gd.layout); - }).then(function() { - assertStyle(dims, - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [1, 1] - ); - - expect(gd._fullData[0].marker.opacity).toEqual(1); - expect(gd._fullData[1].marker.opacity).toEqual(1); - - // edit just affects the first group - gd.data[0].transforms[0].styles[0].value.marker.color = 'green'; - return Plotly.react(gd, gd.data, gd.layout); - }).then(function() { - assertStyle(dims, - ['rgb(0, 128, 0)', 'rgb(0, 0, 255)'], - [1, 1] - ); - - expect(gd._fullData[0].marker.opacity).toEqual(1); - expect(gd._fullData[1].marker.opacity).toEqual(1); - - // edit just affects the second group - gd.data[0].transforms[0].styles[1].value.marker.color = 'red'; - return Plotly.react(gd, gd.data, gd.layout); - }).then(function() { - assertStyle(dims, - ['rgb(0, 128, 0)', 'rgb(255, 0, 0)'], - [1, 1] - ); - }) - .then(done, done.fail); - }); - - it('Plotly.extendTraces should work', function(done) { - var data = Lib.extendDeep([], mockData0); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data[0].x.length).toEqual(7); - expect(gd._fullData[0].x.length).toEqual(4); - expect(gd._fullData[1].x.length).toEqual(3); - - assertDims([4, 3]); - - return Plotly.extendTraces(gd, { - x: [ [-3, 4, 5] ], - y: [ [1, -2, 3] ], - 'transforms[0].groups': [ ['b', 'a', 'b'] ] - }, [0]); - }).then(function() { - expect(gd.data[0].x.length).toEqual(10); - expect(gd._fullData[0].x.length).toEqual(5); - expect(gd._fullData[1].x.length).toEqual(5); - - assertDims([5, 5]); - }) - .then(done, done.fail); - }); - - it('Plotly.deleteTraces should work', function(done) { - var data = Lib.extendDeep([], mockData1); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - assertDims([4, 3, 4, 3]); - - return Plotly.deleteTraces(gd, [1]); - }).then(function() { - assertDims([4, 3]); - - return Plotly.deleteTraces(gd, [0]); - }).then(function() { - assertDims([]); - }) - .then(done, done.fail); - }); - - it('toggling trace visibility should work', function(done) { - var data = Lib.extendDeep([], mockData1); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - assertDims([4, 3, 4, 3]); - - return Plotly.restyle(gd, 'visible', 'legendonly', [1]); - }).then(function() { - assertDims([4, 3]); - - return Plotly.restyle(gd, 'visible', false, [0]); - }).then(function() { - assertDims([]); - - return Plotly.restyle(gd, 'visible', [true, true], [0, 1]); - }).then(function() { - assertDims([4, 3, 4, 3]); - }) - .then(done, done.fail); - }); - - it('Plotly.newPlot should group points properly using typed array', function(done) { - var data = Lib.extendDeep([], mockDataWithTypedArrayGroups); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd._fullData.length).toEqual(2); - expect(gd._fullData[0].x).toEqual([20, 12, 0, 1]); - expect(gd._fullData[0].y).toEqual([1, 3, 2, 5]); - expect(gd._fullData[1].x).toEqual([11, 2, 3]); - expect(gd._fullData[1].y).toEqual([2, 2, 0]); - }) - .then(done, done.fail); - }); - }); - - describe('many-to-many transforms', function() { - it('varies the color for each expanded trace', function() { - var uniqueColors = {}; - var dataOut = []; - var dataIn = [{ - y: [1, 2, 3], - transforms: [ - {type: 'filter', operation: '<', value: 4}, - {type: 'groupby', groups: ['a', 'b', 'c']} - ] - }, { - y: [4, 5, 6], - transforms: [ - {type: 'filter', operation: '<', value: 4}, - {type: 'groupby', groups: ['a', 'b', 'b']} - ] - }]; - - supplyDataDefaults(dataIn, dataOut); - - for(var i = 0; i < dataOut.length; i++) { - uniqueColors[dataOut[i].marker.color] = true; - } - - // Confirm that five total colors exist: - expect(Object.keys(uniqueColors).length).toEqual(5); - }); - }); - - - // these tests can be shortened, once the meaning of edge cases gets clarified - describe('symmetry/degeneracy testing of one-to-many transforms on arbitrary arrays where there is no grouping (implicit 1):', function() { - 'use strict'; - - var mockData = [{ - mode: 'markers', - x: [1, -1, -2, 0, 1, 2, 3], - y: [1, 2, 3, 1, 2, 3, 1], - - // everything is present: - transforms: [{ - type: 'groupby', - groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'], - styles: [ - {target: 'a', value: {marker: {color: 'red'}}}, - {target: 'b', value: {marker: {color: 'blue'}}} - ] - }] - }]; - - var mockData0 = [{ - mode: 'markers', - x: [1, -1, -2, 0, 1, 2, 3], - y: [1, 2, 3, 1, 2, 3, 1], - - // groups, styles not present - transforms: [{ - type: 'groupby' - // groups not present - // styles not present - }] - }]; - - // transform attribute with empty list - var mockData1 = [{ - mode: 'markers', - x: [1, -1, -2, 0, 1, 2, 3], - y: [1, 2, 3, 1, 2, 3, 1], - - // transforms is present but there are no items in it - transforms: [ /* list is empty */ ] - }]; - - // transform attribute with null value - var mockData2 = [{ - mode: 'markers', - x: [1, -1, -2, 0, 1, 2, 3], - y: [1, 2, 3, 1, 2, 3, 1], - transforms: null - }]; - - // no transform is present at all - var mockData3 = [{ - mode: 'markers', - x: [1, -1, -2, 0, 1, 2, 3], - y: [1, 2, 3, 1, 2, 3, 1] - }]; - - afterEach(destroyGraphDiv); - - it('Plotly.newPlot should plot the transform traces', function(done) { - var data = Lib.extendDeep([], mockData); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data.length).toEqual(1); - expect(gd.data[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd.data[0].y).toEqual([1, 2, 3, 1, 2, 3, 1]); - - expect(gd._fullData.length).toEqual(2); // two groups - expect(gd._fullData[0].x).toEqual([1, -1, 0, 3]); - expect(gd._fullData[0].y).toEqual([1, 2, 1, 1]); - expect(gd._fullData[1].x).toEqual([-2, 1, 2]); - expect(gd._fullData[1].y).toEqual([3, 2, 3]); - - assertDims([4, 3]); - }) - .then(done, done.fail); - }); - - it('Plotly.newPlot should plot the transform traces', function(done) { - var data = Lib.extendDeep([], mockData0); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data.length).toEqual(1); - expect(gd.data[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd.data[0].y).toEqual([1, 2, 3, 1, 2, 3, 1]); - - expect(gd._fullData.length).toEqual(1); - assertDims([7]); - }) - .then(done, done.fail); - }); - - it('Plotly.newPlot should plot the transform traces', function(done) { - var data = Lib.extendDeep([], mockData1); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data.length).toEqual(1); - expect(gd.data[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd.data[0].y).toEqual([1, 2, 3, 1, 2, 3, 1]); - - expect(gd._fullData.length).toEqual(1); - expect(gd._fullData[0].x).toEqual([ 1, -1, -2, 0, 1, 2, 3 ]); - expect(gd._fullData[0].y).toEqual([1, 2, 3, 1, 2, 3, 1]); - - assertDims([7]); - }) - .then(done, done.fail); - }); - - it('Plotly.newPlot should plot the transform traces', function(done) { - var data = Lib.extendDeep([], mockData2); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data.length).toEqual(1); - expect(gd.data[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd.data[0].y).toEqual([1, 2, 3, 1, 2, 3, 1]); - - expect(gd._fullData.length).toEqual(1); - - expect(gd._fullData[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd._fullData[0].y).toEqual([1, 2, 3, 1, 2, 3, 1]); - - assertDims([7]); - }) - .then(done, done.fail); - }); - - it('Plotly.newPlot should plot the transform traces', function(done) { - var data = Lib.extendDeep([], mockData3); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data.length).toEqual(1); - expect(gd.data[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd.data[0].y).toEqual([1, 2, 3, 1, 2, 3, 1]); - - expect(gd._fullData.length).toEqual(1); - - expect(gd._fullData[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd._fullData[0].y).toEqual([1, 2, 3, 1, 2, 3, 1]); - - assertDims([7]); - }) - .then(done, done.fail); - }); - }); - - describe('grouping with basic, heterogenous and overridden attributes', function() { - 'use strict'; - - afterEach(destroyGraphDiv); - - function test(mockData) { - return function(done) { - var data = Lib.extendDeep([], mockData); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data.length).toEqual(1); - expect(gd.data[0].ids).toEqual(['q', 'w', 'r', 't', 'y', 'u', 'i']); - expect(gd.data[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd.data[0].y).toEqual([0, 1, 2, 3, 5, 4, 6]); - expect(gd.data[0].marker.line.width).toEqual([4, 2, 4, 2, 2, 3, 3]); - - expect(gd._fullData.length).toEqual(2); - - expect(gd._fullData[0].ids).toEqual(['q', 'w', 't', 'i']); - expect(gd._fullData[0].x).toEqual([1, -1, 0, 3]); - expect(gd._fullData[0].y).toEqual([0, 1, 3, 6]); - expect(gd._fullData[0].marker.line.width).toEqual([4, 2, 2, 3]); - - - expect(gd._fullData[1].ids).toEqual(['r', 'y', 'u']); - expect(gd._fullData[1].x).toEqual([-2, 1, 2]); - expect(gd._fullData[1].y).toEqual([2, 5, 4]); - expect(gd._fullData[1].marker.line.width).toEqual([4, 2, 3]); - - assertDims([4, 3]); - }) - .then(done, done.fail); - }; - } - - // basic test - var mockData1 = [{ - mode: 'markers', - ids: ['q', 'w', 'r', 't', 'y', 'u', 'i'], - x: [1, -1, -2, 0, 1, 2, 3], - y: [0, 1, 2, 3, 5, 4, 6], - marker: {line: {width: [4, 2, 4, 2, 2, 3, 3]}}, - transforms: [{ - type: 'groupby', - groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'], - styles: [ - {target: 'a', value: {marker: {color: 'red'}}}, - {target: 'b', value: {marker: {color: 'blue'}}} - ] - }] - }]; - - // heterogenously present attributes - var mockData2 = [{ - mode: 'markers', - ids: ['q', 'w', 'r', 't', 'y', 'u', 'i'], - x: [1, -1, -2, 0, 1, 2, 3], - y: [0, 1, 2, 3, 5, 4, 6], - marker: {line: {width: [4, 2, 4, 2, 2, 3, 3]}}, - transforms: [{ - type: 'groupby', - groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'], - styles: [{ - target: 'a', - value: { - marker: { - color: 'orange', - size: 20, - line: { - color: 'red' - } - } - } - }, { - target: 'b', - value: { - mode: 'markers+lines', // heterogeonos attributes are OK: group 'a' doesn't need to define this - marker: { - color: 'cyan', - size: 15, - line: { - color: 'purple' - }, - opacity: 0.5, - symbol: 'triangle-up' - }, - line: { - color: 'purple' - } - } - }] - }] - }]; - - // attributes set at top level and partially overridden in the group item level - var mockData3 = [{ - mode: 'markers+lines', - ids: ['q', 'w', 'r', 't', 'y', 'u', 'i'], - x: [1, -1, -2, 0, 1, 2, 3], - y: [0, 1, 2, 3, 5, 4, 6], - marker: { - color: 'darkred', // general 'default' color - line: { - width: [4, 2, 4, 2, 2, 3, 3], - color: ['orange', 'red', 'green', 'cyan', 'magenta', 'blue', 'pink'] - } - }, - line: {color: 'red'}, - transforms: [{ - type: 'groupby', - groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'], - styles: [{ - target: 'a', - value: {marker: {size: 30}} - }, { - // override general color: - target: 'b', - value: {marker: {size: 15, line: {color: 'yellow'}}, line: {color: 'purple'}} - }] - }] - }]; - - var mockData4 = [{ - mode: 'markers+lines', - ids: ['q', 'w', 'r', 't', 'y', 'u', 'i'], - x: [1, -1, -2, 0, 1, 2, 3], - y: [0, 1, 2, 3, 5, 4, 6], - marker: {line: {width: [4, 2, 4, 2, 2, 3, 3]}}, - transforms: [{ - type: 'groupby', - groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'], - styles: [/* can be empty, or of partial group id coverage */] - }] - }]; - - var mockData5 = [{ - mode: 'markers+lines', - ids: ['q', 'w', 'r', 't', 'y', 'u', 'i'], - x: [1, -1, -2, 0, 1, 2, 3], - y: [0, 1, 2, 3, 5, 4, 6], - marker: { - line: {width: [4, 2, 4, 2, 2, 3, 3]}, - size: 10, - color: ['red', '#eee', 'lightgreen', 'blue', 'red', '#eee', 'lightgreen'] - }, - transforms: [{ - type: 'groupby', - groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'] - }] - }]; - - it('`data` preserves user supplied input but `gd._fullData` reflects the grouping', test(mockData1)); - - it('passes with lots of attributes and heterogenous attrib presence', test(mockData2)); - - it('passes with group styles partially overriding top level aesthetics', test(mockData3)); - it('passes extended tests with group styles partially overriding top level aesthetics', function(done) { - var data = Lib.extendDeep([], mockData3); - var gd = createGraphDiv(); - Plotly.newPlot(gd, data).then(function() { - expect(gd._fullData[0].marker.line.color).toEqual(['orange', 'red', 'cyan', 'pink']); - expect(gd._fullData[1].marker.line.color).toEqual('yellow'); - }) - .then(done, done.fail); - }); - - it('passes with no explicit styling for the individual group', test(mockData4)); - - it('passes with no explicit styling in the group transform at all', test(mockData5)); - }); - - describe('passes with no `groups`', function() { - 'use strict'; - - afterEach(destroyGraphDiv); - - function test(mockData) { - return function(done) { - var data = Lib.extendDeep([], mockData); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data.length).toEqual(1); - expect(gd.data[0].ids).toEqual(['q', 'w', 'r', 't', 'y', 'u', 'i']); - expect(gd.data[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd.data[0].y).toEqual([0, 1, 2, 3, 5, 4, 6]); - expect(gd.data[0].marker.line.width).toEqual([4, 2, 4, 2, 2, 3, 3]); - - expect(gd._fullData.length).toEqual(1); - - expect(gd._fullData[0].ids).toEqual(['q', 'w', 'r', 't', 'y', 'u', 'i']); - expect(gd._fullData[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd._fullData[0].y).toEqual([0, 1, 2, 3, 5, 4, 6]); - expect(gd._fullData[0].marker.line.width).toEqual([4, 2, 4, 2, 2, 3, 3]); - - assertDims([7]); - }) - .then(done, done.fail); - }; - } - - var mockData0 = [{ - mode: 'markers+lines', - ids: ['q', 'w', 'r', 't', 'y', 'u', 'i'], - x: [1, -1, -2, 0, 1, 2, 3], - y: [0, 1, 2, 3, 5, 4, 6], - marker: {size: 20, line: {width: [4, 2, 4, 2, 2, 3, 3]}}, - transforms: [{ - type: 'groupby', - // groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'], - styles: [ - {target: 'a', value: {marker: {color: 'red'}}}, - {target: 'b', value: {marker: {color: 'blue'}}} - ] - }] - }]; - - var mockData1 = [{ - mode: 'markers+lines', - ids: ['q', 'w', 'r', 't', 'y', 'u', 'i'], - x: [1, -1, -2, 0, 1, 2, 3], - y: [0, 1, 2, 3, 5, 4, 6], - marker: {size: 20, line: {width: [4, 2, 4, 2, 2, 3, 3]}}, - transforms: [{ - type: 'groupby', - groups: [], - styles: [ - {target: 'a', value: {marker: {color: 'red'}}}, - {target: 'b', value: {marker: {color: 'blue'}}} - ] - }] - }]; - - var mockData2 = [{ - mode: 'markers+lines', - ids: ['q', 'w', 'r', 't', 'y', 'u', 'i'], - x: [1, -1, -2, 0, 1, 2, 3], - y: [0, 1, 2, 3, 5, 4, 6], - marker: {size: 20, line: {width: [4, 2, 4, 2, 2, 3, 3]}}, - transforms: [{ - type: 'groupby', - groups: null, - styles: [ - {target: 'a', value: {marker: {color: 'red'}}}, - {target: 'b', value: {marker: {color: 'blue'}}} - ] - }] - }]; - - it('passes with no groups', test(mockData0)); - it('passes with empty groups', test(mockData1)); - it('passes with falsey groups', test(mockData2)); - }); - - describe('expanded trace coloring', function() { - it('assigns unique colors to each group', function() { - var colors = []; - var dataOut = []; - var dataIn = [{ - y: [1, 2, 3], - transforms: [ - {type: 'filter', operation: '<', value: 4}, - {type: 'groupby', groups: ['a', 'b', 'c']} - ] - }, { - y: [4, 5, 6], - transforms: [ - {type: 'filter', operation: '<', value: 4}, - {type: 'groupby', groups: ['a', 'b', 'b']} - ] - }]; - - supplyDataDefaults(dataIn, dataOut); - - for(var i = 0; i < dataOut.length; i++) { - colors.push(dataOut[i].marker.color); - } - - expect(colors).toEqual([ - '#1f77b4', - '#ff7f0e', - '#2ca02c', - '#d62728', - '#9467bd' - ]); - }); - }); -}); diff --git a/test/jasmine/tests/transform_multi_test.js b/test/jasmine/tests/transform_multi_test.js deleted file mode 100644 index 43550fea52f..00000000000 --- a/test/jasmine/tests/transform_multi_test.js +++ /dev/null @@ -1,1143 +0,0 @@ -var Plotly = require('../../../lib/index'); -var Filter = require('../../../src/transforms/filter'); - -var Plots = require('../../../src/plots/plots'); -var Lib = require('../../../src/lib'); - -var createGraphDiv = require('../assets/create_graph_div'); -var destroyGraphDiv = require('../assets/destroy_graph_div'); - -var customAssertions = require('../assets/custom_assertions'); -var supplyAllDefaults = require('../assets/supply_defaults'); - -var assertDims = customAssertions.assertDims; -var assertStyle = customAssertions.assertStyle; - -var mockFullLayout = { - _subplots: {cartesian: ['xy'], xaxis: ['x'], yaxis: ['y']}, - _modules: [], - _visibleModules: [], - _basePlotModules: [], - _has: function() {}, - _dfltTitle: {x: 'xxx', y: 'yyy'}, - _requestRangeslider: {}, - _traceUids: [] -}; - - -describe('general transforms:', function() { - 'use strict'; - - var fullLayout = { - _transformModules: [], - _subplots: {cartesian: ['xy'], xaxis: ['x'], yaxis: ['y']}, - _modules: [], - _basePlotModules: [] - }; - - var traceIn, traceOut; - - it('passes through empty transforms', function() { - traceIn = { - y: [2, 1, 2], - transforms: [{}] - }; - - traceOut = Plots.supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, fullLayout); - - expect(traceOut.transforms).toEqual([{}]); - }); - - it('does not transform traces with no length', function() { - traceIn = { - y: [], - transforms: [{}] - }; - - traceOut = Plots.supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, fullLayout); - - expect(traceOut.transforms).toBeUndefined(); - }); - - it('supplyTraceDefaults should supply the transform defaults', function() { - traceIn = { - y: [2, 1, 2], - transforms: [{ type: 'filter' }] - }; - - traceOut = Plots.supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, fullLayout); - - expect(traceOut.transforms).toEqual([{ - type: 'filter', - enabled: true, - operation: '=', - value: 0, - target: 'x', - preservegaps: false, - _module: Filter - }]); - }); - - it('supplyTraceDefaults should not bail if transform module is not found', function() { - traceIn = { - y: [2, 1, 2], - transforms: [{ type: 'invalid' }] - }; - - traceOut = Plots.supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, fullLayout); - - expect(traceOut.y).toBe(traceIn.y); - }); - - it('supplyTraceDefaults should honor global transforms', function() { - traceIn = { - y: [2, 1, 2], - transforms: [{ - type: 'filter', - operation: '>', - value: 0, - target: 'x' - }] - }; - - var layout = { - _transformModules: [], - _globalTransforms: [{ - type: 'filter' - }], - _subplots: {cartesian: ['xy'], xaxis: ['x'], yaxis: ['y']}, - _modules: [], - _basePlotModules: [] - }; - - traceOut = Plots.supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, layout); - - expect(traceOut.transforms[0]).toEqual(jasmine.objectContaining({ - type: 'filter', - enabled: true, - operation: '=', - value: 0, - target: 'x', - _module: Filter - }), '- global first'); - - expect(traceOut.transforms[1]).toEqual(jasmine.objectContaining({ - type: 'filter', - enabled: true, - operation: '>', - value: 0, - target: 'x', - _module: Filter - }), '- trace second'); - - expect(layout._transformModules).toEqual([Filter]); - }); - - it('supplyDataDefaults should apply the transform while', function() { - var dataIn = [{ - x: [-2, -2, 1, 2, 3], - y: [1, 2, 2, 3, 1] - }, { - x: [-2, -1, -2, 0, 1, 2, 3], - y: [1, 2, 3, 1, 2, 3, 1], - transforms: [{ - type: 'filter', - operation: '>', - value: 0, - target: 'x' - }] - }]; - - var dataOut = []; - Plots.supplyDataDefaults(dataIn, dataOut, {}, mockFullLayout); - - var msg; - - msg = 'does not mutate user data'; - expect(dataIn[1].x).toEqual([-2, -1, -2, 0, 1, 2, 3], msg); - expect(dataIn[1].y).toEqual([1, 2, 3, 1, 2, 3, 1], msg); - expect(dataIn[1].transforms).toEqual([{ - type: 'filter', - operation: '>', - value: 0, - target: 'x' - }], msg); - - msg = 'supplying the transform defaults'; - expect(dataOut[1].transforms[0]).toEqual(jasmine.objectContaining({ - type: 'filter', - enabled: true, - operation: '>', - value: 0, - target: 'x', - _module: Filter - }), msg); - - msg = 'keeping refs to user data'; - expect(dataOut[1]._input.x).toEqual([-2, -1, -2, 0, 1, 2, 3], msg); - expect(dataOut[1]._input.y).toEqual([1, 2, 3, 1, 2, 3, 1], msg); - expect(dataOut[1]._input.transforms).toEqual([{ - type: 'filter', - operation: '>', - value: 0, - target: 'x', - }], msg); - - msg = 'keeping refs to full transforms array'; - expect(dataOut[1]._fullInput.transforms).toEqual([{ - type: 'filter', - enabled: true, - operation: '>', - value: 0, - target: 'x', - preservegaps: false, - _module: Filter - }], msg); - - msg = 'setting index w.r.t user data'; - expect(dataOut[0].index).toEqual(0, msg); - expect(dataOut[1].index).toEqual(1, msg); - - msg = 'setting _expandedIndex w.r.t full data'; - expect(dataOut[0]._expandedIndex).toEqual(0, msg); - expect(dataOut[1]._expandedIndex).toEqual(1, msg); - }); -}); - -describe('user-defined transforms:', function() { - 'use strict'; - afterEach(destroyGraphDiv); - - it('should pass correctly arguments to transform methods', function() { - var transformIn = { type: 'fake' }; - var transformOut = {}; - - var calledSupplyDefaults = 0; - var calledTransform = 0; - var calledSupplyLayoutDefaults = 0; - - var dataIn = [{ - y: [1, 2, 3], - transforms: [transformIn] - }]; - - var fullData = []; - var layout = {}; - var fullLayout = Lib.extendDeep({}, mockFullLayout); - var transitionData = {}; - - function assertSupplyDefaultsArgs(_transformIn, traceOut, _layout) { - if(!calledSupplyDefaults) { - expect(_transformIn).toBe(transformIn); - } else { - // second supplyDefaults call has _module attached - expect(_transformIn).toEqual(jasmine.objectContaining({ - type: 'fake', - _module: jasmine.objectContaining({name: 'fake'}) - })); - } - expect(_layout).toBe(fullLayout); - - calledSupplyDefaults++; - - return transformOut; - } - - function assertTransformArgs(dataOut, opts) { - expect(dataOut[0]._input).toBe(dataIn[0]); - expect(opts.transform).toBe(transformOut); - expect(opts.fullTrace._input).toBe(dataIn[0]); - expect(opts.layout).toBe(layout); - expect(opts.fullLayout).toBe(fullLayout); - - calledTransform++; - - return dataOut; - } - - function assertSupplyLayoutDefaultsArgs(_layout, _fullLayout, _fullData, _transitionData) { - expect(_layout).toBe(layout); - expect(_fullLayout).toBe(fullLayout); - expect(_fullData).toBe(fullData); - expect(_transitionData).toBe(transitionData); - - calledSupplyLayoutDefaults++; - } - - var fakeTransformModule = { - moduleType: 'transform', - name: 'fake', - attributes: {}, - supplyDefaults: assertSupplyDefaultsArgs, - transform: assertTransformArgs, - supplyLayoutDefaults: assertSupplyLayoutDefaultsArgs - }; - - Plotly.register(fakeTransformModule); - Plots.supplyDataDefaults(dataIn, fullData, layout, fullLayout); - Plots.supplyLayoutModuleDefaults(layout, fullLayout, fullData, transitionData); - delete Plots.transformsRegistry.fake; - expect(calledSupplyDefaults).toBe(2); - expect(calledTransform).toBe(1); - expect(calledSupplyLayoutDefaults).toBe(1); - }); - - it('handles `makesData` transforms when the incoming trace has no data', function(done) { - var transformIn = {type: 'linemaker', x0: 3, y0: 2, x1: 5, y1: 10, n: 3}; - var dataIn = [{transforms: [transformIn], mode: 'lines+markers'}]; - var fullData = []; - var layout = {}; - var fullLayout = Lib.extendDeep({}, mockFullLayout); - - var lineMakerModule = { - moduleType: 'transform', - name: 'linemaker', - makesData: true, - attributes: {}, - supplyDefaults: function(transformIn) { - return Lib.extendFlat({}, transformIn); - }, - transform: function(data, state) { - var transform = state.transform; - var trace = data[0]; - var n = transform.n; - var x = new Array(n); - var y = new Array(n); - - // our exciting transform - make a line! - for(var i = 0; i < n; i++) { - x[i] = transform.x0 + (i / (n - 1)) * (transform.x1 - transform.x0); - y[i] = transform.y0 + (i / (n - 1)) * (transform.y1 - transform.y0); - } - - // we didn't coerce mode before, because there was no data - expect(trace.mode).toBeUndefined(); - expect(trace.line).toBeUndefined(); - expect(trace.marker).toBeUndefined(); - - // just put the input trace back in here, it'll get coerced again after the transform - var traceOut = Lib.extendFlat({}, trace._input, {x: x, y: y}); - - return [traceOut]; - } - }; - - Plotly.register(lineMakerModule); - Plots.supplyDataDefaults(dataIn, fullData, layout, fullLayout); - - expect(fullData.length).toBe(1); - var traceOut = fullData[0]; - expect(traceOut.x).toEqual([3, 4, 5]); - expect(traceOut.y).toEqual([2, 6, 10]); - - // make sure we redid supplyDefaults after the data arrays were added - expect(traceOut.mode).toBe('lines+markers'); - expect(traceOut.line).toBeDefined(); - expect(traceOut.marker).toBeDefined(); - - // make sure plot is really drawn, and changes in the base trace - // are propagated correctly on an edit (either restyle or react) - var gd = createGraphDiv(); - function getLineWidth() { - var line = gd.querySelector('.js-line'); - return line && parseFloat(line.style.strokeWidth); - } - Plotly.newPlot(gd, [{transforms: [transformIn], mode: 'lines+markers'}], layout) - .then(function() { - expect(getLineWidth()).toBe(2); - - return Plotly.restyle(gd, 'line.width', 7); - }) - .then(function() { - expect(getLineWidth()).toBe(7); - - var data2 = [{transforms: [transformIn], mode: 'lines+markers', line: {width: 4}}]; - return Plotly.react(gd, data2, layout); - }) - .then(function() { - expect(getLineWidth()).toBe(4); - }) - .then(function() { - delete Plots.transformsRegistry.linemaker; - done(); - }, done.fail); - }); -}); - -describe('multiple transforms:', function() { - 'use strict'; - - var gd; - - beforeEach(function() { gd = createGraphDiv(); }); - - var mockData0 = [{ - mode: 'markers', - x: [1, -1, -2, 0, 1, 2, 3], - y: [1, 2, 3, 1, 2, 3, 1], - transforms: [{ - type: 'groupby', - groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'], - styles: [{ - target: 'a', - value: {marker: {color: 'red'}} - }, { - target: 'b', - value: {marker: {color: 'blue'}} - }] - }, { - type: 'filter', - operation: '>' - }] - }]; - - var mockData1 = [Lib.extendDeep({}, mockData0[0]), { - mode: 'markers', - x: [20, 11, 12, 0, 1, 2, 3], - y: [1, 2, 3, 2, 5, 2, 0], - transforms: [{ - type: 'groupby', - groups: ['b', 'a', 'b', 'b', 'b', 'a', 'a'], - styles: [{ - target: 'a', - value: {marker: {color: 'green'}} - }, { - target: 'b', - value: {marker: {color: 'black'}} - }] - }, { - type: 'filter', - operation: '<', - value: 10 - }] - }]; - - var mockData2 = [{ - x: [1, 2, 3, 4, 5], - y: [2, 3, 1, 7, 9], - marker: {size: [10, 20, 20, 20, 10]}, - transforms: [ - { - type: 'filter', - operation: '>', - value: 2, - target: 'y' - }, - { - type: 'aggregate', - groups: 'marker.size', - aggregations: [ - {target: 'x', func: 'sum'}, // 20: 6, 10: 5 - {target: 'y', func: 'avg'} // 20: 5, 10: 9 - ] - }, - { - type: 'filter', - operation: '<', - value: 6, - target: 'x' - } - ] - }]; - - afterEach(destroyGraphDiv); - - it('Plotly.newPlot should plot the transform traces - filter|aggregate|filter', function(done) { - var data = Lib.extendDeep([], mockData2); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data.length).toEqual(1); - - // this would be the result if we didn't have a second filter - kept for test case overview - // expect(gd._fullData[0].x).toEqual([6, 5]); - // expect(gd._fullData[0].y).toEqual([5, 9]); - // expect(gd._fullData[0].marker.size).toEqual([20, 10]); - - expect(gd._fullData[0].x).toEqual([5]); - expect(gd._fullData[0].y).toEqual([9]); - expect(gd._fullData[0].marker.size).toEqual([10]); - - expect(gd._fullData[0].transforms[0]._indexToPoints).toEqual({0: [1], 1: [3], 2: [4]}); - expect(gd._fullData[0].transforms[1]._indexToPoints).toEqual({0: [1, 3], 1: [4]}); - expect(gd._fullData[0].transforms[2]._indexToPoints).toEqual({0: [4]}); - }) - .then(done, done.fail); - }); - - - it('Plotly.newPlot should plot the transform traces', function(done) { - var data = Lib.extendDeep([], mockData0); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data.length).toEqual(1); - expect(gd.data[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd.data[0].y).toEqual([1, 2, 3, 1, 2, 3, 1]); - - expect(gd._fullData.length).toEqual(2); - expect(gd._fullData[0].x).toEqual([1, 3]); - expect(gd._fullData[0].y).toEqual([1, 1]); - expect(gd._fullData[1].x).toEqual([1, 2]); - expect(gd._fullData[1].y).toEqual([2, 3]); - - assertDims([2, 2]); - }) - .then(done, done.fail); - }); - - it('Plotly.newPlot should plot the transform traces (reverse case)', function(done) { - var data = Lib.extendDeep([], mockData0); - - data[0].transforms.slice().reverse(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data.length).toEqual(1); - expect(gd.data[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd.data[0].y).toEqual([1, 2, 3, 1, 2, 3, 1]); - - expect(gd._fullData.length).toEqual(2); - expect(gd._fullData[0].x).toEqual([1, 3]); - expect(gd._fullData[0].y).toEqual([1, 1]); - expect(gd._fullData[1].x).toEqual([1, 2]); - expect(gd._fullData[1].y).toEqual([2, 3]); - - assertDims([2, 2]); - }) - .then(done, done.fail); - }); - - it('Plotly.restyle should work', function(done) { - var data = Lib.extendDeep([], mockData0); - data[0].marker = { size: 20 }; - - var dims = [2, 2]; - - Plotly.newPlot(gd, data).then(function() { - assertStyle(dims, - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [1, 1] - ); - - return Plotly.restyle(gd, 'marker.opacity', 0.4); - }).then(function() { - assertStyle(dims, - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [0.4, 0.4] - ); - - expect(gd._fullData[0].marker.opacity).toEqual(0.4); - expect(gd._fullData[1].marker.opacity).toEqual(0.4); - - return Plotly.restyle(gd, 'marker.opacity', 1); - }).then(function() { - assertStyle(dims, - ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [1, 1] - ); - - expect(gd._fullData[0].marker.opacity).toEqual(1); - expect(gd._fullData[1].marker.opacity).toEqual(1); - - return Plotly.restyle(gd, { - 'transforms[0].styles': [[{ - target: 'a', - value: {marker: {color: 'green'}} - }, { - target: 'b', - value: {marker: {color: 'red'}} - }]], - 'marker.opacity': 0.4 - }); - }).then(function() { - assertStyle(dims, - ['rgb(0, 128, 0)', 'rgb(255, 0, 0)'], - [0.4, 0.4] - ); - }) - .then(done, done.fail); - }); - - it('Plotly.extendTraces should work', function(done) { - var data = Lib.extendDeep([], mockData0); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data[0].x.length).toEqual(7); - expect(gd._fullData[0].x.length).toEqual(2); - expect(gd._fullData[1].x.length).toEqual(2); - - assertDims([2, 2]); - - return Plotly.extendTraces(gd, { - x: [ [-3, 4, 5] ], - y: [ [1, -2, 3] ], - 'transforms[0].groups': [ ['b', 'a', 'b'] ] - }, [0]); - }).then(function() { - expect(gd.data[0].x.length).toEqual(10); - expect(gd._fullData[0].x.length).toEqual(3); - expect(gd._fullData[1].x.length).toEqual(3); - - assertDims([3, 3]); - }) - .then(done, done.fail); - }); - - it('Plotly.deleteTraces should work', function(done) { - var data = Lib.extendDeep([], mockData1); - - Plotly.newPlot(gd, data).then(function() { - assertDims([2, 2, 2, 2]); - - return Plotly.deleteTraces(gd, [1]); - }).then(function() { - assertDims([2, 2]); - - return Plotly.deleteTraces(gd, [0]); - }).then(function() { - assertDims([]); - }) - .then(done, done.fail); - }); - - it('toggling trace visibility should work', function(done) { - var data = Lib.extendDeep([], mockData1); - - Plotly.newPlot(gd, data).then(function() { - assertDims([2, 2, 2, 2]); - - return Plotly.restyle(gd, 'visible', 'legendonly', [1]); - }).then(function() { - assertDims([2, 2]); - - return Plotly.restyle(gd, 'visible', false, [0]); - }).then(function() { - assertDims([]); - - return Plotly.restyle(gd, 'visible', [true, true]); - }).then(function() { - assertDims([2, 2, 2, 2]); - }) - .then(done, done.fail); - }); - - it('executes filter and aggregate in the order given', function(done) { - // filter and aggregate do not commute! - - var trace1 = { - x: [0, -5, 7, 4, 5], - y: [2, 4, 6, 8, 10], - transforms: [{ - type: 'aggregate', - groups: [1, 2, 2, 1, 1], - aggregations: [ - {target: 'x', func: 'sum'}, - {target: 'y', func: 'avg'} - ] - }, { - type: 'filter', - target: 'x', - operation: '<', - value: 5 - }] - }; - - var trace2 = Lib.extendDeep({}, trace1); - trace2.transforms.reverse(); - - Plotly.newPlot(gd, [trace1, trace2]).then(function() { - var trace1Out = gd._fullData[0]; - expect(trace1Out.x).toEqual([2]); - expect(trace1Out.y).toEqual([5]); - - var trace2Out = gd._fullData[1]; - expect(trace2Out.x).toEqual([4, -5]); - expect(trace2Out.y).toEqual([5, 4]); - }) - .then(done, done.fail); - }); - - it('always executes groupby before aggregate', function(done) { - // aggregate and groupby wouldn't commute, but groupby always happens first - // because it has a `transform`, and aggregate has a `calcTransform` - - var trace1 = { - x: [1, 2, 3, 4, 5], - y: [2, 4, 6, 8, 10], - transforms: [{ - type: 'groupby', - groups: [1, 1, 2, 2, 2] - }, { - type: 'aggregate', - groups: [1, 2, 2, 1, 1], - aggregations: [ - {target: 'x', func: 'sum'}, - {target: 'y', func: 'avg'} - ] - }] - }; - - var trace2 = Lib.extendDeep({}, trace1); - trace2.transforms.reverse(); - - Plotly.newPlot(gd, [trace1, trace2]).then(function() { - var t1g1 = gd._fullData[0]; - var t1g2 = gd._fullData[1]; - var t2g1 = gd._fullData[2]; - var t2g2 = gd._fullData[3]; - - expect(t1g1.x).toEqual([1, 2]); - expect(t1g1.y).toEqual([2, 4]); - // group 2 has its aggregations switched, since group 2 comes first - expect(t1g2.x).toEqual([3, 9]); - expect(t1g2.y).toEqual([6, 9]); - - // if we had done aggregation first, we'd implicitly get the first val - // for each of the groupby groups, which is [1, 1] - // so we'd only make 1 output trace, and it would look like: - // {x: [10, 5], y: [20/3, 5]} - // (and if we got some other groupby groups values, the most it could do - // is break ^^ into two separate traces) - expect(t2g1.x).toEqual(t1g1.x); - expect(t2g1.y).toEqual(t1g1.y); - expect(t2g2.x).toEqual(t1g2.x); - expect(t2g2.y).toEqual(t1g2.y); - }) - .then(done, done.fail); - }); -}); - -describe('invalid transforms', function() { - var gd; - - beforeEach(function() { - gd = createGraphDiv(); - }); - - afterEach(destroyGraphDiv); - - it('ignores them', function(done) { - Plotly.newPlot(gd, [{ - y: [1, 2, 3], - transforms: [{}] - }]).then(function() { - expect(gd._fullData[0].transforms.length).toEqual(1); - }) - .then(done, done.fail); - }); -}); - -describe('multiple traces with transforms:', function() { - 'use strict'; - - var mockData0 = [{ - mode: 'markers', - x: [1, -1, -2, 0, 1, 2, 3], - y: [1, 2, 3, 1, 2, 3, 1], - marker: { color: 'green' }, - name: 'filtered', - transforms: [{ - type: 'filter', - operation: '>', - value: 1 - }] - }, { - mode: 'markers', - x: [20, 11, 12, 0, 1, 2, 3], - y: [1, 2, 3, 2, 5, 2, 0], - transforms: [{ - type: 'groupby', - groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'], - styles: [{ - target: 'a', - value: {marker: {color: 'red'}}, - }, { - target: 'b', - value: {marker: {color: 'blue'}} - }] - }, { - type: 'filter', - operation: '>' - }] - }]; - - afterEach(destroyGraphDiv); - - it('Plotly.newPlot should plot the transform traces', function(done) { - var data = Lib.extendDeep([], mockData0); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data.length).toEqual(2); - expect(gd.data[0].x).toEqual([1, -1, -2, 0, 1, 2, 3]); - expect(gd.data[0].y).toEqual([1, 2, 3, 1, 2, 3, 1]); - expect(gd.data[1].x).toEqual([20, 11, 12, 0, 1, 2, 3]); - expect(gd.data[1].y).toEqual([1, 2, 3, 2, 5, 2, 0]); - - expect(gd._fullData.length).toEqual(3); - expect(gd._fullData[0].x).toEqual([2, 3]); - expect(gd._fullData[0].y).toEqual([3, 1]); - expect(gd._fullData[1].x).toEqual([20, 11, 3]); - expect(gd._fullData[1].y).toEqual([1, 2, 0]); - expect(gd._fullData[2].x).toEqual([12, 1, 2]); - expect(gd._fullData[2].y).toEqual([3, 5, 2]); - - assertDims([2, 3, 3]); - }) - .then(done, done.fail); - }); - - it('Plotly.restyle should work', function(done) { - var data = Lib.extendDeep([], mockData0); - data[0].marker.size = 20; - - var gd = createGraphDiv(); - var dims = [2, 3, 3]; - - Plotly.newPlot(gd, data).then(function() { - assertStyle(dims, - ['rgb(0, 128, 0)', 'rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [1, 1, 1] - ); - - return Plotly.restyle(gd, 'marker.opacity', 0.4); - }).then(function() { - assertStyle(dims, - ['rgb(0, 128, 0)', 'rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [0.4, 0.4, 0.4] - ); - - gd._fullData.forEach(function(trace) { - expect(trace.marker.opacity).toEqual(0.4); - }); - - return Plotly.restyle(gd, 'marker.opacity', 1); - }).then(function() { - assertStyle(dims, - ['rgb(0, 128, 0)', 'rgb(255, 0, 0)', 'rgb(0, 0, 255)'], - [1, 1, 1] - ); - - gd._fullData.forEach(function(trace) { - expect(trace.marker.opacity).toEqual(1); - }); - - return Plotly.restyle(gd, { - 'transforms[0].styles': [[{ - target: 'a', - value: {marker: {color: 'green'}}, - }, { - target: 'b', - value: {marker: {color: 'red'}} - }]], - 'marker.opacity': [0.4, 0.6] - }); - }).then(function() { - assertStyle(dims, - ['rgb(0, 128, 0)', 'rgb(0, 128, 0)', 'rgb(255, 0, 0)'], - [0.4, 0.6, 0.6] - ); - }) - .then(done, done.fail); - }); - - it('Plotly.extendTraces should work', function(done) { - var data = Lib.extendDeep([], mockData0); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - assertDims([2, 3, 3]); - - return Plotly.extendTraces(gd, { - x: [ [-3, 4, 5] ], - y: [ [1, -2, 3] ], - 'transforms[0].groups': [ ['b', 'a', 'b'] ] - }, [1]); - }).then(function() { - assertDims([2, 4, 4]); - - return Plotly.extendTraces(gd, { - x: [ [5, 7, 10] ], - y: [ [1, -2, 3] ] - }, [0]); - }).then(function() { - assertDims([5, 4, 4]); - }) - .then(done, done.fail); - }); - - it('Plotly.deleteTraces should work', function(done) { - var data = Lib.extendDeep([], mockData0); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - assertDims([2, 3, 3]); - - return Plotly.deleteTraces(gd, [1]); - }).then(function() { - assertDims([2]); - - return Plotly.deleteTraces(gd, [0]); - }).then(function() { - assertDims([]); - }) - .then(done, done.fail); - }); - - it('toggling trace visibility should work', function(done) { - var data = Lib.extendDeep([], mockData0); - - var gd = createGraphDiv(); - - Plotly.newPlot(gd, data).then(function() { - assertDims([2, 3, 3]); - - return Plotly.restyle(gd, 'visible', 'legendonly', [1]); - }).then(function() { - assertDims([2]); - - return Plotly.restyle(gd, 'visible', false, [0]); - }).then(function() { - assertDims([]); - - return Plotly.restyle(gd, 'visible', [true, true]); - }).then(function() { - assertDims([2, 3, 3]); - - return Plotly.restyle(gd, 'visible', 'legendonly', [0]); - }).then(function() { - assertDims([3, 3]); - }) - .then(done, done.fail); - }); -}); - -describe('restyle applied on transforms:', function() { - 'use strict'; - - afterEach(destroyGraphDiv); - - it('should be able', function(done) { - var gd = createGraphDiv(); - - var data = [{ y: [2, 1, 2] }]; - - var transform0 = { - type: 'filter', - target: 'y', - operation: '>', - value: 1 - }; - - var transform1 = { - type: 'groupby', - groups: ['a', 'b', 'b'] - }; - - Plotly.newPlot(gd, data).then(function() { - expect(gd.data.transforms).toBeUndefined(); - - return Plotly.restyle(gd, 'transforms[0]', transform0); - }) - .then(function() { - var msg = 'to generate blank transform objects'; - - expect(gd.data[0].transforms[0]).toBe(transform0, msg); - - // make sure transform actually works - expect(gd._fullData[0].y).toEqual([2, 2], msg); - - return Plotly.restyle(gd, 'transforms[1]', transform1); - }) - .then(function() { - var msg = 'to generate blank transform objects (2)'; - - expect(gd.data[0].transforms[0]).toBe(transform0, msg); - expect(gd.data[0].transforms[1]).toBe(transform1, msg); - expect(gd._fullData[0].y).toEqual([2], msg); - - return Plotly.restyle(gd, 'transforms[0]', null); - }) - .then(function() { - var msg = 'to remove transform objects'; - - expect(gd.data[0].transforms[0]).toBe(transform1, msg); - expect(gd.data[0].transforms[1]).toBeUndefined(msg); - expect(gd._fullData[0].y).toEqual([2], msg); - expect(gd._fullData[1].y).toEqual([1, 2], msg); - - return Plotly.restyle(gd, 'transforms', null); - }) - .then(function() { - var msg = 'to remove all transform objects'; - - expect(gd.data[0].transforms).toBeUndefined(msg); - expect(gd._fullData[0].y).toEqual([2, 1, 2], msg); - }) - .then(done, done.fail); - }); -}); - -describe('supplyDefaults with groupby + filter', function() { - function calcDatatoTrace(calcTrace) { - return calcTrace[0].trace; - } - - function _transform(data, layout) { - var gd = { - data: data, - layout: layout || {} - }; - - supplyAllDefaults(gd); - Plots.doCalcdata(gd); - - return gd.calcdata.map(calcDatatoTrace); - } - - it('filter + groupby with blank target', function() { - var out = _transform([{ - x: [1, 2, 3, 4, 5, 6, 7], - y: [4, 6, 5, 7, 6, 8, 9], - transforms: [{ - type: 'filter', - operation: '<', - value: 6.5 - }, { - type: 'groupby', - groups: [1, 1, 1, 2, 2, 2, 2] - }] - }]); - - expect(out[0].x).toEqual([1, 2, 3]); - expect(out[0].y).toEqual([4, 6, 5]); - - expect(out[1].x).toEqual([4, 5, 6]); - expect(out[1].y).toEqual([7, 6, 8]); - }); - - it('fiter + groupby', function() { - var out = _transform([{ - x: [5, 4, 3], - y: [6, 5, 4], - }, { - x: [1, 2, 3, 4, 5, 6, 7], - y: [4, 6, 5, 7, 8, 9, 10], - transforms: [{ - type: 'filter', - target: [1, 2, 3, 4, 5, 6, 7], - operation: '<', - value: 6.5 - }, { - type: 'groupby', - groups: [1, 1, 1, 2, 2, 2, 2] - }] - }]); - - expect(out[0].x).toEqual([5, 4, 3]); - expect(out[0].y).toEqual([6, 5, 4]); - - expect(out[1].x).toEqual([1, 2, 3]); - expect(out[1].y).toEqual([4, 6, 5]); - - expect(out[2].x).toEqual([4, 5, 6]); - expect(out[2].y).toEqual([7, 8, 9]); - }); - - it('groupby + filter', function() { - var out = _transform([{ - x: [1, 2, 3, 4, 5, 6, 7], - y: [4, 6, 5, 7, 6, 8, 9], - transforms: [{ - type: 'groupby', - groups: [1, 1, 1, 2, 2, 2, 2] - }, { - type: 'filter', - target: [1, 2, 3, 4, 5, 6, 7], - operation: '<', - value: 6.5 - }] - }]); - - expect(out[0].x).toEqual([1, 2, 3]); - expect(out[0].y).toEqual([4, 6, 5]); - - expect(out[1].x).toEqual([4, 5, 6]); - expect(out[1].y).toEqual([7, 6, 8]); - }); - - it('groupby + groupby', function() { - var out = _transform([{ - x: [1, 2, 3, 4, 5, 6, 7, 8], - y: [4, 6, 5, 7, 6, 8, 9, 10], - transforms: [{ - type: 'groupby', - groups: [1, 1, 1, 1, 2, 2, 2, 2] - }, { - type: 'groupby', - groups: [3, 4, 3, 4, 3, 4, 3, 5], - }] - }]); - // | | | | | | | | - // v v v v v v v v - // Trace number: 0 1 0 1 2 3 2 4 - - expect(out.length).toEqual(5); - expect(out[0].x).toEqual([1, 3]); - expect(out[1].x).toEqual([2, 4]); - expect(out[2].x).toEqual([5, 7]); - expect(out[3].x).toEqual([6]); - expect(out[4].x).toEqual([8]); - }); - - it('groupby + groupby + filter', function() { - var out = _transform([{ - x: [1, 2, 3, 4, 5, 6, 7, 8], - y: [4, 6, 5, 7, 6, 8, 9, 10], - transforms: [{ - type: 'groupby', - groups: [1, 1, 1, 1, 2, 2, 2, 2] - }, { - type: 'groupby', - groups: [3, 4, 3, 4, 3, 4, 3, 5], - }, { - type: 'filter', - target: [1, 2, 3, 4, 5, 6, 7, 8], - operation: '<', - value: 4.5 - }] - }]); - // | | | | | | | | - // v v v v v v v v - // Trace number: 0 1 0 1 2 3 2 4 - - expect(out.length).toEqual(5); - expect(out[0].x).toEqual([1, 3]); - expect(out[1].x).toEqual([2, 4]); - expect(out[2].x).toEqual([]); - expect(out[3].x).toEqual([]); - expect(out[4].x).toEqual([]); - }); - - it('fiter + filter', function() { - var out = _transform([{ - x: [1, 2, 3, 4, 5, 6, 7], - y: [4, 6, 5, 7, 8, 9, 10], - transforms: [{ - type: 'filter', - target: [1, 2, 3, 4, 5, 6, 7], - operation: '<', - value: 6.5 - }, { - type: 'filter', - target: [1, 2, 3, 4, 5, 6, 7], - operation: '>', - value: 1.5 - }] - }]); - - expect(out[0].x).toEqual([2, 3, 4, 5, 6]); - expect(out[0].y).toEqual([6, 5, 7, 8, 9]); - }); -}); diff --git a/test/jasmine/tests/transform_sort_test.js b/test/jasmine/tests/transform_sort_test.js deleted file mode 100644 index c9730da3806..00000000000 --- a/test/jasmine/tests/transform_sort_test.js +++ /dev/null @@ -1,430 +0,0 @@ -var Plotly = require('../../../lib/index'); -var Plots = require('../../../src/plots/plots'); -var Lib = require('../../../src/lib'); - -var d3Select = require('../../strict-d3').select; -var createGraphDiv = require('../assets/create_graph_div'); -var destroyGraphDiv = require('../assets/destroy_graph_div'); - -var mouseEvent = require('../assets/mouse_event'); -var supplyAllDefaults = require('../assets/supply_defaults'); - -describe('Test sort transform defaults:', function() { - function _supply(trace, layout) { - layout = layout || {}; - Lib.extendDeep(layout, { - _subplots: {cartesian: ['xy'], xaxis: ['x'], yaxis: ['y']}, - _modules: [], - _basePlotModules: [] - }); - return Plots.supplyTraceDefaults(trace, {type: trace.type || 'scatter'}, 0, layout); - } - - it('should coerce all attributes', function() { - var out = _supply({ - x: [1, 2, 3], - y: [0, 2, 1], - transforms: [{ - type: 'sort', - target: 'marker.size', - order: 'descending' - }] - }); - - expect(out.transforms[0].type).toEqual('sort'); - expect(out.transforms[0].target).toEqual('marker.size'); - expect(out.transforms[0].order).toEqual('descending'); - expect(out.transforms[0].enabled).toBe(true); - }); - - it('should skip unsettable attribute when `enabled: false`', function() { - var out = _supply({ - x: [1, 2, 3], - y: [0, 2, 1], - transforms: [{ - type: 'sort', - enabled: false, - target: 'marker.size', - order: 'descending' - }] - }); - - expect(out.transforms[0].type).toEqual('sort'); - expect(out.transforms[0].target).toBeUndefined(); - expect(out.transforms[0].order).toBeUndefined(); - expect(out.transforms[0].enabled).toBe(false); - }); -}); - -describe('Test sort transform calc:', function() { - var base = { - x: [-2, -1, -2, 0, 1, 3, null, 1], - y: [1, 2, 3, 1, 2, 3, 4, 1], - ids: ['n0', 'n1', 'n2', 'z', 'p1', 'p2', 'n3', 'p3'], - marker: { - color: [0.1, 0.2, 0.3, 0.1, 0.2, 0.3, 0.4, 0.4], - size: [10, 20, 5, 1, 6, 0, 3, 10] - }, - transforms: [{ type: 'sort' }] - }; - - function extend(update) { - return Lib.extendDeep({}, base, update); - } - - function calcDatatoTrace(calcTrace) { - return calcTrace[0].trace; - } - - function _transform(data, layout) { - var gd = { - data: data, - layout: layout || {} - }; - - supplyAllDefaults(gd); - Plots.doCalcdata(gd); - - return gd.calcdata.map(calcDatatoTrace); - } - - it('should sort all array attributes (ascending case)', function() { - var out = _transform([extend({ - transforms: [{ - order: 'ascending' - }] - })]); - - expect(out[0].x).toEqual([-2, -2, -1, 0, 1, 1, 3, null]); - expect(out[0].y).toEqual([1, 3, 2, 1, 2, 1, 3, 4]); - expect(out[0].ids).toEqual(['n0', 'n2', 'n1', 'z', 'p1', 'p3', 'p2', 'n3']); - expect(out[0].marker.color).toEqual([0.1, 0.3, 0.2, 0.1, 0.2, 0.4, 0.3, 0.4]); - expect(out[0].marker.size).toEqual([10, 5, 20, 1, 6, 10, 0, 3]); - expect(out[0].transforms[0]._indexToPoints).toEqual({ - 0: [0], - 1: [2], - 2: [1], - 3: [3], - 4: [4], - 5: [7], - 6: [5], - 7: [6], - }); - }); - - it('should sort all array attributes (descending case)', function() { - var out = _transform([extend({ - transforms: [{ - order: 'descending' - }] - })]); - - expect(out[0].x).toEqual([3, 1, 1, 0, -1, -2, -2, null]); - expect(out[0].y).toEqual([3, 2, 1, 1, 2, 1, 3, 4]); - expect(out[0].ids).toEqual(['p2', 'p1', 'p3', 'z', 'n1', 'n0', 'n2', 'n3']); - expect(out[0].marker.color).toEqual([0.3, 0.2, 0.4, 0.1, 0.2, 0.1, 0.3, 0.4]); - expect(out[0].marker.size).toEqual([0, 6, 10, 1, 20, 10, 5, 3]); - expect(out[0].transforms[0]._indexToPoints).toEqual({ - 0: [5], - 1: [4], - 2: [7], - 3: [3], - 4: [1], - 5: [0], - 6: [2], - 7: [6] - }); - }); - - it('should sort via nested targets', function() { - var out = _transform([extend({ - transforms: [{ - target: 'marker.size', - order: 'descending' - }] - })]); - - expect(out[0].x).toEqual([-1, -2, 1, 1, -2, null, 0, 3]); - expect(out[0].y).toEqual([2, 1, 1, 2, 3, 4, 1, 3]); - expect(out[0].ids).toEqual(['n1', 'n0', 'p3', 'p1', 'n2', 'n3', 'z', 'p2']); - expect(out[0].marker.color).toEqual([0.2, 0.1, 0.4, 0.2, 0.3, 0.4, 0.1, 0.3]); - expect(out[0].marker.size).toEqual([20, 10, 10, 6, 5, 3, 1, 0]); - expect(out[0].transforms[0]._indexToPoints).toEqual({ - 0: [1], - 1: [0], - 2: [7], - 3: [4], - 4: [2], - 5: [6], - 6: [3], - 7: [5], - }); - }); - - it('should sort via dates targets', function() { - var out = _transform([{ - x: ['2015-07-20', '2016-12-02', '2016-09-01', '2016-10-21', '2016-10-20'], - y: [0, 1, 2, 3, 4, 5], - transforms: [{ type: 'sort' }] - }]); - - expect(out[0].x).toEqual([ - '2015-07-20', '2016-09-01', '2016-10-20', '2016-10-21', '2016-12-02' - ]); - expect(out[0].y).toEqual([0, 2, 4, 3, 1]); - }); - - it('should sort via categorical targets', function() { - var trace = extend({ - transforms: [{ target: 'marker.size' }] - }); - trace.x = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']; - - var out = _transform([trace]); - - expect(out[0].x).toEqual(['F', 'D', 'G', 'C', 'E', 'A', 'H', 'B']); - expect(out[0].y).toEqual([3, 1, 4, 3, 2, 1, 1, 2]); - expect(out[0].ids).toEqual(['p2', 'z', 'n3', 'n2', 'p1', 'n0', 'p3', 'n1']); - expect(out[0].marker.size).toEqual([0, 1, 3, 5, 6, 10, 10, 20]); - expect(out[0].marker.color).toEqual([0.3, 0.1, 0.4, 0.3, 0.2, 0.1, 0.4, 0.2]); - }); - - it('should sort via custom targets', function() { - var out = _transform([extend({ - transforms: [{ - target: [10, 20, 30, 10, 20, 30, null, 0] - }] - })]); - - expect(out[0].x).toEqual([1, -2, 0, -1, 1, -2, 3, null]); - expect(out[0].y).toEqual([1, 1, 1, 2, 2, 3, 3, 4]); - expect(out[0].ids).toEqual(['p3', 'n0', 'z', 'n1', 'p1', 'n2', 'p2', 'n3']); - expect(out[0].marker.color).toEqual([0.4, 0.1, 0.1, 0.2, 0.2, 0.3, 0.3, 0.4]); - expect(out[0].marker.size).toEqual([10, 10, 1, 20, 6, 5, 0, 3]); - }); - - it('should truncate transformed arrays to target array length (short target case)', function() { - var out = _transform([ - extend({ - transforms: [{ - order: 'descending', - target: [0, 1] - }] - } - ), extend({ - text: ['A', 'B'], - transforms: [{ target: 'text' }] - })]); - - expect(out[0].x).toEqual([-1, -2]); - expect(out[0].y).toEqual([2, 1]); - expect(out[0].ids).toEqual(['n1', 'n0']); - expect(out[0].marker.color).toEqual([0.2, 0.1]); - expect(out[0].marker.size).toEqual([20, 10]); - expect(out[0]._length).toBe(2); - - expect(out[1].x).toEqual([-2, -1]); - expect(out[1].y).toEqual([1, 2]); - expect(out[1].ids).toEqual(['n0', 'n1']); - expect(out[1].marker.color).toEqual([0.1, 0.2]); - expect(out[1].marker.size).toEqual([10, 20]); - expect(out[1]._length).toBe(2); - }); - - it('should truncate transformed arrays to target array length (long target case)', function() { - var out = _transform([ - extend({ - transforms: [{ - order: 'descending', - target: [0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 3] - }] - } - ), extend({ - text: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], - transforms: [{ target: 'text' }] - })]); - - expect(out[0].x).toEqual([null, -2, 3, -1, 1, -2, 0, 1]); - expect(out[0].y).toEqual([4, 3, 3, 2, 2, 1, 1, 1]); - expect(out[0].ids).toEqual(['n3', 'n2', 'p2', 'n1', 'p1', 'n0', 'z', 'p3']); - expect(out[0].marker.color).toEqual([0.4, 0.3, 0.3, 0.2, 0.2, 0.1, 0.1, 0.4]); - expect(out[0].marker.size).toEqual([3, 5, 0, 20, 6, 10, 1, 10]); - expect(out[0]._length).toBe(8); - - expect(out[1].x).toEqual([-2, -1, -2, 0, 1, 3, null, 1]); - expect(out[1].y).toEqual([1, 2, 3, 1, 2, 3, 4, 1]); - expect(out[1].ids).toEqual(['n0', 'n1', 'n2', 'z', 'p1', 'p2', 'n3', 'p3']); - expect(out[1].marker.color).toEqual([0.1, 0.2, 0.3, 0.1, 0.2, 0.3, 0.4, 0.4]); - expect(out[1].marker.size).toEqual([10, 20, 5, 1, 6, 0, 3, 10]); - expect(out[1]._length).toBe(8); - }); -}); - -describe('Test sort transform interactions:', function() { - afterEach(destroyGraphDiv); - - function _assertFirst(p) { - var parts = d3Select('.point').attr('d').split(',').slice(0, 3).join(','); - expect(parts).toEqual(p); - } - - it('should respond to restyle calls', function(done) { - Plotly.newPlot(createGraphDiv(), [{ - x: [-2, -1, -2, 0, 1, 3, 1], - y: [1, 2, 3, 1, 2, 3, 1], - marker: { - size: [10, 20, 5, 1, 6, 0, 10] - }, - transforms: [{ - type: 'sort', - target: 'marker.size', - }] - }]) - .then(function(gd) { - _assertFirst('M0,0A0,0 0 1'); - - return Plotly.restyle(gd, 'transforms[0].order', 'descending'); - }) - .then(function(gd) { - _assertFirst('M10,0A10,10 0 1'); - - return Plotly.restyle(gd, 'transforms[0].enabled', false); - }) - .then(function(gd) { - _assertFirst('M5,0A5,5 0 1'); - - return Plotly.restyle(gd, 'transforms[0].enabled', true); - }) - .then(function() { - _assertFirst('M10,0A10,10 0 1'); - }) - .then(done, done.fail); - }); - - it('does not preserve event data `pointNumber` value', function(done) { - var gd = createGraphDiv(); - - function getPxPos(gd, id) { - var trace = gd.data[0]; - var fullLayout = gd._fullLayout; - var index = trace.ids.indexOf(id); - - return [ - fullLayout.xaxis.d2p(trace.x[index]), - fullLayout.yaxis.d2p(trace.y[index]) - ]; - } - - function hover(gd, id) { - return new Promise(function(resolve, reject) { - gd.once('plotly_hover', function(eventData) { - Lib.clearThrottle(); - resolve(eventData); - }); - - var pos = getPxPos(gd, id); - mouseEvent('mousemove', pos[0], pos[1]); - - setTimeout(function() { - reject('plotly_hover did not get called!'); - }, 100); - }); - } - - function assertPt(eventData, x, y, pointNumber, id) { - var pt = eventData.points[0]; - - expect(pt.x).toEqual(x, 'x'); - expect(pt.y).toEqual(y, 'y'); - expect(pt.pointNumber).toEqual(pointNumber, 'pointNumber'); - expect(pt.fullData.ids[pt.pointNumber]).toEqual(id, 'id'); - } - - Plotly.newPlot(gd, [{ - mode: 'markers', - x: [-2, -1, -2, 0, 1, 3, 1], - y: [1, 2, 3, 1, 2, 3, 1], - ids: ['A', 'B', 'C', 'D', 'E', 'F', 'G'], - marker: { - size: [10, 20, 5, 1, 6, 0, 10] - }, - transforms: [{ - enabled: false, - type: 'sort', - target: 'marker.size', - }] - }], { - width: 500, - height: 500, - margin: {l: 0, t: 0, r: 0, b: 0}, - hovermode: 'closest' - }) - .then(function() { return hover(gd, 'D'); }) - .then(function(eventData) { - assertPt(eventData, 0, 1, 3, 'D'); - }) - .then(function() { return hover(gd, 'G'); }) - .then(function(eventData) { - assertPt(eventData, 1, 1, 6, 'G'); - }) - .then(function() { - return Plotly.restyle(gd, 'transforms[0].enabled', true); - }) - .then(function() { return hover(gd, 'D'); }) - .then(function(eventData) { - assertPt(eventData, 0, 1, 1, 'D'); - }) - .then(function() { return hover(gd, 'G'); }) - .then(function(eventData) { - assertPt(eventData, 1, 1, 5, 'G'); - }) - .then(function() { - return Plotly.relayout(gd, 'xaxis.range', [-5, 5]); - }) - .then(function() { return hover(gd, 'D'); }) - .then(function(eventData) { - assertPt(eventData, 0, 1, 1, 'D'); - }) - .then(function() { return hover(gd, 'G'); }) - .then(function(eventData) { - assertPt(eventData, 1, 1, 5, 'G'); - }) - .then(done, done.fail); - }); - - it('should honor *categoryarray* when set', function(done) { - var gd = createGraphDiv(); - - Plotly.newPlot(gd, [{ - x: ['C', 'B', 'A'], - y: [3, 1, 2], - marker: { - size: [10, 20, 5] - }, - transforms: [{ - enabled: false, - type: 'sort', - target: [0, 2, 1], - }] - }], { - xaxis: { - categoryorder: 'trace', - categoryarray: ['A', 'B', 'C'] - } - }) - .then(function() { - expect(gd._fullLayout.xaxis._categories).toEqual(['C', 'B', 'A']); - - return Plotly.restyle(gd, 'transforms[0].enabled', true); - }) - .then(function() { - expect(gd._fullLayout.xaxis._categories).toEqual(['C', 'A', 'B']); - - return Plotly.relayout(gd, 'xaxis.categoryorder', 'array'); - }) - .then(function() { - expect(gd._fullLayout.xaxis._categories).toEqual(['A', 'B', 'C']); - }) - .then(done, done.fail); - }); -}); diff --git a/test/jasmine/tests/transition_test.js b/test/jasmine/tests/transition_test.js index ea42d3192b1..4c8858b5c93 100644 --- a/test/jasmine/tests/transition_test.js +++ b/test/jasmine/tests/transition_test.js @@ -193,42 +193,6 @@ describe('Plots.transition', function() { }).then(done, done.fail); }); - - it('with duration:' + transitionDuration + ', transitions a transform', function(done) { - Plotly.restyle(gd, { - 'transforms[0]': { - enabled: true, - type: 'filter', - operation: '<', - target: 'x', - value: 10 - } - }, [0]).then(function() { - expect(gd._fullData[0].transforms).toEqual([jasmine.objectContaining({ - enabled: true, - type: 'filter', - operation: '<', - target: 'x', - value: 10 - })]); - - return Plots.transition(gd, [{ - 'transforms[0].operation': '>' - }], null, [0], - {redraw: true, duration: transitionDuration}, - {duration: transitionDuration, easing: 'cubic-in-out'} - ); - }).then(function() { - expect(gd._fullData[0].transforms).toEqual([jasmine.objectContaining({ - enabled: true, - type: 'filter', - operation: '>', - target: 'x', - value: 10 - })]); - }).then(done, done.fail); - }); - // This doesn't really test anything that the above tests don't cover, but it combines // the behavior and attempts to ensure chaining and events happen in the correct order. it('with duration:' + transitionDuration + ', transitions may be chained', function(done) { diff --git a/test/jasmine/tests/validate_test.js b/test/jasmine/tests/validate_test.js index 13e5d56e3f4..983d6288aaf 100644 --- a/test/jasmine/tests/validate_test.js +++ b/test/jasmine/tests/validate_test.js @@ -339,72 +339,6 @@ describe('Plotly.validate', function() { ); }); - it('should work with attributes in registered transforms', function() { - var base = { - x: [-2, -1, -2, 0, 1, 2, 3], - y: [1, 2, 3, 1, 2, 3, 1], - }; - - var out = Plotly.validate([ - Lib.extendFlat({}, base, { - transforms: [{ - type: 'filter', - operation: '=' - }, { - type: 'filter', - operation: '=', - wrongKey: 'sup?' - }, { - type: 'filter', - operation: 'wrongVal' - }, - 'wont-work' - ] - }), - Lib.extendFlat({}, base, { - transforms: { - type: 'filter' - } - }), - Lib.extendFlat({}, base, { - transforms: [{ - type: 'no gonna work' - }] - }), - ], { - title: { - text: 'my transformed graph' - } - }); - - expect(out.length).toEqual(5); - assertErrorContent( - out[0], 'schema', 'data', 0, - ['transforms', 1, 'wrongKey'], 'transforms[1].wrongKey', - 'In data trace 0, key transforms[1].wrongKey is not part of the schema' - ); - assertErrorContent( - out[1], 'value', 'data', 0, - ['transforms', 2, 'operation'], 'transforms[2].operation', - 'In data trace 0, key transforms[2].operation is set to an invalid value (wrongVal)' - ); - assertErrorContent( - out[2], 'object', 'data', 0, - ['transforms', 3], 'transforms[3]', - 'In data trace 0, key transforms[3] must be linked to an object container' - ); - assertErrorContent( - out[3], 'array', 'data', 1, - ['transforms'], 'transforms', - 'In data trace 1, key transforms must be linked to an array container' - ); - assertErrorContent( - out[4], 'value', 'data', 2, - ['transforms', 0, 'type'], 'transforms[0].type', - 'In data trace 2, key transforms[0].type is set to an invalid value (no gonna work)' - ); - }); - it('should catch input errors for attribute with dynamic defaults', function() { var out = Plotly.validate([ {y: [1, 2]}, @@ -640,27 +574,4 @@ describe('Plotly.validate', function() { }]); expect(out).toBeUndefined(); }); - - it('should not attempt to crawl into nested objects of valType: \'any\' attributes', function() { - var out = Plotly.validate([{ - mode: 'markers', - x: ['a', 'b', 'c', 'a', 'b', 'c'], - y: [1, 2, 3, 4, 5, 6], - transforms: [{ - type: 'groupby', - groups: ['a', 'b', 'c'], - styles: [{ - target: 'a', - value: {marker: {color: 'blue'}} - }, { - target: 'b', - value: {marker: {color: 'red'}} - }, { - target: 'c', - value: {marker: {color: 'black'}} - }] - }] - }]); - expect(out).toBeUndefined(); - }); }); diff --git a/test/jasmine/tests/waterfall_test.js b/test/jasmine/tests/waterfall_test.js index c86f414309d..7b5164a358e 100644 --- a/test/jasmine/tests/waterfall_test.js +++ b/test/jasmine/tests/waterfall_test.js @@ -1045,32 +1045,6 @@ describe('A waterfall plot', function() { .then(done, done.fail); }); - it('should be able to deal with transform that empty out the data coordinate arrays', function(done) { - Plotly.newPlot(gd, { - data: [{ - type: 'waterfall', - x: [1, 2, 3], - xsrc: 'ints', - transforms: [{ - type: 'filter', - target: [1, 2, 3], - targetsrc: 'ints', - operation: '<', - value: 0 - }] - }] - }) - .then(function() { - var traceNodes = getAllTraceNodes(gd); - expect(traceNodes.length).toBe(0); - - expect(gd.calcdata[0][0].x).toEqual(NaN); - expect(gd.calcdata[0][0].y).toEqual(NaN); - expect(gd.calcdata[0][0].isBlank).toBe(undefined); - }) - .then(done, done.fail); - }); - it('should coerce text-related attributes', function(done) { var data = [{ y: [10, 20, 30, 40], diff --git a/test/plot-schema.json b/test/plot-schema.json index 288edc9ad86..4852cce7522 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -216,11 +216,6 @@ "min": 0, "valType": "number" }, - "globalTransforms": { - "description": "Set global transform to be applied to all traces with no specification needed", - "dflt": [], - "valType": "any" - }, "linkText": { "description": "Sets the text appearing in the `showLink` link.", "dflt": "Edit chart", @@ -18322,16 +18317,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "bar", "uid": { "anim": true, @@ -20071,16 +20056,6 @@ "gradians" ] }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "barpolar", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -21441,16 +21416,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "box", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -22276,16 +22241,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "candlestick", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -25359,16 +25314,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "choropleth", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -26644,16 +26589,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "choroplethmap", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -27931,16 +27866,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "choroplethmapbox", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -30880,16 +30805,6 @@ "editType": "plot", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "transpose": { "description": "Transposes the z data.", "dflt": false, @@ -33609,16 +33524,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "densitymap", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -34834,16 +34739,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "densitymapbox", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -36769,16 +36664,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "funnel", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -38144,16 +38029,6 @@ "valType": "string" } }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "funnelarea", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -39437,16 +39312,6 @@ "editType": "plot", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "transpose": { "description": "Transposes the z data.", "dflt": false, @@ -41752,16 +41617,6 @@ "editType": "plot", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "histogram", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -43250,16 +43105,6 @@ "editType": "plot", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "histogram2d", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -44995,16 +44840,6 @@ "editType": "plot", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "histogram2dcontour", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -47316,16 +47151,6 @@ }, "role": "object" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "icicle", "uid": { "anim": true, @@ -49141,16 +48966,6 @@ "valType": "string" } }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "indicator", "uid": { "anim": true, @@ -52849,16 +52664,6 @@ "min": 0, "valType": "number" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "ohlc", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -54209,16 +54014,6 @@ "valType": "integer" } }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "parcats", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -55634,16 +55429,6 @@ "valType": "integer" } }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "parcoords", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -57082,16 +56867,6 @@ "valType": "string" } }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "pie", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -61093,16 +60868,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "scatter", "uid": { "anim": true, @@ -63877,16 +63642,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "scatter3d", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -66244,16 +65999,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "scattercarpet", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -68534,16 +68279,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "scattergeo", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -70843,16 +70578,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "scattergl", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -72549,16 +72274,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "scattermap", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -74096,16 +73811,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "scattermapbox", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -76410,16 +76115,6 @@ "gradians" ] }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "scatterpolar", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -78571,16 +78266,6 @@ "gradians" ] }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "scatterpolargl", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -80861,16 +80546,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "scattersmith", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -83168,16 +82843,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "scatterternary", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -85153,16 +84818,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "splom", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -88521,16 +88176,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "sunburst", "uid": { "anim": true, @@ -93407,16 +93052,6 @@ "valType": "number" } }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "treemap", "uid": { "anim": true, @@ -94731,16 +94366,6 @@ "editType": "none", "valType": "string" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "violin", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -97653,16 +97278,6 @@ }, "role": "object" }, - "transforms": { - "items": { - "transform": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. An array of operations that manipulate the trace data, for example filtering or sorting the data arrays.", - "editType": "calc", - "role": "object" - } - }, - "role": "object" - }, "type": "waterfall", "uid": { "description": "Assign an id to this trace, Use this to provide object constancy between traces during animations and transitions.", @@ -97845,275 +97460,5 @@ }, "type": "waterfall" } - }, - "transforms": { - "aggregate": { - "attributes": { - "aggregations": { - "items": { - "aggregation": { - "editType": "calc", - "enabled": { - "description": "Determines whether this aggregation function is enabled or disabled.", - "dflt": true, - "editType": "calc", - "valType": "boolean" - }, - "func": { - "description": "Sets the aggregation function. All values from the linked `target`, corresponding to the same value in the `groups` array, are collected and reduced by this function. *count* is simply the number of values in the `groups` array, so does not even require the linked array to exist. *first* (*last*) is just the first (last) linked value. Invalid values are ignored, so for example in *avg* they do not contribute to either the numerator or the denominator. Any data type (numeric, date, category) may be aggregated with any function, even though in certain cases it is unlikely to make sense, for example a sum of dates or average of categories. *median* will return the average of the two central values if there is an even count. *mode* will return the first value to reach the maximum count, in case of a tie. *change* will return the difference between the first and last linked values. *range* will return the difference between the min and max linked values.", - "dflt": "first", - "editType": "calc", - "valType": "enumerated", - "values": [ - "count", - "sum", - "avg", - "median", - "mode", - "rms", - "stddev", - "min", - "max", - "first", - "last", - "change", - "range" - ] - }, - "funcmode": { - "description": "*stddev* supports two formula variants: *sample* (normalize by N-1) and *population* (normalize by N).", - "dflt": "sample", - "editType": "calc", - "valType": "enumerated", - "values": [ - "sample", - "population" - ] - }, - "role": "object", - "target": { - "description": "A reference to the data array in the parent trace to aggregate. To aggregate by nested variables, use *.* to access them. For example, set `groups` to *marker.color* to aggregate over the marker color array. The referenced array must already exist, unless `func` is *count*, and each array may only be referenced once.", - "editType": "calc", - "valType": "string" - } - } - }, - "role": "object" - }, - "editType": "calc", - "enabled": { - "description": "Determines whether this aggregate transform is enabled or disabled.", - "dflt": true, - "editType": "calc", - "valType": "boolean" - }, - "groups": { - "arrayOk": true, - "description": "Sets the grouping target to which the aggregation is applied. Data points with matching group values will be coalesced into one point, using the supplied aggregation functions to reduce data in other data arrays. If a string, `groups` is assumed to be a reference to a data array in the parent trace object. To aggregate by nested variables, use *.* to access them. For example, set `groups` to *marker.color* to aggregate about the marker color array. If an array, `groups` is itself the data array by which we aggregate.", - "dflt": "x", - "editType": "calc", - "noBlank": true, - "strict": true, - "valType": "string" - }, - "groupssrc": { - "description": "Sets the source reference on Chart Studio Cloud for `groups`.", - "editType": "none", - "valType": "string" - } - } - }, - "filter": { - "attributes": { - "editType": "calc", - "enabled": { - "description": "Determines whether this filter transform is enabled or disabled.", - "dflt": true, - "editType": "calc", - "valType": "boolean" - }, - "operation": { - "description": "Sets the filter operation. *=* keeps items equal to `value` *!=* keeps items not equal to `value` *<* keeps items less than `value` *<=* keeps items less than or equal to `value` *>* keeps items greater than `value` *>=* keeps items greater than or equal to `value` *[]* keeps items inside `value[0]` to `value[1]` including both bounds *()* keeps items inside `value[0]` to `value[1]` excluding both bounds *[)* keeps items inside `value[0]` to `value[1]` including `value[0]` but excluding `value[1] *(]* keeps items inside `value[0]` to `value[1]` excluding `value[0]` but including `value[1] *][* keeps items outside `value[0]` to `value[1]` and equal to both bounds *)(* keeps items outside `value[0]` to `value[1]` *](* keeps items outside `value[0]` to `value[1]` and equal to `value[0]` *)[* keeps items outside `value[0]` to `value[1]` and equal to `value[1]` *{}* keeps items present in a set of values *}{* keeps items not present in a set of values", - "dflt": "=", - "editType": "calc", - "valType": "enumerated", - "values": [ - "=", - "!=", - "<", - ">=", - ">", - "<=", - "[]", - "()", - "[)", - "(]", - "][", - ")(", - "](", - ")[", - "{}", - "}{" - ] - }, - "preservegaps": { - "description": "Determines whether or not gaps in data arrays produced by the filter operation are preserved. Setting this to *true* might be useful when plotting a line chart with `connectgaps` set to *false*.", - "dflt": false, - "editType": "calc", - "valType": "boolean" - }, - "target": { - "arrayOk": true, - "description": "Sets the filter target by which the filter is applied. If a string, `target` is assumed to be a reference to a data array in the parent trace object. To filter about nested variables, use *.* to access them. For example, set `target` to *marker.color* to filter about the marker color array. If an array, `target` is then the data array by which the filter is applied.", - "dflt": "x", - "editType": "calc", - "noBlank": true, - "strict": true, - "valType": "string" - }, - "targetcalendar": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. Sets the calendar system to use for `target`, if it is an array of dates. If `target` is a string (eg *x*) we use the corresponding trace attribute (eg `xcalendar`) if it exists, even if `targetcalendar` is provided.", - "dflt": "gregorian", - "editType": "calc", - "valType": "enumerated", - "values": [ - "chinese", - "coptic", - "discworld", - "ethiopian", - "gregorian", - "hebrew", - "islamic", - "jalali", - "julian", - "mayan", - "nanakshahi", - "nepali", - "persian", - "taiwan", - "thai", - "ummalqura" - ] - }, - "targetsrc": { - "description": "Sets the source reference on Chart Studio Cloud for `target`.", - "editType": "none", - "valType": "string" - }, - "value": { - "description": "Sets the value or values by which to filter. Values are expected to be in the same type as the data linked to `target`. When `operation` is set to one of the comparison values (=,!=,<,>=,>,<=) `value` is expected to be a number or a string. When `operation` is set to one of the interval values ([],(),[),(],][,)(,](,)[) `value` is expected to be 2-item array where the first item is the lower bound and the second item is the upper bound. When `operation`, is set to one of the set values ({},}{) `value` is expected to be an array with as many items as the desired set elements.", - "dflt": 0, - "editType": "calc", - "valType": "any" - }, - "valuecalendar": { - "description": "WARNING: All transforms are deprecated and may be removed from the API in next major version. Sets the calendar system to use for `value`, if it is a date.", - "dflt": "gregorian", - "editType": "calc", - "valType": "enumerated", - "values": [ - "chinese", - "coptic", - "discworld", - "ethiopian", - "gregorian", - "hebrew", - "islamic", - "jalali", - "julian", - "mayan", - "nanakshahi", - "nepali", - "persian", - "taiwan", - "thai", - "ummalqura" - ] - } - } - }, - "groupby": { - "attributes": { - "editType": "calc", - "enabled": { - "description": "Determines whether this group-by transform is enabled or disabled.", - "dflt": true, - "editType": "calc", - "valType": "boolean" - }, - "groups": { - "description": "Sets the groups in which the trace data will be split. For example, with `x` set to *[1, 2, 3, 4]* and `groups` set to *['a', 'b', 'a', 'b']*, the groupby transform with split in one trace with `x` [1, 3] and one trace with `x` [2, 4].", - "dflt": [], - "editType": "calc", - "valType": "data_array" - }, - "groupssrc": { - "description": "Sets the source reference on Chart Studio Cloud for `groups`.", - "editType": "none", - "valType": "string" - }, - "nameformat": { - "description": "Pattern by which grouped traces are named. If only one trace is present, defaults to the group name (`\"%{group}\"`), otherwise defaults to the group name with trace name (`\"%{group} (%{trace})\"`). Available escape sequences are `%{group}`, which inserts the group name, and `%{trace}`, which inserts the trace name. If grouping GDP data by country when more than one trace is present, for example, the default \"%{group} (%{trace})\" would return \"Monaco (GDP per capita)\".", - "editType": "calc", - "valType": "string" - }, - "styles": { - "items": { - "style": { - "editType": "calc", - "role": "object", - "target": { - "description": "The group value which receives these styles.", - "editType": "calc", - "valType": "string" - }, - "value": { - "_compareAsJSON": true, - "description": "Sets each group styles. For example, with `groups` set to *['a', 'b', 'a', 'b']* and `styles` set to *[{target: 'a', value: { marker: { color: 'red' } }}] marker points in group *'a'* will be drawn in red.", - "dflt": {}, - "editType": "calc", - "valType": "any" - } - } - }, - "role": "object" - } - } - }, - "sort": { - "attributes": { - "editType": "calc", - "enabled": { - "description": "Determines whether this sort transform is enabled or disabled.", - "dflt": true, - "editType": "calc", - "valType": "boolean" - }, - "order": { - "description": "Sets the sort transform order.", - "dflt": "ascending", - "editType": "calc", - "valType": "enumerated", - "values": [ - "ascending", - "descending" - ] - }, - "target": { - "arrayOk": true, - "description": "Sets the target by which the sort transform is applied. If a string, *target* is assumed to be a reference to a data array in the parent trace object. To sort about nested variables, use *.* to access them. For example, set `target` to *marker.size* to sort about the marker size array. If an array, *target* is then the data array by which the sort transform is applied.", - "dflt": "x", - "editType": "calc", - "noBlank": true, - "strict": true, - "valType": "string" - }, - "targetsrc": { - "description": "Sets the source reference on Chart Studio Cloud for `target`.", - "editType": "none", - "valType": "string" - } - } - } } } \ No newline at end of file