Skip to content

Commit b53197b

Browse files
authored
Merge pull request #1794 from plotly/transform-style-rework-2
Rework transform style into array syntax
2 parents 2940d95 + 836f412 commit b53197b

File tree

5 files changed

+213
-49
lines changed

5 files changed

+213
-49
lines changed

src/plot_api/helpers.js

+30-11
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,6 @@ function cleanAxRef(container, attr) {
215215
// Make a few changes to the data right away
216216
// before it gets used for anything
217217
exports.cleanData = function(data, existingData) {
218-
219218
// Enforce unique IDs
220219
var suids = [], // seen uids --- so we can weed out incoming repeats
221220
uids = data.concat(Array.isArray(existingData) ? existingData : [])
@@ -348,18 +347,38 @@ exports.cleanData = function(data, existingData) {
348347

349348
if(!Lib.isPlainObject(transform)) continue;
350349

351-
if(transform.type === 'filter') {
352-
if(transform.filtersrc) {
353-
transform.target = transform.filtersrc;
354-
delete transform.filtersrc;
355-
}
350+
switch(transform.type) {
351+
case 'filter':
352+
if(transform.filtersrc) {
353+
transform.target = transform.filtersrc;
354+
delete transform.filtersrc;
355+
}
356356

357-
if(transform.calendar) {
358-
if(!transform.valuecalendar) {
359-
transform.valuecalendar = transform.calendar;
357+
if(transform.calendar) {
358+
if(!transform.valuecalendar) {
359+
transform.valuecalendar = transform.calendar;
360+
}
361+
delete transform.calendar;
362+
}
363+
break;
364+
365+
case 'groupby':
366+
// Name has changed from `style` to `styles`, so use `style` but prefer `styles`:
367+
transform.styles = transform.styles || transform.style;
368+
369+
if(transform.styles && !Array.isArray(transform.styles)) {
370+
var prevStyles = transform.styles;
371+
var styleKeys = Object.keys(prevStyles);
372+
373+
transform.styles = [];
374+
for(var j = 0; j < styleKeys.length; j++) {
375+
transform.styles.push({
376+
target: styleKeys[j],
377+
value: prevStyles[styleKeys[j]]
378+
});
379+
}
360380
}
361-
delete transform.calendar;
362-
}
381+
break;
363382
}
364383
}
365384
}

src/transforms/groupby.js

+41-14
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,26 @@ exports.attributes = {
3434
'with `x` [1, 3] and one trace with `x` [2, 4].'
3535
].join(' ')
3636
},
37-
style: {
38-
valType: 'any',
39-
dflt: {},
40-
description: [
41-
'Sets each group style.',
42-
'For example, with `groups` set to *[\'a\', \'b\', \'a\', \'b\']*',
43-
'and `style` set to *{ a: { marker: { color: \'red\' } }}',
44-
'marker points in group *\'a\'* will be drawn in red.'
45-
].join(' ')
37+
styles: {
38+
_isLinkedToArray: 'style',
39+
target: {
40+
valType: 'string',
41+
role: 'info',
42+
description: [
43+
'The group value which receives these styles.'
44+
].join(' ')
45+
},
46+
value: {
47+
valType: 'any',
48+
role: 'info',
49+
dflt: {},
50+
description: [
51+
'Sets each group styles.',
52+
'For example, with `groups` set to *[\'a\', \'b\', \'a\', \'b\']*',
53+
'and `styles` set to *[{target: \'a\', value: { marker: { color: \'red\' } }}]',
54+
'marker points in group *\'a\'* will be drawn in red.'
55+
].join(' ')
56+
},
4657
}
4758
};
4859

@@ -71,11 +82,22 @@ exports.supplyDefaults = function(transformIn) {
7182
if(!enabled) return transformOut;
7283

7384
coerce('groups');
74-
coerce('style');
85+
86+
var styleIn = transformIn.styles;
87+
var styleOut = transformOut.styles = [];
88+
89+
if(styleIn) {
90+
for(var i = 0; i < styleIn.length; i++) {
91+
styleOut[i] = {};
92+
Lib.coerce(styleIn[i], styleOut[i], exports.attributes.styles, 'target');
93+
Lib.coerce(styleIn[i], styleOut[i], exports.attributes.styles, 'value');
94+
}
95+
}
7596

7697
return transformOut;
7798
};
7899

100+
79101
/**
80102
* Apply transform !!!
81103
*
@@ -115,6 +137,7 @@ function pasteArray(newTrace, trace, j, a) {
115137
}
116138

117139
function transformOne(trace, state) {
140+
var i;
118141
var opts = state.transform;
119142
var groups = trace.transforms[state.transformIndex].groups;
120143

@@ -128,9 +151,13 @@ function transformOne(trace, state) {
128151

129152
var arrayAttrs = PlotSchema.findArrayAttributes(trace);
130153

131-
var style = opts.style || {};
154+
var styles = opts.styles || [];
155+
var styleLookup = {};
156+
for(i = 0; i < styles.length; i++) {
157+
styleLookup[styles[i].target] = styles[i].value;
158+
}
132159

133-
for(var i = 0; i < groupNames.length; i++) {
160+
for(i = 0; i < groupNames.length; i++) {
134161
var groupName = groupNames[i];
135162

136163
var newTrace = newData[i] = Lib.extendDeepNoArrays({}, trace);
@@ -145,9 +172,9 @@ function transformOne(trace, state) {
145172

146173
newTrace.name = groupName;
147174

148-
// there's no need to coerce style[groupName] here
175+
// there's no need to coerce styleLookup[groupName] here
149176
// as another round of supplyDefaults is done on the transformed traces
150-
newTrace = Lib.extendDeepNoArrays(newTrace, style[groupName] || {});
177+
newTrace = Lib.extendDeepNoArrays(newTrace, styleLookup[groupName] || {});
151178
}
152179

153180
return newData;

test/jasmine/tests/plotschema_test.js

+7
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,13 @@ describe('plot schema', function() {
188188
});
189189
});
190190

191+
it('should work with registered transforms (2)', function() {
192+
var valObjects = plotSchema.transforms.groupby.attributes;
193+
var items = valObjects.styles.items || {};
194+
195+
expect(Object.keys(items)).toEqual(['style']);
196+
});
197+
191198
it('should work with registered components', function() {
192199
expect(plotSchema.traces.scatter.attributes.xcalendar.valType).toEqual('enumerated');
193200
expect(plotSchema.traces.scatter3d.attributes.zcalendar.valType).toEqual('enumerated');

test/jasmine/tests/transform_groupby_test.js

+100-19
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ var destroyGraphDiv = require('../assets/destroy_graph_div');
66
var assertDims = require('../assets/assert_dims');
77
var assertStyle = require('../assets/assert_style');
88

9-
109
describe('groupby', function() {
1110

1211
describe('one-to-many transforms:', function() {
@@ -19,7 +18,10 @@ describe('groupby', function() {
1918
transforms: [{
2019
type: 'groupby',
2120
groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'],
22-
style: { a: {marker: {color: 'red'}}, b: {marker: {color: 'blue'}} }
21+
styles: [
22+
{target: 'a', value: {marker: {color: 'red'}}},
23+
{target: 'b', value: {marker: {color: 'blue'}}}
24+
]
2325
}]
2426
}];
2527

@@ -30,7 +32,10 @@ describe('groupby', function() {
3032
transforms: [{
3133
type: 'groupby',
3234
groups: ['b', 'a', 'b', 'b', 'b', 'a', 'a'],
33-
style: { a: {marker: {color: 'green'}}, b: {marker: {color: 'black'}} }
35+
styles: [
36+
{target: 'a', value: {marker: {color: 'green'}}},
37+
{target: 'b', value: {marker: {color: 'black'}}}
38+
]
3439
}]
3540
}];
3641

@@ -58,6 +63,58 @@ describe('groupby', function() {
5863
});
5964
});
6065

66+
it('Accepts deprecated object notation for styles', function(done) {
67+
var oldStyleMockData = [{
68+
mode: 'markers',
69+
x: [1, -1, -2, 0, 1, 2, 3],
70+
y: [1, 2, 3, 1, 2, 3, 1],
71+
transforms: [{
72+
type: 'groupby',
73+
groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'],
74+
styles: {
75+
a: {marker: {color: 'red'}},
76+
b: {marker: {color: 'blue'}}
77+
}
78+
}]
79+
}];
80+
var data = Lib.extendDeep([], oldStyleMockData);
81+
data[0].marker = { size: 20 };
82+
83+
var gd = createGraphDiv();
84+
var dims = [4, 3];
85+
86+
Plotly.plot(gd, data).then(function() {
87+
assertStyle(dims,
88+
['rgb(255, 0, 0)', 'rgb(0, 0, 255)'],
89+
[1, 1]
90+
);
91+
92+
return Plotly.restyle(gd, 'marker.opacity', 0.4);
93+
}).then(function() {
94+
assertStyle(dims,
95+
['rgb(255, 0, 0)', 'rgb(0, 0, 255)'],
96+
[0.4, 0.4]
97+
);
98+
99+
expect(gd._fullData[0].marker.opacity).toEqual(0.4);
100+
expect(gd._fullData[1].marker.opacity).toEqual(0.4);
101+
102+
return Plotly.restyle(gd, 'marker.opacity', 1);
103+
}).then(function() {
104+
assertStyle(dims,
105+
['rgb(255, 0, 0)', 'rgb(0, 0, 255)'],
106+
[1, 1]
107+
);
108+
109+
expect(gd._fullData[0].marker.opacity).toEqual(1);
110+
expect(gd._fullData[1].marker.opacity).toEqual(1);
111+
}).then(done);
112+
113+
// The final test for restyle updates using deprecated syntax
114+
// is ommitted since old style syntax is *only* sanitized on
115+
// initial plot, *not* on restyle.
116+
});
117+
61118
it('Plotly.restyle should work', function(done) {
62119
var data = Lib.extendDeep([], mockData0);
63120
data[0].marker = { size: 20 };
@@ -92,7 +149,10 @@ describe('groupby', function() {
92149
expect(gd._fullData[1].marker.opacity).toEqual(1);
93150

94151
return Plotly.restyle(gd, {
95-
'transforms[0].style': { a: {marker: {color: 'green'}}, b: {marker: {color: 'red'}} },
152+
'transforms[0].styles': [[
153+
{target: 'a', value: {marker: {color: 'green'}}},
154+
{target: 'b', value: {marker: {color: 'red'}}}
155+
]],
96156
'marker.opacity': 0.4
97157
});
98158
}).then(function() {
@@ -192,7 +252,10 @@ describe('groupby', function() {
192252
transforms: [{
193253
type: 'groupby',
194254
groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'],
195-
style: { a: {marker: {color: 'red'}}, b: {marker: {color: 'blue'}} }
255+
styles: [
256+
{target: 'a', value: {marker: {color: 'red'}}},
257+
{target: 'b', value: {marker: {color: 'blue'}}}
258+
]
196259
}]
197260
}];
198261

@@ -387,7 +450,10 @@ describe('groupby', function() {
387450
transforms: [{
388451
type: 'groupby',
389452
groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'],
390-
style: { a: {marker: {color: 'red'}}, b: {marker: {color: 'blue'}} }
453+
styles: [
454+
{target: 'a', value: {marker: {color: 'red'}}},
455+
{target: 'b', value: {marker: {color: 'blue'}}}
456+
]
391457
}]
392458
}];
393459

@@ -401,17 +467,20 @@ describe('groupby', function() {
401467
transforms: [{
402468
type: 'groupby',
403469
groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'],
404-
style: {
405-
a: {
470+
styles: [{
471+
target: 'a',
472+
value: {
406473
marker: {
407474
color: 'orange',
408475
size: 20,
409476
line: {
410477
color: 'red'
411478
}
412479
}
413-
},
414-
b: {
480+
}
481+
}, {
482+
target: 'b',
483+
value: {
415484
mode: 'markers+lines', // heterogeonos attributes are OK: group 'a' doesn't need to define this
416485
marker: {
417486
color: 'cyan',
@@ -426,7 +495,7 @@ describe('groupby', function() {
426495
color: 'purple'
427496
}
428497
}
429-
}
498+
}]
430499
}]
431500
}];
432501

@@ -447,11 +516,14 @@ describe('groupby', function() {
447516
transforms: [{
448517
type: 'groupby',
449518
groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'],
450-
style: {
451-
a: {marker: {size: 30}},
519+
styles: [{
520+
target: 'a',
521+
value: {marker: {size: 30}}
522+
}, {
452523
// override general color:
453-
b: {marker: {size: 15, line: {color: 'yellow'}}, line: {color: 'purple'}}
454-
}
524+
target: 'b',
525+
value: {marker: {size: 15, line: {color: 'yellow'}}, line: {color: 'purple'}}
526+
}]
455527
}]
456528
}];
457529

@@ -464,7 +536,7 @@ describe('groupby', function() {
464536
transforms: [{
465537
type: 'groupby',
466538
groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'],
467-
style: {/* can be empty, or of partial group id coverage */}
539+
styles: [/* can be empty, or of partial group id coverage */]
468540
}]
469541
}];
470542

