@@ -38,11 +38,8 @@ module.exports = function calc(gd, trace) {
38
38
for ( var i = 0 ; i < cd . length ; i ++ ) {
39
39
var cdi = cd [ i ] ;
40
40
var vals = cdi . pts . map ( helpers . extractVal ) ;
41
- var len = vals . length ;
42
41
43
- // sample standard deviation
44
- var ssd = Lib . stdev ( vals , len - 1 , cdi . mean ) ;
45
- var bandwidth = cdi . bandwidth = trace . bandwidth || ruleOfThumbBandwidth ( vals , ssd , cdi . q3 - cdi . q1 ) ;
42
+ var bandwidth = cdi . bandwidth = calcBandwidth ( trace , cdi , vals ) ;
46
43
var span = cdi . span = calcSpan ( trace , cdi , valAxis , bandwidth ) ;
47
44
48
45
// step that well covers the bandwidth and is multiple of span distance
@@ -74,13 +71,30 @@ module.exports = function calc(gd, trace) {
74
71
return cd ;
75
72
} ;
76
73
77
- // Default to Silveman's rule of thumb:
74
+ // Default to Silveman's rule of thumb, but if 'too small' use Scott's rule
78
75
// - https://stats.stackexchange.com/a/6671
79
76
// - https://en.wikipedia.org/wiki/Kernel_density_estimation#A_rule-of-thumb_bandwidth_estimator
80
77
// - https://github.com/statsmodels/statsmodels/blob/master/statsmodels/nonparametric/bandwidths.py
81
- function ruleOfThumbBandwidth ( vals , ssd , iqr ) {
78
+ function silvermanRule ( len , ssd , iqr ) {
82
79
var a = Math . min ( ssd , iqr / 1.349 ) ;
83
- return 1.059 * a * Math . pow ( vals . length , - 0.2 ) ;
80
+ return 1.059 * a * Math . pow ( len , - 0.2 ) ;
81
+ }
82
+
83
+ function scottRule ( len , ssd ) {
84
+ return ssd * Math . pow ( len , - 0.2 ) ;
85
+ }
86
+
87
+ function calcBandwidth ( trace , cdi , vals ) {
88
+ if ( trace . bandwidth ) return trace . bandwidth ;
89
+
90
+ var len = vals . length ;
91
+ var ssd = Lib . stdev ( vals , len - 1 , cdi . mean ) ;
92
+ var bw = silvermanRule ( len , ssd , cdi . q3 - cdi . q1 ) ;
93
+
94
+ if ( ( cdi . max - cdi . min ) / bw > 1e5 ) {
95
+ bw = scottRule ( len , ssd ) ;
96
+ }
97
+ return bw ;
84
98
}
85
99
86
100
function calcSpan ( trace , cdi , valAxis , bandwidth ) {
0 commit comments