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,