Skip to content

Commit 74e6d4a

Browse files
authored
Merge pull request #804 from plotly/date-axis
Fix date handling
2 parents 9eeb72c + f6bc8e1 commit 74e6d4a

File tree

9 files changed

+98
-12
lines changed

9 files changed

+98
-12
lines changed

src/EditorControls.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
shamefullyAdjustSplitStyleTargetContainers,
1212
shamefullyDeleteRelatedAnalysisTransforms,
1313
shamefullyAdjustSizeref,
14+
shamefullyAdjustBinSize,
1415
} from './shame';
1516
import {EDITOR_ACTIONS} from './lib/constants';
1617
import isNumeric from 'fast-isnumeric';
@@ -72,6 +73,7 @@ class EditorControls extends Component {
7273
}
7374

7475
shamefullyAdjustSizeref(graphDiv, payload);
76+
7577
shamefullyClearAxisTypes(graphDiv, payload);
7678
shamefullyAdjustAxisRef(graphDiv, payload);
7779
shamefullyAddTableColumns(graphDiv, payload);
@@ -80,6 +82,9 @@ class EditorControls extends Component {
8082
for (let i = 0; i < payload.traceIndexes.length; i++) {
8183
for (const attr in payload.update) {
8284
const traceIndex = payload.traceIndexes[i];
85+
86+
shamefullyAdjustBinSize(graphDiv, payload, traceIndex);
87+
8388
const splitTraceGroup = payload.splitTraceGroup
8489
? payload.splitTraceGroup.toString()
8590
: null;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import Field from './Field';
2+
import {UnconnectedNumeric} from './Numeric';
3+
import {UnconnectedText} from './Text';
4+
import PropTypes from 'prop-types';
5+
import React, {Component} from 'react';
6+
import {connectToContainer} from 'lib';
7+
import {isDateTime} from 'plotly.js/src/lib';
8+
import {isJSDate} from 'plotly.js/src/lib/dates';
9+
10+
export class UnconnectedNumericOrDate extends Component {
11+
render() {
12+
const fullValueIsDate =
13+
typeof this.props.fullValue === 'string' &&
14+
(isDateTime(this.props.fullValue) || isJSDate(this.props.fullValue));
15+
16+
return fullValueIsDate ? (
17+
<UnconnectedText {...this.props} placeholder={'yyyy-mm-dd 00:00:00.00'} />
18+
) : (
19+
<UnconnectedNumeric {...this.props} />
20+
);
21+
}
22+
}
23+
24+
UnconnectedNumericOrDate.propTypes = {
25+
defaultValue: PropTypes.any,
26+
fullValue: PropTypes.any,
27+
min: PropTypes.number,
28+
max: PropTypes.number,
29+
multiValued: PropTypes.bool,
30+
hideArrows: PropTypes.bool,
31+
showSlider: PropTypes.bool,
32+
step: PropTypes.number,
33+
fullContainer: PropTypes.object,
34+
updatePlot: PropTypes.func,
35+
...Field.propTypes,
36+
};
37+
38+
export default connectToContainer(UnconnectedNumericOrDate);

src/components/fields/derived.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {UnconnectedDropdown} from './Dropdown';
33
import {UnconnectedDropdownCustom} from './DropdownCustom';
44
import {UnconnectedFlaglist} from './Flaglist';
55
import {UnconnectedNumeric} from './Numeric';
6+
import {UnconnectedNumericOrDate} from './NumericOrDate';
67
import {UnconnectedAxisRangeValue} from './AxisRangeValue';
78
import {UnconnectedRadio} from './Radio';
89
import Info from './Info';
@@ -432,7 +433,7 @@ export const PositioningRef = connectToContainer(UnconnectedDropdown, {
432433
},
433434
});
434435

435-
export const PositioningNumeric = connectToContainer(UnconnectedNumeric, {
436+
export const PositioningNumeric = connectToContainer(UnconnectedNumericOrDate, {
436437
modifyPlotProps: (props, context, plotProps) => {
437438
const {fullContainer, fullValue, updatePlot} = plotProps;
438439
if (
@@ -676,3 +677,15 @@ export const HoverColor = connectToContainer(UnconnectedColorPicker, {
676677
return plotProps;
677678
},
678679
});
680+
681+
export const BinSize = connectToContainer(UnconnectedNumeric, {
682+
modifyPlotProps: (props, context, plotProps) => {
683+
const {localize: _} = context;
684+
if (typeof plotProps.fullValue === 'string' && plotProps.fullValue[0] === 'M') {
685+
plotProps.fullValue = plotProps.fullValue.substring(1);
686+
plotProps.min = 1;
687+
plotProps.max = 12;
688+
plotProps.units = parseInt(plotProps.fullValue, 10) === 1 ? _('Month') : _('Months');
689+
}
690+
},
691+
});

src/components/fields/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Radio from './Radio';
1313
import TextEditor from './TextEditor';
1414
import DataSelector from './DataSelector';
1515
import Numeric from './Numeric';
16+
import NumericOrDate from './NumericOrDate';
1617
import DualNumeric from './DualNumeric';
1718
import AxisRangeValue from './AxisRangeValue';
1819
import Text from './Text';
@@ -55,6 +56,7 @@ import {
5556
HoveronDropdown,
5657
HovermodeDropdown,
5758
TickFormat,
59+
BinSize,
5860
} from './derived';
5961
import {LineDashSelector, LineShapeSelector} from './LineSelectors';
6062

@@ -118,4 +120,6 @@ export {
118120
LocationSelector,
119121
HoveronDropdown,
120122
HovermodeDropdown,
123+
BinSize,
124+
NumericOrDate,
121125
};

src/components/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import {
5757
HoveronDropdown,
5858
HovermodeDropdown,
5959
TickFormat,
60+
NumericOrDate,
6061
} from './fields';
6162

6263
import {
@@ -175,4 +176,5 @@ export {
175176
LocationSelector,
176177
HoveronDropdown,
177178
HovermodeDropdown,
179+
NumericOrDate,
178180
};

src/default_panels/StyleColorbarsPanel.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
FontSelector,
1515
ColorPicker,
1616
VisibilitySelect,
17+
NumericOrDate,
1718
} from '../components';
1819

1920
export const traceHasColorbar = (trace, fullTrace) =>
@@ -211,7 +212,7 @@ const StyleColorBarsPanel = (props, {localize: _}) => {
211212
label={_('Tick spacing')}
212213
/>
213214

214-
<Numeric label={_('Step Offset')} attr={prefix + 'colorbar.tick0'} />
215+
<NumericOrDate label={_('Step Offset')} attr={prefix + 'colorbar.tick0'} />
215216
<Numeric label={_('Step Size')} attr={prefix + 'colorbar.dtick'} />
216217
<Numeric label={_('Max Number of Labels')} attr={prefix + 'colorbar.nticks'} />
217218
</VisibilitySelect>
@@ -239,7 +240,7 @@ const StyleColorBarsPanel = (props, {localize: _}) => {
239240
label={_('Tick spacing')}
240241
/>
241242

242-
<Numeric label={_('Step Offset')} attr={prefix + 'colorbar.tick0'} />
243+
<NumericOrDate label={_('Step Offset')} attr={prefix + 'colorbar.tick0'} />
243244
<Numeric label={_('Step Size')} attr={prefix + 'colorbar.dtick'} />
244245
<Numeric label={_('Max Number of Labels')} attr={prefix + 'colorbar.nticks'} />
245246
</VisibilitySelect>

src/default_panels/StyleNotesPanel.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
Radio,
1414
TextEditor,
1515
PlotlySection,
16+
NumericOrDate,
1617
} from '../components';
1718

1819
const StyleNotesPanel = (props, {localize: _}) => (
@@ -35,8 +36,8 @@ const StyleNotesPanel = (props, {localize: _}) => (
3536
<Numeric label={_('Scale')} step={0.1} attr="arrowsize" units="px" />
3637
<AnnotationArrowRef label={_('X Offset')} attr="axref" />
3738
<AnnotationArrowRef label={_('Y Offset')} attr="ayref" />
38-
<Numeric label={_('X Vector')} attr="ax" />
39-
<Numeric label={_('Y Vector')} attr="ay" />
39+
<NumericOrDate label={_('X Vector')} attr="ax" />
40+
<NumericOrDate label={_('Y Vector')} attr="ay" />
4041
</PlotlySection>
4142
<PlotlySection name={_('Horizontal Positioning')}>
4243
<Dropdown

src/default_panels/StyleTracesPanel.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ import {
3131
DataSelector,
3232
VisibilitySelect,
3333
GroupCreator,
34+
NumericOrDate,
3435
} from '../components';
3536
import {
3637
BinningDropdown,
3738
NumericReciprocal,
3839
ShowInLegend,
3940
TextInfo,
4041
HoveronDropdown,
42+
BinSize,
4143
} from '../components/fields/derived';
4244

4345
const StyleTracesPanel = (props, {localize: _}) => (
@@ -193,18 +195,18 @@ const StyleTracesPanel = (props, {localize: _}) => (
193195
/>
194196
</PlotlySection>
195197
<PlotlySection name={_('Binning')}>
196-
<Numeric label={_('X Bin Start')} attr="xbins.start" axis="x" />
197-
<Numeric label={_('X Bin End')} attr="xbins.end" axis="x" />
198-
<Numeric label={_('X Bin Size')} attr="xbins.size" axis="x" />
198+
<NumericOrDate label={_('X Bin Start')} attr="xbins.start" axis="x" />
199+
<NumericOrDate label={_('X Bin End')} attr="xbins.end" axis="x" />
200+
<BinSize label={_('X Bin Size')} attr="xbins.size" axis="x" />
199201
<Numeric label={_('Max X Bins')} attr="nbinsx" />
200202

201-
<Numeric label={_('Y Bin Start')} attr="ybins.start" axis="y" />
202-
<Numeric label={_('Y Bin End')} attr="ybins.end" axis="y" />
203-
<Numeric label={_('Y Bin Size')} attr="ybins.size" axis="y" />
203+
<NumericOrDate label={_('Y Bin Start')} attr="ybins.start" axis="y" />
204+
<NumericOrDate label={_('Y Bin End')} attr="ybins.end" axis="y" />
205+
<BinSize label={_('Y Bin Size')} attr="ybins.size" axis="y" />
204206
<Numeric label={_('Max Y Bins')} attr="nbinsy" />
205207
</PlotlySection>
206208
<PlotlySection label={_('Bar Position')}>
207-
<Numeric label={_('Base')} attr="base" />
209+
<NumericOrDate label={_('Base')} attr="base" />
208210
<Numeric label={_('Offset')} attr="offset" />
209211
<Numeric label={_('Width')} attr="width" />
210212
</PlotlySection>

src/shame.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44
import {getFromId} from 'plotly.js/src/plots/cartesian/axis_ids';
55
import nestedProperty from 'plotly.js/src/lib/nested_property';
6+
import {isDateTime} from 'plotly.js/src/lib';
67

78
// Temporary fix for:
89
// https://github.com/plotly/react-chart-editor/issues/103
@@ -212,3 +213,22 @@ export const shamefullyAdjustSizeref = (gd, {update}) => {
212213
update['marker.sizemode'] = 'area';
213214
}
214215
};
216+
217+
export const shamefullyAdjustBinSize = (gd, {update}, traceIndexInDataArray) => {
218+
const traceIndexInFullDataArray = gd._fullData.filter(t => t.index === traceIndexInDataArray)[0]
219+
._expandedIndex;
220+
const binSizeAttrs = Object.keys(update).filter(attr => attr.includes('bins.size'));
221+
222+
binSizeAttrs.forEach(attr => {
223+
const attrHead = attr.split('.')[0];
224+
if (
225+
gd._fullData[traceIndexInFullDataArray] &&
226+
gd._fullData[traceIndexInFullDataArray][attrHead] &&
227+
gd._fullData[traceIndexInFullDataArray][attrHead].start &&
228+
isDateTime(gd._fullData[traceIndexInFullDataArray][attrHead].start)
229+
) {
230+
const monthNum = update[attr];
231+
update[attr] = 'M' + monthNum;
232+
}
233+
});
234+
};

0 commit comments

Comments
 (0)