| 278 | } |
| 279 | |
| 280 | private prepareBoxPlots() { |
| 281 | // Sets plot data on this.plotData and this.outlierData |
| 282 | const autoDetectOutliers = this.model.get('auto_detect_outliers') !== false; |
| 283 | |
| 284 | // convert the domain data to the boxes to be drawn on the screen |
| 285 | // find the quantiles, min/max and outliers for the box plot |
| 286 | this.plotData = []; |
| 287 | this.outlierData = []; |
| 288 | for (let i = 0; i < this.model.mark_data.length; ++i) { |
| 289 | const values = this.model.mark_data[i]; |
| 290 | |
| 291 | const dataDict = { |
| 292 | x: values[0], |
| 293 | q1: d3.quantile(values[1], 0.25), |
| 294 | q3: d3.quantile(values[1], 0.75), |
| 295 | median: d3.quantile(values[1], 0.5), |
| 296 | }; |
| 297 | |
| 298 | const x = this.scales.x.scale(dataDict.x); |
| 299 | const boxUpper = this.scales.y.scale(dataDict.q3); |
| 300 | const boxLower = this.scales.y.scale(dataDict.q1); |
| 301 | const boxMedian = this.scales.y.scale(dataDict.median); |
| 302 | |
| 303 | // The domain Y to screen Y is an inverse scale, so be aware of that |
| 304 | // The max from the domain Y becomes min on the screen (display) scale |
| 305 | const iqr = boxLower - boxUpper; |
| 306 | const lowerBound = boxLower + 1.5 * iqr; |
| 307 | const upperBound = boxUpper - 1.5 * iqr; |
| 308 | |
| 309 | let whiskerMax = Number.MAX_VALUE; |
| 310 | let whiskerMin = Number.MIN_VALUE; |
| 311 | |
| 312 | for (let j = 0; j < values[1].length; ++j) { |
| 313 | const plotY = this.scales.y.scale(values[1][j]); |
| 314 | |
| 315 | // Find the outlier |
| 316 | if (autoDetectOutliers && (plotY > lowerBound || plotY < upperBound)) { |
| 317 | this.outlierData.push({ |
| 318 | x: this.scales.x.scale(values[0]), |
| 319 | y: plotY, |
| 320 | }); |
| 321 | } else { |
| 322 | // Find the whisker points max and min from normal data. |
| 323 | // ( exclude the outliers ) |
| 324 | if (plotY > whiskerMin) { |
| 325 | whiskerMin = plotY; |
| 326 | } |
| 327 | |
| 328 | if (plotY < whiskerMax) { |
| 329 | whiskerMax = plotY; |
| 330 | } |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | this.plotData.push({ |
| 335 | x, |
| 336 | boxLower, |
| 337 | boxMedian, |