Skip to content

Commit 1fd52c3

Browse files
authored
Merge pull request #1066 from plotly/ohlc-global-offset
ohlc: use all coords on given x-axis to compute min coord diff
2 parents 9468a8c + 612fb3d commit 1fd52c3

File tree

3 files changed

+168
-12
lines changed

3 files changed

+168
-12
lines changed

src/traces/box/set_positions.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ module.exports = function setPositions(gd, plotinfo) {
7474
Axes.minDtick(posAxis, boxdv.minDiff, boxdv.vals[0], true);
7575

7676
// set the width of all boxes
77-
for(i = 0; i < boxlist.length; ++i) {
78-
gd.calcdata[i][0].t.dPos = dPos;
77+
for(i = 0; i < boxlist.length; i++) {
78+
var boxListIndex = boxlist[i];
79+
gd.calcdata[boxListIndex][0].t.dPos = dPos;
7980
}
8081

8182
// autoscale the x axis - including space for points if they're off the side

src/traces/ohlc/transform.js

+43-9
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ exports.calcTransform = function calcTransform(gd, trace, opts) {
121121

122122
var xa = axisIds.getFromTrace(gd, trace, 'x'),
123123
ya = axisIds.getFromTrace(gd, trace, 'y'),
124-
tickWidth = convertTickWidth(trace.x, xa, trace._fullInput.tickwidth);
124+
tickWidth = convertTickWidth(gd, xa, trace);
125125

126126
var open = trace.open,
127127
high = trace.high,
@@ -191,16 +191,50 @@ exports.calcTransform = function calcTransform(gd, trace, opts) {
191191
trace.text = textOut;
192192
};
193193

194-
function convertTickWidth(coords, ax, tickWidth) {
195-
if(coords.length < 2) return tickWidth;
194+
function convertTickWidth(gd, xa, trace) {
195+
var fullInput = trace._fullInput,
196+
tickWidth = fullInput.tickwidth,
197+
minDiff = fullInput._minDiff;
196198

197-
var _coords = coords.map(ax.d2c),
198-
minDTick = Math.abs(_coords[1] - _coords[0]);
199+
if(!minDiff) {
200+
var fullData = gd._fullData,
201+
ohlcTracesOnThisXaxis = [];
199202

200-
for(var i = 1; i < _coords.length - 1; i++) {
201-
var dist = Math.abs(_coords[i + 1] - _coords[i]);
202-
minDTick = Math.min(dist, minDTick);
203+
minDiff = Infinity;
204+
205+
// find min x-coordinates difference of all traces
206+
// attached to this x-axis and stash the result
207+
208+
var i;
209+
210+
for(i = 0; i < fullData.length; i++) {
211+
var _trace = fullData[i]._fullInput;
212+
213+
if(_trace.type === 'ohlc' &&
214+
_trace.visible === true &&
215+
_trace.xaxis === xa._id
216+
) {
217+
ohlcTracesOnThisXaxis.push(_trace);
218+
219+
// - _trace.x may be undefined here,
220+
// it is filled later in calcTransform
221+
//
222+
// - handle trace of length 1 separately.
223+
224+
if(_trace.x && _trace.x.length > 1) {
225+
var _minDiff = Lib.distinctVals(_trace.x.map(xa.d2c)).minDiff;
226+
minDiff = Math.min(minDiff, _minDiff);
227+
}
228+
}
229+
}
230+
231+
// if minDiff is still Infinity here, set it to 1
232+
if(minDiff === Infinity) minDiff = 1;
233+
234+
for(i = 0; i < ohlcTracesOnThisXaxis.length; i++) {
235+
ohlcTracesOnThisXaxis[i]._minDiff = minDiff;
236+
}
203237
}
204238

205-
return minDTick * tickWidth;
239+
return minDiff * tickWidth;
206240
}

test/jasmine/tests/finance_test.js

+122-1
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ describe('finance charts calc transforms:', function() {
512512

513513
expect(out[2].name).toEqual('trace 0 - increasing');
514514
expect(out[2].x.map(ms2DateTime)).toEqual([
515-
'2016-09-03 23:59:59.999', '2016-09-04', '2016-09-04', '2016-09-04', '2016-09-04', '2016-09-04', null
515+
'2016-09-03 22:48', '2016-09-04', '2016-09-04', '2016-09-04', '2016-09-04', '2016-09-04 01:12', null
516516
]);
517517
expect(out[2].y).toEqual([
518518
32.06, 32.06, 34.25, 31.62, 33.18, 33.18, null
@@ -564,6 +564,78 @@ describe('finance charts calc transforms:', function() {
564564
32.87, 33.5, 33.37, 33.37, 33.37, 33.62
565565
]);
566566
});
567+
568+
it('should use the smallest trace minimum x difference to convert *tickwidth* to data coords for all traces attached to a given x-axis', function() {
569+
var trace0 = Lib.extendDeep({}, mock1, {
570+
type: 'ohlc',
571+
tickwidth: 0.5
572+
});
573+
574+
var trace1 = Lib.extendDeep({}, mock1, {
575+
type: 'ohlc',
576+
tickwidth: 0.5
577+
});
578+
579+
// shift time coordinates by 10 hours
580+
trace1.x = trace1.x.map(function(d) {
581+
return d + ' 10:00';
582+
});
583+
584+
var out = _calc([trace0, trace1]);
585+
586+
expect(out[0].x.map(ms2DateTime)).toEqual([
587+
'2016-08-31 12', '2016-09-01', '2016-09-01', '2016-09-01', '2016-09-01', '2016-09-01 12', null,
588+
'2016-09-03 12', '2016-09-04', '2016-09-04', '2016-09-04', '2016-09-04', '2016-09-04 12', null,
589+
'2016-09-05 12', '2016-09-06', '2016-09-06', '2016-09-06', '2016-09-06', '2016-09-06 12', null,
590+
'2016-09-09 12', '2016-09-10', '2016-09-10', '2016-09-10', '2016-09-10', '2016-09-10 12', null
591+
]);
592+
593+
expect(out[1].x.map(ms2DateTime)).toEqual([
594+
'2016-09-01 12', '2016-09-02', '2016-09-02', '2016-09-02', '2016-09-02', '2016-09-02 12', null,
595+
'2016-09-02 12', '2016-09-03', '2016-09-03', '2016-09-03', '2016-09-03', '2016-09-03 12', null,
596+
'2016-09-04 12', '2016-09-05', '2016-09-05', '2016-09-05', '2016-09-05', '2016-09-05 12', null,
597+
'2016-09-06 12', '2016-09-07', '2016-09-07', '2016-09-07', '2016-09-07', '2016-09-07 12', null
598+
]);
599+
600+
expect(out[2].x.map(ms2DateTime)).toEqual([
601+
'2016-08-31 22', '2016-09-01 10', '2016-09-01 10', '2016-09-01 10', '2016-09-01 10', '2016-09-01 22', null,
602+
'2016-09-03 22', '2016-09-04 10', '2016-09-04 10', '2016-09-04 10', '2016-09-04 10', '2016-09-04 22', null,
603+
'2016-09-05 22', '2016-09-06 10', '2016-09-06 10', '2016-09-06 10', '2016-09-06 10', '2016-09-06 22', null,
604+
'2016-09-09 22', '2016-09-10 10', '2016-09-10 10', '2016-09-10 10', '2016-09-10 10', '2016-09-10 22', null
605+
]);
606+
607+
expect(out[3].x.map(ms2DateTime)).toEqual([
608+
'2016-09-01 22', '2016-09-02 10', '2016-09-02 10', '2016-09-02 10', '2016-09-02 10', '2016-09-02 22', null,
609+
'2016-09-02 22', '2016-09-03 10', '2016-09-03 10', '2016-09-03 10', '2016-09-03 10', '2016-09-03 22', null,
610+
'2016-09-04 22', '2016-09-05 10', '2016-09-05 10', '2016-09-05 10', '2016-09-05 10', '2016-09-05 22', null,
611+
'2016-09-06 22', '2016-09-07 10', '2016-09-07 10', '2016-09-07 10', '2016-09-07 10', '2016-09-07 22', null
612+
]);
613+
});
614+
615+
it('should fallback to a minimum x difference of 0.5 in one-item traces', function() {
616+
var trace0 = Lib.extendDeep({}, mock1, {
617+
type: 'ohlc',
618+
tickwidth: 0.5
619+
});
620+
trace0.x = [ '2016-01-01' ];
621+
622+
var trace1 = Lib.extendDeep({}, mock0, {
623+
type: 'ohlc',
624+
tickwidth: 0.5
625+
});
626+
trace1.x = [ 10 ];
627+
628+
var out = _calc([trace0, trace1]);
629+
630+
var x0 = out[0].x;
631+
expect(x0[x0.length - 2] - x0[0]).toEqual(1);
632+
633+
var x2 = out[2].x;
634+
expect(x2[x2.length - 2] - x2[0]).toEqual(1);
635+
636+
expect(out[1].x).toEqual([]);
637+
expect(out[3].x).toEqual([]);
638+
});
567639
});
568640

569641
describe('finance charts updates:', function() {
@@ -780,4 +852,53 @@ describe('finance charts updates:', function() {
780852
done();
781853
});
782854
});
855+
856+
it('Plotly.addTraces + Plotly.relayout should update candlestick box position values', function(done) {
857+
858+
function assertBoxPosFields(dPos) {
859+
expect(gd.calcdata.length).toEqual(dPos.length);
860+
861+
gd.calcdata.forEach(function(calcTrace, i) {
862+
if(dPos[i] === undefined) {
863+
expect(calcTrace[0].t.dPos).toBeUndefined();
864+
}
865+
else {
866+
expect(calcTrace[0].t.dPos).toEqual(dPos[i]);
867+
}
868+
});
869+
}
870+
871+
var trace0 = {
872+
type: 'candlestick',
873+
x: ['2011-01-01'],
874+
open: [0],
875+
high: [3],
876+
low: [1],
877+
close: [3]
878+
};
879+
880+
Plotly.plot(gd, [trace0]).then(function() {
881+
assertBoxPosFields([0.5, undefined]);
882+
883+
return Plotly.addTraces(gd, {});
884+
885+
})
886+
.then(function() {
887+
var update = {
888+
type: 'candlestick',
889+
x: [['2011-02-02']],
890+
open: [[0]],
891+
high: [[3]],
892+
low: [[1]],
893+
close: [[3]]
894+
};
895+
896+
return Plotly.restyle(gd, update);
897+
})
898+
.then(function() {
899+
assertBoxPosFields([0.5, undefined, 0.5, undefined]);
900+
901+
done();
902+
});
903+
});
783904
});

0 commit comments

Comments
 (0)