Skip to content

Commit

Permalink
Allow for multiple color schemes (apache#3295)
Browse files Browse the repository at this point in the history
* Allow for multiple color schemes

1. create ColorSchemeControl component
2. using the same new control component for linear colors

* add color spectum for linear color scheme

* remove dup css

* fix controls setting for linear color scheme

* minor fix by code review comment
  • Loading branch information
Grace Guo authored and mistercrunch committed Aug 17, 2017
1 parent 3c8577b commit b9a2fa4
Show file tree
Hide file tree
Showing 14 changed files with 241 additions and 25 deletions.
2 changes: 2 additions & 0 deletions superset/assets/javascripts/explore/components/Control.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import SelectControl from './controls/SelectControl';
import TextAreaControl from './controls/TextAreaControl';
import TextControl from './controls/TextControl';
import VizTypeControl from './controls/VizTypeControl';
import ColorSchemeControl from './controls/ColorSchemeControl';

const controlMap = {
BoundsControl,
Expand All @@ -21,6 +22,7 @@ const controlMap = {
TextAreaControl,
TextControl,
VizTypeControl,
ColorSchemeControl,
};
const controlTypes = Object.keys(controlMap);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Creatable } from 'react-select';
import ControlHeader from '../ControlHeader';

import { colorScalerFactory } from '../../../modules/colors';

const propTypes = {
description: PropTypes.string,
label: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
onChange: PropTypes.func,
value: PropTypes.string,
default: PropTypes.string,
choices: PropTypes.arrayOf(React.PropTypes.array).isRequired,
schemes: PropTypes.object.isRequired,
isLinear: PropTypes.bool,
};

const defaultProps = {
choices: [],
schemes: {},
onChange: () => {},
};

export default class ColorSchemeControl extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
scheme: this.props.value,
};

this.onChange = this.onChange.bind(this);
this.renderOption = this.renderOption.bind(this);
}

onChange(option) {
const optionValue = option ? option.value : null;
this.props.onChange(optionValue);
this.setState({ scheme: optionValue });
}

renderOption(key) {
const currentScheme = key.value ?
this.props.schemes[key.value] :
this.props.schemes[defaultProps.value];

let colors = currentScheme;
if (this.props.isLinear) {
const colorScaler = colorScalerFactory(currentScheme);
colors = [...Array(20).keys()].map(d => (colorScaler(d / 20)));
}

const list = colors.map((color, i) => (
<li
key={`${currentScheme}-${i}`}
style={{ backgroundColor: color, border: `1px solid ${color === 'white' ? 'black' : color}` }}
>&nbsp;</li>
));
return (<ul className="color-scheme-container">{list}</ul>);
}

render() {
const selectProps = {
multi: false,
name: `select-${this.props.name}`,
placeholder: `Select (${this.props.choices.length})`,
default: this.props.default,
options: this.props.choices.map(choice => ({ value: choice[0], label: choice[1] })),
value: this.props.value,
autosize: false,
clearable: false,
onChange: this.onChange,
optionRenderer: this.renderOption,
valueRenderer: this.renderOption,
};
return (
<div>
<ControlHeader {...this.props} />
<Creatable {...selectProps} />
</div>
);
}
}

ColorSchemeControl.propTypes = propTypes;
ColorSchemeControl.defaultProps = defaultProps;
13 changes: 13 additions & 0 deletions superset/assets/javascripts/explore/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,16 @@
cursor: not-allowed;
border: 1px solid #aaa;
}

.color-scheme-container {
list-style: none;
margin: 0;
padding: 0;
display: flex;
align-items: center;
}
.color-scheme-container li {
flex-basis: 9px;
height: 10px;
margin: 9px 1px;
}
16 changes: 15 additions & 1 deletion superset/assets/javascripts/explore/stores/controls.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { formatSelectOptionsForRange, formatSelectOptions } from '../../modules/utils';
import * as v from '../validators';
import { ALL_COLOR_SCHEMES, spectrums } from '../../modules/colors';
import MetricOption from '../../components/MetricOption';
import ColumnOption from '../../components/ColumnOption';

Expand Down Expand Up @@ -155,7 +156,7 @@ export const controls = {
},

