Skip to content

Commit 2b831a0

Browse files
authored
Merge pull request #1655 from plotly/pr-1619-ohlc-equal-open-close
OHLC equal open close cases fix
2 parents 9779c96 + dd1f770 commit 2b831a0

File tree

6 files changed

+91
-8
lines changed

6 files changed

+91
-8
lines changed

src/traces/candlestick/transform.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
'use strict';
1111

12+
var isNumeric = require('fast-isnumeric');
13+
1214
var Lib = require('../../lib');
1315
var helpers = require('../ohlc/helpers');
1416

@@ -115,7 +117,7 @@ exports.calcTransform = function calcTransform(gd, trace, opts) {
115117
};
116118

117119
for(var i = 0; i < len; i++) {
118-
if(filterFn(open[i], close[i])) {
120+
if(filterFn(open[i], close[i]) && isNumeric(high[i]) && isNumeric(low[i])) {
119121
appendX(i);
120122
appendY(open[i], high[i], low[i], close[i]);
121123
}

src/traces/ohlc/helpers.js

+32-6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
'use strict';
1111

12+
var isNumeric = require('fast-isnumeric');
13+
1214
var Lib = require('../../lib');
1315

1416
// This routine gets called during the trace supply-defaults step.
@@ -95,14 +97,38 @@ exports.makeTransform = function(traceIn, state, direction) {
9597
};
9698

9799
exports.getFilterFn = function(direction) {
98-
switch(direction) {
99-
case 'increasing':
100-
return function(o, c) { return o <= c; };
100+
return new _getFilterFn(direction);
101+
};
101102

102-
case 'decreasing':
103-
return function(o, c) { return o > c; };
103+
function _getFilterFn(direction) {
104+
// we're optimists - before we have any changing data, assume increasing
105+
var isPrevIncreasing = true;
106+
var cPrev = null;
107+
108+
function _isIncreasing(o, c) {
109+
if(o === c) {
110+
if(c > cPrev) {
111+
isPrevIncreasing = true; // increasing
112+
} else if(c < cPrev) {
113+
isPrevIncreasing = false; // decreasing
114+
}
115+
// else isPrevIncreasing is not changed
116+
}
117+
else isPrevIncreasing = (o < c);
118+
cPrev = c;
119+
return isPrevIncreasing;
104120
}
105-
};
121+
122+
function isIncreasing(o, c) {
123+
return isNumeric(o) && isNumeric(c) && _isIncreasing(+o, +c);
124+
}
125+
126+
function isDecreasing(o, c) {
127+
return isNumeric(o) && isNumeric(c) && !_isIncreasing(+o, +c);
128+
}
129+
130+
return direction === 'increasing' ? isIncreasing : isDecreasing;
131+
}
106132

107133
exports.addRangeSlider = function(data, layout) {
108134
var hasOneVisibleTrace = false;

src/traces/ohlc/transform.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
'use strict';
1111

12+
var isNumeric = require('fast-isnumeric');
13+
1214
var Lib = require('../../lib');
1315
var helpers = require('./helpers');
1416
var Axes = require('../../plots/cartesian/axes');
@@ -195,7 +197,7 @@ exports.calcTransform = function calcTransform(gd, trace, opts) {
195197
};
196198

197199
for(var i = 0; i < len; i++) {
198-
if(filterFn(open[i], close[i])) {
200+
if(filterFn(open[i], close[i]) && isNumeric(high[i]) && isNumeric(low[i])) {
199201
appendX(i);
200202
appendY(open[i], high[i], low[i], close[i]);
201203
appendText(i, open[i], high[i], low[i], close[i]);
-65 Bytes
Loading
Loading

test/jasmine/tests/finance_test.js

+53
Original file line numberDiff line numberDiff line change
@@ -395,14 +395,28 @@ describe('finance charts calc transforms:', function() {
395395
return gd.calcdata.map(calcDatatoTrace);
396396
}
397397

398+
// add some points that shouldn't make it into calcdata because
399+
// one of o, h, l, c is not numeric
400+
function addJunk(trace) {
401+
// x filtering happens in other ways
402+
if(trace.x) trace.x.push(1, 1, 1, 1);
403+
404+
trace.open.push('', 1, 1, 1);
405+
trace.high.push(1, null, 1, 1);
406+
trace.low.push(1, 1, [1], 1);
407+
trace.close.push(1, 1, 1, 'close');
408+
}
409+
398410
it('should fill when *x* is not present', function() {
399411
var trace0 = Lib.extendDeep({}, mock0, {
400412
type: 'ohlc',
401413
});
414+
addJunk(trace0);
402415

403416
var trace1 = Lib.extendDeep({}, mock0, {
404417
type: 'candlestick',
405418
});
419+
addJunk(trace1);
406420

407421
var out = _calc([trace0, trace1]);
408422

@@ -704,6 +718,45 @@ describe('finance charts calc transforms:', function() {
704718
expect(out[1].x).toEqual([]);
705719
expect(out[3].x).toEqual([]);
706720
});
721+
722+
it('should handle cases where \'open\' and \'close\' entries are equal', function() {
723+
var out = _calc([{
724+
type: 'ohlc',
725+
open: [0, 1, 0, 2, 1, 1, 2, 2],
726+
high: [3, 3, 3, 3, 3, 3, 3, 3],
727+
low: [-1, -1, -1, -1, -1, -1, -1, -1],
728+
close: [0, 2, 0, 1, 1, 1, 2, 2],
729+
tickwidth: 0
730+
}, {
731+
type: 'candlestick',
732+
open: [0, 2, 0, 1],
733+
high: [3, 3, 3, 3],
734+
low: [-1, -1, -1, -1],
735+
close: [0, 1, 0, 2]
736+
}]);
737+
738+
expect(out[0].x).toEqual([
739+
0, 0, 0, 0, 0, 0, null,
740+
1, 1, 1, 1, 1, 1, null,
741+
6, 6, 6, 6, 6, 6, null,
742+
7, 7, 7, 7, 7, 7, null
743+
]);
744+
expect(out[1].x).toEqual([
745+
2, 2, 2, 2, 2, 2, null,
746+
3, 3, 3, 3, 3, 3, null,
747+
4, 4, 4, 4, 4, 4, null,
748+
5, 5, 5, 5, 5, 5, null
749+
]);
750+
751+
expect(out[2].x).toEqual([
752+
0, 0, 0, 0, 0, 0,
753+
3, 3, 3, 3, 3, 3
754+
]);
755+
expect(out[3].x).toEqual([
756+
1, 1, 1, 1, 1, 1,
757+
2, 2, 2, 2, 2, 2
758+
]);
759+
});
707760
});
708761

709762
describe('finance charts updates:', function() {

0 commit comments

Comments
 (0)