Skip to content

Commit 4d8616e

Browse files
committed
legendgroup and other legend attrs
1 parent 5627ff8 commit 4d8616e

File tree

7 files changed

+95
-11
lines changed

7 files changed

+95
-11
lines changed

src/components/fields/AxesCreator.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ UnconnectedAxisCreator.propTypes = {
9999
attr: PropTypes.string,
100100
label: PropTypes.string,
101101
options: PropTypes.array,
102-
canAddAxis: PropTypes.bool,
103102
container: PropTypes.object,
104103
fullContainer: PropTypes.object,
105104
updateContainer: PropTypes.func,

src/components/fields/GroupCreator.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import React, {Component} from 'react';
2+
import {connectToContainer} from 'lib';
3+
import Field from './Field';
4+
import Dropdown from './Dropdown';
5+
import PropTypes from 'prop-types';
6+
import Button from '../widgets/Button';
7+
import {PlusIcon} from 'plotly-icons';
8+
9+
class UnconnectedGroupCreator extends Component {
10+
canAddGroup() {
11+
const {fullContainer, attr} = this.props;
12+
const currentGroup = fullContainer[attr];
13+
const currentTraceIndex = fullContainer.index;
14+
15+
return (
16+
!currentGroup ||
17+
this.context.fullData.some(d => d.index !== currentTraceIndex && d[attr] === currentGroup)
18+
);
19+
}
20+
21+
addAndUpdateGroup() {
22+
const allGroups = this.context.fullData
23+
.map(t => parseInt(t[this.props.attr], 10))
24+
.filter(n => Number.isInteger(n));
25+
// don't want to pass empty array to max
26+
allGroups.push(0);
27+
28+
const lastGroupNumber = Math.max.apply(Math, allGroups);
29+
30+
this.props.updatePlot(lastGroupNumber + 1);
31+
}
32+
33+
render() {
34+
const {localize: _, data} = this.context;
35+
const {attr, label, prefix, updatePlot} = this.props;
36+
37+
const options = [{label: _('None'), value: ''}];
38+
const allGroups = [...new Set(data.map(t => t[attr]))].filter(g => Boolean(g));
39+
allGroups.forEach(g => options.push({label: `${prefix} ${g}`, value: g}));
40+
options.sort((a, b) => a.value - b.value);
41+
42+
const icon = <PlusIcon />;
43+
const addButton = this.canAddGroup() ? (
44+
<Button variant="no-text" icon={icon} onClick={() => this.addAndUpdateGroup()} />
45+
) : (
46+
<Button variant="no-text--disabled" icon={icon} onClick={() => {}} />
47+
);
48+
49+
return (
50+
<Dropdown
51+
label={label}
52+
attr={attr}
53+
clearable={false}
54+
options={options}
55+
updatePlot={updatePlot}
56+
extraComponent={addButton}
57+
/>
58+
);
59+
}
60+
}
61+
62+
UnconnectedGroupCreator.propTypes = {
63+
attr: PropTypes.string,
64+
fullContainer: PropTypes.object,
65+
prefix: PropTypes.string,
66+
...Field.propTypes,
67+
};
68+
69+
UnconnectedGroupCreator.contextTypes = {
70+
localize: PropTypes.func,
71+
data: PropTypes.array,
72+
fullData: PropTypes.array,
73+
};
74+
75+
export default connectToContainer(UnconnectedGroupCreator);

src/components/fields/SubplotCreator.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1+
import React, {Component} from 'react';
12
import Dropdown from './Dropdown';
23
import Info from './Info';
34
import PropTypes from 'prop-types';
4-
import React, {Component} from 'react';
55
import {EDITOR_ACTIONS, SUBPLOT_TO_ATTR} from 'lib/constants';
66
import Button from '../widgets/Button';
77
import {PlusIcon} from 'plotly-icons';
88
import {connectToContainer, traceTypeToAxisType, getSubplotTitle} from 'lib';
99
import {PlotlySection} from 'components';
1010

1111
class UnconnectedSingleSubplotCreator extends Component {
12-
canAddAxis() {
12+
canAddSubplot() {
1313
const currentAxisId = this.props.fullContainer[this.props.attr];
1414
const currentTraceIndex = this.props.fullContainer.index;
1515
return this.context.fullData.some(
@@ -62,7 +62,7 @@ class UnconnectedSingleSubplotCreator extends Component {
6262

6363
render() {
6464
const icon = <PlusIcon />;
65-
const extraComponent = this.canAddAxis() ? (
65+
const extraComponent = this.canAddSubplot() ? (
6666
<Button variant="no-text" icon={icon} onClick={() => this.addAndUpdateSubplot()} />
6767
) : (
6868
<Button variant="no-text--disabled" icon={icon} onClick={() => {}} />
@@ -86,7 +86,6 @@ UnconnectedSingleSubplotCreator.propTypes = {
8686
layoutAttr: PropTypes.string,
8787
label: PropTypes.string,
8888
options: PropTypes.array,
89-
canAddAxis: PropTypes.bool,
9089
container: PropTypes.object,
9190
fullContainer: PropTypes.object,
9291
updateContainer: PropTypes.func,

src/components/fields/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import TraceSelector from './TraceSelector';
2121
import ErrorBars from './ErrorBars';
2222
import AxesCreator from './AxesCreator';
2323
import SubplotCreator from './SubplotCreator';
24+
import GroupCreator from './GroupCreator';
2425
import UpdateMenuButtons from './UpdateMenuButtons';
2526
import {FilterOperation, FilterValue} from './FilterOperation';
2627
import MarkerSize from './MarkerSize';
@@ -100,6 +101,7 @@ export {
100101
TraceSelector,
101102
AxesCreator,
102103
SubplotCreator,
104+
GroupCreator,
103105
AxisOverlayDropdown,
104106
AxisSide,
105107
UpdateMenuButtons,

src/components/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
RangesliderVisible,
4040
AxesCreator,
4141
SubplotCreator,
42+
GroupCreator,
4243
SymbolSelector,
4344
TextEditor,
4445
TraceOrientation,
@@ -146,6 +147,7 @@ export {
146147
SingleSidebarItem,
147148
AxesCreator,
148149
SubplotCreator,
150+
GroupCreator,
149151
SymbolSelector,
150152
TextEditor,
151153
SubplotAccordion,

src/default_panels/StyleLegendPanel.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,16 @@ const StyleLegendPanel = (props, {localize: _}) => (
6363
/>
6464
</PlotlySection>
6565
<PlotlySection name={_('Trace Order')}>
66-
<Radio
66+
<Dropdown
6767
attr="legend.traceorder"
6868
options={[
6969
{label: _('Normal'), value: 'normal'},
7070
{label: _('Reversed'), value: 'reversed'},
71+
{label: _('Grouped'), value: 'grouped'},
72+
{label: _('Reversed and Grouped'), value: 'reversed+grouped'},
7173
]}
7274
/>
75+
<Numeric label={_('Gap Between Groups')} attr="legend.tracegroupgap" units="px" />
7376
</PlotlySection>
7477
</PlotlyFold>
7578
</TraceRequiredPanel>

src/default_panels/StyleTracesPanel.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
ErrorBars,
3131
DataSelector,
3232
VisibilitySelect,
33+
GroupCreator,
3334
} from '../components';
3435
import {
3536
BinningNumeric,
@@ -43,12 +44,15 @@ import {
4344
const StyleTracesPanel = (props, {localize: _}) => (
4445
<TraceAccordion canGroup>
4546
<TextEditor label={_('Name')} attr="name" richTextOnly />
46-
<ShowInLegend
47-
label={_('Show in Legend')}
48-
attr="showlegend"
49-
options={[{label: _('Show'), value: true}, {label: _('Hide'), value: false}]}
50-
/>
5147
<NumericFraction label={_('Trace Opacity')} attr="opacity" />
48+
<PlotlySection name={_('Legend')}>
49+
<ShowInLegend
50+
label={_('Show in Legend')}
51+
attr="showlegend"
52+
options={[{label: _('Show'), value: true}, {label: _('Hide'), value: false}]}
53+
/>
54+
<GroupCreator label={_('Legend Group')} prefix={_('Group')} attr="legendgroup" />
55+
</PlotlySection>
5256
<PlotlySection name={_('Cones & Streamtubes')}>
5357
<Numeric label={_('Size')} attr="sizeref" />
5458
<Dropdown

0 commit comments

Comments
 (0)