@@ -548,7 +620,10 @@ describe('groupby', function() {
548620
transforms: [{
549621
type: 'groupby',
550622
// groups: ['a', 'a', 'b', 'a', 'b', 'b', 'a'],
551-
style: { a: {marker: {color: 'red'}}, b: {marker: {color: 'blue'}} }
623+
styles: [
624+
{target: 'a', value: {marker: {color: 'red'}}},
625+
{target: 'b', value: {marker: {color: 'blue'}}}
626+
]
552627
}]
553628
}];
554629

@@ -561,7 +636,10 @@ describe('groupby', function() {
561636
transforms: [{
562637
type: 'groupby',
563638
groups: [],
564-
style: { a: {marker: {color: 'red'}}, b: {marker: {color: 'blue'}} }
639+
styles: [
640+
{target: 'a', value: {marker: {color: 'red'}}},
641+
{target: 'b', value: {marker: {color: 'blue'}}}
642+
]
565643
}]
566644
}];
567645

@@ -574,7 +652,10 @@ describe('groupby', function() {
574652
transforms: [{
575653
type: 'groupby',
576654
groups: null,
577-
style: { a: {marker: {color: 'red'}}, b: {marker: {color: 'blue'}} }
655+
styles: [
656+
{target: 'a', value: {marker: {color: 'red'}}},
657+
{target: 'b', value: {marker: {color: 'blue'}}}
658+
]
578659
}]
579660
}];
580661

0 commit comments

Comments
 (0)