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/ErrorBars.js b/src/components/fields/ErrorBars.js
new file mode 100644
index 000000000..98395189b
--- /dev/null
+++ b/src/components/fields/ErrorBars.js
@@ -0,0 +1,171 @@
+import PropTypes from 'prop-types';
+import React, {Component, Fragment} from 'react';
+import {DataSelector, Radio, Numeric} from '../index';
+import RadioBlocks from '../widgets/RadioBlocks';
+import Field from './Field';
+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,
+ });
+ }
+
+ if (value === 'asymmetric') {
+ this.props.updatePlot({
+ ...this.props.fullValue,
+ visible: true,
+ symmetric: false,
+ });
+ }
+
+ 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 ||
+ 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 === false
+ ) {
+ // it has to be explicitly set to false, because we don't want it to catch
+ // cases when it's undefined
+ mode = 'asymmetric';
+ }
+
+ return mode;
+ }
+
+ renderModeSelector() {
+ 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}
+
+ );
+ }
+
+ if (mode === 'asymmetric') {
+ return (
+
+
+
+
+ {showCustomDataControl ? (
+
+
+
+
+ ) : null}
+
+ );
+ }
+
+ 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 415be998b..e55b7b7ee 100644
--- a/src/components/fields/derived.js
+++ b/src/components/fields/derived.js
@@ -1,8 +1,8 @@
import isNumeric from 'fast-isnumeric';
-import {UnconnectedNumeric} from './Numeric';
import {UnconnectedDropdown} from './Dropdown';
-import {UnconnectedRadio} from './Radio';
import {UnconnectedFlaglist} from './Flaglist';
+import {UnconnectedNumeric} from './Numeric';
+import {UnconnectedRadio} from './Radio';
import {
connectLayoutToPlot,
connectToContainer,
diff --git a/src/components/fields/index.js b/src/components/fields/index.js
index 006cae50e..e9035791d 100644
--- a/src/components/fields/index.js
+++ b/src/components/fields/index.js
@@ -12,6 +12,7 @@ import DataSelector from './DataSelector';
import Numeric from './Numeric';
import SymbolSelector from './SymbolSelector';
import TraceSelector from './TraceSelector';
+import ErrorBars from './ErrorBars';
import {
AnnotationArrowRef,
AnnotationRef,
@@ -40,6 +41,7 @@ export {
ContourNumeric,
DataSelector,
Dropdown,
+ ErrorBars,
FillDropdown,
Flaglist,
FontSelector,
diff --git a/src/components/index.js b/src/components/index.js
index 992556a3b..c367cd500 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -10,6 +10,7 @@ import {
ContourNumeric,
DataSelector,
Dropdown,
+ ErrorBars,
FillDropdown,
Flaglist,
FontSelector,
@@ -63,6 +64,7 @@ export {
ContourNumeric,
DataSelector,
Dropdown,
+ ErrorBars,
FillDropdown,
Flaglist,
Fold,
diff --git a/src/default_panels/GraphCreatePanel.js b/src/default_panels/GraphCreatePanel.js
index 91f466f6c..a29612f86 100644
--- a/src/default_panels/GraphCreatePanel.js
+++ b/src/default_panels/GraphCreatePanel.js
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import {
DataSelector,
Dropdown,
+ ErrorBars,
GeoProjections,
GeoScope,
Radio,
@@ -62,6 +63,18 @@ const GraphCreatePanel = ({localize: _}) => {
+
+
+
+
+
+
diff --git a/src/index.js b/src/index.js
index a1413d085..3eed986d2 100644
--- a/src/index.js
+++ b/src/index.js
@@ -25,6 +25,7 @@ import {
ColorPicker,
ColorscalePicker,
ContourNumeric,
+ ErrorBars,
DataSelector,
Dropdown,
Flaglist,
@@ -75,6 +76,7 @@ export {
ColorPicker,
ColorscalePicker,
ContourNumeric,
+ ErrorBars,
DataSelector,
Dropdown,
EDITOR_ACTIONS,