linear_color_scheme: {
type: 'SelectControl',
type: 'ColorSchemeControl',
label: 'Linear Color Scheme',
choices: [
['fire', 'fire'],
Expand All @@ -165,6 +166,9 @@ export const controls = {
],
default: 'blue_white_yellow',
description: '',
renderTrigger: true,
schemes: spectrums,
isLinear: true,
},

normalize_across: {
Expand Down Expand Up @@ -1307,5 +1311,15 @@ export const controls = {
description: 'Leaf nodes that represent fewer than this number of events will be initially ' +
'hidden in the visualization',
},

color_scheme: {
type: 'ColorSchemeControl',
label: 'Color Scheme',
default: 'bnbColors',
renderTrigger: true,
choices: Object.keys(ALL_COLOR_SCHEMES).map(s => ([s, s])),
description: 'The color scheme for rendering chart',
schemes: ALL_COLOR_SCHEMES,
},
};
export default controls;
21 changes: 21 additions & 0 deletions superset/assets/javascripts/explore/stores/visTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ export const sections = {
['slice_id', 'cache_timeout'],
],
},
colorScheme: {
label: 'Color Scheme',
controlSetRows: [
['color_scheme'],
],
},
sqlaTimeSeries: {
label: 'Time',
description: 'Time related form attributes',
Expand Down Expand Up @@ -83,6 +89,7 @@ export const visTypes = {
{
label: 'Chart Options',
controlSetRows: [
['color_scheme'],
['metrics'],
['groupby'],
['columns'],
Expand Down Expand Up @@ -119,6 +126,7 @@ export const visTypes = {
['pie_label_type'],
['donut', 'show_legend'],
['labels_outside'],
['color_scheme'],
],
},
],
Expand All @@ -133,6 +141,7 @@ export const visTypes = {
{
label: 'Chart Options',
controlSetRows: [
['color_scheme'],
['show_brush', 'show_legend'],
['rich_tooltip', null],
['show_markers', 'x_axis_showminmax'],
Expand Down Expand Up @@ -164,6 +173,7 @@ export const visTypes = {
{
label: 'Chart Options',
controlSetRows: [
['color_scheme'],
['x_axis_format'],
],
},
Expand Down Expand Up @@ -204,6 +214,7 @@ export const visTypes = {
{
label: 'Chart Options',
controlSetRows: [
['color_scheme'],
['show_brush', 'show_legend', 'show_bar_value'],
['rich_tooltip', 'contribution'],
['line_interpolation', 'bar_stacked'],
Expand Down Expand Up @@ -237,6 +248,7 @@ export const visTypes = {
{
label: 'Chart Options',
controlSetRows: [
['color_scheme'],
['x_axis_format', 'y_axis_format'],
],
},
Expand All @@ -260,6 +272,7 @@ export const visTypes = {
controlSetRows: [
['show_brush', 'show_legend'],
['line_interpolation', 'stacked_style'],
['color_scheme'],
['rich_tooltip', 'contribution'],
['show_controls', null],
],
Expand Down Expand Up @@ -383,6 +396,7 @@ export const visTypes = {
['series', 'metric', 'limit'],
['size_from', 'size_to'],
['rotation'],
['color_scheme'],
],
},
],
Expand All @@ -401,6 +415,7 @@ export const visTypes = {
{
label: 'Chart Options',
controlSetRows: [
['color_scheme'],
['treemap_ratio'],
['number_format'],
],
Expand Down Expand Up @@ -436,6 +451,7 @@ export const visTypes = {
{
label: 'Chart Options',
controlSetRows: [
['color_scheme'],
['whisker_options'],
],
},
Expand All @@ -455,6 +471,7 @@ export const visTypes = {
{
label: 'Chart Options',
controlSetRows: [
['color_scheme'],
['show_legend', null],
],
},
Expand Down Expand Up @@ -553,6 +570,7 @@ export const visTypes = {
{
label: 'Histogram Options',
controlSetRows: [
['color_scheme'],
['link_length'],
],
},
Expand All @@ -579,6 +597,7 @@ export const visTypes = {
['groupby'],
['metric', 'secondary_metric'],
['row_limit'],
['color_scheme'],
],
},
],
Expand Down Expand Up @@ -609,6 +628,7 @@ export const visTypes = {
['groupby'],
['metric'],
['row_limit'],
['color_scheme'],
],
},
],
Expand Down Expand Up @@ -655,6 +675,7 @@ export const visTypes = {
['groupby', 'columns'],
['metric'],
['row_limit', 'y_axis_format'],
['color_scheme'],
],
},
],
Expand Down
65 changes: 58 additions & 7 deletions superset/assets/javascripts/modules/colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import $ from 'jquery';
import d3 from 'd3';

// Color related utility functions go in this object
export const bnbColors = [
const bnbColors = [
'#ff5a5f', // rausch
'#7b0051', // hackb
'#007A87', // kazan
Expand All @@ -25,8 +25,55 @@ export const bnbColors = [
'#b37e00',
'#988b4e',
];
const d3Category10 = d3.scale.category10().range();
const d3Category20 = d3.scale.category20().range();
const d3Category20b = d3.scale.category20b().range();
const d3Category20c = d3.scale.category20c().range();
const googleCategory10c = [
'#3366cc',
'#dc3912',
'#ff9900',
'#109618',
'#990099',
'#0099c6',
'#dd4477',
'#66aa00',
'#b82e2e',
'#316395',
];
const googleCategory20c = [
'#3366cc',
'#dc3912',
'#ff9900',
'#109618',
'#990099',
'#0099c6',
'#dd4477',
'#66aa00',
'#b82e2e',
'#316395',
'#994499',
'#22aa99',
'#aaaa11',
'#6633cc',
'#e67300',
'#8b0707',
'#651067',
'#329262',
'#5574a6',
'#3b3eac',
];
export const ALL_COLOR_SCHEMES = {
bnbColors,
d3Category10,
d3Category20,
d3Category20b,
d3Category20c,
googleCategory10c,
googleCategory20c,
};

const spectrums = {
export const spectrums = {
blue_white_yellow: [
'#00d1c1',
'white',
Expand All @@ -48,21 +95,25 @@ const spectrums = {
],
};

export const category21 = (function () {
export const getColorFromScheme = (function () {
// Color factory
const seen = {};
return function (s) {
return function (s, scheme) {
if (!s) {
return;
}
const selectedScheme = scheme ? ALL_COLOR_SCHEMES[scheme] : ALL_COLOR_SCHEMES.bnbColors;
let stringifyS = String(s);
// next line is for superset series that should have the same color
stringifyS = stringifyS.replace('---', '');
if (seen[stringifyS] === undefined) {
seen[stringifyS] = Object.keys(seen).length;
if (seen[selectedScheme] === undefined) {
seen[selectedScheme] = {};
}
if (seen[selectedScheme][stringifyS] === undefined) {
seen[selectedScheme][stringifyS] = Object.keys(seen[selectedScheme]).length;
}
/* eslint consistent-return: 0 */
return bnbColors[seen[stringifyS] % bnbColors.length];
return selectedScheme[seen[selectedScheme][stringifyS] % selectedScheme.length];
};
}());

Expand Down
Loading

0 comments on commit b9a2fa4

Please sign in to comment.