Skip to content

Commit 2ba2ecd

Browse files
authored
Merge pull request #593 from plotly/marker-color
Marker color
2 parents 9d20d69 + 0f25c71 commit 2ba2ecd

File tree

12 files changed

+216
-34
lines changed

12 files changed

+216
-34
lines changed

src/components/containers/ShapeAccordion.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import TraceRequiredPanel from './TraceRequiredPanel';
33
import PropTypes from 'prop-types';
44
import React, {Component} from 'react';
55
import {connectShapeToLayout} from 'lib';
6+
import {COLORS} from 'lib/constants';
67

78
const ShapeFold = connectShapeToLayout(PlotlyFold);
89

@@ -35,8 +36,8 @@ class ShapeAccordion extends Component {
3536
const key = `shapes[${shapeIndex}]`;
3637
const value = {
3738
text: `${_('Shape')} ${shapeIndex}`,
38-
line: {color: '#444444'},
39-
fillcolor: '#7F7F7F',
39+
line: {color: COLORS.charcoal},
40+
fillcolor: COLORS.middleGray,
4041
opacity: 0.3,
4142
};
4243

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import Field from './Field';
2+
import PropTypes from 'prop-types';
3+
import React, {Component} from 'react';
4+
import {connectToContainer} from 'lib';
5+
import RadioBlocks from '../widgets/RadioBlocks';
6+
import Color from './Color';
7+
import DataSelector from './DataSelector';
8+
import Colorscale from './Colorscale';
9+
import {MULTI_VALUED, COLORS} from 'lib/constants';
10+
11+
class UnconnectedMarkerColor extends Component {
12+
constructor(props, context) {
13+
super(props, context);
14+
15+
let type = null;
16+
if (
17+
!props.container.marker ||
18+
(props.container.marker && !props.container.marker.colorsrc)
19+
) {
20+
type = 'constant';
21+
} else if (
22+
props.container.marker &&
23+
Array.isArray(props.container.marker.color) &&
24+
props.fullContainer.marker &&
25+
Array.isArray(props.fullContainer.marker.color)
26+
) {
27+
type = 'variable';
28+
}
29+
30+
this.state = {
31+
type,
32+
value: {
33+
constant: type === 'constant' ? props.fullValue : COLORS.mutedBlue,
34+
variable: type === 'variable' ? props.fullValue : null,
35+
},
36+
};
37+
38+
this.setType = this.setType.bind(this);
39+
this.setValue = this.setValue.bind(this);
40+
this.setColorScale = this.setColorScale.bind(this);
41+
}
42+
43+
setType(type) {
44+
this.setState({type: type});
45+
this.props.updatePlot(this.state.value[type]);
46+
if (type === 'constant') {
47+
this.context.updateContainer({
48+
['marker.colorsrc']: null,
49+
['marker.colorscale']: null,
50+
});
51+
this.setState({colorscale: null});
52+
} else {
53+
this.context.updateContainer({
54+
['marker.color']: null,
55+
['marker.colorsrc']: null,
56+
['marker.colorscale']: [],
57+
});
58+
}
59+
}
60+
61+
setValue(inputValue) {
62+
const {type} = this.state;
63+
64+
this.setState(
65+
type === 'constant'
66+
? {value: {constant: inputValue}}
67+
: {value: {variable: inputValue}}
68+
);
69+
this.props.updatePlot(inputValue);
70+
}
71+
72+
setColorScale(inputValue) {
73+
this.setState({colorscale: inputValue});
74+
this.context.updateContainer({['marker.colorscale']: inputValue});
75+
}
76+
77+
render() {
78+
const {attr, fullValue, container} = this.props;
79+
const {localize: _} = this.context;
80+
const {type, value, colorscale} = this.state;
81+
const options = [
82+
{label: _('Constant'), value: 'constant'},
83+
{label: _('Variable'), value: 'variable'},
84+
];
85+
const multiValued =
86+
this.props.multiValued ||
87+
(Array.isArray(fullValue) && fullValue.includes(MULTI_VALUED)) ||
88+
(container.marker && container.marker.colorscale === MULTI_VALUED) ||
89+
(container.marker && container.marker.colorsrc === MULTI_VALUED) ||
90+
(container.marker &&
91+
container.marker.color &&
92+
Array.isArray(container.marker.color) &&
93+
container.marker.color.includes(MULTI_VALUED));
94+
95+
return (
96+
<div>
97+
<Field {...this.props} multiValued={multiValued} attr={attr}>
98+
<RadioBlocks
99+
options={options}
100+
activeOption={type}
101+
onOptionChange={this.setType}
102+
/>
103+
{!type ? null : type === 'constant' ? (
104+
<Color
105+
suppressMultiValuedMessage
106+
attr="marker.color"
107+
updatePlot={this.setValue}
108+
fullValue={value.constant}
109+
/>
110+
) : container.marker &&
111+
container.marker.colorsrc === MULTI_VALUED ? null : (
112+
<div>
113+
<DataSelector suppressMultiValuedMessage attr="marker.color" />
114+
{container.marker &&
115+
container.marker.colorscale === MULTI_VALUED ? null : (
116+
<Colorscale
117+
suppressMultiValuedMessage
118+
attr="marker.colorscale"
119+
updatePlot={this.setColorScale}
120+
colorscale={colorscale}
121+
/>
122+
)}
123+
</div>
124+
)}
125+
</Field>
126+
</div>
127+
);
128+
}
129+
}
130+
131+
UnconnectedMarkerColor.propTypes = {
132+
fullValue: PropTypes.any,
133+
updatePlot: PropTypes.func,
134+
...Field.propTypes,
135+
};
136+
137+
UnconnectedMarkerColor.contextTypes = {
138+
localize: PropTypes.func,
139+
updateContainer: PropTypes.func,
140+
};
141+
142+
export default connectToContainer(UnconnectedMarkerColor);

src/components/fields/SymbolSelector.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import React, {Component} from 'react';
44
import SymbolSelectorWidget from '../widgets/SymbolSelector';
55
import nestedProperty from 'plotly.js/src/lib/nested_property';
66
import {connectToContainer, tooLight} from 'lib';
7-
import {MULTI_VALUED} from '../../lib/constants';
7+
import {MULTI_VALUED, COLORS} from 'lib/constants';
88

99
// TODO compute these from plotly.js
1010
const SYMBOLS = [
@@ -373,6 +373,9 @@ class SymbolSelector extends Component {
373373
if (this.markerColor === MULTI_VALUED) {
374374
this.markerColor = nestedProperty(defaultContainer, 'marker.color').get();
375375
}
376+
this.markerColor = Array.isArray(this.markerColor)
377+
? COLORS.mutedBlue
378+
: this.markerColor;
376379

377380
this.borderColor = this.markerColor;
378381
if (this.borderWidth) {
@@ -388,6 +391,10 @@ class SymbolSelector extends Component {
388391
}
389392
}
390393

394+
this.borderColor = Array.isArray(this.borderColor)
395+
? COLORS.charcoal
396+
: this.borderColor;
397+
391398
if (this.props.is3D) {
392399
this.symbolOptions = SYMBOLS.filter(option => {
393400
return option.threeD;

src/components/fields/lineSelectors.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
33
import React, {Component} from 'react';
44
import nestedProperty from 'plotly.js/src/lib/nested_property';
55
import {tooLight} from 'lib';
6+
import {COLORS} from 'lib/constants';
67

78
/* eslint-disable react/prop-types */
89
const styledRenderer = ({label}) => {
@@ -36,9 +37,7 @@ const strokeShapes = [
3637

3738
const strokeStyle = {fill: 'none', strokeWidth: '4px'};
3839

39-
const mutedBlue = '#1f77b4';
40-
41-
const computeOptions = (strokeData, stroke = mutedBlue) =>
40+
const computeOptions = (strokeData, stroke = COLORS.mutedBlue) =>
4241
strokeData.map(({value, strokeDasharray, d = 'M0,8h100'}) => ({
4342
label: <path d={d} style={{...strokeStyle, stroke, strokeDasharray}} />,
4443
value,

src/components/widgets/ColorPicker.js

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,7 @@ import {
1010
Checkboard,
1111
} from 'react-color/lib/components/common';
1212
import {CustomPicker as customPicker} from 'react-color';
13-
14-
/* eslint-disable no-inline-comments */
15-
const defaultColors = [
16-
'#444444',
17-
'#ffffff',
18-
'#1f77b4', // muted blue
19-
'#ff7f0e', // safety orange
20-
'#2ca02c', // cooked asparagus green
21-
'#d62728', // brick red
22-
'#9467bd', // muted purple
23-
'#8c564b', // chestnut brown
24-
'#e377c2', // raspberry yogurt pink
25-
'#7f7f7f', // middle gray
26-
'#bcbd22', // curry yellow-green
27-
'#17becf', // blue-teal
28-
];
29-
/* eslint-enable no-inline-comments */
13+
import {DEFAULT_COLORS} from 'lib/constants';
3014

3115
// Utility functions for converting ColorPicker color objects or raw strings
3216
// into TinyColor objects.
@@ -73,7 +57,7 @@ class Custom extends Component {
7357
<div>
7458
<p className="colorpicker__title">{_('Default Colors')}</p>
7559
<div className="colorpicker__preset-colors">
76-
<PresetColors colors={defaultColors} onClick={onChangeComplete} />
60+
<PresetColors colors={DEFAULT_COLORS} onClick={onChangeComplete} />
7761
</div>
7862
</div>
7963
</div>
@@ -108,7 +92,6 @@ class ColorPicker extends Component {
10892
// We use our own toTinyColor because this value is a ColorPicker
10993
// color value which is an object that needs unpacking. We also handle
11094
// the case where a color string is passed in (just in case).
111-
11295
const color = toTinyColor(newColor);
11396

11497
// relayout call only wants a RGB String

src/components/widgets/text_editors/RichText/configuration.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22
import {INLINE_STYLE} from 'draft-js-utils';
33
import {LinkIcon} from 'plotly-icons';
4+
import {COLORS} from 'lib/constants';
45

56
export const SUPERSCRIPT = 'SUPERSCRIPT';
67
export const SUBSCRIPT = 'SUBSCRIPT';
@@ -46,7 +47,7 @@ export const STYLE_MAP = {
4647
top: '-5px',
4748
},
4849
[LINK]: {
49-
color: '#447bdc',
50+
color: COLORS.editorLink,
5051
linkDecoration: 'none',
5152
cursor: 'pointer',
5253
},

src/default_panels/GraphCreatePanel.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,6 @@ const GraphCreatePanel = (props, {localize: _}) => {
205205
/>
206206
</LayoutSection>
207207
<Numeric label={_('Sum')} step={10} attr="sum" />
208-
<DataSelector label={_('Color')} attr="marker.color" />
209208
<Radio
210209
label={_('Transpose')}
211210
attr="transpose"

src/default_panels/StyleTracesPanel.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
BinningDropdown,
3333
NumericReciprocal,
3434
} from '../components/fields/derived';
35+
import MarkerColor from '../components/fields/MarkerColor';
3536

3637
const StyleTracesPanel = (props, {localize: _}) => (
3738
<TraceAccordion canGroup>
@@ -223,8 +224,7 @@ const StyleTracesPanel = (props, {localize: _}) => (
223224
/>
224225
<NumericFraction label={_('Jitter')} attr="jitter" />
225226
<Numeric label={_('Position')} attr="pointpos" step={0.1} showSlider />
226-
<ColorscalePicker label={_('Colorscale')} attr="marker.colorscale" />
227-
<ColorPicker label={_('Color')} attr="marker.color" />
227+
<MarkerColor label={_('Color')} attr="marker.color" />
228228
<NumericFraction label={_('Opacity')} attr="marker.opacity" />
229229
<MarkerSize label={_('Size')} attr="marker.size" />
230230
<Radio

src/lib/constants.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,35 @@ export const TRACE_TO_AXIS = {
7777
};
7878

7979
export const TRANSFORMS_LIST = ['filter', 'groupby', 'aggregate'];
80+
81+
export const COLORS = {
82+
charcoal: '#444444',
83+
white: '#ffffff',
84+
mutedBlue: '#1f77b4',
85+
safetyOrange: '#ff7f0e',
86+
cookedAsparagusGreen: '#2ca02c',
87+
brickRed: '#d62728',
88+
mutedPurple: '#9467bd',
89+
chestnutBrown: '#8c564b',
90+
raspberryYogurtPink: '#e377c2',
91+
middleGray: '#7f7f7f',
92+
curryYellowGreen: '#bcbd22',
93+
blueTeal: '#17becf',
94+
editorLink: '#447bdc',
95+
black: '#000000',
96+
};
97+
98+
export const DEFAULT_COLORS = [
99+
COLORS.charcoal,
100+
COLORS.white,
101+
COLORS.mutedBlue,
102+
COLORS.safetyOrange,
103+
COLORS.cookedAsparagusGreen,
104+
COLORS.brickRed,
105+
COLORS.mutedPurple,
106+
COLORS.chestnutBrown,
107+
COLORS.raspberryYogurtPink,
108+
COLORS.middleGray,
109+
COLORS.curryYellowGreen,
110+
COLORS.blueTeal,
111+
];

src/lib/customTraceType.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import {COLORS} from 'lib/constants';
2+
13
export function plotlyTraceToCustomTrace(trace) {
24
const gl = 'gl';
35
const type = trace.type
@@ -37,18 +39,18 @@ export function traceTypeToPlotlyInitFigure(traceType, gl = '') {
3739
case 'ohlc':
3840
return {
3941
type: 'ohlc',
40-
decreasing: {line: {color: '#7F7F7F'}},
41-
increasing: {line: {color: '#17BECF'}},
42+
decreasing: {line: {color: COLORS.middleGray}},
43+
increasing: {line: {color: COLORS.blueTeal}},
4244
};
4345
case 'candlestick':
4446
return {
4547
type: 'candlestick',
4648
decreasing: {
47-
line: {color: '#7F7F7F'},
49+
line: {color: COLORS.middleGray},
4850
fillcolor: 'rgba(127, 127, 127, 0.5)',
4951
},
5052
increasing: {
51-
line: {color: '#17BECF'},
53+
line: {color: COLORS.blueTeal},
5254
fillcolor: 'rgba(23, 190, 207, 0.5)',
5355
},
5456
};

0 commit comments

Comments
 (0)