From fd6b3a806d7110b155d95c44eb0ab723b4824a8c Mon Sep 17 00:00:00 2001 From: VeraZab Date: Fri, 9 Feb 2018 10:44:58 -0500 Subject: [PATCH 1/5] Added x | y | z | error bars --- src/components/fields/DataSelector.js | 10 ++++----- src/components/fields/derived.js | 19 ++++++++++++++-- src/components/fields/index.js | 2 ++ src/components/index.js | 2 ++ src/default_panels/GraphCreatePanel.js | 31 ++++++++++++++++++++++++++ src/index.js | 2 ++ 6 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/components/fields/DataSelector.js b/src/components/fields/DataSelector.js index 3007aec7c..6ff1d8778 100644 --- a/src/components/fields/DataSelector.js +++ b/src/components/fields/DataSelector.js @@ -5,11 +5,11 @@ import Field from './Field'; import nestedProperty from 'plotly.js/src/lib/nested_property'; import {connectToContainer} from 'lib'; -function attributeIsData(meta = {}) { +export function attributeIsData(meta = {}) { return meta.valType === 'data_array' || meta.arrayOk; } -class DataSelector extends Component { +export class UnconnectedDataSelector extends Component { constructor(props, context) { super(props, context); @@ -91,14 +91,14 @@ class DataSelector extends Component { } } -DataSelector.propTypes = { +UnconnectedDataSelector.propTypes = { fullValue: PropTypes.any, updatePlot: PropTypes.func, container: PropTypes.object, ...Field.propTypes, }; -DataSelector.contextTypes = { +UnconnectedDataSelector.contextTypes = { dataSources: PropTypes.object, dataSourceOptions: PropTypes.array, dataSourceValueRenderer: PropTypes.func, @@ -111,4 +111,4 @@ function modifyPlotProps(props, context, plotProps) { } } -export default connectToContainer(DataSelector, {modifyPlotProps}); +export default connectToContainer(UnconnectedDataSelector, {modifyPlotProps}); diff --git a/src/components/fields/derived.js b/src/components/fields/derived.js index 415be998b..5ccc527c2 100644 --- a/src/components/fields/derived.js +++ b/src/components/fields/derived.js @@ -1,8 +1,9 @@ import isNumeric from 'fast-isnumeric'; -import {UnconnectedNumeric} from './Numeric'; +import {UnconnectedDataSelector, attributeIsData} from './DataSelector'; import {UnconnectedDropdown} from './Dropdown'; -import {UnconnectedRadio} from './Radio'; import {UnconnectedFlaglist} from './Flaglist'; +import {UnconnectedNumeric} from './Numeric'; +import {UnconnectedRadio} from './Radio'; import { connectLayoutToPlot, connectToContainer, @@ -402,3 +403,17 @@ export const FillDropdown = connectToContainer(UnconnectedDropdown, { plotProps.clearable = false; }, }); + +export const CustomErrorBars = connectToContainer(UnconnectedDataSelector, { + modifyPlotProps: (props, context, plotProps) => { + const errorBar = props.attr.replace('.array', ''); + if ( + attributeIsData(plotProps.attrMeta) && + context.container && + context.container[errorBar] && + context.container[errorBar].visible + ) { + plotProps.isVisible = true; + } + }, +}); diff --git a/src/components/fields/index.js b/src/components/fields/index.js index 006cae50e..ef14bbc96 100644 --- a/src/components/fields/index.js +++ b/src/components/fields/index.js @@ -18,6 +18,7 @@ import { AxesRange, CanvasSize, ContourNumeric, + CustomErrorBars, FillDropdown, GeoProjections, GeoScope, @@ -38,6 +39,7 @@ export { ColorPicker, ColorscalePicker, ContourNumeric, + CustomErrorBars, DataSelector, Dropdown, FillDropdown, diff --git a/src/components/index.js b/src/components/index.js index 992556a3b..4880df166 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -8,6 +8,7 @@ import { ColorPicker, ColorscalePicker, ContourNumeric, + CustomErrorBars, DataSelector, Dropdown, FillDropdown, @@ -61,6 +62,7 @@ export { ColorPicker, ColorscalePicker, ContourNumeric, + CustomErrorBars, DataSelector, Dropdown, FillDropdown, diff --git a/src/default_panels/GraphCreatePanel.js b/src/default_panels/GraphCreatePanel.js index 91f466f6c..70e65f03c 100644 --- a/src/default_panels/GraphCreatePanel.js +++ b/src/default_panels/GraphCreatePanel.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { + CustomErrorBars, DataSelector, Dropdown, GeoProjections, @@ -62,6 +63,36 @@ const GraphCreatePanel = ({localize: _}) => { +
+ + + + + + +
+
diff --git a/src/index.js b/src/index.js index a1413d085..d4c01e1f1 100644 --- a/src/index.js +++ b/src/index.js @@ -25,6 +25,7 @@ import { ColorPicker, ColorscalePicker, ContourNumeric, + CustomErrorBars, DataSelector, Dropdown, Flaglist, @@ -75,6 +76,7 @@ export { ColorPicker, ColorscalePicker, ContourNumeric, + CustomErrorBars, DataSelector, Dropdown, EDITOR_ACTIONS, From 52ac127d15c66992732200433e3d6c61eeb58969 Mon Sep 17 00:00:00 2001 From: VeraZab Date: Fri, 9 Feb 2018 11:12:45 -0500 Subject: [PATCH 2/5] Add arrayminus data_array --- src/components/fields/derived.js | 2 +- src/default_panels/GraphCreatePanel.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/components/fields/derived.js b/src/components/fields/derived.js index 5ccc527c2..62515e81b 100644 --- a/src/components/fields/derived.js +++ b/src/components/fields/derived.js @@ -406,7 +406,7 @@ export const FillDropdown = connectToContainer(UnconnectedDropdown, { export const CustomErrorBars = connectToContainer(UnconnectedDataSelector, { modifyPlotProps: (props, context, plotProps) => { - const errorBar = props.attr.replace('.array', ''); + const errorBar = props.attr.split('.')[0].trim(); if ( attributeIsData(plotProps.attrMeta) && context.container && diff --git a/src/default_panels/GraphCreatePanel.js b/src/default_panels/GraphCreatePanel.js index 70e65f03c..60f45a0bf 100644 --- a/src/default_panels/GraphCreatePanel.js +++ b/src/default_panels/GraphCreatePanel.js @@ -73,6 +73,10 @@ const GraphCreatePanel = ({localize: _}) => { ]} /> + { ]} /> + { ]} /> +
From 2a0c92eb6cdc1cc353a0a45307439b296b91e13a Mon Sep 17 00:00:00 2001 From: VeraZab Date: Sun, 11 Feb 2018 23:01:12 -0500 Subject: [PATCH 3/5] Make one more complete error bars control --- src/components/fields/ErrorBars.js | 112 +++++++++++++++++++++++++ src/components/fields/derived.js | 15 ---- src/components/fields/index.js | 4 +- src/components/index.js | 4 +- src/default_panels/GraphCreatePanel.js | 52 +++--------- src/index.js | 4 +- 6 files changed, 129 insertions(+), 62 deletions(-) create mode 100644 src/components/fields/ErrorBars.js diff --git a/src/components/fields/ErrorBars.js b/src/components/fields/ErrorBars.js new file mode 100644 index 000000000..bd338320e --- /dev/null +++ b/src/components/fields/ErrorBars.js @@ -0,0 +1,112 @@ +import PropTypes from 'prop-types'; +import React, {Component, Fragment} from 'react'; +import {DataSelector, Radio, Numeric} from '../index'; +import {UnconnectedRadio} from './Radio'; +import {connectToContainer} from 'lib'; + +class ErrorBars extends Component { + constructor(props, context) { + super(props, context); + + this.state = { + mode: 'hidden', + }; + + if (props.fullValue.visible) { + if (props.fullValue.symmetric) { + this.state.mode = 'symmetric'; + } else { + this.state.mode = 'custom'; + } + } + } + + renderModeSelector() { + const {localize: _} = this.props; + + return ( + this.setState({mode: value})} + activeOption={this.state.mode} + options={[ + {label: _('Symmetric'), value: 'symmetric'}, + {label: _('Custom'), value: 'custom'}, + {label: _('Disable'), value: 'hidden'}, + ]} + /> + ); + } + + renderErrorBarControls() { + const {localize: _} = this.props; + + if (this.state.mode === 'symmetric') { + if (!this.props.fullValue.visible || !this.props.fullValue.symmetric) { + this.props.updatePlot({ + ...this.props.fullValue, + visible: true, + symmetric: true, + }); + } + + return ( + + + + + ); + } + + if (this.state.mode === 'custom') { + if (!this.props.fullValue.visible || this.props.fullValue.symmetric) { + this.props.updatePlot({ + ...this.props.fullValue, + visible: true, + symmetric: false, + }); + } + + return ( + + + + + ); + } + + return null; + } + + render() { + return ( + + {this.renderModeSelector()} + {this.renderErrorBarControls()} + + ); + } +} + +ErrorBars.propTypes = { + attr: PropTypes.string, + localize: PropTypes.func, + fullValue: PropTypes.object, + updatePlot: PropTypes.func, +}; + +export default connectToContainer(ErrorBars); diff --git a/src/components/fields/derived.js b/src/components/fields/derived.js index 62515e81b..e55b7b7ee 100644 --- a/src/components/fields/derived.js +++ b/src/components/fields/derived.js @@ -1,5 +1,4 @@ import isNumeric from 'fast-isnumeric'; -import {UnconnectedDataSelector, attributeIsData} from './DataSelector'; import {UnconnectedDropdown} from './Dropdown'; import {UnconnectedFlaglist} from './Flaglist'; import {UnconnectedNumeric} from './Numeric'; @@ -403,17 +402,3 @@ export const FillDropdown = connectToContainer(UnconnectedDropdown, { plotProps.clearable = false; }, }); - -export const CustomErrorBars = connectToContainer(UnconnectedDataSelector, { - modifyPlotProps: (props, context, plotProps) => { - const errorBar = props.attr.split('.')[0].trim(); - if ( - attributeIsData(plotProps.attrMeta) && - context.container && - context.container[errorBar] && - context.container[errorBar].visible - ) { - plotProps.isVisible = true; - } - }, -}); diff --git a/src/components/fields/index.js b/src/components/fields/index.js index ef14bbc96..e9035791d 100644 --- a/src/components/fields/index.js +++ b/src/components/fields/index.js @@ -12,13 +12,13 @@ import DataSelector from './DataSelector'; import Numeric from './Numeric'; import SymbolSelector from './SymbolSelector'; import TraceSelector from './TraceSelector'; +import ErrorBars from './ErrorBars'; import { AnnotationArrowRef, AnnotationRef, AxesRange, CanvasSize, ContourNumeric, - CustomErrorBars, FillDropdown, GeoProjections, GeoScope, @@ -39,9 +39,9 @@ export { ColorPicker, ColorscalePicker, ContourNumeric, - CustomErrorBars, DataSelector, Dropdown, + ErrorBars, FillDropdown, Flaglist, FontSelector, diff --git a/src/components/index.js b/src/components/index.js index 4880df166..c367cd500 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -8,9 +8,9 @@ import { ColorPicker, ColorscalePicker, ContourNumeric, - CustomErrorBars, DataSelector, Dropdown, + ErrorBars, FillDropdown, Flaglist, FontSelector, @@ -62,9 +62,9 @@ export { ColorPicker, ColorscalePicker, ContourNumeric, - CustomErrorBars, DataSelector, Dropdown, + ErrorBars, FillDropdown, Flaglist, Fold, diff --git a/src/default_panels/GraphCreatePanel.js b/src/default_panels/GraphCreatePanel.js index 60f45a0bf..a29612f86 100644 --- a/src/default_panels/GraphCreatePanel.js +++ b/src/default_panels/GraphCreatePanel.js @@ -1,9 +1,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - CustomErrorBars, DataSelector, Dropdown, + ErrorBars, GeoProjections, GeoScope, Radio, @@ -63,46 +63,16 @@ const GraphCreatePanel = ({localize: _}) => {
-
- - - - - - - - - +
+ +
+ +
+ +
+ +
+
diff --git a/src/index.js b/src/index.js index d4c01e1f1..3eed986d2 100644 --- a/src/index.js +++ b/src/index.js @@ -25,7 +25,7 @@ import { ColorPicker, ColorscalePicker, ContourNumeric, - CustomErrorBars, + ErrorBars, DataSelector, Dropdown, Flaglist, @@ -76,7 +76,7 @@ export { ColorPicker, ColorscalePicker, ContourNumeric, - CustomErrorBars, + ErrorBars, DataSelector, Dropdown, EDITOR_ACTIONS, From 7156e07166283b4e26913301997061b08e002d99 Mon Sep 17 00:00:00 2001 From: VeraZab Date: Mon, 12 Feb 2018 09:53:42 -0500 Subject: [PATCH 4/5] Remove state --- src/components/fields/ErrorBars.js | 79 ++++++++++++++++++------------ 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/src/components/fields/ErrorBars.js b/src/components/fields/ErrorBars.js index bd338320e..34c28b26a 100644 --- a/src/components/fields/ErrorBars.js +++ b/src/components/fields/ErrorBars.js @@ -7,32 +7,64 @@ import {connectToContainer} from 'lib'; class ErrorBars extends Component { constructor(props, context) { super(props, context); + this.updatePlot = this.updatePlot.bind(this); + } + + updatePlot(value) { + if (value === 'symmetric') { + this.props.updatePlot({ + ...this.props.fullValue, + visible: true, + symmetric: true, + }); + } - this.state = { - mode: 'hidden', - }; + if (value === 'asymmetric') { + this.props.updatePlot({ + ...this.props.fullValue, + visible: true, + symmetric: false, + }); + } - if (props.fullValue.visible) { - if (props.fullValue.symmetric) { - this.state.mode = 'symmetric'; - } else { - this.state.mode = 'custom'; - } + if (value === 'hidden') { + this.props.updatePlot({ + ...this.props.fullValue, + visible: false, + }); } } + getMode() { + let mode; + + if (!this.props.fullValue.visible) { + mode = 'hidden'; + } + + if (this.props.fullValue.visible && this.props.fullValue.symmetric) { + mode = 'symmetric'; + } + + if (this.props.fullValue.visible && !this.props.fullValue.symmetric) { + mode = 'asymmetric'; + } + + return mode; + } + renderModeSelector() { const {localize: _} = this.props; return ( this.setState({mode: value})} - activeOption={this.state.mode} + updatePlot={this.updatePlot} + activeOption={this.getMode()} options={[ {label: _('Symmetric'), value: 'symmetric'}, - {label: _('Custom'), value: 'custom'}, - {label: _('Disable'), value: 'hidden'}, + {label: _('Asymmetric'), value: 'asymmetric'}, + {label: _('Hidden'), value: 'hidden'}, ]} /> ); @@ -40,16 +72,9 @@ class ErrorBars extends Component { renderErrorBarControls() { const {localize: _} = this.props; + const mode = this.getMode(); - if (this.state.mode === 'symmetric') { - if (!this.props.fullValue.visible || !this.props.fullValue.symmetric) { - this.props.updatePlot({ - ...this.props.fullValue, - visible: true, - symmetric: true, - }); - } - + if (mode === 'symmetric') { return ( Date: Mon, 12 Feb 2018 15:02:43 -0500 Subject: [PATCH 5/5] Use RadioBlocks && correct controls --- src/components/fields/ErrorBars.js | 82 ++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/src/components/fields/ErrorBars.js b/src/components/fields/ErrorBars.js index 34c28b26a..98395189b 100644 --- a/src/components/fields/ErrorBars.js +++ b/src/components/fields/ErrorBars.js @@ -1,7 +1,8 @@ import PropTypes from 'prop-types'; import React, {Component, Fragment} from 'react'; import {DataSelector, Radio, Numeric} from '../index'; -import {UnconnectedRadio} from './Radio'; +import RadioBlocks from '../widgets/RadioBlocks'; +import Field from './Field'; import {connectToContainer} from 'lib'; class ErrorBars extends Component { @@ -42,11 +43,24 @@ class ErrorBars extends Component { mode = 'hidden'; } - if (this.props.fullValue.visible && this.props.fullValue.symmetric) { + if ( + this.props.fullValue.visible && + (this.props.fullValue.symmetric || + typeof this.props.fullValue.symmetric === 'undefined') + ) { + // when this.props.fullValue.type === 'sqrt', + // then this.props.fullValue.symmetric is undefined, but 'sqrt' is only + // applicable when we want symmetric error bars + // https://github.com/plotly/plotly.js/issues/2359 mode = 'symmetric'; } - if (this.props.fullValue.visible && !this.props.fullValue.symmetric) { + if ( + this.props.fullValue.visible && + this.props.fullValue.symmetric === false + ) { + // it has to be explicitly set to false, because we don't want it to catch + // cases when it's undefined mode = 'asymmetric'; } @@ -57,36 +71,46 @@ class ErrorBars extends Component { const {localize: _} = this.props; return ( - + + + ); } renderErrorBarControls() { const {localize: _} = this.props; const mode = this.getMode(); + const showCustomDataControl = this.props.fullValue.type === 'data'; if (mode === 'symmetric') { return ( + {showCustomDataControl ? ( + + ) : null} ); } @@ -94,14 +118,32 @@ class ErrorBars extends Component { if (mode === 'asymmetric') { return ( - - + + {showCustomDataControl ? ( + + + + + ) : null} ); }