Skip to content

Commit 6e9244b

Browse files
committed
use Scott's rule to compute the dflt bandwidth
... when Silverman's rule give too small of a results
1 parent 9329a4d commit 6e9244b

File tree

1 file changed

+21
-7
lines changed

1 file changed

+21
-7
lines changed

src/traces/violin/calc.js

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,8 @@ module.exports = function calc(gd, trace) {
3838
for(var i = 0; i < cd.length; i++) {
3939
var cdi = cd[i];
4040
var vals = cdi.pts.map(helpers.extractVal);
41-
var len = vals.length;
4241

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);
4643
var span = cdi.span = calcSpan(trace, cdi, valAxis, bandwidth);
4744

4845
// step that well covers the bandwidth and is multiple of span distance
@@ -74,13 +71,30 @@ module.exports = function calc(gd, trace) {
7471
return cd;
7572
};
7673

77-
// Default to Silveman's rule of thumb:
74+
// Default to Silveman's rule of thumb, but if 'too small' use Scott's rule
7875
// - https://stats.stackexchange.com/a/6671
7976
// - https://en.wikipedia.org/wiki/Kernel_density_estimation#A_rule-of-thumb_bandwidth_estimator
8077
// - https://github.com/statsmodels/statsmodels/blob/master/statsmodels/nonparametric/bandwidths.py
81-
function ruleOfThumbBandwidth(vals, ssd, iqr) {
78+
function silvermanRule(len, ssd, iqr) {
8279
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;
8498
}
8599

86100
function calcSpan(trace, cdi, valAxis, bandwidth) {

0 commit comments

Comments
 (0)