Skip to content

Commit 2dc6d7a

Browse files
authored
Merge pull request #1020 from plotly/finance
OHLC and Candlestick trace types
2 parents f7a8afa + c9de6c8 commit 2dc6d7a

33 files changed

+5058
-25
lines changed

lib/candlestick.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
module.exports = require('../src/traces/candlestick');

lib/index-finance.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
var Plotly = require('./core');
12+
13+
Plotly.register([
14+
require('./bar'),
15+
require('./histogram'),
16+
require('./pie'),
17+
require('./ohlc'),
18+
require('./candlestick')
19+
]);
20+
21+
module.exports = Plotly;

lib/index.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,22 @@ Plotly.register([
2020
require('./histogram2dcontour'),
2121
require('./pie'),
2222
require('./contour'),
23+
require('./scatterternary'),
24+
2325
require('./scatter3d'),
2426
require('./surface'),
2527
require('./mesh3d'),
28+
2629
require('./scattergeo'),
2730
require('./choropleth'),
31+
2832
require('./scattergl'),
2933
require('./pointcloud'),
30-
require('./scatterternary'),
31-
require('./scattermapbox')
34+
35+
require('./scattermapbox'),
36+
37+
require('./ohlc'),
38+
require('./candlestick')
3239
]);
3340

3441
// transforms

lib/ohlc.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
module.exports = require('../src/traces/ohlc');

src/components/legend/draw.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,10 +367,28 @@ function drawTexts(g, gd) {
367367
.call(textLayout)
368368
.on('edit', function(text) {
369369
this.attr({'data-unformatted': text});
370+
370371
this.text(text)
371372
.call(textLayout);
373+
372374
if(!this.text()) text = ' \u0020\u0020 ';
373-
Plotly.restyle(gd, 'name', text, traceIndex);
375+
376+
var fullInput = legendItem.trace._fullInput || {},
377+
astr;
378+
379+
// N.B. this block isn't super clean,
380+
// is unfortunately untested at the moment,
381+
// and only works for for 'ohlc' and 'candlestick',
382+
// but should be generalized for other one-to-many transforms
383+
if(['ohlc', 'candlestick'].indexOf(fullInput.type) !== -1) {
384+
var transforms = legendItem.trace.transforms,
385+
direction = transforms[transforms.length - 1].direction;
386+
387+
astr = direction + '.legenditem.name';
388+
}
389+
else astr = 'name';
390+
391+
Plotly.restyle(gd, astr, text, traceIndex);
374392
});
375393
}
376394
else text.call(textLayout);

src/lib/coerce.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ var isNumeric = require('fast-isnumeric');
1313
var tinycolor = require('tinycolor2');
1414
var nestedProperty = require('./nested_property');
1515
var isPlainObject = require('./is_plain_object');
16+
var filterUnique = require('./filter_unique');
1617

1718
var getColorscale = require('../components/colorscale/get_scale');
1819
var colorscaleNames = Object.keys(require('../components/colorscale/scales'));
@@ -457,5 +458,17 @@ exports.findArrayAttributes = function(trace) {
457458

458459
exports.crawl(trace._module.attributes, callback);
459460

461+
// Look into the fullInput module attributes for array attributes
462+
// to make sure that 'custom' array attributes are detected.
463+
//
464+
// At the moment, we need this block to make sure that
465+
// ohlc and candlestick 'open', 'high', 'low', 'close' can be
466+
// used with filter ang groupby transforms.
467+
if(trace._fullInput) {
468+
exports.crawl(trace._fullInput._module.attributes, callback);
469+
470+
arrayAttributes = filterUnique(arrayAttributes);
471+
}
472+
460473
return arrayAttributes;
461474
};

src/lib/filter_unique.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
13+
/**
14+
* Return news array containing only the unique items
15+
* found in input array.
16+
*
17+
* IMPORTANT: Note that items are considered unique
18+
* if `String({})` is unique. For example;
19+
*
20+
* Lib.filterUnique([ { a: 1 }, { b: 2 } ])
21+
*
22+
* returns [{ a: 1 }]
23+
*
24+
* and
25+
*
26+
* Lib.filterUnique([ '1', 1 ])
27+
*
28+
* returns ['1']
29+
*
30+
*
31+
* @param {array} array base array
32+
* @return {array} new filtered array
33+
*/
34+
module.exports = function filterUnique(array) {
35+
var seen = {},
36+
out = [],
37+
j = 0;
38+
39+
for(var i = 0; i < array.length; i++) {
40+
var item = array[i];
41+
42+
if(seen[item] !== 1) {
43+
seen[item] = 1;
44+
out[j++] = item;
45+
}
46+
}
47+
48+
return out;
49+
};

src/lib/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ lib.error = loggersModule.error;
7575

7676
lib.notifier = require('./notifier');
7777

