From 8e3dc844d16441e62ca0c332a95057b4c42ff46a Mon Sep 17 00:00:00 2001 From: Cindy Zhang Date: Wed, 1 Nov 2017 00:06:50 -0700 Subject: [PATCH] adding traceColorDefaults config --- src/plot_api/helpers.js | 4 ++-- src/plot_api/plot_api.js | 6 ++--- src/plot_api/plot_config.js | 7 +++++- src/plots/plots.js | 5 +++- src/traces/pie/calc.js | 9 +++---- test/image/mocks/trace-color-defaults.json | 21 ++++++++++++++++ test/jasmine/tests/plots_test.js | 28 ++++++++++++++++++++++ 7 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 test/image/mocks/trace-color-defaults.json diff --git a/src/plot_api/helpers.js b/src/plot_api/helpers.js index e27eff1cb9b..46e7ab94dff 100644 --- a/src/plot_api/helpers.js +++ b/src/plot_api/helpers.js @@ -192,7 +192,7 @@ function cleanAxRef(container, attr) { // Make a few changes to the data right away // before it gets used for anything -exports.cleanData = function(data, existingData) { +exports.cleanData = function(data, existingData, traceColors) { // Enforce unique IDs var suids = [], // seen uids --- so we can weed out incoming repeats uids = data.concat(Array.isArray(existingData) ? existingData : []) @@ -229,7 +229,7 @@ exports.cleanData = function(data, existingData) { // error_y.opacity is obsolete - merge into color if(trace.error_y && 'opacity' in trace.error_y) { - var dc = Color.defaults, + var dc = traceColors, yeColor = trace.error_y.color || (Registry.traceIs(trace, 'bar') ? Color.defaultLine : dc[tracei % dc.length]); trace.error_y.color = Color.addOpacity( diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index e4a1e83d9bb..ebd7b398054 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -115,7 +115,7 @@ Plotly.plot = function(gd, data, layout, config) { // if there is already data on the graph, append the new data // if you only want to redraw, pass a non-array for data if(Array.isArray(data)) { - helpers.cleanData(data, gd.data); + helpers.cleanData(data, gd.data, gd._context.traceColorDefaults); if(graphWasEmpty) gd.data = data; else gd.data.push.apply(gd.data, data); @@ -587,7 +587,7 @@ Plotly.redraw = function(gd) { throw new Error('This element is not a Plotly plot: ' + gd); } - helpers.cleanData(gd.data, gd.data); + helpers.cleanData(gd.data, gd.data, gd._context.traceColorDefaults); helpers.cleanLayout(gd.layout); gd.calcdata = undefined; @@ -1045,7 +1045,7 @@ Plotly.addTraces = function addTraces(gd, traces, newIndices) { return Lib.extendFlat({}, trace); }); - helpers.cleanData(traces, gd.data); + helpers.cleanData(traces, gd.data, gd._context.traceColorDefaults); // add the traces to gd.data (no redrawing yet!) for(i = 0; i < traces.length; i++) { diff --git a/src/plot_api/plot_config.js b/src/plot_api/plot_config.js index 27f4735a24e..ed171a93116 100644 --- a/src/plot_api/plot_config.js +++ b/src/plot_api/plot_config.js @@ -16,6 +16,8 @@ * so we get the right experience without any config argument. */ +var Color = require('../components/color'); + module.exports = { // no interactivity, for export or image generation @@ -126,5 +128,8 @@ module.exports = { // Set global transform to be applied to all traces with no // specification needed - globalTransforms: [] + globalTransforms: [], + + // Set the default trace color scheme + traceColorDefaults: Color.defaults }; diff --git a/src/plots/plots.js b/src/plots/plots.js index 03799b4c270..85accedb5f3 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -459,6 +459,8 @@ plots.supplyDefaults = function(gd) { // then do the data newFullLayout._globalTransforms = (gd._context || {}).globalTransforms; + // pass along default trace colors + newFullLayout._traceColors = (gd._context || {}).traceColorDefaults; plots.supplyDataDefaults(newData, newFullData, newLayout, newFullLayout); // attach helper method to check whether a plot type is present on graph @@ -950,8 +952,9 @@ plots.supplyFrameDefaults = function(frameIn) { }; plots.supplyTraceDefaults = function(traceIn, traceOutIndex, layout, traceInIndex) { + var traceColors = layout._traceColors || Color.defaults; var traceOut = {}, - defaultColor = Color.defaults[traceOutIndex % Color.defaults.length]; + defaultColor = traceColors[traceOutIndex % traceColors.length]; function coerce(attr, dflt) { return Lib.coerce(traceIn, traceOut, plots.attributes, attr, dflt); diff --git a/src/traces/pie/calc.js b/src/traces/pie/calc.js index bb425b1a606..cf9542816c6 100644 --- a/src/traces/pie/calc.js +++ b/src/traces/pie/calc.js @@ -25,6 +25,7 @@ module.exports = function calc(gd, trace) { var allThisTraceLabels = {}; var vTotal = 0; var hiddenLabels = fullLayout.hiddenlabels || []; + var traceColors = gd._context.traceColorDefaults; var i, v, label, hidden, pt; @@ -107,7 +108,7 @@ module.exports = function calc(gd, trace) { pt.color = colorMap[pt.label]; } else { - colorMap[pt.label] = pt.color = nextDefaultColor(fullLayout._piedefaultcolorcount); + colorMap[pt.label] = pt.color = nextDefaultColor(fullLayout._piedefaultcolorcount, traceColors); fullLayout._piedefaultcolorcount++; } } @@ -148,10 +149,10 @@ module.exports = function calc(gd, trace) { */ var pieDefaultColors; -function nextDefaultColor(index) { +function nextDefaultColor(index, traceColors) { if(!pieDefaultColors) { // generate this default set on demand (but then it gets saved in the module) - var mainDefaults = Color.defaults; + var mainDefaults = traceColors; pieDefaultColors = mainDefaults.slice(); var i; @@ -160,7 +161,7 @@ function nextDefaultColor(index) { pieDefaultColors.push(tinycolor(mainDefaults[i]).lighten(20).toHexString()); } - for(i = 0; i < Color.defaults.length; i++) { + for(i = 0; i < traceColors.length; i++) { pieDefaultColors.push(tinycolor(mainDefaults[i]).darken(20).toHexString()); } } diff --git a/test/image/mocks/trace-color-defaults.json b/test/image/mocks/trace-color-defaults.json new file mode 100644 index 00000000000..9a4f2fa1922 --- /dev/null +++ b/test/image/mocks/trace-color-defaults.json @@ -0,0 +1,21 @@ +{ + "data": [ + {"y": [8, 7, 7, 6, 5, 4, 4, 3, 2, 2, 3]}, + {"y": [7, 7, 6, 5, 4, 4, 3, 2, 2, 3, 8]}, + {"y": [7, 6, 5, 4, 4, 3, 2, 2, 3, 8, 7]}, + {"y": [6, 5, 4, 4, 3, 2, 2, 3, 8, 7, 7]}, + {"y": [5, 4, 4, 3, 2, 2, 3, 8, 7, 7, 6]} + ], + "layout": { + "title": "Trace Color Defaults" + }, + "config": { + "traceColorDefaults": [ + "#DE5845", + "#E83898", + "#A83DD1", + "#5A38E8", + "#3C71DE" + ] + } +} \ No newline at end of file diff --git a/test/jasmine/tests/plots_test.js b/test/jasmine/tests/plots_test.js index d529b7363ed..39ee98dc277 100644 --- a/test/jasmine/tests/plots_test.js +++ b/test/jasmine/tests/plots_test.js @@ -152,6 +152,17 @@ describe('Test Plots', function() { testSanitizeMarginsHasBeenCalledOnlyOnce(gd); }); + + it('should include the trace color override', function() { + var gd = { + _context: { + traceColorDefaults: ['red', 'yellow', 'blue'] + } + }; + + Plots.supplyDefaults(gd); + expect(gd._fullLayout._traceColors).toBe(gd._context.traceColorDefaults); + }); }); describe('Plots.supplyLayoutGlobalDefaults should', function() { @@ -244,6 +255,23 @@ describe('Test Plots', function() { expect(traceOut.hoverinfo).toEqual('name'); }); }); + + it('should pass defined trace colors to supplyDefaults', function() { + var originalGetModule = Plots.getModule; + var supplyDefaultsSpy; + + spyOn(Plots, 'getModule').and.callFake(function(traceOut) { + var mod = originalGetModule(traceOut); + spyOn(mod, 'supplyDefaults').and.callThrough(); + supplyDefaultsSpy = mod.supplyDefaults; + return mod; + }); + + layout._traceColors = ['red', 'yellow', 'blue']; + traceIn = {}; + traceOut = supplyTraceDefaults(traceIn, 0, layout); + expect(supplyDefaultsSpy).toHaveBeenCalledWith(traceIn, traceOut, 'red', layout); + }); }); describe('Plots.supplyTransformDefaults', function() {