78+
lib.filterUnique = require('./filter_unique');
79+
7880
/**
7981
* swap x and y of the same attribute in container cont
8082
* specify attr with a ? in place of x/y

src/plot_api/plot_api.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ Plotly.plot = function(gd, data, layout, config) {
140140

141141
// generate calcdata, if we need to
142142
// to force redoing calcdata, just delete it before calling Plotly.plot
143-
var recalc = !gd.calcdata || gd.calcdata.length !== (gd.data || []).length;
143+
var recalc = !gd.calcdata || gd.calcdata.length !== (gd._fullData || []).length;
144144
if(recalc) Plots.doCalcdata(gd);
145145

146146
// in case it has changed, attach fullData traces to calcdata
@@ -1245,6 +1245,7 @@ function _restyle(gd, aobj, _traces) {
12451245
'histfunc', 'histnorm', 'text',
12461246
'x', 'y', 'z',
12471247
'a', 'b', 'c',
1248+
'open', 'high', 'low', 'close',
12481249
'xtype', 'x0', 'dx', 'ytype', 'y0', 'dy', 'xaxis', 'yaxis',
12491250
'line.width',
12501251
'connectgaps', 'transpose', 'zsmooth',
@@ -1287,7 +1288,8 @@ function _restyle(gd, aobj, _traces) {
12871288
// TODO: could we break this out as well?
12881289
var autorangeAttrs = [
12891290
'marker', 'marker.size', 'textfont',
1290-
'boxpoints', 'jitter', 'pointpos', 'whiskerwidth', 'boxmean'
1291+
'boxpoints', 'jitter', 'pointpos', 'whiskerwidth', 'boxmean',
1292+
'tickwidth'
12911293
];
12921294

12931295
// replotAttrs attributes need a replot (because different

src/plots/plots.js

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ plots.supplyDefaults = function(gd) {
369369

370370
// then do the data
371371
newFullLayout._globalTransforms = (gd._context || {}).globalTransforms;
372-
plots.supplyDataDefaults(newData, newFullData, newFullLayout);
372+
plots.supplyDataDefaults(newData, newFullData, newLayout, newFullLayout);
373373

374374
// attach helper method to check whether a plot type is present on graph
375375
newFullLayout._has = plots._hasPlotType.bind(newFullLayout);
@@ -530,7 +530,7 @@ function relinkPrivateKeys(toContainer, fromContainer) {
530530
var isPlainObject = Lib.isPlainObject,
531531
isArray = Array.isArray;
532532

533-
var keys = Object.keys(fromContainer);
533+
var keys = Object.keys(fromContainer || {});
534534

535535
for(var i = 0; i < keys.length; i++) {
536536
var k = keys[i],
@@ -593,9 +593,9 @@ plots.linkSubplots = function(newFullData, newFullLayout, oldFullData, oldFullLa
593593
}
594594
};
595595

596-
plots.supplyDataDefaults = function(dataIn, dataOut, layout) {
597-
var modules = layout._modules = [],
598-
basePlotModules = layout._basePlotModules = [],
596+
plots.supplyDataDefaults = function(dataIn, dataOut, layout, fullLayout) {
597+
var modules = fullLayout._modules = [],
598+
basePlotModules = fullLayout._basePlotModules = [],
599599
cnt = 0;
600600

601601
function pushModule(fullTrace) {
@@ -612,18 +612,18 @@ plots.supplyDataDefaults = function(dataIn, dataOut, layout) {
612612

613613
for(var i = 0; i < dataIn.length; i++) {
614614
var trace = dataIn[i],
615-
fullTrace = plots.supplyTraceDefaults(trace, cnt, layout);
615+
fullTrace = plots.supplyTraceDefaults(trace, cnt, fullLayout);
616616

617617
fullTrace.index = i;
618618
fullTrace._input = trace;
619619
fullTrace._expandedIndex = cnt;
620620

621621
if(fullTrace.transforms && fullTrace.transforms.length) {
622-
var expandedTraces = applyTransforms(fullTrace, dataOut, layout);
622+
var expandedTraces = applyTransforms(fullTrace, dataOut, layout, fullLayout);
623623

624624
for(var j = 0; j < expandedTraces.length; j++) {
625625
var expandedTrace = expandedTraces[j],
626-
fullExpandedTrace = plots.supplyTraceDefaults(expandedTrace, cnt, layout);
626+
fullExpandedTrace = plots.supplyTraceDefaults(expandedTrace, cnt, fullLayout);
627627

628628
// mutate uid here using parent uid and expanded index
629629
// to promote consistency between update calls
@@ -805,7 +805,7 @@ function supplyTransformDefaults(traceIn, traceOut, layout) {
805805
if(!_module) Lib.warn('Unrecognized transform type ' + type + '.');
806806

807807
if(_module && _module.supplyDefaults) {
808-
transformOut = _module.supplyDefaults(transformIn, traceOut, layout);
808+
transformOut = _module.supplyDefaults(transformIn, traceOut, layout, traceIn);
809809
transformOut.type = type;
810810
}
811811
else {
@@ -816,7 +816,7 @@ function supplyTransformDefaults(traceIn, traceOut, layout) {
816816
}
817817
}
818818

819-
function applyTransforms(fullTrace, fullData, layout) {
819+
function applyTransforms(fullTrace, fullData, layout, fullLayout) {
820820
var container = fullTrace.transforms,
821821
dataOut = [fullTrace];
822822

@@ -830,6 +830,7 @@ function applyTransforms(fullTrace, fullData, layout) {
830830
fullTrace: fullTrace,
831831
fullData: fullData,
832832
layout: layout,
833+
fullLayout: fullLayout,
833834
transformIndex: i
834835
});
835836
}

0 commit comments

Comments
 (0)